code:
//
//  ログウィンドウ&蓄積型戦闘ログ ver1.04
//
// ------------------------------------------------------
// Copyright (c) 2016 Yana
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
// ------------------------------------------------------
//
// author Yana
//

var Imported = Imported || {};
Imported['StackBattleLog'] = 1.04;

/*:
 * @plugindesc ver1.04/戦闘ログを蓄積型に変更し、戦闘ログを表示するパーティコマンドを追加します。
 * @author Yana
 *
 * @param Stack Log UseLog
 * @desc パーティコマンドにログのコマンドを追加するかの設定です。
 * true/falseで設定してください。
 * @default true
 *
 * @param Stack Log UseStack
 * @desc 戦闘ログを蓄積型に変更するかの設定です。
 * true/falseで設定してください。
 * @default true
 *
 * @param Stack Log Text
 * @desc パーティコマンドに表示するコマンドの名前です。
 * @default Log
 *
 * @param Stack Log Start
 * @desc ログウィンドウに表示する戦闘開始のテキストです。
 * @default ------Start Battle------
 *
 * @param Stack Log TurnEnd
 * @desc ログウィンドウに表示するターン終了のテキストです。
 * %dをターン数に変換します。
 * @default ------ %d Turn End------
 *
 * @param Stack Log MaxLines
 * @desc 戦闘ログの最大行数です。
 * @default 6
 *
 * @param Stack Log FontSize
 * @desc 戦闘ログ及びログウィンドウの文字サイズです。
 * @default 24
 *
 * @param Stack Log Size
 * @desc 蓄積するログの行数です。
 * @default 100
 *
 * @help このプラグインにはプラグインコマンドはありません。
 * ------------------------------------------------------
 * 仕様
 * ------------------------------------------------------
 * このプラグインは、同時に以下の制御文字を追加します。
 *
 * \FS[FontSize]
 * メッセージなど、drawTextExを使用しているテキストの文字サイズを
 * FontSizeに変更します。
 * この制御文字は\{や\}と違い、最小値、最大値を持ちません。
 * ------------------------------------------------------
 * 利用規約
 * ------------------------------------------------------
 * 当プラグインはMITライセンスで公開されています。
 * 使用に制限はありません。商用、アダルト、いずれにも使用できます。
 * 二次配布も制限はしませんが、サポートは行いません。
 * 著作表示は任意です。行わなくても利用できます。
 * 要するに、特に規約はありません。
 * バグ報告や使用方法等のお問合せはネ実ツクールスレ、または、Twitterにお願いします。
 * https://twitter.com/yanatsuki_
 * 素材利用は自己責任でお願いします。
 * ------------------------------------------------------
 * ver1.04:YEP_MessageCoreとの競合を回避
 * ver1.03:制御文字の変換が正常に行われていないバグを修正
 *		  :100行を超えるログを削除する際、正常に削除できていなかったバグを修正
 *		  :残っていたconsole.logを削除
 * ver1.01:パーティコマンドのログを無効化する設定にしていても、正常に動作しないバグを修正
 * ver1.00:公開
 *
 */

(function() {

	var parameters = PluginManager.parameters('StackBattleLog');
	var stackLogUseLog = String(parameters['Stack Log UseLog'] || "true") == "true";
	var stackLogUseStack = String(parameters['Stack Log UseStack'] || "true") == "true";
	var stackLogText = String(parameters['Stack Log Text'] || "Log");
	var stackLogStart = String(parameters['Stack Log Start'] || "------Start Battle------");
	// %dをターン数に変換します。
	var stackLogTurnEnd = String(parameters['Stack Log TurnEnd'] || "------ %d Turn End------");
	var stackLogMaxLines = Number(parameters['Stack Log LineMax'] || 6);
	var stackLogFontSize = Number(parameters['Stack Log FontSize'] || 24);
	var stackLogSize = Number(parameters['Stack Log Size'] || 24);

	// ログウィンドウの制御に関する部分です。
	Game_Temp.prototype.addLog = function (text){
		this._battleLog = this._battleLog || [];
		if (this._battleLog.length > stackLogSize){
			this._battleLog.shift();
		}
		this._battleLog.push(text);
	};

	Game_Temp.prototype.battleLog = function () {
		return (this._battleLog || []);
	};

	var _stacklogw_Window_BattleLog_addText = Window_BattleLog.prototype.addText;
	Window_BattleLog.prototype.addText = function(text){
		//text = ('00000'+Graphics.frameCount).slice(-6) + ':' + text//
		text = "\\FS[" + stackLogFontSize + "]" + text;
		_stacklogw_Window_BattleLog_addText.call(this,text);
		$gameTemp.addLog(text);
	};

	var _stacklogw_Game_Message_add = Game_Message.prototype.add;
	Game_Message.prototype.add = function(text){
		_stacklogw_Game_Message_add.call(this,text);
		text = "\\FS[" + stackLogFontSize + "]" + text;
		if ($gameParty.inBattle()) { $gameTemp.addLog(text) }
	};

	var _stacklogw_BattleManager_startBattle = BattleManager.startBattle;
	BattleManager.startBattle = function() {
		var text = stackLogStart;
		text = "\\FS[" + stackLogFontSize + "]" + text;
		$gameTemp.addLog(text);
		_stacklogw_BattleManager_startBattle.call(this);
	};

	var _stacklogw_BattleManager_endTurn = BattleManager.endTurn;
	BattleManager.endTurn = function(){
		var text = stackLogTurnEnd;
		text = "\\FS[" + stackLogFontSize + "]" + text;
		text = text.replace(/%d/g,$gameTroop._turnCount);
		$gameTemp.addLog(text);
		_stacklogw_BattleManager_endTurn.call(this);
	};

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

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

	Window_StackLog.prototype.initialize = function(){
		var x = 64;
		var y = 64;
		var width = Graphics.boxWidth - 128;
		var height = Graphics.boxHeight - 128;
		Window_Selectable.prototype.initialize.call(this, x, y, width, height);
		this.openness = 0;
		this.refresh();
	};

	Window_StackLog.prototype.contentsHeight = function() {
		return (this.lineHeight() * this.maxItems());
	};

	Window_StackLog.prototype.maxItems = function() {
		if ($gameTemp.battleLog() == []) {
			return 1;
		}else{
			return $gameTemp.battleLog().length;
		}
	};

	Window_StackLog.prototype.drawItem = function(index)　{
		var text = $gameTemp.battleLog()[index];
		var y = this.lineHeight() * (index - this.topRow());
		if (text){
			this.drawTextEx(text,0,y);
		}
	};

	Window_StackLog.prototype.refresh = function() {
		this.createContents();
		Window_Selectable.prototype.refresh.call(this);
	};
	Window_StackLog.prototype.lineHeight = function() {
		return stackLogFontSize + 8;
	};
	Scene_Battle.prototype.createStackLogWindow = function() {
		this._stackLogWindow = new Window_StackLog();
    	this._stackLogWindow.setHandler('ok',     this.onLogOk.bind(this));
    	this._stackLogWindow.setHandler('cancel', this.onLogOk.bind(this));
		this.addWindow(this._stackLogWindow);
	};
	var _stacklogw_Scene_Battle_createPartyCommandWindow = Scene_Battle.prototype.createPartyCommandWindow;
	Scene_Battle.prototype.createPartyCommandWindow = function() {
		_stacklogw_Scene_Battle_createPartyCommandWindow.call(this);
		if(stackLogUseLog) { this._partyCommandWindow.setHandler('log', this.commandLog.bind(this)) };
	};
	var _stacklogw_Scene_Battle_createAllWindows = Scene_Battle.prototype.createAllWindows;
	Scene_Battle.prototype.createAllWindows = function() {
		_stacklogw_Scene_Battle_createAllWindows.call(this);
		this.createStackLogWindow();
	};

	var _stacklogw_Scene_Battle_isAnyInputWindowActive = Scene_Battle.prototype.isAnyInputWindowActive;
	Scene_Battle.prototype.isAnyInputWindowActive = function() {
		return (_stacklogw_Scene_Battle_isAnyInputWindowActive.call(this) || this._stackLogWindow.active);
    };

	var _stacklogw_Scene_Battle_changeInputWindow = Scene_Battle.prototype.changeInputWindow;
	Scene_Battle.prototype.changeInputWindow = function() {
		if(!this._stackLogWindow.active){
			_stacklogw_Scene_Battle_changeInputWindow.call(this);
		}
	};

	Scene_Battle.prototype.commandLog = function() {
		this._stackLogWindow.refresh();
		this._stackLogWindow.open();
		this._stackLogWindow.activate();
		this._stackLogWindow.select($gameTemp.battleLog().length - 1);
		this._partyCommandWindow.deactivate();
	};

	Scene_Battle.prototype.onLogOk = function() {
		this._stackLogWindow.close();
		this._stackLogWindow.deactivate();
		this._partyCommandWindow.activate();
	};

	var _stacklogw_Window_PartyCommand_makeCommandList = Window_PartyCommand.prototype.makeCommandList;
	Window_PartyCommand.prototype.makeCommandList = function() {
		_stacklogw_Window_PartyCommand_makeCommandList.call(this);
   		if(stackLogUseLog) { this.addCommand(stackLogText,  'log') }
	};

	//　ログをスタック式に変換する部分です。

	// 再定義
	Window_BattleLog.prototype.lineHeight = function() {
		return stackLogFontSize + 8;
	};

	if (stackLogUseStack) { //　蓄積型ログを使用する時のみ定義を行います。
	// エイリアス　ただし、再定義に近い
	var _stacklogw_Window_BattleLog_clear = Window_BattleLog.prototype.clear;
	Window_BattleLog.prototype.clear = function() {
		  this.refresh();
	};
	Window_BattleLog.prototype.logClear = function() {
		_stacklogw_Window_BattleLog_clear.call(this)
	};
	// 再定義
	Window_BattleLog.prototype.maxLines = function() {
		return stackLogMaxLines;
	};
	//　再定義
	Window_BattleLog.prototype.popBaseLine = function() {
	};
	var _stacklogw_Window_BattleLog_refresh = Window_BattleLog.prototype.refresh;
	Window_BattleLog.prototype.refresh = function() {
		var text = "\\FS[" + stackLogFontSize + "]";
		this.drawTextEx(text,0,0,24); // 変更したダミーの文字を送ることでテキストの高さを調整する。
		_stacklogw_Window_BattleLog_refresh.call(this);
	};
	// 再定義
	Window_BattleLog.prototype.drawLineText = function(index) {
		var length = this._lines.length;
		var topLength = length - this.maxLines();
		if (topLength < 0) { topLength = 0 }
		if (index < topLength){ return }
	    var indexPos = index - topLength;
	    var rect = this.itemRectForText(indexPos);

	    this.contents.clearRect(rect.x, rect.y, rect.width, rect.height);
	    this.drawTextEx(this._lines[index], rect.x, rect.y, rect.width);
	};
	var _stacklogw_Window_BattleLog_numLines = Window_BattleLog.prototype.numLines;
	Window_BattleLog.prototype.numLines = function() {
		var n = _stacklogw_Window_BattleLog_numLines.call(this);
		if ( n >= this.maxLines() ) {
			return this.maxLines();
		}else{
			return n;
		}
	};
	var _stacklogw_Scene_Battle_startPartyCommandSelection =  Scene_Battle.prototype.startPartyCommandSelection;
	Scene_Battle.prototype.startPartyCommandSelection = function() {
		_stacklogw_Scene_Battle_startPartyCommandSelection.call(this);
		this._logWindow.logClear();
	};
	var _stacklogw_Scene_Battle_update = Scene_Battle.prototype.update;
	Scene_Battle.prototype.update = function() {
		_stacklogw_Scene_Battle_update.call(this);
		if (BattleManager.isAborting() || BattleManager.isBattleEnd()) { this._logWindow.logClear() };
	};
	}// 蓄積型ログ専用処理はここまでです。

	if (!Imported.YEP_MessageCore) {
		// \FS[FontSize]の制御文字を追加する部分です。
		var _stacklogw_Window_Base_processEscapeCharacter = Window_Base.prototype.processEscapeCharacter;
		Window_Base.prototype.processEscapeCharacter = function (code, textState) {
			if (code === 'FS') {
				this.makeFontSize(this.obtainEscapeParam(textState));
			} else {
				_stacklogw_Window_Base_processEscapeCharacter.call(this, code, textState);
			}
		};
	}
	Window_Base.prototype.makeFontSize = function(fontSize) {
        //if (fontSize >= 96){ fontSize = 96 };
       	//if (fontSize <= 24){ fontSize = 24 };
       	this.contents.fontSize = fontSize;
	};

})();


code:
//
//  ステート付与解除時コモン特徴 ver1.03
//
// ------------------------------------------------------
// Copyright (c) 2016 Yana
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
// ------------------------------------------------------
//
// author yana
//

var Imported = Imported || {};
Imported['StateAddRemoveCommonTrait'] = 1.03;
/*:
 * @plugindesc ver1.03/ステートが付与または解除された時に、コモンイベントを予約する特徴を追加します。
 * @author Yana
 *
 * @param SubjectIndex
 * @desc 起動者のインデックスを格納する変数のIDです。
 * 格納されたインデックスがエネミーの場合、+1000された値が入ります。
 * @default 13
 *
 * @help ------------------------------------------------------
 * プラグインについて
 * ------------------------------------------------------
 *
 * このプラグインは、ステートが付与または解除された時にコモンイベントを予約する機能を、
 * メモを使って特徴を持ったオブジェクトに作ることができるようにします。
 *
 * ------------------------------------------------------
 * 使い方
 * ------------------------------------------------------
 *
 * ・ステート付与時に予約
 * 特徴を持ったオブジェクトのメモに
 * <ステート○付与時コモン:□>
 * または、
 * <AddState○Common:□>
 * と記述すると、○番のステートが付与された際に□番のコモンイベントを予約します。
 *
 * ・ステート解除時に予約
 * 特徴を持ったオブジェクトのメモに
 * <ステート○解除時コモン:□>
 * または、
 * <RemoveState○Common:□>
 * と記述すると、○番のステートが解除された際に□番のコモンイベントを予約します。
 *
 * <ステート○自然解除時コモン:□>
 * または、
 * <AutoRemoveState○Common:□>
 * と記述すると、ターン数による自然解除時のみを対象として□番のコモンイベントを予約できます。
 *
 * ------------------------------------------------------
 * 利用規約
 * ------------------------------------------------------
 * 当プラグインはMITライセンスで公開されています。
 * 使用に制限はありません。商用、アダルト、いずれにも使用できます。
 * 二次配布も制限はしませんが、サポートは行いません。
 * 著作表示は任意です。行わなくても利用できます。
 * 要するに、特に規約はありません。
 * バグ報告や使用方法等のお問合せはネ実ツクールスレ、または、Twitterにお願いします。
 * https://twitter.com/yanatsuki_
 * 素材利用は自己責任でお願いします。
 * ------------------------------------------------------
 * 更新履歴:
 * ver1.03:
 * 同時に予約されたコモンイベントも実行されるように処理を変更。
 * ver1.02:
 * 起動者のインデックスを変数に入れる処理を追加。
 * ver1.01:
 * 死亡時に判定が行われていなかったバグを修正。
 * ver1.00:
 * 公開
 */

