Regionpassage
//=============================================================================
// RegionPassage.js
//=============================================================================

/*:
 * @target MZ
 * @plugindesc Provide advanced options for tile passage.
 * @author taroxd
 *
 * @param Passable Regions
 * @desc Tiles are always passable in these regions.
 * @type number[]
 * @max 255
 * @min 0
 * @default []
 *
 * @param Impassable Regions
 * @desc Tiles are always not passable in these regions.
 * @type number[]
 * @max 255
 * @min 0
 * @default []
 *
 * @help This plugin does not provide plugin commands.
 */

void function() {

    var parameters = PluginManager.parameters('RegionPassage');
    var PASSABLE_REGIONS = JSON.parse(parameters['Passable Regions'])
    var IMPASSABLE_REGIONS = JSON.parse(parameters['Impassable Regions'])

    var REGIONS = {};
    PASSABLE_REGIONS.forEach(function(r) {
        REGIONS[r] = true;
    });
    IMPASSABLE_REGIONS.forEach(function(r) {
        REGIONS[r] = false;
    });

    /* Advanced options:
     *
     * REGIONS[r] = function(regionId)
     *
     * The function determines whether it is possible
     * to go to region `regionId' from region `r'.
     * If the return value is true,
     * then it is always possible regardless of the tile.
     * If the return value is false,
     * then it is always not possible regardless of the tile.
     * Any other return value will leave the passage settings unchanged.
     *
     * For example,
     * Region 3 can be entered from and only from region 4.
     * And Tiles are always passable in region 3.
     * REGIONS[3] = function(r) { return r === 3 || r === 4; };
     *
     * You cannot walk between region 5 and region 6.
     * REGIONS[5] = function(r) { return r !== 6 && null };
     */

    var enable = Object.keys(REGIONS).length > 0;
    if (!enable) return;

    var ip = Game_Map.prototype.isPassable;
    Game_Map.prototype.isPassable = function(x, y, d) {
        var settings = REGIONS[$gameMap.regionId(x, y)];
        if (typeof(settings) === 'function') {
            var x2 = $gameMap.roundXWithDirection(x, d);
            var y2 = $gameMap.roundYWithDirection(y, d);
            settings = settings($gameMap.regionId(x2, y2));
        }
        if (typeof(settings) === 'boolean') {
            return settings;
        }
        return ip.call(this, x, y, d);
    };
}();

Parallaxfix
//=============================================================================
// ParallaxFix.js
//=============================================================================

/*:
 * @target MZ
 * @plugindesc Keeps parallax changes and screen shake from exposing blank edges.
 * @author taroxd
 *
 * @help ParallaxFix.js
 *
 * When an event command or $gameMap.changeParallax changes the parallax, RPG Maker MZ updates the parallax sprite while the new image is still loading.
 * Its width and height are zero at that point, which can make the parallax disappear briefly.
 *
 * This plugin keeps the old parallax visible until the new image finishes loading.
 * When parallaxes are changed repeatedly in quick succession, obsolete load requests cannot overwrite the latest parallax.
 * It also compensates screen shake so the parallax does not expose blank canvas edges.
 *
 * This plugin has no parameters or plugin commands.
 */

(() => {
    Spriteset_Map.prototype.parallaxFixUpdateFrame = function(shake) {
        const x = -shake;
        const width = Graphics.width;
        const height = Graphics.height;

        if (
            this._parallaxFixX !== x ||
            this._parallaxFixWidth !== width ||
            this._parallaxFixHeight !== height
        ) {
            this._parallaxFixX = x;
            this._parallaxFixWidth = width;
            this._parallaxFixHeight = height;
            this._parallax.move(x, 0, width, height);
        }
    };

    Spriteset_Map.prototype.parallaxFixEffectiveShakeX = function(bitmap, originX, shake) {
        if (this._parallaxFixLoopX) {
            return shake;
        }

        if (shake > 0) {
            return Math.min(shake, Math.max(0, originX));
        } else if (shake < 0) {
            const rightEdge = originX + Graphics.width;
            return -Math.min(-shake, Math.max(0, bitmap.width - rightEdge));
        } else {
            return 0;
        }
    };

    Spriteset_Map.prototype.updateParallax = function() {
        const name = $gameMap.parallaxName();
        const shake = Math.round($gameScreen.shake());

        this.parallaxFixUpdateFrame(shake);

        if (this._pendingParallaxName !== name) {
            this._pendingParallaxName = name;

            const requestId = (this._parallaxRequestId || 0) + 1;
            const bitmap = ImageManager.loadParallax(name);
            const parallax = this._parallax;

            this._parallaxRequestId = requestId;

            bitmap.addLoadListener(() => {
                const isCurrentRequest = this._parallaxRequestId === requestId && $gameMap.parallaxName() === name;
                const isAlive = this._parallax === parallax && parallax.texture;

                if (isCurrentRequest && isAlive) {
                    this._parallaxName = name;
                    this._parallaxFixLoopX = $gameMap._parallaxLoopX;
                    parallax.bitmap = bitmap;
                }
            });
        }

        if (this._parallaxName === name) {
            const bitmap = this._parallax.bitmap;

            if (bitmap && bitmap.width > 0 && bitmap.height > 0) {
                const originX = $gameMap.parallaxOx() % bitmap.width;
                this._parallaxFixLoopX = $gameMap._parallaxLoopX;

                const effectiveShake = this.parallaxFixEffectiveShakeX(bitmap, originX, shake);

                this._parallax.origin.x = originX - effectiveShake;
                this._parallax.origin.y = $gameMap.parallaxOy() % bitmap.height;
            }
        }
    };
})();

Inputextra
//=============================================================================
// InputExtra.js
//=============================================================================

/*:
 * @target MZ
 * @plugindesc Extend Input with the full keyboard.
 * @author taroxd
 *
 * @help
 *
 * API:
 *   InputExtra.isPressed(keyCode)
 *   InputExtra.isTriggered(keyCode)
 *   InputExtra.isRepeated(keyCode)
 *   InputExtra.isLongPressed(keyCode)
 *
 *   `InputExtra' is basically the same as `Input'
 *   except that it accepts the keyCode as a parameter.
 */

window.InputExtra = function() {

    var states = {};

    function appendToInput(name, func) {
        var old = Input[name];
        Input[name] = function() {
            old.apply(Input, arguments);
            func.apply(null, arguments);
        }
    }

    function onKeyDown(event) {
        var keyCode = event.keyCode;
        if(!states[keyCode]) {
            states[keyCode] = 0;
        }
    }

    function onKeyUp(event) {
        var keyCode = event.keyCode;
        if (keyCode) {
            delete states[keyCode];
        }
    }

    function clear() {
        states = {};
    }

    function update() {
        for (var code in states) {
            ++states[code];
        }
    }

    appendToInput('_onKeyDown', onKeyDown);
    appendToInput('_onKeyUp', onKeyUp);
    appendToInput('_onLostFocus', clear);

    appendToInput('update', update);
    appendToInput('clear', clear);

    return {
        isPressed: function(keyCode) {
            return states[keyCode] != null;
        },

        isTriggered: function(keyCode) {
            return states[keyCode] === 1;
        },

        isRepeated: function(keyCode) {
            var state = states[keyCode];
            return (state === 1 ||
                (state >= Input.keyRepeatWait &&
                state % Input.keyRepeatInterval === 0));
        },

        isLongPressed: function(keyCode) {
            return states[keyCode] >= Input.keyRepeatWait;
        }
    };

}();