(function() {
    ////////////////////////////////////////////////////////////////////////////////////

    var parameters = PluginManager.parameters('StateAddRemoveCommonTrait');
    var subjectIndexVarId = Number(parameters['SubjectIndex']);

    ////////////////////////////////////////////////////////////////////////////////////

    DataManager.stateCommonEvent = function(item, stateId, type) {
        if (!item || !type) return null;
        if (item._stateCommonId && item._stateCommonId[stateId] !== undefined &&
            item._stateCommonId[stateId][type] !== undefined ) {
            return item._stateCommonId[stateId][type];
        }
        item._stateCommonId = item._stateCommonId || {};
        item._stateCommonId[stateId] = { add:null, remove:null };
        if (item.meta['ステート' + stateId + '付与時コモン']) {
            item._stateCommonId[stateId]['add'] = item.meta['ステート' + stateId + '付与時コモン'];
        } else if (item.meta['AddState' + stateId + 'Common']){
            item._stateCommonId[stateId]['add'] = item.meta['AddState' + stateId + 'Common'];
        }
        if (item.meta['ステート' + stateId + '解除時コモン']) {
            item._stateCommonId[stateId]['remove'] = item.meta['ステート' + stateId + '解除時コモン'];
        } else if (item.meta['RemoveState' + stateId + 'Common']){
            item._stateCommonId[stateId]['remove'] = item.meta['RemoveState' + stateId + 'Common'];
        }
        if (item.meta['ステート' + stateId + '自然解除時コモン']) {
            item._stateCommonId[stateId]['autoRemove'] = item.meta['ステート' + stateId + '自然解除時コモン'];
        } else if (item.meta['AutoRemoveState' + stateId + 'Common']){
            item._stateCommonId[stateId]['autoRemove'] = item.meta['AutoRemoveState' + stateId + 'Common'];
        }

        return item._stateCommonId[stateId][type];
    };

    ////////////////////////////////////////////////////////////////////////////////////

    Game_Temp.prototype.setStackCommonEvent = function(ary) {
        if (!this._commonStack) this._commonStack = [];
        this._commonStack.push(ary);
    };

    ////////////////////////////////////////////////////////////////////////////////////

    var __GInterpreter_setupReservedCommonEvent = Game_Interpreter.prototype.setupReservedCommonEvent;
    Game_Interpreter.prototype.setupReservedCommonEvent = function() {
        if (!$gameTemp.isCommonEventReserved() && $gameTemp._commonStack && $gameTemp._commonStack.length > 0) {
            var ci = $gameTemp._commonStack.shift();
            if (subjectIndexVarId) $gameVariables.setValue(subjectIndexVarId, ci[1]);
            $gameTemp.reserveCommonEvent(ci[0]);
        }
        return __GInterpreter_setupReservedCommonEvent.call(this);
    };

    ////////////////////////////////////////////////////////////////////////////////////

    var __GBBase_clearStates = Game_BattlerBase.prototype.clearStates;
    Game_BattlerBase.prototype.clearStates = function() {
        if (this._states) {
            this._states.forEach(function (stateId) {
                this.reserveCommonState(stateId, 'remove');
            }.bind(this));
        }
        __GBBase_clearStates.call(this);
    };

    var __GBBase_addNewState = Game_BattlerBase.prototype.addNewState;
    Game_BattlerBase.prototype.addNewState = function(stateId) {
        __GBBase_addNewState.call(this, stateId);
        this.reserveCommonState(stateId, 'add');
    };

    var __GBBase_eraseState = Game_BattlerBase.prototype.eraseState;
    Game_BattlerBase.prototype.eraseState = function(stateId) {
        __GBBase_eraseState.call(this, stateId);
        if (this._autoRemoveStates && this._autoRemoveStates.contains(stateId)) {
            this.reserveCommonState(stateId, 'autoRemove');
        }
        this.reserveCommonState(stateId, 'remove');
    };

    Game_BattlerBase.prototype.reserveCommonState = function(stateId, type) {
        var id = this.isTriggerStateCommon(stateId, type);
        if (id > 0){
            if (subjectIndexVarId) {
                var index = this.index();
                if (this.isEnemy()) index += 1000;
                $gameVariables.setValue(subjectIndexVarId, index);
            }
            $gameTemp.setStackCommonEvent([id,index]);
        }
    };

    Game_BattlerBase.prototype.isTriggerStateCommon = function(stateId, type) {
        var to = this.traitObjects();
        var v = $gameVariables._data;
        for (var i=0,max=to.length;i<max;i++) {
            var sc = DataManager.stateCommonEvent(to[i], stateId, type);
            if (sc) return eval(sc);
        }
        return 0;
    };

    ////////////////////////////////////////////////////////////////////////////////////

    var __GBattler_removeStatesAuto = Game_Battler.prototype.removeStatesAuto;
    Game_Battler.prototype.removeStatesAuto = function(timing) {
        this._autoRemoveStates = [];
        this.states().forEach(function(state) {
            if (this.isStateExpired(state.id) && state.autoRemovalTiming === timing) {
                this._autoRemoveStates.push(state.id);
            }
        }, this);
        __GBattler_removeStatesAuto.call(this, timing);
        this._autoRemoveStates = [];
    };

    ////////////////////////////////////////////////////////////////////////////////////

}());

repo_name: onms/sister

license: unknown


code:
/*=============================================================================
 StateAfterDeath.js
----------------------------------------------------------------------------
 (C)2018 Triacontane
 This software is released under the MIT License.
 http://opensource.org/licenses/mit-license.php
----------------------------------------------------------------------------
 Version
 1.0.1 2018/08/12 継続ステートが戦闘不能後にターン数で解除されなくなっていた問題を修正
 1.0.0 2018/08/12 初版
----------------------------------------------------------------------------
 [Blog]   : https://triacontane.blogspot.jp/
 [Twitter]: https://twitter.com/triacontane/
 [GitHub] : https://github.com/triacontane/
=============================================================================*/

/*:
 * @plugindesc StateAfterDeathPlugin
 * @author triacontane
 *
 * @param states
 * @desc 戦闘不能後も継続するステートの配列の一覧です。
 * @type state[]
 * @default []
 *
 * @help StateAfterDeath.js
 *
 * 戦闘不能後も解除されず継続するステートを作成できます。
 * パラメータから対象となるステートを指定してください。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc 戦闘不能後継続ステートプラグイン
 * @author トリアコンタン
 *
 * @param states
 * @text 対象ステート
 * @desc 戦闘不能後も継続するステートの配列の一覧です。
 * @type state[]
 * @default []
 *
 * @help StateAfterDeath.js
 *
 * 戦闘不能後も解除されず継続するステートを作成できます。
 * パラメータから対象となるステートを指定してください。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function() {
    'use strict';

    /**
     * Create plugin parameter. param[paramName] ex. param.commandPrefix
     * @param pluginName plugin name(EncounterSwitchConditions)
     * @returns {Object} Created parameter
     */
    var createPluginParameter = function(pluginName) {
        var paramReplacer = function(key, value) {
            if (value === 'null') {
                return value;
            }
            if (value[0] === '"' && value[value.length - 1] === '"') {
                return value;
            }
            try {
                return JSON.parse(value);
            } catch (e) {
                return value;
            }
        };
        var parameter     = JSON.parse(JSON.stringify(PluginManager.parameters(pluginName), paramReplacer));
        PluginManager.setParameters(pluginName, parameter);
        return parameter;
    };

    var param = createPluginParameter('StateAfterDeath');
    if (!param.states) {
        param.states = [];
    }

    var _Game_BattlerBase_die      = Game_BattlerBase.prototype.die;
    Game_BattlerBase.prototype.die = function() {
        var stillStates     = this._states.filter(function(stateId) {
            return param.states.contains(stateId);
        });
        var stillStateTurns = {};
        stillStates.forEach(function(stateId) {
            stillStateTurns[stateId] = this._stateTurns[stateId];
        }, this);
        _Game_BattlerBase_die.apply(this, arguments);
        this._states     = this._states.concat(stillStates);
        this._stateTurns = stillStateTurns;
    };
})();


code:
//=============================================================================
// StepCountCallCommonEvent.js
// ----------------------------------------------------------------------------
// Copyright (c) 2017 n2naokun(柊菜緒)
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.0.2 2018/07/26 メニューからタイトルに戻ると予約したイベントが残るバグを修正
// 1.0.1 2017/11/18 説明文と細かい処理を変更
// 1.0.0 2017/11/17 初版
// ----------------------------------------------------------------------------
// [Twitter]: https://twitter.com/n2naokun/
// [GitHub] : https://github.com/n2naokun/
//=============================================================================

/*:
 * @plugindesc 指定歩数後にコモンイベントを実行するプラグイン
 * ※要SaveVariableCore（今プラグインより先に読み込んでください）
 * @author n2naokun(柊菜緒)
 *
 * @help ※前提となるSaveVariableCoreを導入し、このプラグインより先に読み込んでください。
 * ※SetStepEventにて同じ名前のイベントをセットアップすると一度DelStepEventによって
 *  同名のイベントが一度削除されてから再セットアップされます。
 *
 * プラグインコマンドにて
 * SetStepEvent イベント名 歩数 実行するコモンイベントの番号
 * 歩数イベントをセットアップします。
 * （上手く初期化できなかった場合有効化できません）
 *
 * DelStepEvent イベント名
 * 歩数イベントを削除します。
 *
 * EnableStepEvent イベント名
 * 歩数イベントを可能な場合有効化します。
 * （初期化できていた場合はセットアップ後自動的に有効になっています）
 *
 * DisableStepEvent イベント名
 * 歩数イベントを無効化します。
 * （歩数カウントが停止しますが歩数は保持します）
 *
 * ResetStepEvent イベント名
 * 歩数イベントの歩数をリセットします。
 *
 *
 * スクリプトにて
 * $EVsteps("イベント名")
 * 歩数イベントの現在の歩数を取得します。
 * また、取得に失敗した場合は-1が送られます。
 * ※イベント名はダブルクォーテーション " またはシングルクォーテーション ' で囲むこと。
 *
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

// ESLint向けグローバル変数宣言
/*global ,Imported ,saveObject ,$EVsteps*/

"use strict";//厳格なエラーチェック

(function (_global) {

   // SaveVariableCoreの読み込みチェック
   if (Imported.SaveVariableCore) {
      var Events = new saveObject("StepCountCallCommonEvent");

      var Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
      Game_Interpreter.prototype.pluginCommand = function (command, args) {
         switch (command) {
            case "SetStepEvent":
               Utility.setupEvent(args[0], args[1], args[2]);
               break;

            case "DelStepEvent":
               Utility.deleteEvent(args[0]);
               break;

            case "EnableStepEvent":
               Utility.enableEvent(args[0]);
               break;

            case "DisableStepEvent":
               Utility.disableEvent(args[0]);
               break;

            case "ResetStepEvent":
               Utility.resetEvent(args[0]);
               break;
         }

         Game_Interpreter_pluginCommand.call(this, command, args);
      };

      var Game_Party_increaseSteps = Game_Party.prototype.increaseSteps;
      Game_Party.prototype.increaseSteps = function () {
         Game_Party_increaseSteps.call(this);

         if (Events) {
            for (var EventName in Events.saveParams) {
               Utility.updateEvent(Events.saveParams[EventName]);
            }
         }
      };

   } else {
      // SaveVariableCoreが読み込まれていなかったら警告を出す
      console.error("SaveVariableCoreを読み込んでください");
   }

   var Scene_Title_initialize = Scene_Title.prototype.initialize;
   Scene_Title.prototype.initialize = function () {
      Scene_Title_initialize.call(this);
      if (Events) {
         Events.saveParams = {};
      }
   };

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

   StepEvent.prototype.initialize = function (TargetStep, EventId) {
      this._TargetStep = Number(TargetStep);
      this._EventId = Number(EventId);
      this._steps = 0;
      if (this._TargetStep > 0 && !isNaN(this._TargetStep) && !isNaN(this._EventId)) {
         this._enabled = true;
      } else {
         this._enabled = false;
      }
   };

   window.$EVsteps = function (EventName) {
      if (!EventName || !Events) return -1;
      return Events.saveParams[String(EventName)]._steps;
   };

   function Utility() { }

   Utility.setupEvent = function (EventName, TargetStep, EventId) {
      if (!EventName) return;
      Utility.deleteEvent(EventName);
      if (!Events.saveParams[EventName]) {
         Events.saveParams[EventName] = new StepEvent(TargetStep, EventId);
      }
   };

   Utility.deleteEvent = function (EventName) {
      if (!EventName) return;
      if (Events.saveParams[EventName]) {
         delete Events.saveParams[EventName];
      }
   };

   Utility.enableEvent = function (EventName) {
      if (!EventName) return;
      if (Events.saveParams[EventName]) {
         if (Events.saveParams[EventName]._TargetStep > 0
            && !isNaN(Events.saveParams[EventName]._TargetStep)
            && !isNaN(Events.saveParams[EventName]._EventId)) {

            Events.saveParams[EventName]._enabled = true;
         } else {
            Utility.disableEvent(EventName);
         }
      }
   };

   Utility.disableEvent = function (EventName) {
      if (!EventName) return;
      if (Events.saveParams[EventName]) {
         Events.saveParams[EventName]._enabled = false;
      }
   };

   Utility.resetEvent = function (EventName) {
      if (!EventName) return;
      if (Events.saveParams[EventName]) {
         Events.saveParams[EventName]._steps = 0;
      }
   };

   Utility.updateEvent = function (EVobj) {
      if (EVobj._enabled) {
         EVobj._steps++;

         if (EVobj._steps >= EVobj._TargetStep) {
            EVobj._enabled = false;
            $gameTemp.reserveCommonEvent(EVobj._EventId);
         }
      }
   };

})(this);


code:
//=============================================================================
// StopSelfMovementWithPlayer.js (ver 1.01)
//=============================================================================
// [Change History]
// 2017.Jun     First Release
// 2017.Dec.13  avoid collision with Tsumio's ExpandStatusScene.js

/*:
 * @plugindesc While an event is running, events stop self movement
 * @author Sasuke KANNAZUKI
 *
 * @param Varidate Switch ID
 * @desc It works only when the id's switch is on. If set 0, always works.
 * @default 0
 *
 * @help
 * This plugin does not provide plugin commands.
 *
 * [Summary]
 * At default system, events do self movement even if any event is running.
 * This plugin stops events' self movent during any event is running.
 *
 * Note:
 * - events don't stop self movement if only parallel events are running.
 * - events also stop self movement when message window is opening
 * (ex. when state removed message is displaying).
 * - You can toggle mode by switch set at parameter "Varidate Switch ID".
 *
 * [License]
 * this plugin is released under MIT license.
 * http://opensource.org/licenses/mit-license.php
 */

/*:ja
 * @plugindesc イベント起動中にイベントの自律移動を停止します。
 * @author 神無月サスケ
 *
 * @param Varidate Switch ID
 * @desc このIDのスイッチがONの時に有効になります。0を指定すると常に有効です。
 * @default 0
 *
 * @help
 * このプラグインには、プラグインコマンドはありません。
 *
 * ■概要
 * 通常のシステムでは、イベント起動中も他のイベントは自律移動を続けます。
 * このプラグインは、イベント起動中の自律移動を行わなくします。
 *
 * - 並列イベントのみが起動中の場合は、自律移動はやめません。
 * - イベント起動中以外でも、メッセージウィンドウ表示中は自律移動を行いません。
 * (例：「○○のステートが切れた」というメッセージの表示中)
 * - パラメータ"Varidate Switch ID"のスイッチの操作でゲーム中の機能のON/OFFが
 *  可能です。
 *
 * ■ライセンス表記
 * このプラグインは MIT ライセンスで配布されます。
 * ご自由にお使いください。
 * http://opensource.org/licenses/mit-license.php
 */

(function() {
  //
  // process parameters
  //
  var parameters = PluginManager.parameters('StopSelfMovementWithPlayer');
  var validateSwitchId = Number(parameters['Varidate Switch ID'] || 0);

  //
  // stop self movement routine
  //
  var isStopWithPlayerMode = function () {
    return validateSwitchId === 0 || $gameSwitches.value(validateSwitchId);
  };

  var shouldStopWithPlayer = function () {
    if (isStopWithPlayerMode()) {
      var mw;
      if ($gameMap.isEventRunning()) {
        // when another event is running, stop moving.
        // ex. when the player is inspecting treasure box or talking with NPC.
        return true;
      } else if ((mw = SceneManager._scene._messageWindow) && mw.isOpen()) {
        // ex. when state removed message is displaying, stop moving.
        return true;
      }
    }
    return false;
  };

  var _Game_CharacterBase_updateStop = Game_CharacterBase.prototype.updateStop;
  Game_CharacterBase.prototype.updateStop = function() {
    if (!shouldStopWithPlayer()) {
      _Game_CharacterBase_updateStop.call(this);
    }
  };

  var _Game_Event_updateSelfMovement = Game_Event.prototype.updateSelfMovement;
  Game_Event.prototype.updateSelfMovement = function() {
    if (!shouldStopWithPlayer()) {
      _Game_Event_updateSelfMovement.call(this);
    }
  };

})();


code:
//========================================
// TF_LayeredMap.js
// Version :1.0.4.0
// For : RPGツクールMV (RPG Maker MV)
// -----------------------------------------------
// Copyright : Tobishima-Factory 2018 - 2020
// Website : http://tonbi.jp
//
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
//========================================
/*:
 * @plugindesc Upper[☆]tile display like billboard.
 * @author Tonbi@Tobishima-Factory
 *
 *
 * @param BillboardPriority
 * @type select
 * @option Put it front
 * @value front
 * @option Put it back
 * @value back
 * @desc Put billboard in front or back.
 * @default back
 *
 *
 * @param Autotile
 *
 * @param FillWithNeighborTile
 * @type boolean
 * @on Fill with neighbor tile
 * @off Default lower tile
 * @desc Fill with neighbor tile.It is function for A3 or A4 tile.
 * @default true
 * @parent Autotile
 *
 * @param DefaultLowerTile
 * @type number
 * @min 0
 * @max 127
 * @desc If FillWithNeighborTile option is OFF, fill with this tile.
 * Start with 0 at upper left A5 to right.
 * @default 16
 * @parent Autotile
 *
 * @param UseLayeredCounter
 * @type boolean
 * @on Layered counter
 * @off Normal
 * @desc Counter becomes layered.
 * A2 counter tile can layered like billboard.
 *  (HalfMove.js is needed)
 * @default true
 * @parent Autotile
 *
 * @param IsA2FullCollision
 * @type boolean
 * @on Full collision
 * @off Closed and inside is accessible
 * @desc Entire tile on the ground(A2) collision to activate.
 * @default false
 * @parent Autotile
 *
 * @param IsA3UpperOpen
 * @type boolean
 * @on Open
 * @off Close
 * @desc Remove the south collision of the roof(A3)?
 * @default false
 * @parent Autotile
 *
 * @param IsA4UpperOpen
 * @type boolean
 * @on Open
 * @off Close
 * @desc Remove the south collision of the wall top(A4)?
 * @default false
 * @parent Autotile
 *
 *
 * @param Overpass
 *
 * @param OverpassTerrainTag
 * @type number
 * @min 0
 * @max 7
 * @desc Terraing tag for overpass tile.
 * @default 3
 * @parent Overpass
 *
 * @param CharacterSize
 * @type select
 * @option 1tile size
 * @value 1
 * @option 2tile size
 * @value 2
 * @desc Collision of overpass for.
 * @default 1
 * @parent Overpass
 *
 *
 * @help
 * Alert !!
 * If you use HalfMove.js by Triacontane.Place HalfMove.js before TF_LayeredMap.js.
 * And Place TF_LayeredMap.js before TF_Undulation.js.
 *
 * This plug-in provides the following functions.
 * 　1. [☆]+[4 direction pass] Billboard function for B〜E tile is added.
 * 　2. [TerrainTag] Crosspass function for B〜E tile is added.
 * 　3. [Counter] Billboard function for auto tile is added.
 * 　4. [TerrainTag] Auto tile collision and overpass function for bridge is added.
 * 　5. [Counter] [TerrainTag]  Upper auto tile overpass function is added.
 * 　6. [TerrainTag] [×] The wall top that does not walk for A4 upper tile is added.
 * 　7. [TerrainTag] A5 tile up one layer.
 * 　8. <TF_zDef:Number> Put this tag in the note in event and adjust the overlap.
 * 　9. <TF_higherLevel:Boolean> Put this tag in the note in event and set overpass higher level.
 *
 * 1. set [☆] to BCDE tile, and set 4 direction setting.
 *      0x0 ↑→←↓ : [☆]  Same as no plugin.
 *      0x1 ↑→←・ : billboard, ↑　←→ pass, ground (for fence)
 *      0x2 ↑→・↓ : billboard, ↑↓　→ pass, ground (left side of fence)┃
 *      0x3 ↑→・・ : billboard, ↑　　→ pass, ground (bottom left)┗
 *      0x4 ↑・←↓ : billboard, ↑↓←　 pass, ground (right)   ┃
 *      0x5 ↑・←・ : billboard, ↑　←　 pass, ground (bottom right)   ┛
 *      0x6 ↑・・↓ : billboard, ↑↓　　 pass, ground (both side)┃┃
 *      0x7 ↑・・・ : billboard, ↑　　　 pass, ground (like bartizan)┗┛
 *      0x8 ・→←↓ : billboard,  all directtion , ground (for bush)
 *      0x9 ・→←・ : billboard,  all directtion , 2nd floor
 *      0xA ・→・↓ : billboard,  all directtion , 3rd floor
 *      0xB ・→・・ : Same as [○] and north half blocked (for lower shelf) (HalfMove.js is needed)
 *      0xC ・・←↓ : Same as 0x1 and south half blocked (for Barrel) (HalfMove.js is needed)
 *      0xD ・・←・ : Same as 0xB and collision is half (for lower tree) (HalfMove.js is needed)
 *      0xE ・・・↓ : Same as 0xC and collision is half  (for chair) (HalfMove.js is needed)
 *      0xF ・・・・ : Same as 0x1 and collision is half (for peg)(HalfMove.js is needed)
 *
 * 2. Set TerrainTag to 3(default)
 *      If you enter from blocke direction, you can move under the tile.
 *      If you enter from pass direction, you can move over the tile.
 *
 * 3. For the clif.
 * 　First, set [counter].
 *      A3・A4 odd line(roof・walltop)
 *      　[○] All = upper[☆]
 *      A3・A4 even line(wallside)
 *      　[○] All = billboard, South=can't pass.(floor height set automaticaly)
 *      Common to A3 and A4
 *      　[×] North = billboard, Perimeter = can't pass.
 *
 * 4.  For the bridge or the stairs.
 * 　First, set [TerrainTag:3].
 *      A3 odd line(roof)
 *          [○] SouthNorth = can't pass, WestEast = pass.
 *          [×] SouthNorth = pass under、WestEast = pass over.
 *      A3・A4 even line(wallside)
 *          [○] SouthNorth = pass, WestEast = can't pass.
 *          [×] SouthNorth = pass over, WestEast = pass under.
 *
 * 5.  For the overpass.
 * 　First, set [counter][TerrainTag:3].
 *      A3・A4 odd line(roof・walltop)
 *          [○] All = overpass.
 *          [×] North = overpass, Perimeter = can't pass.
 *
 * 6.  For the wall that does not walk on.
 *      A4 odd line(walltop)
 *          [TerrainTag:3][×] North = upper[☆], All = can't enter.
 *
 * 7. Move up one layer.
 * 　Add [TerrainTag:3] to A5 tile, Set the tile at base layer and target tile up one layer.
 *      The overpass will not work. If the right side of A2 is on the target tile, it will gone.
 *
 * 8. adjust the overlap
 * 　<TF_zDef:Number> Put this tag in the note in event.
 *      Add a number to the y position and set a virtual y position.
 * 　Enter a number greater than 6 (default) to bring the character to the front.
 *
 * 9. set overpass higher level.
 * 　 <TF_higherLevel:Boolean> Put this tag in the note in event.
 * 　true:front(upper)、false:back(lower)
 * 　default:false
 *
 * Released under the MIT License.
 */
/*:ja
 * @plugindesc 高層[☆]タイルを書き割り風に配置する
 * @author とんび@鳶嶋工房
 *
 * @param BillboardPriority
 * @type select
 * @option 手前
 * @value front
 * @option 奥(規定値)
 * @value back
 * @text 奥行き優先度
 * @desc  書き割りの奥・手前配置の設定
 * @default back
 *
 *
 * @param Autotile
 * @text オートタイル
 *
 * @param FillWithNeighborTile
 * @type boolean
 * @on 周辺のタイル
 * @off 補完用規定タイル
 * @text 周辺のタイルでの補完
 * @desc 低層(地面)を北(最南端は南)のタイルで補完するか
 * @default true
 * @parent Autotile
 *
 * @param DefaultLowerTile
 * @type number
 * @min 0
 * @max 127
 * @text 補完用規定タイル
 * @desc [周辺のタイルでの補完]がOFFの場合に使う規定タイル
 * 番号はA5左上を0として右への順。規定値:16(草原)
 * @default 16
 * @parent Autotile
 *
 * @param UseLayeredCounter
 * @type boolean
 * @text カウンター回り込み
 * @on 回り込み
 * @off 通常
 * @desc A2のカウンターの後ろに回り込めるようにするか
 * (HalfMove.js が必要)
 * @default true
 * @parent Autotile
 *
 * @param IsA2FullCollision
 * @type boolean
 * @on 通行止め
 * @off 閉じて内側は通行可
 * @text タイル全体を通行不可にするか
 * @desc A2(地面)のタイル全体を通行不可にするか
 * @default false
 * @parent Autotile
 *
 * @param IsA3UpperOpen
 * @type boolean
 * @on 南を開く
 * @off 閉じて内側は通行可
 * @text 屋根南を開くか
 * @desc A3(屋根)[周囲=通行不可]の場合に、南の衝突判定をなくすか
 * @default false
 * @parent Autotile
 *
 * @param IsA4UpperOpen
 * @type boolean
 * @on 南を開く
 * @off 閉じて内側は通行可
 * @text 壁上面南を開くか
 * @desc A4(壁上上面)[周囲=通行不可]の場合に、南の衝突判定をなくすか
 * @default false
 * @parent Autotile
 *
 *
 * @param Overpass
 * @text 立体交差
 *
 * @param OverpassTerrainTag
 * @type number
 * @min 0
 * @max 7
 * @text 立体交差の地形タグ
 * @desc 立体交差不使用 : 0
 * 立体交差をさせたいタイルに指定する地形タグ
 * @default 3
 * @parent Overpass
 *
 * @param CharacterSize
 * @type select
 * @option 1tile size
 * @value 1
 * @option 2tile size
 * @value 2
 * @desc Collision of overpass for.
 * @text キャラのタイルサイズ
 * @desc 立体交差の衝突判定用のキャラサイズ
 * @default 1
 * @parent Overpass
 *
 *
 * @help
 * 注意 : トリアコンタンさんの HalfMove.js を利用する場合は。
 * TF_LayeredMap.js の前に HalfMove.js を配置するようにしてください。
 * TF_Undulation.js と一緒の場合は、TF_LayeredMap.js が前です。
 *
 * このプラグインは以下の機能を提供します。
 * 　1. [☆]+[通行設定(4方向)]で、B〜Eタイルの重なり機能を追加。
 * 　2. [地形タグ]で、B〜Eタイルの立体交差機能を追加。
 * 　3. [カウンター]で、A3・A4タイルに回り込み機能を追加。
 * 　4. [地形タグ]で、A3・A4タイルに橋の衝突判定と立体交差機能を追加。
 * 　5. [カウンター] [地形タグ] で、A3・A4タイル上面に立体交差機能を追加。
 * 　6. [地形タグ] [×] で、A4上面タイルに上を歩かない壁用の設定。
 * 　7. [地形タグ]で、A5タイルをひとつ上のレイヤーに移動。
 * 　8. <TF_zDef:数値> をイベントのメモに記入して重なりの調整。
 * 　9. <TF_higherLevel:真偽値> をイベントのメモに記入して立体交差の奥手前の指定。
 *   10. TF_HIGHER_LEVEL コマンドで立体交差の奥手前の指定。
 *
 * 1. B〜Eタイルに[☆]を指定したあと、[通行設定(4方向)]
 *      0x0 ↑→←↓ : [☆] 設定、全方向に 通行可(プラグインなしと同じ)
 *      0x1 ↑→←・ : 書き割り、北　西東 通行可、1階 【基本、柵とか】
 *      0x2 ↑→・↓ : 書き割り、北南　東 通行可、1階 （柵の西側とか）┃
 *      0x3 ↑→・・ : 書き割り、北　　東 通行可、1階 （柵の西南とか）┗
 *      0x4 ↑・←↓ : 書き割り、北南西　 通行可、1階 （柵の東側とか）   ┃
 *      0x5 ↑・←・ : 書き割り、北　西　 通行可、1階 （柵の東南とか）   ┛
 *      0x6 ↑・・↓ : 書き割り、北南　　 通行可、1階 （両脇に木とか）┃┃
 *      0x7 ↑・・・ : 書き割り、北　　　 通行可、1階 （張り出し的な）┗┛
 *      0x8 ・→←↓ : 書き割り、全方向に 通行可、1階 （草むらなどに）
 *      0x9 ・→←・ : 書き割り、全方向に 通行可、2階
 *      0xA ・→・↓ : 書き割り、全方向に 通行可、3階
 *      0xB ・→・・ : 地面[○] 設定かつ北半分通行不可 （棚などに）(HalfMove.js が必要)
 *      0xC ・・←↓ : 0x1 と同じだが南半分が通行不可 （机などに）(HalfMove.js が必要)
 *      0xD ・・←・ : 0xB と同じだが北の両脇が通行可 （根元とか）(HalfMove.js が必要)
 *      0xE ・・・↓ : 0xC と同じだが南の両脇が通行可 （椅子とか）(HalfMove.js が必要)
 *      0xF ・・・・ : 0x1 と同じだが南の両脇が通行可 （杭などに）(HalfMove.js が必要)
 *
 * 2. [地形タグ]を3(規定値)に設定
 *      通行設定で侵入可の方向から入ると上を通ります。
 * 　侵入不可の方向から入ると下を通ります。
 *
 * 3. 崖など回り込み用
 * 　[カウンター]設定
 *      A3・A4の奇数列(屋根・壁上面)
 *      　[○] 全体=高層[☆]
 *      A3・A4の偶数列(壁)
 *      　[○] 全体=回り込み、南方向は通行不可(壁の高さは自動調整)
 *      A3・A4に共通
 *      　[×] 北=回り込み、周囲=通行不可
 *
 * 4.  橋の立体交差や階段用
 * 　[地形タグ:3]設定
 *      A3の奇数列(屋根)
 *          [○]南北=通行不可、東西=通行
 *          [×]南北=下通行、東西=上通行(立体交差)
 *      A3・A4の偶数列(壁)
 *          [○]南北=通行、東西=通行不可
 *          [×]南北=上通行、東西=下通行(立体交差)
 *
 * 5.  立体交差
 * 　[カウンター] [地形タグ:3] 設定
 *      A3・A4の奇数列(屋根・壁上面)
 *          [○]全面立体交差
 *          [×]北=立体交差、周囲=通行不可
 *
 * 6.  上を歩かない壁用の設定
 *      A4の奇数列(壁上面)
 *          [地形タグ:3][×] 北=高層[☆]、全面通行不可
 *
 * 7. ひとつ上のレイヤーに移動
 * 　A5タイルに[地形タグ:3] で、背景を補完しA2右側レイヤーに移動。
 *      立体交差は機能しないし、A2右側タイルがあれば消える。
 *
 * 8. 重ね合わせの順番を調節
 * 　<TF_zDef:数値> をイベントのメモに入力。
 * 　数値はy位置に加えられて、仮想的にy位置をずらす。
 * 　キャラ画像は標準環境でy方向に-6ずれているので、例えば8を入れると手前に表示される。
 *
 * 9. 立体交差の奥手前の指定
 * 　<TF_higherLevel:真偽値> をイベントのメモに入力
 * 　trueだと立体交差の手前(上)、falseだと奥(下)に配置される。
 * 　規定値はfalse。
 *
 * 10. プラグインコマンドで立体交差の奥手前の指定。
 * 　TF_HIGHER_LEVEL 真偽値 対象(省略可)
 * 　対象は -2~-4:隊列キャラ、-1:プレイヤーキャラ、0:イベント自身(規定値)、1以降:イベントID
 *
 * 利用規約 : MITライセンス
 */
( function() {
    'use strict';
    const TF_HIGHER_LEVEL = 'TF_HIGHER_LEVEL';

    // flag用定数
    const FLAG_NORTH_DIR = 0x8; // 北の通行設定
    const FLAG_UPPER = 0x10; // 高層[☆]
    const FLAG_COUNTER = 0x80; // カウンター
    // flagのマスク
    const MASK_WITHOUT_DIR_UPPER = 0xFF60; // 方向と高層[☆]とカウンターを除いたもの用マスク
    const MASK_WITHOUT_TAG_DIR_UPPER = 0xF60; // 方向と高層[☆]と地形タグとカウンターを除いたもの用マスク
    const MASK_ALL_DIR = 0xF; // 通行設定用マスク

    // 書割り設定
    const FLOOR2_BOARD = 0x19; // 09 書き割り、全方向に 通行可、2階
    const FLOOR3_BOARD = 0x1A; // 10 書き割り、全方向に 通行可、3階

    const MASK_UPPER_DIR = 0x1F; // 高層[☆]と通行設定用マスク
    const FLOOR1_N_FULL = 0x1B; // 11 棚
    const FLOOR1_S_FULL = 0x1C; // 12 机
    const FLOOR1_N_HALF = 0x1D; // 13 椅子(北)
    const FLOOR1_S_HALF = 0x1E; // 14 椅子(南)
    const FLOOR1_S_FLAT = 0x1F; // 15 杭

    const AUTOTILE_BLOCK = 48; // オートタイル1ブロック分のパターン数

    /*---- パラメータパース関数 ----*/
    const PARAM_TRUE = 'true';
    const PARAM_ON = 'on';
    const TYPE_BOOLEAN = 'boolean';
    const TYPE_NUMBER = 'number';
    /**
     * 指定したパラメータが、指定した値と同じか。
     * @param {String} paramName パラメータ名
     * @param {String} param 比較する値(小文字)
     * @param {Boolean} defaultParam 規定値
     * @returns {Boolean}
     */
    function conpairPluginParam( paramName, param, defaultParam ) {
        if( pluginParams[ paramName ] ) {
            return pluginParams[ paramName ].toLowerCase() === param;
        } else {
            return defaultParam;
        }
    }

    /**
     * 与えられた文字列に変数が指定されていたら、変数の内容に変換して返す。
     * @param {String} value 変換元の文字列( v[n]形式を含む )
     * @return {String} 変換後の文字列
     */
    function treatValue( value ) {
        if( value === undefined || value === '' ) return '0';
        const result = value.match( /v\[(.+)\]/i );
        if( result === null ) return value;
        const id = parseInt( result[ 1 ], 10 );
        if( isNaN( id ) ) {
            return $gameVariables.valueByName( id );
        } else {
            return $gameVariables.value( id );
        }
    }
    /*--- Game_Variables ---*/
    /**
     * 変数を文字列で指定し、値を返す。
     * @param {String} name 変数(ID, 名前, V[n]による指定が可能)
     */
    Game_Variables.prototype.valueByName = function( name ) {
        return this.value( stringToVariableId( name ) );
    };
    /**
     * 指定された変数のIDを返す。
     * @param {String} name 変数(ID, 名前, V[n]による指定が可能)
     */
    function stringToVariableId( name ) {
        name = treatValue( name );
        let i = $dataSystem.variables.findIndex( i => i === name );
        if( 0 <= i ) return i;
        i = parseInt( name, 10 );
        if( isNaN( i ) ) throw new Error( `I can't find the variable '${name}'` );
        return i;
    }

    /**
     * 文字列を整数に変換して返す。
     * @param {String|Number} value
     * @return {Number} 数値に変換した結果
     */
    function parseIntStrict( value ) {
        if( typeof value === TYPE_NUMBER ) return Math.floor( value );
        const result = parseInt( treatValue( value ), 10 );
        if( isNaN( result ) ) throw Error( '指定した値[' + value + ']が数値ではありません。' );
        return result;
    }

    /**
     * 文字列を実数に変換して返す。
     * @param {String|Number} value
     * @return {Number} 数値に変換した結果
     */
    function parseFloatStrict( value ) {
        if( typeof value === 'number' ) return value;
        const result = parseFloat( treatValue( value ) );
        if( isNaN( result ) ) throw Error( '指定した値[' + value + ']が数値ではありません。' );
        return result;
    }

    /**
     * 文字列を真偽値に変換して返す。
     * @param {String|Boolean} value 変換元文字列
     * @returns {Boolean}
     */
    function parseBooleanStrict( value ) {
        if( typeof value === TYPE_BOOLEAN ) return value;
        value = treatValue( value );
        const result = value.toLowerCase();
        return ( result === PARAM_TRUE || result === PARAM_ON );
    }

    /**
     * character を拡張して隊列メンバーも指定できるようにしたもの。
     * @param {Game_Interpreter} interpreter インタプリタ
     * @param {Number} id 拡張イベントID
     * @returns {Game_CharacterBase}
     */
    function getEventById( interpreter, id ) {
        if( id < -1 ) {
            return $gamePlayer.followers().follower( -2 - id );			// 隊列メンバー(0〜2)
        } else {
            return interpreter.character( id );			// プレイヤーキャラおよびイベント
        }
    }

    const EVENT_THIS = 'this';
    const EVENT_SELF = 'self';
    const EVENT_PLAYER = 'player';
    const EVENT_FOLLOWER0 = 'follower0';
    const EVENT_FOLLOWER1 = 'follower1';
    const EVENT_FOLLOWER2 = 'follower2';
    /**
     * 文字列をイベントIDへ変換
     * @param {String} value イベントIDの番号か識別子
     * @returns {Number} 拡張イベントID
     */
    function stringToEventId( value ) {
        value = treatValue( value );
        const result = parseInt( value, 10 );
        if( !isNaN( result ) ) return result;

        const lowValue = value.toLowerCase();
        switch( lowValue ) {
            case EVENT_THIS:
            case EVENT_SELF: return 0;
            case EVENT_PLAYER: return -1;
            case EVENT_FOLLOWER0: return -2;
            case EVENT_FOLLOWER1: return -3;
            case EVENT_FOLLOWER2: return -4;
        }

        // イベント名で指定できるようにする
        const i = $gameMap._events.findIndex( event => {
            if( event === undefined ) return false;	// _events[0] が undefined なので無視

            const eventId = event._eventId;
            return $dataMap.events[ eventId ].name === value;
        } );
        if( i === -1 ) throw Error( `指定したイベント[${value}]がありません。` );
        return i;
    }

    /**
     * パラメータを受け取る
     */
    const pluginParams = PluginManager.parameters( 'TF_LayeredMap' );
    const TF_FillWithNeighborTile = parseBooleanStrict( pluginParams.FillWithNeighborTile );
    const TF_DefaultLowerTileId = Tilemap.TILE_ID_A5 + parseIntStrict( pluginParams.DefaultLowerTile );
    const TF_UseLayeredCounter = parseBooleanStrict( pluginParams.UseLayeredCounter );
    const TF_BillboardPriority = conpairPluginParam( 'BillboardPriority', 'front', false ) ? Infinity : -Infinity;
    const TF_IsA2FullCollision = parseBooleanStrict( pluginParams.IsA2FullCollision );
    const TF_IsA3UpperOpen = parseBooleanStrict( pluginParams.IsA3UpperOpen );
    const TF_IsA4UpperOpen = parseBooleanStrict( pluginParams.IsA4UpperOpen );
    const TF_OverpassTerrainTag = parseIntStrict( pluginParams.OverpassTerrainTag );
    const TF_CharacterSize = parseIntStrict( pluginParams.CharacterSize );

    /*---- SceneManager ----*/
    // URLでの指定がない限り、WebGL モードを採用する。
    const MODE_CANVAS = 'canvas';
    const MODE_WEBGL = 'webgl';
    SceneManager.preferableRendererType = function() {
        return ( Utils.isOptionValid( MODE_CANVAS ) ) ? MODE_CANVAS : MODE_WEBGL;
    };

    /*---- Game_Interpreter ----*/
    /**
     * プラグインコマンドの実行
     */
    const _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
    Game_Interpreter.prototype.pluginCommand = function( command, args ) {
        _Game_Interpreter_pluginCommand.apply( this, arguments );

        // _higherLevel のON/OFF
        if( command.toUpperCase() !== TF_HIGHER_LEVEL ) return;

        const targetCharacter = getEventById( this, stringToEventId( args[ 1 ] ) );
        targetCharacter._higherLevel = parseBooleanStrict( args[ 0 ] );
    };

    /*---- Tilemap ----*/
    /**
     * その位置が立体交差であるかチェック(地形タグで決定)
     */
    const _Tilemap_isOverpassPosition = Tilemap.prototype._isOverpassPosition;
    Tilemap.prototype._isOverpassPosition = function( x, y ) {
        if( TF_OverpassTerrainTag !== 0 && $gameMap.terrainTag( x, y ) === TF_OverpassTerrainTag ) return true;
        return _Tilemap_isOverpassPosition.apply( this, arguments );
    };

    /**
     * イベントの重なりのソート用関数。
     */
    Tilemap.prototype._compareChildOrder = function( a, b ) {
        if( a.z !== b.z ) return a.z - b.z;
        const zDefA = a._character ? a._character._TF_zDef : 0;
        const zDefB = b._character ? b._character._TF_zDef : 0;
        const ay = a.y + ( zDefA ? zDefA : 0 );
        const by = b.y + ( zDefB ? zDefB : 0 );
        if( ay !== by ) {
            return ay - by;
        }
        return a.spriteId - b.spriteId;
    };

    /*---- ShaderTilemap ----*/
    /**
     * タイルセットの画像を設定する。
     * マップ開始時に呼ばれる。
     */
    const _ShaderTilemap_refreshTileset = ShaderTilemap.prototype.refreshTileset;
    ShaderTilemap.prototype.refreshTileset = function() {
        _ShaderTilemap_refreshTileset.call( this );

        // BitmapをPIXI.Textureにコンバート
        const bitmaps = this.bitmaps.map( function( x ) {
            return x._baseTexture ? new PIXI.Texture( x._baseTexture ) : x;
        } );

        // 書き割りのタイルセットの画像をアップデート
        for( let curItem of this.TF_billboards ) {
            curItem.children[ 0 ].setBitmaps( bitmaps );
        }
    };

    /**
     * 書き割りレイヤーの生成と追加。
     */
    const _ShaderTilemap_createLayers = ShaderTilemap.prototype._createLayers;
    ShaderTilemap.prototype._createLayers = function() {
        _ShaderTilemap_createLayers.call( this );

        // 書き割り風オブジェクトを生成
        // +3 はスクロールの際にはみ出す部分と2・3階用
        const th = this._tileHeight;
        const tileRows = Math.ceil( this._height / th ) + 3;

        if( !this.hasOwnProperty( 'TF_billboards' ) ) {
            this.TF_billboards = [];
        }

        for( let i = 0; i < tileRows; i++ ) {
            const billboard = new PIXI.tilemap.ZLayer( this, 3 );
            billboard.spriteId = TF_BillboardPriority;
            this.addChild( billboard );
            this.TF_billboards.push( billboard );
            const layer = new PIXI.tilemap.CompositeRectTileLayer( 0, [], 0 );
            billboard.addChild( layer );
        }
    };

    /**
     * 描画前に書き割りの中を空にしておく。
     */
    const _ShaderTilemap_paintAllTiles = ShaderTilemap.prototype._paintAllTiles;
    ShaderTilemap.prototype._paintAllTiles = function( startX, startY ) {
        for( let curItem of this.TF_billboards ) {
            curItem.clear();
        }

        _ShaderTilemap_paintAllTiles.apply( this, arguments );
    };

    /**
     * タイルマップと書き割りの描画。
     * 関数をまるっと書き換えているので
     * 他のプラグインとコンフリクトを起こしてしまうので注意。
     * @param {Number} startX 開始 マップ x座標(タイル数)
     * @param {Number} startY 開始 マップ y座標(タイル数)
     * @param {Number} x 画面上の x座標(タイル数)
     * @param {Number} y 画面上の y座標(タイル数)
     */
    ShaderTilemap.prototype._paintTiles = function( startX, startY, x, y ) {
        const mx = startX + x; //  描画対象のマップ x座標(タイル数)
        const my = startY + y; //  描画対象のマップ y座標(タイル数)
        const dx = x * this._tileWidth; //  描画位置の x座標(ピクセル)
        const dy = y * this._tileHeight; //  描画位置の y座標(ピクセル)
        const tileId0 = this._readMapData( mx, my, 0 ); // 低層タイルA
        const tileId1 = this._readMapData( mx, my, 1 ); // 低層タイルA2右側など
        const tileId2 = this._readMapData( mx, my, 2 ); // B 〜 E タイル
        const tileId3 = this._readMapData( mx, my, 3 ); // B 〜 E タイル
        const shadowBits = this._readMapData( mx, my, 4 ); // 影ペン
        const northTileId1 = this._readMapData( mx, my - 1, 1 ); // 北位置の低層タイルA
        const lowerLayer = this.lowerLayer.children[ 0 ];     // 低層レイヤ( z: 0 )
        const upperLayer = this.upperLayer.children[ 0 ];   // 高層レイヤ( z: 4 )

        /**
         * タイルを描画(upperLayer,lowerLayer,dx,dy は親の変数を使う)
         * @param {Number} tileId タイルID
         */
        const drawTile = ( tileId ) => {
            if( !this._isHigherTile( tileId )
                || ( this.flags[ tileId ] & MASK_UPPER_DIR ) === FLOOR1_N_FULL
                || ( this.flags[ tileId ] & MASK_UPPER_DIR ) === FLOOR1_N_HALF
            ) {
                // 高層タイルではない
                this._drawTile( lowerLayer, tileId, dx, dy );
                return;
            }

            // 優先階(priorityFloor)を設定
            let priorityFloor;
            if( ( this.flags[ tileId ] & MASK_UPPER_DIR ) === FLOOR2_BOARD ) {
                priorityFloor = 2;
            } else if( ( this.flags[ tileId ] & MASK_UPPER_DIR ) === FLOOR3_BOARD ) {
                priorityFloor = 3;
            } else {
                priorityFloor = 1;
            }

            let floorNumber = 1;
            if( priorityFloor === 2 || priorityFloor === 3 ) {
                const wallSideType = getWallSideType( this._readMapData( mx, my + 1, 1 ) );

                if( wallSideType === 1 ) {
                    floorNumber = 2;
                } else if( wallSideType === 2 ) {
                    floorNumber = 3;
                } else if( wallSideType === 3 ) {
                    floorNumber = priorityFloor;
                } else {
                    // 壁ではない場合
                    floorNumber = priorityFloor;
                    // TODO : B〜E タイルのオート位置設定を行う…か?
                }
            }

            if( floorNumber === 2 ) {
                // 2階設定は、ひとつ下の書き割りに書き込む
                this._drawTile( this.TF_billboards[ y + 1 ].children[ 0 ].children[ 0 ], tileId, dx, -this._tileHeight * 2 );

            } else if( floorNumber === 3 ) {
                // 3階設定は、ふたつ下の書き割りに書き込む
                this._drawTile( this.TF_billboards[ y + 2 ].children[ 0 ].children[ 0 ], tileId, dx, -this._tileHeight * 3 );

            } else if( this.flags[ tileId ] & MASK_ALL_DIR ) {
                // 通行不可設定のどれかがONだと書き割り
                this._drawTile( this.TF_billboards[ y ].children[ 0 ].children[ 0 ], tileId, dx, -this._tileHeight );

            } else {
                // 全方向通行可の場合は通常の高層[☆]表示
                this._drawTile( upperLayer, tileId, dx, dy );
            }
        };

        drawTile( tileId0 );
        drawTile( tileId1 );

        // 影の描画
        this._drawShadow( lowerLayer, shadowBits, dx, dy );

        // テーブルの描画
        if( this._isTableTile( northTileId1 ) && !this._isTableTile( tileId1 ) ) {
            if( !Tilemap.isShadowingTile( tileId0 ) && !Tilemap.isShadowingTile( tileId1 ) ) {
                this._drawTableEdge( lowerLayer, northTileId1, dx, dy );
            }
        }

        // 立体交差の描画
        if( this._isOverpassPosition( mx, my ) ) {
            this._drawTile( upperLayer, tileId2, dx, dy );
            this._drawTile( upperLayer, tileId3, dx, dy );
        } else {
            drawTile( tileId2 );
            drawTile( tileId3 );
        }

        /**
         * 指定位置の壁の状態を調べる。
         * @param {Number} tileId タイルID
         * @returns {Number}  0:壁ではない, 1:下端, 2:上下に接続した壁, 3:上端
         */
        function getWallSideType( tileId ) {
            if( !Tilemap.isWallSideTile( tileId ) ) return 0; // 壁タイルではない

            // autotileShape のビットは 下右上左 に対応しているので、それで判定
            const autotileShape = Tilemap.getAutotileShape( tileId );
            if( autotileShape & 2 ) return 3;
            if( autotileShape & 8 ) return 1;
            return 2;
        }
    };

    /**
     * (スクロールに合わせて)書き割りの表示位置を変更。
     * @param {Number} startX
     * @param {Number} startY
     */
    const _ShaderTilemap_updateLayerPositions = ShaderTilemap.prototype._updateLayerPositions;
    ShaderTilemap.prototype._updateLayerPositions = function( startX, startY ) {
        _ShaderTilemap_updateLayerPositions.apply( this, arguments );

        let ox, oy;
        if( this.roundPixels ) {
            ox = Math.floor( this.origin.x );
            oy = Math.floor( this.origin.y );
        } else {
            ox = this.origin.x;
            oy = this.origin.y;
        }
        const th = this._tileHeight;
        const tw = this._tileWidth;
        const posX = startX * tw - ox;
        const posY = startY * th - oy;
        const l = this.TF_billboards.length;
        for( let i = 0; i < l; i++ ) {
            const curItem = this.TF_billboards[ i ];
            curItem.position.x = posX;
            curItem.position.y = posY + ( i + 1 ) * th;
        };
    };

    /*---- DataManager ---*/
    /**
     * 読み込み直後に、タイルセットデータを書き換える。
     * @param {Object} object 読み込んだデータ
     */
    const _DataManager_onLoad = DataManager.onLoad;
    DataManager.onLoad = function( object ) {
        _DataManager_onLoad.apply( this, arguments );
        if( object !== $dataTilesets ) return;

        // 全タイルセットに対してflagの走査・変更
        for( const curTileset of $dataTilesets ) {
            if( !curTileset ) continue;
            treatA2Tilesets( curTileset.flags );
            treatA3Tilesets( curTileset.flags );
            treatA4Tilesets( curTileset.flags );
        }
    };
    /* ---- DataManager.onLoad 用ユーティリティ ---- */
    // $gameMap が無い段階なので、必要な関数を代わりに定義したり、flags をまる渡ししたりしてる

    const OPTT = ( TF_OverpassTerrainTag << 12 ); // 立体交差地形タグ

    /**
     * カウンター設定か。
     * @param {Number} tileFlag タイルのフラグ情報
     */
    function isCounterTile( tileFlag ) {
        return ( tileFlag & FLAG_COUNTER ) === FLAG_COUNTER;
    }
    /**
     * 指定タイルが立体交差地形タグを持っているか。
     * @param {Number} tileFlag タイルのフラグ情報
     */
    function isOverpassTile( tileFlag ) {
        if( TF_OverpassTerrainTag === 0 ) return false;
        return tileFlag >> 12 === TF_OverpassTerrainTag;
    }

    /**
     * 指定タイルが全方位に衝突判定を持っているか。
     * @param {Number} tileFlag タイルのフラグ情報
     */
    function isFullCollisionTile( tileFlag ) {
        return MASK_ALL_DIR === ( tileFlag & MASK_ALL_DIR );
    }
    /**
     * 指定タイルが衝突判定を持っているか。
     * @param {Number} tileFlag タイルのフラグ情報
     */
    function isCollisionTile( tileFlag ) {
        return 0 < ( tileFlag & MASK_ALL_DIR );
    }

    // A2タイルの走査・変更。
    function treatA2Tilesets( flags ) {
        for( let tileId = Tilemap.TILE_ID_A2; tileId < Tilemap.TILE_ID_A3; tileId += AUTOTILE_BLOCK ) {
            const autotileFlags =
                ( isCounterTile( flags[ tileId ] ) ? 2 : 0 ) +
                ( isCollisionTile( flags[ tileId + 46 ] ) ? 1 : 0 );
            switch( autotileFlags ) {
                case 1: if( !TF_IsA2FullCollision ) { setEmptyLinePass( flags, tileId ); }; break;   // [×]
                case 3: if( TF_UseLayeredCounter ) { setCounterPass( flags, tileId ); }; break;   // [×][♢]
            }
        }
    }

    // A3タイルの走査・変更。
    function treatA3Tilesets( flags ) {
        for( let tileId = Tilemap.TILE_ID_A3; tileId < Tilemap.TILE_ID_A4; tileId += AUTOTILE_BLOCK ) {
            const autotileFlags =
                ( Tilemap.isRoofTile( tileId ) ? 8 : 0 ) +
                ( isOverpassTile( flags[ tileId ] ) ? 4 : 0 ) +
                ( isCounterTile( flags[ tileId ] ) ? 2 : 0 ) +
                ( isCollisionTile( flags[ tileId + 15 ] ) ? 1 : 0 );
            switch( autotileFlags ) {
                // 側面
                case 2: setWallSidePass( flags, tileId ); break;   // [○][♢]
                case 3: setWallSideEdgePass( flags, tileId ); break;   // [×][♢]
                case 4: setBridgeSNPass( flags, tileId, false ); break;    // [○][TT]
                case 5: setBridgeSNPass( flags, tileId, true ); break;   // [×][TT]
                // case 6 : ; break;   // [○][♢][TT]
                // case 7 : ; break;   // [×][♢][TT]

                // 上面
                case 9: setRoofBottomPass( flags, tileId ); break;   // [×]
                case 10: setAutoUpperPass( flags, tileId, 16 ); break;   // [○][♢]
                case 11: setRoofUpperPass( flags, tileId ); break;   // [×][♢]
                case 12: setBridgeWEPass( flags, tileId, false ); break;   // [○][TT]
                case 13: setBridgeWEPass( flags, tileId, true ); break;   // [×][TT]
                case 14: setEmptySquarePass( flags, tileId ); break;     // [○][♢][TT]
                case 15: setA3UpperOverPass( flags, tileId ); break;       // [×][♢][TT]
            }
        }
    }

    // A4タイルの走査・変更。
    function treatA4Tilesets( flags ) {
        for( let tileId = Tilemap.TILE_ID_A4; tileId < Tilemap.TILE_ID_MAX; tileId += AUTOTILE_BLOCK ) {
            const autotileFlags =
                ( Tilemap.isWallTopTile( tileId ) ? 8 : 0 ) +
                ( isOverpassTile( flags[ tileId ] ) ? 4 : 0 ) +
                ( isCounterTile( flags[ tileId ] ) ? 2 : 0 ) +
                ( isCollisionTile( flags[ tileId + 46 ] ) ? 1 : 0 );
            switch( autotileFlags ) {
                // 側面
                case 2: setWallSidePass( flags, tileId ); break;                  // [○][♢]
                case 3: setWallSideEdgePass( flags, tileId ); break;       // [×][♢]
                case 4: setBridgeSNPass( flags, tileId, false ); break;    // [○][TT]
                case 5: setBridgeSNPass( flags, tileId, true ); break;   // [×][TT]
                // case 6 : ; break;   // [○][♢][TT]
                // case 7 : ; break;   // [×][♢][TT]

                // 上面
                case 9: if( !TF_IsA4UpperOpen ) { setEmptyLinePass( flags, tileId ); } break;   // [×]
                case 10: setAutoUpperPass( flags, tileId, 47 ); break;   // [○][♢]
                case 11: setA4UpperPass( flags, tileId ); break;               // [×][♢]
                // case 12 : ; break;       // [○][TT]
                case 13: setA4UpperStarPass( flags, tileId ); break;   // [×][TT]
                case 14: setEmptyLinePass( flags, tileId ); break;   // [○][♢][TT]
                case 15: setA4UpperOverPass( flags, tileId ); break;       // [×][♢][TT]
            }
        }
    }

    /**
     * 衝突判定を指定した設定に変換。
     * @param {Array} flags
     * @param {Number} tileId
     * @param {Number} mask flagのマスク
     * @param {Array} collisionSetting 適用するflag設定
     */
    function replaceCollision( flags, tileId, mask, collisionSetting ) {
        const maxNum = collisionSetting.length;
        for( let i = 0; i < maxNum; i++ ) {
            flags[ tileId + i ] = flags[ tileId + i ] & mask | collisionSetting[ i ];
        }
    }

    /**
     * 高層[☆] 全通行に変更。
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     * @param {Number} maxNum 変更数
     */
    function setAutoUpperPass( flags, tileId, maxNum ) {
        for( let i = 0; i < maxNum; i++ ) {
            flags[ tileId + i ] = flags[ tileId + i ] & MASK_WITHOUT_DIR_UPPER | FLAG_UPPER;
        }
    }
    /**
     * カウンター用に変更。
     * 地面(カウンター) : 北が半分侵入可書き割り、■通行不可
     * [A2 右側][×][♢][UseLayeredCounter:ON]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setCounterPass( flags, tileId ) {
        const COUNTER_PASS = [
            15, 15, 15, 15, 15, 15, 15, 15,
            15, 15, 15, 15, 15, 15, 15, 15,
            15, 15, 15, 15, 28, 28, 28, 28,
            15, 15, 15, 15, 15, 15, 15, 15,
            15, 28, 28, 28, 28, 28, 15, 15,
            15, 15, 28, 28, 15, 28, 28, 28,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_DIR_UPPER | FLAG_COUNTER, COUNTER_PASS );
    }
    /**
     * 中空の地形に変更。
     * [A2][×][IsA2FullCollision:OFF] □周囲=通行不可
     * [A4][○][♢][TT] □周囲=通行不可
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setEmptyLinePass( flags, tileId ) {
        const EMPTY_PASS = [
            0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
            2, 2, 2, 2, 8, 8, 8, 8,
            4, 4, 4, 4, 1, 1, 1, 1,
            6, 9, 10, 10, 12, 12, 5, 5,
            3, 3, 14, 11, 7, 13, 15, 15
        ];
        //if( isCrossPass ) EMPTY_PASS.map( v => OPTT + v );
        replaceCollision( flags, tileId, MASK_WITHOUT_DIR_UPPER, EMPTY_PASS );
    };
    /**
     * 屋根 : 北が立体交差、他は周囲通行不可に変更。
     * [A3 奇数列][×][♢][TT]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setA3UpperOverPass( flags, tileId ) {
        const A3_UPPER_OVERPASS = TF_IsA3UpperOpen ? [
            0, 2, OPTT + 8, OPTT + 10,
            4, 6, OPTT + 12, OPTT + 14,
            0, 2, OPTT + 8, OPTT + 10,
            4, 6, OPTT + 12, OPTT + 14,
        ] : [
            0, 2, OPTT + 8, OPTT + 10,
            4, 6, OPTT + 12, OPTT + 14,
            1, 3, OPTT + 9, OPTT + 11,
            5, 7, OPTT + 15, OPTT + 13,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, A3_UPPER_OVERPASS );
    }
    /**
     * 屋根 : 北が書き割り、他は周囲通行不可に変更。
     * [A3 奇数列][×][カウンター]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setRoofUpperPass( flags, tileId ) {
        const A3_UPPER_PASS = TF_IsA3UpperOpen ? [
            0, 2, 17, 17,
            4, 6, 17, 17,
            0, 2, 17, 17,
            4, 6, 17, 17,
        ] : [
            0, 2, 17, 17,
            4, 6, 17, 17,
            1, 3, 17, 17,
            5, 7, 17, 17,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_DIR_UPPER, A3_UPPER_PASS );
    }
    /**
     * 壁(上面) : 北が立体交差、他は周囲通行不可に変更。
     * [A4 奇数列][×][カウンター][OverpassTerrainTag]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setA4UpperOverPass( flags, tileId ) {
        const A4_UPPER_OVERPASS = TF_IsA4UpperOpen ? [
            0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
            2, 2, 2, 2, OPTT + 8, OPTT + 8, OPTT + 8, OPTT + 8,
            4, 4, 4, 4, 0, 0, 0, 0,
            6, OPTT + 8, OPTT + 10, OPTT + 10, OPTT + 12, OPTT + 12, 4, 4,
            2, 2, OPTT + 14, OPTT + 10, 6, OPTT + 12, OPTT + 14, OPTT + 15,
        ] : [
            0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
            2, 2, 2, 2, OPTT + 8, OPTT + 8, OPTT + 8, OPTT + 8,
            4, 4, 4, 4, 1, 1, 1, 1,
            6, OPTT + 9, OPTT + 10, OPTT + 10, OPTT + 12, OPTT + 12, 5, 5,
            3, 3, OPTT + 14, OPTT + 11, 7, OPTT + 13, OPTT + 15, OPTT + 15,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, A4_UPPER_OVERPASS );
    }
    /**
     * 壁(上面) : 北が書き割り、他は周囲通行不可に変更。
     * [A4 奇数列][×][カウンター]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setA4UpperPass( flags, tileId ) {
        const A4_UPPER_PASS = TF_IsA4UpperOpen ? [
            0, 2, 4, 6, 0, 2, 4, 6,
            0, 2, 4, 6, 0, 2, 4, 6,
            2, 6, 2, 6, 17, 17, 17, 17,
            4, 4, 6, 6, 0, 2, 4, 6,
            6, 17, 17, 17, 17, 17, 4, 6,
            2, 6, 17, 17, 6, 17, 17, 17,
        ] : [
            0, 2, 4, 6, 0, 2, 4, 6,
            0, 2, 4, 6, 0, 2, 4, 6,
            2, 6, 2, 6, 17, 17, 17, 17,
            4, 4, 6, 6, 1, 3, 5, 7,
            6, 17, 17, 17, 17, 17, 5, 7,
            3, 7, 17, 17, 7, 17, 17, 17,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_DIR_UPPER, A4_UPPER_PASS );
    }
    /**
     * 壁(上面) : 北が☆、他は通行不可に変更。
     * [A4 奇数列][○][TT]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setA4UpperStarPass( flags, tileId ) {
        const A4_UPPER_STAR_PASS = [
            15, 15, 15, 15, 15, 15, 15, 15,
            15, 15, 15, 15, 15, 15, 15, 15,
            15, 15, 15, 15, 16, 16, 16, 16,
            15, 15, 15, 15, 15, 15, 15, 15,
            15, 16, 16, 16, 16, 16, 15, 15,
            15, 15, 16, 16, 15, 16, 16, 16,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, A4_UPPER_STAR_PASS );
    }
    /**
     * 壁(側面):南が書き割り、他は通行可に変更。
     * [A3・A4 偶数列][○]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setWallSideEdgePass( flags, tileId ) {
        const WALL_SIDE_PASS_EDGE = [
            15, 15, 17, 17,
            15, 15, 17, 17,
            15, 15, 17, 17,
            15, 15, 17, 17,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_DIR_UPPER, WALL_SIDE_PASS_EDGE );
    }
    /**
     * 壁(側面): 北が書き割り、他は全通行不可に変更。
     * [A3・A4 偶数列][○][♢]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setWallSidePass( flags, tileId ) {
        const WALL_SIDE_PASS = [
            25, 25, 26, 26,
            25, 25, 26, 26,
            17, 17, 17, 17,
            17, 17, 17, 17,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_DIR_UPPER, WALL_SIDE_PASS );
    }
    /**
     * 屋根 (地面) : 周囲通行不可に変更。
     * [A3 奇数列][×]
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setRoofBottomPass( flags, tileId ) {
        if( TF_IsA3UpperOpen ) {
            setSquareOpenPass( flags, tileId );
        } else {
            setEmptySquarePass( flags, tileId );
        }
    }
    /**
     * 屋根 (地面) : 南以外通行不可に変更。
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setSquareOpenPass( flags, tileId ) {
        const SQUARE_PASS = [
            0, 2, 8, 10,
            4, 6, 12, 14,
            0, 2, 8, 10,
            4, 6, 12, 14,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_DIR_UPPER, SQUARE_PASS );
    }
    /**
     * 屋根 (地面) : 全周通行不可に変更。
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     */
    function setEmptySquarePass( flags, tileId ) {
        const SQUARE_PASS = [
            0, 2, 8, 10,
            4, 6, 12, 14,
            1, 3, 9, 11,
            5, 7, 13, 15,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_DIR_UPPER, SQUARE_PASS );
    }
    /**
     * 南北の橋設定に変更。
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     * @param {Boolean} isCrossPass 立体交差か
     */
    function setBridgeSNPass( flags, tileId, isCrossPass ) {
        const BRIDGE_SN_PASS = isCrossPass ? [
            OPTT + 0, OPTT + 2, OPTT + 0, OPTT + 2,
            OPTT + 4, OPTT + 6, OPTT + 4, OPTT + 6,
            OPTT + 0, OPTT + 2, OPTT + 0, OPTT + 2,
            OPTT + 4, OPTT + 6, OPTT + 4, OPTT + 6,
        ] : [
            0, 2, 0, 2,
            4, 6, 4, 6,
            0, 2, 0, 2,
            4, 6, 4, 6,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, BRIDGE_SN_PASS );
    }
    /**
     * 東西の橋設定に変更。
     * @param {Array<Number>} flags 地形フラグの配列
     * @param {Number} tileId タイルID
     * @param {Boolean} isCrossPass 立体交差か
     */
    function setBridgeWEPass( flags, tileId, isCrossPass ) {
        const BRIDGE_WE_PASS = isCrossPass ? [
            OPTT + 0, OPTT + 0, OPTT + 8, OPTT + 8,
            OPTT + 0, OPTT + 0, OPTT + 8, OPTT + 8,
            OPTT + 1, OPTT + 1, OPTT + 9, OPTT + 9,
            OPTT + 1, OPTT + 1, OPTT + 9, OPTT + 9,
        ] : [
            0, 0, 8, 8,
            0, 0, 8, 8,
            1, 1, 9, 9,
            1, 1, 9, 9,
        ];
        replaceCollision( flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, BRIDGE_WE_PASS );
    }

    /*---- Scene_Map ---*/
    /**
     * シーン表示前に、マップデータを書き換える。
     */
    const _Scene_Map_onMapLoaded = Scene_Map.prototype.onMapLoaded;
    Scene_Map.prototype.onMapLoaded = function() {
        if( this._transfer ) $gamePlayer.performTransfer();    // シーン遷移時のマップデータ置き換え処理
        treatDataMap();
        _Scene_Map_onMapLoaded.call( this );

        /**
         * カウンター設定のA3・A4オートタイルの箇所に、低層の補完タイルを設定。
         */
        function treatDataMap() {
            const flags = $gameMap.tilesetFlags();
            for( let y = 0; y < $dataMap.height; y++ ) {
                for( let x = 0; x < $dataMap.width; x++ ) {
                    const tileId = getMapData( x, y, 0 );

                    // 対象タイルを上層へ
                    if( Tilemap.isTileA5( tileId ) && isOverpassTile( flags[ tileId ] ) ) {
                        setMapData( x, y, 1, tileId );
                    } else if( isA3A4Tile( tileId ) ) {
                        if( isOverpassTile( flags[ tileId ] ) ) {
                            setMapData( x, y, 2, tileId );
                        } else if( !isFullCollisionTile( flags[ tileId ] ) && isCollisionTile( flags[ tileId ] ) ) {
                            setMapData( x, y, 1, tileId );
                        } else continue;    // 衝突判定が完全に[○]か[×]のタイルは通常処理(A2右タイルを上に置ける)
                    } else continue;

                    if( TF_FillWithNeighborTile ) {
                        // 北タイルで補完ただし、一番南は南で補完
                        const southTileId = getMapData( x, $gameMap.roundY( y + 1 ), 0 );
                        if( isA3A4Tile( southTileId ) || Tilemap.isTileA5( southTileId ) && isOverpassTile( flags[ southTileId ] ) ) {
                            const northTileId = getMapData( x, $gameMap.roundY( y - 1 ), 0 );
                            setMapData( x, y, 0, northTileId ? northTileId : TF_DefaultLowerTileId );
                        } else {
                            setMapData( x, y, 0, southTileId ? southTileId : TF_DefaultLowerTileId );
                        }
                    } else {
                        // 指定タイルで補完
                        setMapData( x, y, 0, TF_DefaultLowerTileId );
                    }
                }
            }

            /**
             * A3・A4タイルか。
             * @param {Number} tileId タイルID
             * @returns {Boolean}
             */
            function isA3A4Tile( tileId ) {
                return ( Tilemap.isTileA3( tileId ) || Tilemap.isTileA4( tileId ) );
            }
            /**
             * 指定位置のタイルIDを返す。
             * @param {Number} x x座標(タイル数)
             * @param {Number} y y座標(タイル数)
             * @param {*} z レイヤー位置
             * @returns {Number} タイルID
             */
            function getMapData( x, y, z ) {
                return $dataMap.data[ x + ( $gameMap.roundY( y ) + z * $dataMap.height ) * $dataMap.width ];
            }
            /**
             * マップデータにタイルIDを書き込む。
             * @param {Number} x x座標(タイル数)
             * @param {Number} y y座標(タイル数)
             * @param {Number} z レイヤー位置
             * @param {Number} tileId タイルID
             */
            function setMapData( x, y, z, tileId ) {
                $dataMap.data[ x + ( $gameMap.roundY( y ) + z * $dataMap.height ) * $dataMap.width ] = tileId;
            }

        }
    };

    /*---- Game_CharacterBase ----*/
    /**
     * レイヤー位置を返す。
     * @returns {Number} レイヤー位置(立体交差上5、その他3)
     */
    const _Game_CharacterBase_screenZ = Game_CharacterBase.prototype.screenZ;
    Game_CharacterBase.prototype.screenZ = function() {
        return this._higherLevel ? 5 : _Game_CharacterBase_screenZ.call( this );
    };

    /**
     * 指定座標がイベントで塞がれているか。高さレベルを考慮する。
     * TODO : HalfMove.js とコンフリクトするので、回避方法を探る
     * @param {Number} x タイル数
     * @param {Number} y タイル数
     * @returns {Boolean}
     */
    //const _Game_CharacterBase_isCollidedWithEvents = Game_CharacterBase.prototype.isCollidedWithEvents;
    // Game_CharacterBase.prototype.isCollidedWithEvents = function( x, y ){
    //     const events = $gameMap.eventsXyNt( x, y );
    //     return events.some( event => Boolean( this._higherLevel ) === Boolean( event._higherLevel ) );
    // };

    /**
     * 指定方向への移動が可能か
     * キャラクタ半分の位置が関係するものは、ここで判定。
     * @param {Number} halfX タイル数(0.5刻み)
     * @param {Number} halfY タイル数(0.5刻み)
     * @param {Number} d 向き(テンキー対応)
     * @returns {Boolean} 移動可能か
     */
    const _Game_CharacterBase_isMapPassable = Game_CharacterBase.prototype.isMapPassable;
    Game_CharacterBase.prototype.isMapPassable = function( halfX, halfY, d ) {
        const x = Math.floor( halfX + 0.5 );
        const y = Math.floor( halfY + 0.5 );
        const halfPos = getHalfPos( halfX, halfY );
        const dx = getDx( d );
        // const dy =getDy( d );
        const rd = this.reverseDir( d );
        const flags = $gameMap.tilesetFlags();

        /**
         * 指定位置に指定flagがあるか
         * @param {Number} x タイル数
         * @param {Number} y タイル数
         * @param {Number} collisionType 調べるタイルのflag(高層[☆]と通行)
         * @returns {Boolean}
         */
        const checkCollision = ( x, y, collisionType ) => {
            const tiles = $gameMap.allTiles( Math.floor( x ), Math.floor( y ) );

            for( let i = 0; i < tiles.length; i++ ) {
                if( ( flags[ tiles[ i ] ] & MASK_UPPER_DIR ) === collisionType ) return true;
            }
            return false;
        };

        const isFurniturePassable = () => {
            // FLOOR1_N_FULL
            if( d === 2 ) {
                if( ( halfPos === 2 || halfPos === 3 ) && checkCollision( x, y + 1, FLOOR1_N_FULL ) ) return false;
                if( halfPos === 2 && checkCollision( x - 1, y + 1, FLOOR1_N_FULL ) ) return false;
            } else if( d === 8 ) {
                if( ( halfPos === 2 || halfPos === 3 ) && checkCollision( x, y, FLOOR1_N_FULL ) ) return false;
                if( ( halfPos === 2 ) && checkCollision( x - 1, y, FLOOR1_N_FULL ) ) return false;
            } else if( d === 4 || d === 6 ) {
                if( halfPos === 1 && checkCollision( x + dx, y, FLOOR1_N_FULL ) ) return false;
            }

            //FLOOR1_S_FULL
            if( d === 2 ) {
                if( ( halfPos === 0 || halfPos === 1 ) && checkCollision( x, y, FLOOR1_S_FULL ) ) return false;
                if( halfPos === 0 && checkCollision( x - 1, y, FLOOR1_S_FULL ) ) return false;
            } else if( d === 8 ) {
                if( ( halfPos === 0 || halfPos === 1 ) && checkCollision( x, y - 1, FLOOR1_S_FULL ) ) return false;
                if( halfPos === 0 && checkCollision( x - 1, y - 1, FLOOR1_S_FULL ) ) return false;
            } else if( d === 4 || d === 6 ) {
                if( halfPos === 3 && checkCollision( x + dx, y, FLOOR1_S_FULL ) ) return false;
            }

            // FLOOR1_N_HALF
            if( d === 2 ) {
                if( halfPos === 3 && checkCollision( x, y + 1, FLOOR1_N_HALF ) ) return false;
            } else if( d === 8 ) {
                if( halfPos === 3 && checkCollision( x, y, FLOOR1_N_HALF ) ) return false;
            } else if( d === 4 ) {
                if( halfPos === 0 && checkCollision( x - 1, y, FLOOR1_N_HALF ) ) return false;
            } else if( d === 6 ) {
                if( halfPos === 0 && checkCollision( x, y, FLOOR1_N_HALF ) ) return false;
            }

            // FLOOR1_S_HALF
            if( d === 2 ) {
                if( halfPos === 1 && checkCollision( x, y, FLOOR1_S_HALF ) ) return false;
            } else if( d === 8 ) {
                if( halfPos === 1 && checkCollision( x, y - 1, FLOOR1_S_HALF ) ) return false;
            } else if( d === 4 ) {
                if( halfPos === 2 && checkCollision( x - 1, y, FLOOR1_S_HALF ) ) return false;
            } else if( d === 6 ) {
                if( halfPos === 2 && checkCollision( x, y, FLOOR1_S_HALF ) ) return false;
            }

            // FLOOR1_S_FLAT
            if( d === 2 ) {
                if( halfPos === 3 && checkCollision( x, y, FLOOR1_S_FLAT ) ) return false;
            } else if( d === 8 ) {
                if( halfPos === 1 && checkCollision( x, y - 1, FLOOR1_S_FLAT ) ) return false;
            }

            return null;
        };

        // Overpass タグが設定されていない
        if( TF_OverpassTerrainTag === 0 ) {
            const isFPassable = isFurniturePassable();
            if( isFPassable !== null ) return isFPassable;
            return _Game_CharacterBase_isMapPassable.apply( this, arguments );
        }

        /*---- Overpass 用のプログラム ----*/

        // 立体交差の下では、家具の衝突判定は行わない
        if( this._higherLevel || ( !this._higherLevel && !isOverpassTileAt( x, y ) ) ) {
            const isFPassable = isFurniturePassable();
            if( isFPassable !== null ) return isFPassable;
        }

        const isOverpassMapPassable = () => {
            if( isOverpassTileAt( x, y ) ) {
                // 下を潜っている状態は端の通行判定を逆転
                if( d === 2 ) {
                    if( ( halfPos === 2 || halfPos === 3 ) &&
                        !isOverpassTileAt( x, y + 1 ) && checkOverpassCollision( x, y, 2 ) === false
                    ) return false;
                } else if( d === 8 ) {
                    if( halfPos === 2 || halfPos === 3 ) {
                        if( TF_CharacterSize === 2 ) {
                            if( !isOverpassTileAt( x, y - 2 ) && checkOverpassCollision( x, y - 1, 8 ) === false ) return false;
                        } else if( !isOverpassTileAt( x, y - 1 ) && checkOverpassCollision( x, y, 8 ) === false ) return false;
                    }
                } else if( d === 4 || d === 6 ) {
                    if( ( halfPos === 1 || halfPos === 3 ) &&
                        !isOverpassTileAt( x + dx, y ) && checkOverpassCollision( x, y, d ) === false
                    ) return false;
                }
                return true;
            }

            // 東の境界
            if( isOverpassTileAt( x - 1, y ) ) {
                if( halfPos === 0 ) return true;
                if( halfPos === 2 ) {
                    if( d === 2 ) {
                        if( !isOverpassTileAt( x - 1, y + 1 ) && checkOverpassCollision( x - 1, y, 2 ) === false ) return false;
                    } else if( d === 8 ) {
                        if( TF_CharacterSize === 2 ) {
                            if( !isOverpassTileAt( x - 1, y - 2 ) && checkOverpassCollision( x - 1, y - 1, 8 ) === false ) return false;
                        } else if( !isOverpassTileAt( x - 1, y - 1 ) && checkOverpassCollision( x - 1, y, 8 ) === false ) return false;
                    }
                    return true;
                }
            } else if( d === 8 && halfPos === 0 && checkOverpassCollisionBit( x - 1, y - 1, 5 ) ) return true; // 東の角┘

            // 潜る
            if( d === 2 ) {
                if( halfPos === 2 ) {
                    if( checkOverpassCollisionBit( x - 1, y + 1, 12 ) ) return true; // 東の角┐
                    if( checkOverpassCollisionBit( x, y + 1, 9 ) ) return true; // 西の角┌
                    if( checkOverpassCollision( x, y + 1, 8 ) ) {
                        if( checkOverpassCollision( x - 1, y + 1, 8 ) ) return true;
                    }
                } else if( halfPos === 3 ) {
                    if( checkOverpassCollision( x, y + 1, 8 ) ) return true;
                }
            } else if( d === 8 ) {
                if( halfPos === 0 ) {
                    if( checkOverpassCollisionBit( x, y - 1, 3 ) ) return true; // 西の角└
                    if( checkOverpassCollision( x, y - 1, 2 ) && checkOverpassCollision( x - 1, y - 1, 2 ) ) return true;
                } else if( halfPos === 1 ) {
                    if( checkOverpassCollision( x, y - 1, 2 ) ) return true;
                }
            } else if( d === 4 || d === 6 ) {
                if( checkOverpassCollision( x + dx, y, rd ) ) {
                    if( checkOverpassCollision( x + dx, y - 1, rd ) ) {
                        if( halfPos === 3 ) return true;
                        if( halfPos === 1 && TF_CharacterSize === 1 || checkOverpassCollision( x + dx, y - 2, rd ) ) return true;
                    }
                    if( ( halfPos === 1 || halfPos === 3 ) && checkOverpassCollision( x + dx, y, 8 ) ) return true;   // ┌西東┐の角
                }
            }

            // 境界の北の衝突判定
            if( d === 2 ) {
                if( halfPos === 0 && !isOverpassTileAt( x, y ) && !isOverpassTileAt( x - 1, y ) ) {
                    if( !isOverpassTileAt( x - 1, y + 1 ) &&
                        checkOverpassCollision( x, y + 1, 4 ) === false &&
                        checkOverpassCollision( x, y + 1, 2 ) ) return false;
                    if( !isOverpassTileAt( x, y + 1 ) &&
                        checkOverpassCollision( x - 1, y + 1, 6 ) === false &&
                        checkOverpassCollision( x - 1, y + 1, 2 ) ) return false;
                }
            } else if( d === 4 || d === 6 ) {
                if( halfPos === 3 && !isOverpassTileAt( x + dx, y ) ) {
                    if( !isOverpassTileAt( x + dx, y + 1 ) &&
                        checkOverpassCollision( x, y + 1, d ) === false &&
                        checkOverpassCollision( x, y + 1, 8 ) ) return false;
                    if( !isOverpassTileAt( x, y + 1 ) &&
                        checkOverpassCollision( x + dx, y + 1, rd ) === false &&
                        checkOverpassCollision( x + dx, y + 1, 8 ) ) return false;
                }
            }

            // 境界の南の衝突判定
            if( halfPos === 1 || ( TF_CharacterSize === 2 && halfPos === 3 ) ) {
                if( ( d === 4 || d === 6 ) && !isOverpassTileAt( x + dx, y ) ) {
                    if( !isOverpassTileAt( x + dx, y - 1 ) &&
                        checkOverpassCollision( x, y - 1, d ) === false &&
                        checkOverpassCollision( x, y - 1, 2 ) ) return false;
                    if( !isOverpassTileAt( x, y - 1 ) &&
                        checkOverpassCollision( x + dx, y - 1, rd ) === false &&
                        checkOverpassCollision( x + dx, y - 1, 2 ) ) return false;
                }
            } else if( d === 8 ) {
                if( TF_CharacterSize === 2 ) {
                    if( halfPos === 0 && !isOverpassTileAt( x, y - 1 ) && !isOverpassTileAt( x - 1, y - 1 ) ) {
                        if( !isOverpassTileAt( x - 1, y - 2 ) &&
                            checkOverpassCollision( x, y - 2, 4 ) === false &&
                            checkOverpassCollision( x, y - 2, 2 ) ) return false;
                        if( !isOverpassTileAt( x, y - 2 ) &&
                            checkOverpassCollision( x - 1, y - 2, 6 ) === false &&
                            checkOverpassCollision( x - 1, y - 2, 2 ) ) return false;
                    }
                } else if( halfPos === 2 && !isOverpassTileAt( x, y ) && !isOverpassTileAt( x - 1, y ) ) {
                    if( !isOverpassTileAt( x - 1, y - 1 ) &&
                        checkOverpassCollision( x, y - 1, 4 ) === false &&
                        checkOverpassCollision( x, y - 1, 2 ) ) return false;
                    if( !isOverpassTileAt( x, y - 1 ) &&
                        checkOverpassCollision( x - 1, y - 1, 6 ) === false &&
                        checkOverpassCollision( x - 1, y - 1, 2 ) ) return false;
                }
            }
            return null;
        };

        // 乗る
        const isGateway = isUp2Higher( x, y, d, halfPos );
        if( isGateway ) this._higherLevel = true;

        if( this._higherLevel ) {
            if( isDownFromUpperTile( x, y, d, halfPos ) ) this._higherLevel = false;
            return _Game_CharacterBase_isMapPassable.apply( this, arguments );
        }

        const isOPMapPassable = isOverpassMapPassable();
        if( isOPMapPassable === null ) return _Game_CharacterBase_isMapPassable.apply( this, arguments );
        if( isOPMapPassable === false ) return false;

        const checkUnderpassCollision = ( x, y, d ) => {
            const x2 = $gameMap.roundX( x + getDx( d ) );
            const y2 = $gameMap.roundY( y + getDy( d ) );
            if( isOverpassTileAt( x2, y2 ) ) {
                if( isGateway ) return true;
                if( ( flags[ $gameMap.tileId( x, y, 0 ) ] |
                    flags[ $gameMap.tileId( x, y, 1 ) ] ) &
                    getFlag( d )
                ) return false;
                if( ( flags[ $gameMap.tileId( x2, y2, 0 ) ] |
                    flags[ $gameMap.tileId( x2, y2, 1 ) ] ) &
                    getFlag( rd )
                ) return false;
            }
            return true;
        };

        // レイヤー0,1の衝突判定
        if( !this._higherLevel &&
            ( ( halfPos === 1 || halfPos === 3 ) && ( d === 4 || d === 6 ) ) ||
            ( ( halfPos === 0 || halfPos === 1 ) && d === 8 ) ||
            ( ( halfPos === 2 || halfPos === 3 ) && d === 2 )
        ) {
            if( checkUnderpassCollision( x, y, d ) ) {
                if( ( halfPos === 0 && d === 8 ) || ( halfPos === 2 && d === 2 ) ) {
                    if( !checkUnderpassCollision( x - 1, y, d ) ) return false;
                }
            } else return false;
        }

        return isOPMapPassable;
    };

    /*---- Game_Follower ----*/
    /**
     * 指定位置の指定フラグビットが通行可か。
     * @param {Number} character 追うキャラクタ
     */
    const _Game_Follower_chaseCharacter = Game_Follower.prototype.chaseCharacter;
    Game_Follower.prototype.chaseCharacter = function( character ) {
        if( TF_OverpassTerrainTag === 0 ) {
            _Game_Follower_chaseCharacter.apply( this, arguments );
            return;
        }

        const sx = this.deltaXFrom( character.x );
        const sy = this.deltaYFrom( character.y );
        const d = 5 - Math.sign( sx ) + ( ( sx === 0 ) ? Math.sign( sy ) * 3 : 0 );
        if( d === 5 ) {
            _Game_Follower_chaseCharacter.apply( this, arguments );
            return;
        }

        const x = Math.floor( this.x + 0.5 );
        const y = Math.floor( this.y + 0.5 );
        const halfPos = getHalfPos( this.x, this.x );
        if( this._higherLevel ) {
            if( isDownFromUpperTile( x, y, d, halfPos ) ) this._higherLevel = false;
        } else {
            if( isUp2Higher( x, y, d, halfPos ) ) this._higherLevel = true;
        }

        _Game_Follower_chaseCharacter.apply( this, arguments );
    };

    /*---- Game_Event ----*/
    var _Game_Event_initialize = Game_Event.prototype.initialize;
    Game_Event.prototype.initialize = function( mapId, eventId ) {
        _Game_Event_initialize.apply( this, arguments );

        const getMetaValue = ( object, name ) => {
            const metaTagName = 'TF_' + name;
            return object.meta.hasOwnProperty( metaTagName ) ? object.meta[ metaTagName ] : undefined;
        };

        const zDef = getMetaValue( this.event(), 'zDef' );
        if( zDef !== undefined ) this._TF_zDef = parseFloat( zDef );

        const higherLevel = getMetaValue( this.event(), 'higherLevel' );
        if( higherLevel !== undefined ) this._higherLevel = ( higherLevel.toLowerCase() === PARAM_TRUE );
    };

    /*---- Game_Map ----*/
    /**
     * 指定位置の指定フラグビットが通行可か。
     * @param {Number} x タイル数
     * @param {Number} y タイル数
     * @param {Number} bit {@link RPG.Tileset}の flagsチェック用ビット
     * @returns {Boolean} 高層表示[☆]の4方向の通行設定については@helpを参照
     */
    //const _Game_Map_checkPassage = Game_Map.prototype.checkPassage;
    Game_Map.prototype.checkPassage = function( x, y, bit ) {
        const flags = this.tilesetFlags();
        const tiles = this.allTiles( x, y );
        const isOverpass = isOverpassTileAt( x, y );
        const lastIndex = tiles.length - ( ( $gamePlayer._higherLevel && isOverpass ) ? 2 : 0 );
        for( let i = 0; i < lastIndex; i++ ) {
            const tileId = tiles[ i ];
            const flag = flags[ tileId ];

            if( tileId === 0 ||    // Bタイルの左上は無視
                ( flag & FLAG_UPPER ) && (          // [☆]かつ
                    ( flag & FLAG_NORTH_DIR ) ||  // ・北通行不可タイルは無視
                    !( flag & MASK_ALL_DIR )        // ・全通行可タイルは無視
                )
            ) continue;
            if( ( flag & bit ) === 0 ) return true;
            if( ( flag & bit ) === bit ) return false;
        }
        return $gamePlayer._higherLevel && isOverpass;
        //return _Game_Map_checkPassage.apply( this, arguments );
    };

    /**
     * 指定位置の立体交差地形タグを持つタイルの通行判定(4方向)チェック
     * @param {Number} ax タイル数
     * @param {Number} ay タイル数
     * @param {Number} d 通行設定(テンキー方向)
     * @returns {Boolean} 立体交差タイルでない場合nullを返す
     */
    function checkOverpassCollision( x, y, d ) {
        return checkOverpassCollisionBit( x, y, getFlag( d ) );
    }

    /**
     * 指定位置の立体交差地形タグを持つタイルの通行判定(ビットフラグ)チェック
     * @param {Number} ax タイル数
     * @param {Number} ay タイル数
     * @param {Number} bit 通行設定(ビットフラグ)
     * @returns {Boolean} 立体交差タイルでない場合nullを返す
     */
    function checkOverpassCollisionBit( x, y, bit ) {
        const flags = $gameMap.tilesetFlags();
        const tiles = $gameMap.allTiles( Math.floor( $gameMap.roundX( x ) ), Math.floor( $gameMap.roundY( y ) ) );

        for( let i = 0; i < tiles.length; i++ ) {
            const flag = flags[ tiles[ i ] ];
            if( flag >> 12 === TF_OverpassTerrainTag && !Tilemap.isTileA5( tiles[ i ] ) ) {
                return ( flag & bit ) === bit;
            }
        }
        return null;
    }

    /**
     * 指定位置のタイルは立体交差地形タグを持つか
     * @param {Number} x タイル数
     * @param {Number} y タイル数
     * @returns {Boolean} 立体交差タイルでない場合nullを返す
     */
    function isOverpassTileAt( x, y ) {
        const flags = $gameMap.tilesetFlags();
        const tiles = $gameMap.layeredTiles( $gameMap.roundX( x ), $gameMap.roundY( y ) );
        for( let i = 0; i < tiles.length; i++ ) {
            if( flags[ tiles[ i ] ] >> 12 === TF_OverpassTerrainTag && !Tilemap.isTileA5( tiles[ i ] ) ) {
                return true;
            }
        }
        return false;
    }

    /**
     * 高層へ上がるタイミングか
     * @param {Number} x タイル数
     * @param {Number} y タイル数
     * @param {Number} d 通行設定(テンキー方向)
     * @param {Number} halfPos タイル内での位置
     * @returns {Boolean}
     */
    function isUp2Higher( x, y, d, halfPos ) {
        if( halfPos === 0 || halfPos === 2 ) {
            if( !isOverpassTileAt( x - 1, y ) && checkOverpassCollision( x, y, 4 ) === false ) return true;   // 西出入口境界
        }
        if( isOverpassTileAt( x, y ) ) return false;   // 立体交差タイルの上は帰す

        return (
            checkOverpassCollision( x - 1, y, 6 ) === false ||  // 東出入口
            checkOverpassCollision( x + 1, y, 4 ) === false ||  // 西出入口
            checkOverpassCollision( x, y + 1, 8 ) === false ||  // 北入り口↓
            ( !isOverpassTileAt( x - 1, y ) && checkOverpassCollision( x - 1, y + 1, 8 ) === false ) ||
            ( !isOverpassTileAt( x, y - 1 ) && checkOverpassCollision( x, y - 2, 2 ) === false ) ||  // 南入口↓
            ( !isOverpassTileAt( x - 1, y ) && ( checkOverpassCollision( x - 1, y - 1, 2 ) === false ||
                ( !isOverpassTileAt( x - 1, y - 1 ) && checkOverpassCollision( x - 1, y - 2, 2 ) === false ) )
            ) ||
            ( !isOverpassTileAt( x + 1, y ) && checkOverpassCollision( x + 1, y - 1, 2 ) === false )
        );
    }

    /**
     * 高層から降りるタイミングか
     * @param {Number} x タイル数
     * @param {Number} y タイル数
     * @param {Number} d 通行設定(テンキー方向)
     * @param {Number} halfPos タイル内での位置
     * @returns {Boolean}
     */
    function isDownFromUpperTile( x, y, d, halfPos ) {
        if( isOverpassTileAt( x, y ) ) return false;  // 立体交差タイルの上は帰す
        if( checkOverpassCollision( x, y - 1, 2 ) === false ) return false;  // 南入り口タイルは帰す
        if( ( halfPos === 0 || halfPos === 2 ) && checkOverpassCollision( x - 1, y - 1, 2 ) === false ) return false;

        // 全周に立体交差タイルの入り口がない
        return checkOverpassCollision( x + 1, y, 4 ) !== false &&   // 東
            checkOverpassCollision( x - 1, y, 6 ) !== false &&    // 西
            checkOverpassCollision( x, y + 1, 8 ) !== false &&    // 南
            checkOverpassCollision( x - 1, y + 1, 8 ) !== false &&  // 南西
            checkOverpassCollision( x, y - 2, 2 ) !== false;  // ふたつ北
    }

    /**
     * タイル内の位置を返す( 0:左上, 1:上, 2:左下, 3:下 )
     * @param {Number} x x座標(タイル数)
     * @param {Number} y y座標(タイル数)
     */
    function getHalfPos( x, y ) {
        return ( ( ( x % 1 ) === 0 ) ? 1 : 0 ) + ( ( ( y % 1 ) === 0 ) ? 2 : 0 );
    }
    /**
     * 指定方向のX要素を返す。
     * @param {Number} d 方向(テンキー対応)
     */
    function getDx( d ) {
        return ( d === 6 ) ? 1 : ( d === 4 ) ? -1 : 0;
    }
    /**
     * 指定方向のY要素を返す。
     * @param {Number} d 方向(テンキー対応)
     */
    function getDy( d ) {
        return ( d === 2 ) ? 1 : ( d === 8 ) ? -1 : 0;
    }
    /**
     * 指定方向をflagに変換して返す。
     * @param {Number} d 方向(テンキー対応)
     */
    function getFlag( d ) {
        return 1 << ( d / 2 - 1 );
    }
} )();


code:
//=============================================================================
// TMVplugin - フキダシループ
// 作者: tomoaky (http://hikimoki.sakura.ne.jp/)
// Version: 1.11
// 最終更新日: 2016/06/20
//=============================================================================

/*:
 * @plugindesc フキダシアイコンをループ表示させます。
 *
 * @author tomoaky (http://hikimoki.sakura.ne.jp/)
 *
 * @help
 * 使い方:
 *   プラグインコマンドまたはメモ欄タグを使ってイベントにフキダシループを設
 *   定すると、指定されたフキダシアイコンが繰り返し表示され続けるようになり
 *   ます。
 *
 *   イベントのメモ欄以外に、実行内容の一番上にある注釈コマンド内でも同様の
 *   タグでフキダシループを設定することができます。メモ欄と注釈の両方にタグ
 *   がある場合は注釈が優先されます。
 *
 *   プラグインコマンドによるフキダシループは、イベントページの切り替わりや
 *   イベントコマンド『イベントの一時消去』などによって解除されます。
 *
 * プラグインコマンド:
 *   setBalloonLoop 2 1
 *   ２番のイベントにフキダシループとしてびっくりアイコンを設定します。イベ
 *   ント番号は -1 ならプレイヤー、0 ならコマンドを実行しているイベントが対
 *   象となります。
 *   表示するアイコンの番号はイベントコマンド『フキダシアイコンの表示』での
 *   並びに対応していて、0 を指定するとフキダシループが解除されます。
 *
 * メモ欄タグ（イベント）:
 *   <balloonLoop:1>
 *   このタグがついているイベントは setBalloonLoop を実行しなくても自動的に
 *   フキダシループが設定されます。数値は表示するアイコン番号です。
 *
 */

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

if (!Imported.TMEventBase) {
  Imported.TMEventBase = true;
  (function() {

    //-----------------------------------------------------------------------------
    // Game_Event
    //

    var _Game_Event_setupPage = Game_Event.prototype.setupPage;
    Game_Event.prototype.setupPage = function() {
      _Game_Event_setupPage.call(this);
      if (this._pageIndex >= 0) {
        this.loadCommentParams();
      }
    };

    Game_Event.prototype.loadCommentParams = function() {
      this._commentParams = {};
      var re = /<([^<>:]+)(:?)([^>]*)>/g;
      var list = this.list();
      for (var i = 0; i < list.length; i++) {
        var command = list[i];
        if (command && command.code == 108 || command.code == 408) {
          for (;;) {
            var match = re.exec(command.parameters[0]);
            if (match) {
              if (match[2] === ':') {
                this._commentParams[match[1]] = match[3];
              } else {
                this._commentParams[match[1]] = true;
              }
            } else {
              break;
            }
          }
        } else {
          break;
        }
      }
    };

    Game_Event.prototype.loadTagParam = function(paramName) {
      if (this._commentParams[paramName]) {
        return this._commentParams[paramName];
      } else if (this.event().meta[paramName]) {
        return this.event().meta[paramName];
      } else {
        return null;
      }
    };

  })();
}

(function() {

  //-----------------------------------------------------------------------------
  // Game_CharacterBase
  //

  var _Game_CharacterBase_endBalloon = Game_CharacterBase.prototype.endBalloon;
  Game_CharacterBase.prototype.endBalloon = function() {
    _Game_CharacterBase_endBalloon.call(this);
    var balloonLoop = this.balloonLoop();
    if (balloonLoop) {
      this.requestBalloon(balloonLoop);
    }
  };

  Game_CharacterBase.prototype.setBalloonLoop = function(balloonLoop) {
    this._balloonLoop = balloonLoop;
  };

  Game_CharacterBase.prototype.balloonLoop = function() {
    return this._balloonLoop;
  };

  //-----------------------------------------------------------------------------
  // Game_Event
  //

  var _Game_Event_setupPage = Game_Event.prototype.setupPage;
  Game_Event.prototype.setupPage = function() {
    _Game_Event_setupPage.call(this);
    if (this._pageIndex >= 0) {
      var balloonLoop = +this.loadTagParam('balloonLoop');
      if (balloonLoop) {
        this.setBalloonLoop(balloonLoop);
      }
    } else {
      this.setBalloonLoop(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);
    if (command === 'setBalloonLoop') {
      var character = this.character(+args[0]);
      if (character) {
        character.setBalloonLoop(+args[1]);
      }
    }
  };

  //-----------------------------------------------------------------------------
  // Sprite_Character
  //

  var _Sprite_Character_endBalloon = Sprite_Character.prototype.endBalloon;
  Sprite_Character.prototype.endBalloon = function() {
    var balloonLoop = this._character.balloonLoop();
    if (balloonLoop) {
      this._balloonSprite.setup(balloonLoop);
    } else {
      _Sprite_Character_endBalloon.call(this);
    }
  };

})();