/*============================================================================
 *    ## Plugin Info
 *----------------------------------------------------------------------------
 *    # Plugin Name
 *      DoubleX RMMV Preloaded Resources
 *----------------------------------------------------------------------------
 *    # Terms Of Use
 *      1. Commercial use's always allowed and crediting me's always optional.
 *      2. You shall keep this plugin's Plugin Info part's contents intact.
 *      3. You shalln't claim that this plugin's written by anyone other than
 *         DoubleX or my aliases. I always reserve the right to deny you from
 *         using any of my plugins anymore if you've violated this.
 *      4. If you repost this plugin directly(rather than just linking back),
 *         you shall inform me of these direct repostings. I always reserve
 *         the right to request you to edit those direct repostings.
 *      5. CC BY 4.0, except those conflicting with any of the above, applies
 *         to this plugin, unless you've my permissions not needing follow so.
 *      6. I always reserve the right to deny you from using this plugin
 *         anymore if you've violated any of the above.
 *----------------------------------------------------------------------------
 *    # Prerequisites
 *      Abilities:
 *      1. Nothing special for most ordinary cases
 *         (No capability on Javascript ES5 experience but can still make
 *         reasonable guesses on readable novice codes up to 100 LoC scale)
 *      2. Little RMMV plugin development proficiency to fully utilize this
 *         plugin in intended ways
 *         (Elementary Javascript ES5 exposures being able to write beginner
 *         codes up to 300LoC scale )
 *----------------------------------------------------------------------------
 *    # Links
 *      This Plugin:
 *      1. [url]https://pastebin.com/qjqn9sE0[/url]
 *      Posts:
 *      1. [url]https://forums.rpgmakerweb.com/index.php?threads/doublex-rmmv-preloaded-resources.123760/[/url]
 *      2. [url]https://www.rpgmakercentral.com/topic/42479-doublex-rmmv-preloaded-resources/[/url]
 *      3. [url]https://rpgmaker.net/scripts/789/[/url]
 *      4. [url]http://www.hbgames.org/forums/viewtopic.php?f=332&t=80223[/url]
 *      Mentioned Patreon Supporters:
 *      [url]https://www.patreon.com/posts/71738797[/url]
 *----------------------------------------------------------------------------
 *    # Contributors
 *      Authors:
 *      1. DoubleX
 *      Plugin Development Collaborators:
 *      - None So Far
 *      Bug Reporters:
 *      - None So Far
 *      Compatibility Issue Raisers:
 *      - None So Far
 *      Feature Requesters:
 *      - None So Far
 *----------------------------------------------------------------------------
 *    # Changelog
 *      v1.00b(GMT 0300 27-Mar-2020):
 *      1. You no longer have to edit the value of
 *         DoubleX_RMMZ.Preloaded_Resources_File when changing the plugin file
 *         name
 *      2. Fixed the crashes when preloading animations, images, etc, wthout
 *         hues(such cases will be understood as having the default hue 0 only)
 *      v1.00a(GMT 1500 7-Jul-2020):
 *      1. 1st version of this plugin finished
 *============================================================================*/
/*~struct~PreloadedAnimation:
 * @param filename
 * @type file
 * @dir img/animations/
 * @desc The filename of the animation to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the animation to be preloaded
 */
/*~struct~PreloadedBattleBack1:
 * @param filename
 * @type file
 * @dir img/battlebacks1/
 * @desc The filename of the 1st battle back to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the 1st battle back to be preloaded
 */
/*~struct~PreloadedBattleBack2:
 * @param filename
 * @type file
 * @dir img/battlebacks2/
 * @desc The filename of the 2nd battle back to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the 2nd battle back to be preloaded
 */
/*~struct~PreloadedCharacter:
 * @param filename
 * @type file
 * @dir img/characters/
 * @desc The filename of the character to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the character to be preloaded
 */
/*~struct~PreloadedEnemy:
 * @param filename
 * @type file
 * @dir img/enemies/
 * @desc The filename of the enemy to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the enemy to be preloaded
 */
/*~struct~PreloadedFace:
 * @param filename
 * @type file
 * @dir img/faces/
 * @desc The filename of the face to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the face to be preloaded
 */
/*~struct~PreloadedParallax:
 * @param filename
 * @type file
 * @dir img/parallaxes/
 * @desc The filename of the parallax to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the parallax to be preloaded
 */
/*~struct~PreloadedPicture:
 * @param filename
 * @type file
 * @dir img/pictures/
 * @desc The filename of the picture to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the parallax to be preloaded
 */
/*~struct~PreloadedSVActor:
 * @param filename
 * @type file
 * @dir img/sv_actors/
 * @desc The filename of the sideview actor to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the sideview actor to be preloaded
 */
/*~struct~PreloadedSVEnemy:
 * @param filename
 * @type file
 * @dir img/sv_enemies/
 * @desc The filename of the sideview enemy to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the sideview enemy to be preloaded
 */
/*~struct~PreloadedSystem:
 * @param filename
 * @type file
 * @dir img/system/
 * @desc The filename of the system image to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the system image to be preloaded
 */
/*~struct~PreloadedTileset:
 * @param filename
 * @type file
 * @dir img/tilesets/
 * @desc The filename of the tileset to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the tileset to be preloaded
 */
/*~struct~PreloadedTitle1:
 * @param filename
 * @type file
 * @dir img/titles1/
 * @desc The filename of the 1st title to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the 1st title to be preloaded
 */
/*~struct~PreloadedTitle2:
 * @param filename
 * @type file
 * @dir img/titles2/
 * @desc The filename of the 2nd title to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the 2nd title to be preloaded
 */
/*~struct~PreloadedMiscImage:
 * @param path
 * @type file
 * @dir img/
 * @desc The filename of the misc image to be preloaded
 * @param hues
 * @type number[]
 * @max 360
 * @min 0
 * @desc The hue of the misc image to be preloaded
 * @param smooth
 * @type boolean
 * @desc The smooth of the misc image to be preloaded
 */
/*:
 * @plugindesc (v1.00b)Lets you sets some audios/images to be loaded upon game start
 * This should boost the FPS on phones noticeably if there's enough memory
 * @author DoubleX
 *
 * @param IsPreloadAudio
 * @type boolean
 * @desc Sets whether the specified audios will be preloaded
 * @default true
 *
 * @param preloadAudioMSInterval
 * @parent IsPreloadAudio
 * @type number
 * @desc Sets the number of milliseconds to wait before loading the
 * next audio included by the same parameter(0 means no wait)
 * @default 0
 *
 * @param preloadedBGMs
 * @parent IsPreloadAudio
 * @type file[]
 * @dir audio/bgm/
 * @desc Sets the list of BGMs to be preloaded
 * @default []
 *
 * @param preloadedBGSs
 * @parent IsPreloadAudio
 * @type file[]
 * @dir audio/bgs/
 * @desc Sets the list of BGSs to be preloaded
 * @default []
 *
 * @param preloadedMEs
 * @parent IsPreloadAudio
 * @type file[]
 * @dir audio/me/
 * @desc Sets the list of MEs to be preloaded
 * @default []
 *
 * @param preloadedSEs
 * @parent IsPreloadAudio
 * @type file[]
 * @dir audio/se/
 * @desc Sets the list of SEs to be preloaded
 * @default []
 *
 * @param preloadedStaticSEs
 * @parent IsPreloadAudio
 * @type file[]
 * @dir audio/se/
 * @desc Sets the list of static SEs to be preloaded
 * @default []
 *
 * @param preloadedMiscAudios
 * @parent IsPreloadAudio
 * @type file[]
 * @dir audio/
 * @desc Sets the list of other audio files to be preloaded
 * @default []
 *
 * @param IsPreloadImage
 * @type boolean
 * @desc Sets whether the specified images will be preloaded
 * @default true
 *
 * @param preloadImageMSInterval
 * @parent IsPreloadImage
 * @type number
 * @desc Sets the number of milliseconds to wait before loading the
 * next hue and image under the same parameter(0 means no wait)
 * @default 0
 *
 * @param preloadedAnimations
 * @parent IsPreloadImage
 * @type struct<PreloadedAnimation>[]
 * @desc Sets the list of animations to be preloaded
 * @default []
 *
 * @param preloadedBattleBack1s
 * @parent IsPreloadImage
 * @type struct<PreloadedBattleBack1>[]
 * @desc Sets the list of 1st battle backs to be preloaded
 * @default []
 *
 * @param preloadedBattleBack2s
 * @parent IsPreloadImage
 * @type struct<PreloadedBattleBack2>[]
 * @desc Sets the list of 2nd battle backs to be preloaded
 * @default []
 *
 * @param preloadedCharacters
 * @parent IsPreloadImage
 * @type struct<PreloadedCharacter>[]
 * @desc Sets the list of characters to be preloaded
 * @default []
 *
 * @param preloadedEnemies
 * @parent IsPreloadImage
 * @type struct<PreloadedEnemy>[]
 * @desc Sets the list of enemies to be preloaded
 * @default []
 *
 * @param preloadedFaces
 * @parent IsPreloadImage
 * @type struct<PreloadedFace>[]
 * @desc Sets the list of faces to be preloaded
 * @default []
 *
 * @param preloadedParallaxes
 * @parent IsPreloadImage
 * @type struct<PreloadedParallax>[]
 * @desc Sets the list of parallaxes to be preloaded
 * @default []
 *
 * @param preloadedPictures
 * @parent IsPreloadImage
 * @type struct<PreloadedPicture>[]
 * @desc Sets the list of pictures to be preloaded
 * @default []
 *
 * @param preloadedSVActors
 * @parent IsPreloadImage
 * @type struct<PreloadedSVActor>[]
 * @desc Sets the list of sideview actors to be preloaded
 * @default []
 *
 * @param preloadedSVEnemies
 * @parent IsPreloadImage
 * @type struct<PreloadedSVEnemy>[]
 * @desc Sets the list of sideview enemies to be preloaded
 * @default []
 *
 * @param preloadedSystem
 * @parent IsPreloadImage
 * @type struct<PreloadedSystem>[]
 * @desc Sets the list of system images to be preloaded
 * @default []
 *
 * @param preloadedTilesets
 * @parent IsPreloadImage
 * @type struct<PreloadedTileset>[]
 * @desc Sets the list of tilesets to be preloaded
 * @default []
 *
 * @param preloadedTitles1
 * @parent IsPreloadImage
 * @type struct<PreloadedTitle1>[]
 * @desc Sets the list of 1st titles to be preloaded
 * @default []
 *
 * @param preloadedTitles2
 * @parent IsPreloadImage
 * @type struct<PreloadedTitle2>[]
 * @desc Sets the list of 2nd titles to be preloaded
 * @default []
 *
 * @param preloadedMiscImages
 * @parent IsPreloadImage
 * @type struct<PreloadedMiscImage>[]
 * @desc Sets the list of other image files to be preloaded
 * @default []
 *
 * @help
 *============================================================================
 * 1. You should only preload resources that are actually used or the game can
 *    take an excessively and unnecessarily long time to start
 * 2. You might have to test the values of preloadAudioMSInterval and
 *    preloadImageMSInterval to have the optimal preload time for your project
 * 3. Setting preloadAudioMSInterval/preloadImageMSInterval as 0 might block
 *    the UI thread for too long and thus crashing/freezing the game in phones
 * 4. You should consider not preloading resources that are only rarely used
 *    in case the preloading times are still too long
 * 5. Some plugins might use HTML5Audio instead of WebAudio, and preloading
 *    audios using HTML5Audio is meaningless as HTML5Audio is a static class
 *    having nothing to preload
 * 6. You should compress the resources to be preoloaded for phones or the
 *    extra memory consumption from preloading them can quickly crash/freeze
 *    the game there
 * 7. No identical resource should be duplicated in the same parameter or
 *    across parameters(this plugin won't explicitly skip those duplicates as
 *    simplifying the codes this way can actually reduce preload time)
 * 8. If you want to keep the current parameter values in the plugin manager
 *    upon using a newer version, you can do the following:
 *    - Renames the newer version to be that of the older version
 *    - Edits the value of DoubleX_RMMV.Preloaded_Resources_File to be the
 *      filename of the older version, which must be done via opening this
 *      plugin js file directly
 * 9. (Advanced)By default, the images are cached upon their first uses, and
 *    the cache is a Least Recently Used(LRU) cache. This plugin reserves all
 *    preloaded images so the LRU will never release them unless they're
 *    explicitly told to be released via a script call
 * 10. (Advanced)To preload images in nested folders(like pictures/folderX),
 *     you've to use preloadedMiscImages, and their paths must be entered via
 *     raw texts, because the default RMMV plugin manager doesn't natively
 *     support resources in nested folders, meaning that hacks are inevitable
 *============================================================================
 *    ## (Advanced)Script Call Info
 *----------------------------------------------------------------------------
 *    # Image manipulations
 *      1. ImageManager.releasePreloadedFolderImg(param, filename, hue)
 *         - Releases the image with the filename filename and hue hue
 *           specified in parameter param
 *         - This can be useful when an image becomes rarely used and/or the
 *           preloaded images are consuming too much memory
 *         - Please note that using this script call doesn't always remove the
 *           image from the LRU cache instantly as it's still up to the LRU
 *           cache to determine when to remove that image now that it can be
 *           removed due to no longer being reserved
 *         - param and filename are supposed to be String
 *         - hue is supposed to be an integer from 0 to 360 inclusive
 *         - The script call's supposed to be Idempotent
 *      2. ImageManager.releasePreloadedMiscImg(path, hue, smooth)
 *         - Releases the image with the path path, hue hue and smooth smooth
 *         - This can be useful when an image becomes rarely used and/or the
 *           preloaded images are consuming too much memory
 *         - Please note that using this script call doesn't always remove the
 *           image from the LRU cache instantly as it's still up to the LRU
 *           cache to determine when to remove that image now that it can be
 *           removed due to no longer being reserved
 *         - path is supposed to be a String
 *         - hue is supposed to be an integer from 0 to 360 inclusive
 *         - smooth is supposed to be a Boolean
 *         - The script call's supposed to be Idempotent
 *    # Audio manipulations
 *      1. AudioManager.invalidateCachedWebAudio(folder, name)
 *         - Releases the audio with folder folder and filename name from the
 *           audio cache
 *         - This doesn't work for static SE audio loaded as WebAudio
 *         - folder is supposed to be a String
 *         - name is supposed to be a String
 *         - The script call's supposed to be Idempotent
 *============================================================================
 */

var DoubleX_RMMV = DoubleX_RMMV || {};
DoubleX_RMMV["Preloaded Resources"] = "v1.00b";

(function() {

    "use strict";

    var src = document.currentScript.src;
    var name = src.split("/").slice(-1)[0].split(".")[0].replace(/%20/g, " ");
    DoubleX_RMMV.Preloaded_Resources_File = name;

})();

/*============================================================================
 *    ## Plugin Implementations
 *       You need not edit this part as it's about how this plugin works
 *----------------------------------------------------------------------------
 *    # Plugin Support Info:
 *      1. Prerequisites
 *         - Basic knowledge on what Graphics, DataManager, ImageManager and
 *           AudioManager do in general
 *         - Some RMMV plugin development proficiency to fully comprehend this
 *           plugin
 *           (Basic knowledge on what RMMV plugin development does in general
 *           with several easy, simple and small plugins written without
 *           nontrivial bugs up to 1000 LoC scale but still being
 *           inexperienced)
 *      2. Parameter/Return value of type * means it might be of any type
 *      3. Function signature with (**) means it might take any number of
 *         parameters of any type
 *----------------------------------------------------------------------------*/

DoubleX_RMMV.Preloaded_Resources = {};

/*----------------------------------------------------------------------------
 *    # Edit class: Graphics
 *      - Preloads all resources specified in parameters upon game start
 *----------------------------------------------------------------------------*/

(function() {

    "use strict";

    // It's unlikely that the original version's needed
    Graphics._paintUpperCanvas = function() { // v1.00a - v1.00a; Rewritten
        this._clearUpperCanvas();
        // It's unlikely that these codes will be edited
        if (isPaintUpperCanvas.call(this)) paintUpperCanvas.call(this);
        //
    }; // Graphics._paintUpperCanvas
    //

    var MIN_LOADING_COUNT = 20;

    /**
     * Nullipotent
     * @since v1.00a @version v1.00a
     * @return {Boolean} The check result
     */
    function isPaintUpperCanvas() { // It's unlikely that it'll ever be reused
        return this._loadingImage && this._loadingCount >= MIN_LOADING_COUNT;
    } // isPaintUpperCanvas

    /**
     * Idempotent
     * @since v1.00a @version v1.00a
     * @todo Stops redrawing the loading image every frame
     */
    function paintUpperCanvas() { // It's unlikely that it'll ever be reused
        var context = this._upperCanvas.getContext("2d");
        context.save();
        var alpha = ((this._loadingCount - MIN_LOADING_COUNT) / 30).clamp(0, 1);
        context.globalAlpha = alpha;
        var dx = (this._width - this._loadingImage.width) / 2;
        var dy = (this._height - this._loadingImage.height) / 2;
        context.drawImage(this._loadingImage, dx, dy);
        drawPreloadProgressBar.call(this, context, dx, dy);
        context.restore();
    } // paintUpperCanvas

    /**
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {CanvasRenderingContext2D} context - The 2D canvas context
     * @param {Int} dx - The starting x coordinate of the canvas drawing
     * @param {Int} dy - The starting y coordinate of the canvas drawing
     * @todo Breaks this excessively long function into several shorter pieces
     */
    function drawPreloadProgressBar(context, dx, dy) {
        if (!this.isDrawPreloadProgressBar) return;
        var num = DataManager.preloadResourceNum;
        if (num <= 0) return;
        var fillStyle = context.fillStyle;
        context.fillStyle = "white";
        var y = dy + this._loadingImage.height;
        var width = this._loadingImage.width;
        var height = this._loadingImage.height / 4;
        context.fillRect(dx, y, width, height);
        context.fillStyle = "green";
        var progress = DataManager.preloadResourceProgress;
        context.fillRect(dx, y, width * progress / num, height);
        context.fillStyle = "blue";
        var font = context.font;
        context.font = "16px GameFont";
        var text = "Preloaded " + progress + "/" + num + " specified resources";
        var textX = dx + width / 2 - context.measureText(text).width / 2;
        // The formalu of textY is derived from actual testings
        var textY = y + height / 2 + 4, lineJoin = context.lineJoin;
        //
        context.lineJoin = "round";
        context.strokeText(text, textX, textY, width);
        context.fillText(text, textX, textY, width);
        context.lineJoin = lineJoin;
        context.font = font, context.fillStyle = fillStyle;
    } // drawPreloadProgressBar

})(); // Graphics

/*----------------------------------------------------------------------------
 *    # Edit class: DataManager
 *      - Preloads all resources specified in parameters upon game start
 *----------------------------------------------------------------------------*/

(function(PR) {

    "use strict";

    PR.DataManager = { orig: {}, new: {} };
    var _DM = PR.DataManager.orig, _PR = PR.DataManager.new;

    _PR.BOOL_PARAM_RESULT = function(val) {
        return val && (val === "true" || val !== "false");
    }; // _PR.BOOL_PARAM_RESULT

    _PR._PARSE_IMG_PARAM = function(parsedVal, v, i) {
        var obj = parsedVal[i] = JSON.parse(v);
        var hues = JSON.parse(obj.hues || "[]");
        hues.forEach(function(hue, j) { hues[j] = JSON.parse(hue); });
        // Animations, images, etc without hues are treated as with hue 0 only
        if (hues.length <= 0) hues.push(0);
        //
        // Smooth is either true or false so an array of smoothes' not needed
        obj.hues = hues, obj.smooth = obj.smooth && JSON.parse(obj.smooth);
        //
    }; // _PR._PARSE_IMG_PARAM
    _PR._PARSED_IMG_PARAM = function(parsedVal) {
        // Not using declarative counterparts' minimize perload time and memory
        parsedVal.forEach(function(v, i) {
            _PR._PARSE_IMG_PARAM(parsedVal, v, i);
        });
        return parsedVal;
        //
    }; // _PR._PARSED_IMG_PARAM
    _PR._PARSED_PARAM = function(param, val) {
        var parsedVal = JSON.parse(val);
        if (PR.ImageManager.new.PRELOAD_IMG_PARAMS.contains(param)) {
            return _PR._PARSED_IMG_PARAM(parsedVal);
        }
        return parsedVal;
    }; // _PR._PARSED_PARAM
    _PR._PARSED_PARAMS = function(params) {
        Object.keys(params).forEach(function(param) {
            params[param] = _PR._PARSED_PARAM(param, params[param]);
        });
        return params;
    }; // _PR._PARSED_PARAMS

    // Marks whether the parameters in the parent are all preloaded or skipped
    DataManager._isParentParamPreloaded = { // New private variable
        IsPreloadAudio: false,
        IsPreloadImage: false
    }; // DataManager._isParentParamPreloaded
    //

    DataManager.preloadResourceNum = DataManager.preloadResourceProgress = 0;

    _PR._PARENT_PARAMS = Object.keys(DataManager._isParentParamPreloaded);

    _DM.loadDatabase = DataManager.loadDatabase;
    _PR.loadDatabase = DataManager.loadDatabase = function() {
    // v1.00a - v1.00a; Extended
        _DM.loadDatabase.apply(this, arguments);
        // Added to preload all specified audio and image resources as well
        _PR._preload.call(this);
        //
    }; // DataManager.loadDatabase

    _DM.isDatabaseLoaded = DataManager.isDatabaseLoaded;
    _PR.isDatabaseLoaded = DataManager.isDatabaseLoaded = function() {
    // v1.00a - v1.00a; Extended
        // Edited to start the game only after all resources are preloaded too
        if (!_DM.isDatabaseLoaded.apply(this, arguments)) return false;
        return this._areAllResourcesPreloaded;
        //
    }; // DataManager.isDatabaseLoaded

    /**
     * Idempotent
     * @interface @since v1.00a @version v1.00a
     * @param {Param} parentParam - The parameter as the parent of other ones
     */
    DataManager.onFinishPreload = function(parentParam) {
        console.info("All parameters under " + parentParam + " are preloaded.");
        this._isParentParamPreloaded[parentParam] = true;
        if (!_PR._areAllParentParamsPreloaded.call(this)) return;
        _PR._onFinishPreload.call(this);
    }; // DataManager.onFinishPreload

    /**
     * The this pointer is DataManager
     * Idempotent
     * @since v1.00a @version v1.00a
     */
    _PR._preload = function() {
        // Ensures this method will only be called once
        if (this._isPreloadResourceRun) return;
        Graphics.isDrawPreloadProgressBar = true;
        _PR._preloadStartNow = Date.now();
        _PR._preloadResources.call(this);
        this._isPreloadResourceRun = true; // New private variable
        //
    }; // _PR._preload

    /**
     * The this pointer is DataManager
     * Idempotent
     * @since v1.00a @version v1.00a
     */
    _PR._preloadResources = function() {
        var params = _PR._parsedParams.call(this);
        // They must be placed here to have the most accurate report
        var elapsedMs = Date.now() - _PR._preloadStartNow;
        console.info("Parameters parsing time: " + elapsedMs + " milliseconds");
        //
        ImageManager.preloadImgs(params);
        AudioManager.preloadAudios(params);
    }; // _PR._preloadResources

    /**
     * The this pointer is DataManager
     * Nullipotent
     * @since v1.00a @version v1.00a
     * @returns {{*}} The mapping of all parameter name-value pairs
     */
    _PR._parsedParams = function() {
        // This method's called only once anyway so it won't hurt performance
        var filename = DoubleX_RMMV.Preloaded_Resources_File;
        var params = PluginManager.parameters(filename);
        //
        // Parsing the whole thing all at once's much faster than parsing later
        return _PR._PARSED_PARAMS(JsonEx.makeDeepCopy(params));
        // The original plugin parameter container shouldn't be ever edited
    }; // _PR._parsedParams

    /**
     * The this pointer is DataManager
     * Nullipotent
     * @since v1.00a @version v1.00a
     * @returns {Boolean} The check result
     */
    _PR._areAllParentParamsPreloaded = function() {
        return _PR._PARENT_PARAMS.every(_PR._isParentParamPreloaded, this);
    }; // _PR._areAllParentParamsPreloaded

    /**
     * The this pointer is DataManager
     * Nullipotent
     * @since v1.00a @version v1.00a
     * @param {Param} parentParam - The parameter as the parent of other ones
     * @returns {Boolean} The check result
     */
    _PR._isParentParamPreloaded = function(parentParam) {
        return this._isParentParamPreloaded[parentParam];
    }; // _PR._isParentParamPreloaded

    /**
     * The this pointer is DataManager
     * Idempotent
     * @since v1.00a @version v1.00a
     */
    _PR._onFinishPreload = function() {
        // It's better to be clear by using 2 variables even when 1 is suffice
        this._areAllResourcesPreloaded = true;
        Graphics.isDrawPreloadProgressBar = false;
        //
        var elapsedMs = Date.now() - _PR._preloadStartNow;
        console.info("Preload time elapsed: " + elapsedMs + " milliseconds");
    }; // _PR._onFinishPreload

})(DoubleX_RMMV.Preloaded_Resources); // DataManager

/*----------------------------------------------------------------------------
 *    # Edit class: ImageManager
 *      - Preloads all specified image resources upon game start
 *----------------------------------------------------------------------------*/

(function(PR) {

    "use strict";

    PR.ImageManager = { orig: {}, new: {} };
    var DM = PR.DataManager.new, _PR = PR.ImageManager.new;

    _PR._FOLDER_IMG_RESERVATION_ID = function(param, filename, hue) {
        return JSON.stringify({ param: param, filename: filename, hue: hue });
    }; // _PR._FOLDER_IMG_RESERVATION_ID
    _PR._IMG_HUE_COUNT = function(imgs) {
        return imgs.reduce(_PR._REDUCED_IMG_HUE_COUNT, 0);
    }; // _PR._IMG_HUE_COUNT
    _PR._IS_VALID_HUE = function(hue) {
        return Number.isInteger(hue) && hue >= 0 && hue <= 360;
    }; // _PR._IS_VALID_HUE
    _PR._MISC_IMG_RESERVATION_ID = function(path, hue, smooth) {
        return JSON.stringify({ path: path, hue: hue, smooth: smooth });
    }; // _PR._MISC_IMG_RESERVATION_ID
    _PR._REDUCED_IMG_HUE_COUNT = function(imgHueCount, img) {
        return imgHueCount + img.hues.length;
    }; // _PR._REDUCED_IMG_HUE_COUNT
    _PR._SHOW_INVALID_IMG_HUE = function(name, hue) {
        try { asdasdasdasdasdasd; /* Forcibly throws an error */ } catch (err) {
            console.warn([
                "The hue of image " + name + " is " + hue + ".",
                "But hue must be an integer from 0 to 360 inclusive!",
                "The relevant stacktrace is as follows:",
                err.stack
            ].join("\n"));
        }
    }; // _PR._SHOW_INVALID_IMG_HUE

    // Maps the preload image parameter to the ImageManager function to be used
    _PR._PRELOAD_IMG_PARAM_FUNCS = {
        preloadedAnimations: "reserveAnimation",
        preloadedBattleBack1s: "reserveBattleback1",
        preloadedBattleBack2s: "reserveBattleback2",
        preloadedCharacters: "reserveCharacter",
        preloadedEnemies: "reserveEnemy",
        preloadedFaces: "reserveFace",
        preloadedParallaxes: "reserveParallax",
        preloadedPictures: "reservePicture",
        preloadedSVActors: "reserveSvActor",
        preloadedSVEnemies: "reserveSvEnemy",
        preloadedSystem: "reserveSystem",
        preloadedTilesets: "reserveTileset",
        preloadedTitles1: "reserveTitle1",
        preloadedTitles2: "reserveTitle2"
    }; // _PR._PRELOAD_IMG_PARAM_FUNCS
    //

    _PR.PRELOAD_IMG_PARAMS = Object.keys(_PR._PRELOAD_IMG_PARAM_FUNCS);
    _PR.PRELOAD_IMG_PARAMS.push("preloadedMiscImages");

    // Marks which image parameters have finished preloading image files
    ImageManager._isImgParamPreloaded = {}; // New private variable
    //

    /**
     * DON'T CALL THIS MANUALLY UNLESS YOU REALLY KNOW WHAT YOU'RE TRULY DOING
     * Idempotent
     * @interface @since v1.00a @version v1.00a
     * @param {{String}} params - The mapping of all parameter name-value pairs
     */
    ImageManager.preloadImgs = function(params) {
        if (DM.BOOL_PARAM_RESULT(params.IsPreloadImage)) {
            return _PR._preloadImgs.call(this, params);
        }
        DataManager.onFinishPreload("IsPreloadImage");
    }; // ImageManager.preloadImgs

    /**
     * Idempotent
     * @interface @since v1.00a @version v1.00a
     * @param {Param} param - The name of the parameter of images in folder
     * @param {String} filename - The name of the image to be preloaded
     * @param {Hue} hue - The hue of the image to be preloaded
     */
    ImageManager.releasePreloadedFolderImg = function(param, filename, hue) {
        var id = _PR._FOLDER_IMG_RESERVATION_ID(param, filename, hue);
        this.releaseReservation(id);
    }; // ImageManager.releasePreloadedFolderImg

    /**
     * Idempotent
     * @interface @since v1.00a @version v1.00a
     * @param {String} path - The path of the image to be preloaded
     * @param {Hue} hue - The hue of the image to be preloaded
     * @param {Boolean} smooth - The smooth of the image to be preloaded
     */
    ImageManager.releasePreloadedMiscImg = function(path, hue, smooth) {
        var reservationId = _PR._MISC_IMG_RESERVATION_ID(path, hue, smooth);
        this.releaseReservation(reservationId);
    }; // ImageManager.releasePreloadedMiscImg

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {{String}} params - The mapping of all parameter name-value pairs
     */
    _PR._preloadImgs = function(params) {
        _PR._preloadImgsInFolders.call(this, params, interval);
        var interval = params.preloadImageMSInterval;
        _PR._preloadMiscImgs.call(this, params.preloadedMiscImages, interval);
    }; // _PR._preloadImgs

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {{String}} params - The mapping of all parameter name-value pairs
     */
    _PR._preloadImgsInFolders = function(params) {
        // This method's called only once anyway so it won't hurt performance
        Object.keys(_PR._PRELOAD_IMG_PARAM_FUNCS).forEach(function(param) {
            _PR._preloadImgsInFolder.call(this, params, param);
        }, this);
        // Not binding _preloadImgsInFolder is to minimize preload memory leaks
    }; // _PR._preloadImgsInFolders

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {{String}} params - The mapping of all parameter name-value pairs
     * @param {Param} param - The name of the parameter of images in folder
     */
    _PR._preloadImgsInFolder = function(params, param) {
        var imgs = params[param], interval = params.preloadImageMSInterval;
        // Not binding _preloadImgHues is to minimize preload memory leaks
        var preloadHuesFunc = function(image, nextFunc) {
            var self = ImageManager;
            _PR._preloadImgHues.call(self, param, interval, image, nextFunc);
        };
        //
        _PR._runPreloadImgQueue.call(this, imgs, param, preloadHuesFunc);
    }; // _PR._preloadImgsInFolder

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {Param} param - The name of the parameter of images in folder
     * @param {Number} interval - The number of milliseconds as interval
     * @param {{String, [Hue]}} img - The image information to preload image
     * @param {()} nextFunc - The function as the image preload queue
     */
    _PR._preloadImgHues = function(param, interval, img, nextFunc) {
        // Not binding _callReserveImgFunc is to minimize preload memory leaks
        var filename = img.filename, hues = img.hues, callFunc = function(hue) {
            _PR._callReserveImgFunc.call(ImageManager, param, filename, hue);
        };
        //
        _PR._runPreloadHueQueue.call(this, hues, nextFunc, callFunc, interval);
    }; // _PR._preloadImgHues

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {Param} param - The name of the parameter of images in folder
     * @param {String} filename - The name of the image to be preloaded
     * @param {Hue} hue - The hue of the image to be preloaded
     */
    _PR._callReserveImgFunc = function(param, filename, hue) {
        if (!_PR._IS_VALID_HUE(hue)) { // Users might input raw values directly
            return _PR._SHOW_INVALID_IMG_HUE(filename, hue);
        }
        // Users might input raw values or empty images directly
        if (filename) _PR._reserveImg.call(this, param, filename, hue);
        //
    }; // _PR._callReserveImgFunc

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {Param} param - The name of the parameter of images in folder
     * @param {String} filename - The name of the image to be preloaded
     * @param {Hue} hue - The hue of the image to be preloaded
     */
    _PR._reserveImg = function(param, filename, hue) {
        var id = _PR._FOLDER_IMG_RESERVATION_ID(param, filename, hue);
        // _PR._PRELOAD_IMG_PARAM_FUNCS[param] is the reserve image function
        this[_PR._PRELOAD_IMG_PARAM_FUNCS[param]](filename, hue, id);
        //
    }; // _PR._reserveImg

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {[String]} imgs - The list of misc image file paths
     * @param {Number} interval - The number of milliseconds as interval
     */
    _PR._preloadMiscImgs = function(imgs, interval) {
        // Not binding _preloadMiscImgHues is to minimize preload memory leaks
        var preloadHuesFunc = function(img, nextFunc) {
            _PR._preloadMiscImgHues.call(ImageManager, interval, img, nextFunc);
        };
        //
        var param = "preloadedMiscImages";
        _PR._runPreloadImgQueue.call(this, imgs, param, preloadHuesFunc);
    }; // _PR._preloadMiscImgs

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {[{String, [Hue], Boolean]}} imgs - image files to be preloaded
     * @param {Param} param - The name of the parameter of images in folder
     * @param {(**)} preloadFunc - The function preloading the image hues
     */
    _PR._runPreloadImgQueue = function(imgs, param, preloadHuesFunc) {
        DataManager.preloadResourceNum += _PR._IMG_HUE_COUNT(imgs);
        // Otherwise loading too many images all at once can be too slow
        (function preload() {
            if (imgs.length <= 0) {
                return _PR._onFinishPreloadImgs.call(ImageManager, param);
            }
            preloadHuesFunc(imgs.shift(), preload);
        })();
        /** @todo Thinks of a way to eliminate the inner function memory leak */
    }; // _PR._runPreloadImgQueue

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {Param} param - The name of the parameter of images in folder
     */
    _PR._onFinishPreloadImgs = function(param) {
        console.info("All images specified in " + param + " are preloaded.");
        this._isImgParamPreloaded[param] = true;
        if (!_PR._areAllImgParamsPreloaded.call(this)) return;
        DataManager.onFinishPreload("IsPreloadImage");
    }; // _PR._onFinishPreloadImgs

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @returns {Boolean} The check result
     */
    _PR._areAllImgParamsPreloaded = function() {
        return _PR.PRELOAD_IMG_PARAMS.every(_PR._isImgParamPreloaded, this);
    }; // _PR._areAllImgParamsPreloaded

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {Param} param - The name of the parameter of images in folder
     * @returns {Boolean} The check result
     */
    _PR._isImgParamPreloaded = function(param) {
        return this._isImgParamPreloaded[param];
    }; // _PR._isImgParamPreloaded

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {Number} interval - The number of milliseconds as interval
     * @param {{String, [Hue], Boolean}} img - Misc image file to be preloaded
     * @param {()} nextFunc - The function as the image preload queue
     */
    _PR._preloadMiscImgHues = function(interval, img, nextFunc) {
        // smooth is either true or false so an array of smoothes' not needed
        var path = img.path, smooth = img.smooth, hues = img.hues;
        //
        // Not binding _preloadMiscImg is to minimize preload memory leaks
        var preload = function(hue) {
            _PR._preloadMiscImg.call(ImageManager, path, smooth, hue);
        };
        //
        _PR._runPreloadHueQueue.call(this, hues, nextFunc, preload, interval);
    }; // _PR._preloadMiscImgHues

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {[Hue]} hues - The list of hues of the current image to preload
     * @param {()} nextFunc - The as the image preload queue
     * @param {(**)} preloadFunc - The function preloading the image hue
     * @param {Number} interval - The number of milliseconds as interval
     */
    _PR._runPreloadHueQueue = function(hues, nextFunc, preloadFunc, interval) {
        // Using inner function's more performant by avoiding repeated bindings
        var isSetTimeout = interval > 0; // It's better than redundant checkings
        (function preload() {
            if (hues.length <= 0) return nextFunc();
            // Extracting them into a function can hurt perload time and memory
            preloadFunc(hues.shift());
            DataManager.preloadResourceProgress++;
            isSetTimeout ? setTimeout(preload, interval) : preload();
            //
        })();
        /** @todo Thinks of a way to eliminate the inner function memory leak */
    }; // _PR._runPreloadHueQueue

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {String} path - The path of the image to be preloaded
     * @param {Boolean} smooth - The smooth of the image to be preloaded
     * @param {Hue} hue - The hue of the image to be preloaded
     */
    _PR._preloadMiscImg = function(path, smooth, hue) {
        if (!_PR._IS_VALID_HUE(hue)) { // Users might input raw values directly
            return _PR._SHOW_INVALID_IMG_HUE(path, hue);
        }
        _PR._preloadValidMiscImg.call(this, path, hue, smooth);
    }; // _PR._preloadMiscImg

    /**
     * The this pointer is ImageManager
     * Idempotent
     * @since v1.00a @version v1.00b
     * @param {String} path - The path of the image to be preloaded
     * @param {Hue} hue - The hue of the image to be preloaded
     * @param {Boolean} smooth - The smooth of the image to be preloaded
     */
    _PR._preloadValidMiscImg = function(path, hue, smooth) {
        // It's to support nested folders for misc images only
        var filename = path.replace(/.*\//gmi, "");
        var folder = "img/" + path.replace(new RegExp(filename + "$"), "");
        //
        // Users might input raw values or empty images directly
        if (!folder && filename) return; // Empty images are allowed
        //
        // Extracting them into a method would pass redundant variables
        var reservationId = _PR._MISC_IMG_RESERVATION_ID(path, hue, smooth);
        this.reserveBitmap(folder, filename, hue, smooth, reservationId);
        //
    }; // _PR._preloadValidMiscImg

})(DoubleX_RMMV.Preloaded_Resources); // ImageManager

/*----------------------------------------------------------------------------
 *    # Edit class: AudioManager
 *      - Caches all previously created WebAudios and preloads them all
 *----------------------------------------------------------------------------*/

(function(PR) {

    "use strict";

    PR.AudioManager = { orig: {}, new: {} };
    var DM = PR.DataManager.new;
    var _AM = PR.AudioManager.orig, _PR = PR.AudioManager.new;

    _PR._PRELOAD_AUDIO_PARAM_FOLDERS = {
        preloadedBGMs: "bgm",
        preloadedBGSs: "bgs",
        preloadedMEs: "me",
        preloadedSEs: "se"
    }; // _PR._PRELOAD_AUDIO_PARAM_FOLDERS

    _PR._PRELOAD_AUDIO_PARAMS = Object.keys(_PR._PRELOAD_AUDIO_PARAM_FOLDERS);
    _PR._PRELOAD_AUDIO_PARAMS.push("preloadedStaticSEs");
    _PR._PRELOAD_AUDIO_PARAMS.push("preloadedMiscAudios");

    // Marks which audio parameters have finished preloading audio files
    AudioManager._isAudioParamPreloaded = {}; // New private variable
    //
    // Stores the mapping from all urls to their preloaded web audios
    AudioManager._preloadedWebAudios = {}; // New private variable
    //

    _AM.createBuffer = AudioManager.createBuffer;
    _PR.createBuffer = AudioManager.createBuffer = function(folder, name) {
    // v1.00a - v1.00a; Rewritten
        // Rewritten to cache the already created WebAudio instead
        var url = _PR._bufferUrl.call(this, folder, name);
        if (_PR._isHTML5Audio.call(this, folder)) {
            return _PR._html5Audio.call(this, url);
        } else return _PR._webAudio.call(this, url);
        //
    }; // AudioManager.createBuffer

    /**
     * DON'T CALL THIS MANUALLY UNLESS YOU REALLY KNOW WHAT YOU'RE TRULY DOING
     * Idempotent
     * @interface @since v1.00a @version v1.00a
     * @param {{String}} params - The mapping of all parameter name-value pairs
     */
    AudioManager.preloadAudios = function(params) {
        if (DM.BOOL_PARAM_RESULT(params.IsPreloadAudio)) {
            return _PR._preloadAudios.call(this, params);
        }
        DataManager.onFinishPreload("IsPreloadAudio");
    }; // AudioManager.preloadAudios

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {String} folder - The name of the folder under the audio folder
     * @param {String}  name - The name of the audio to create its buffer
     */
    AudioManager.invalidateCachedWebAudio = function(folder, name) {
        var url = _PR._bufferUrl.call(this, folder, name);
        // Using isStaticSe might risk name collision for non se audios
        if (!this._staticBuffers.contains(this._preloadedWebAudios[url])) {
            delete this._preloadedWebAudios[url];
        }
        //
    }; // AudioManager.invalidateCachedWebAudio

    /**
     * The this pointer is AudioManager
     * Nullipotent
     * @since v1.00a @version v1.00a
     * @param {String} folder - The name of the folder under the audio folder
     * @param {String}  name - The name of the audio to create its buffer
     * @returns {String} The url of the audio buffer to be created
     */
    _PR._bufferUrl = function(folder, name) {
        var ext = this.audioFileExt();
        return this._path + folder + "/" + encodeURIComponent(name) + ext;
    }; // _PR._bufferUrl

    /**
     * The this pointer is AudioManager
     * Nullipotent
     * @since v1.00a @version v1.00a
     * @param {String} folder - The name of the folder under the audio folder
     * @returns {Boolean} The check result
     */
    _PR._isHTML5Audio = function(folder) {
        // shouldUseHtml5Audio is false now but might be changed by plugins
        return folder === "bgm" && this.shouldUseHtml5Audio();
        //
    }; // _PR._isHTML5Audio

    /**
     * The this pointer is AudioManager
     * Nullipotent
     * @since v1.00a @version v1.00a
     * @param {String} url - The url of the audio buffer to be created
     * @returns {Html5Audio} The Html5Audio as the audio buffer to be created
     */
    _PR._html5Audio = function(url) {
        Html5Audio.setup(this._blobUrl || url);
        return Html5Audio;
    }; // _PR._html5Audio

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {String} url - The url of the audio buffer to be created
     * @returns {WebAudio} The WebAudio as the audio buffer to be created
     */
    _PR._webAudio = function(url) {
        if (!this._preloadedWebAudios[url]) {
            this._preloadedWebAudios[url] = new WebAudio(url);
        }
        return this._preloadedWebAudios[url];
    }; // _PR._webAudio

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {{String}} params - The mapping of all parameter name-value pairs
     */
    _PR._preloadAudios = function(params) {
        _PR._preloadAudioInFolders.call(this, params);
         var interval = params.preloadAudioMSInterval;
        _PR._preloadStaticSEs.call(this, params.preloadedStaticSEs, interval);
        _PR._preloadMiscAudios.call(this, params.preloadedMiscAudios, interval);
    }; // _PR._preloadAudios

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {{String}} params - The mapping of all parameter name-value pairs
     */
    _PR._preloadAudioInFolders = function(params) {
        // This method's called only once anyway so it won't hurt performance
        Object.keys(_PR._PRELOAD_AUDIO_PARAM_FOLDERS).forEach(function(param) {
            _PR._preloadAudioInFolder.call(this, params, param);
        }, this);
        // Not binding _preloadAudioInFolder is to minimize preload memory leaks
    }; // _PR._preloadAudioInFolders

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {{String}} params - The mapping of all parameter name-value pairs
     * @param {Param} param - The name of the parameter of audios in folder
     */
    _PR._preloadAudioInFolder = function(params, param) {
        var folder = _PR._PRELOAD_AUDIO_PARAM_FOLDERS[param];
        // Not binding _preloadAudio is to minimize preload memory leaks
        var func = function(audio) {
            _PR._preloadAudio.call(AudioManager, folder, audio);
        }, audios = params[param];
        //
        var interval = params.preloadAudioMSInterval;
        _PR._runPreloadAudioQueue.call(this, audios, param, func, interval);
    }; // _PR._preloadAudioInFolder

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {[String]} audios - The list of misc audio file paths
     * @param {Number} interval - The number of milliseconds as interval
     */
    _PR._preloadStaticSEs = function(audios, interval) {
        // Not binding loadStaticSe is to minimize preload memory leaks
        var func = function(audio) { AudioManager.loadStaticSe(audio); };
        //
        var param = "preloadedStaticSEs";
        _PR._runPreloadAudioQueue.call(this, audios, param, func, interval);
    }; // _PR._preloadStaticSEs

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {[String]} audios - The list of misc audio file paths
     * @param {Number} interval - The number of milliseconds as interval
     */
    _PR._preloadMiscAudios = function(audios, interval) {
        // Not binding _preloadMiscAudio is to minimize preload memory leaks
        var func = function(audio) {
            _PR._preloadMiscAudio.call(AudioManager, audio);
        }, param = "preloadedMiscAudios";
        //
        _PR._runPreloadAudioQueue.call(this, audios, param, func, interval);
    }; // _PR._preloadMiscAudios

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {String} audios - The list of filenames of the audios to preload
     * @param {Param} param - The name of the parameter of audios in folder
     * @param {(**)} preloadFunc - The function preloading the audio file
     * @param {Number} interval - The number of milliseconds as interval
     */
    _PR._runPreloadAudioQueue = function(audios, param, preloadFunc, interval) {
        DataManager.preloadResourceNum += audios.length;
        // Using inner function's more performant by avoiding repeated bindings
        var isSetTimeout = interval > 0; // It's better than redundant checkings
        (function preload() {
            if (audios.length <= 0) {
                return _PR._onFinishPreloadAudios.call(AudioManager, param);
            }
            // Extracting them into a function can hurt perload time and memory
            preloadFunc(audios.shift());
            DataManager.preloadResourceProgress++;
            isSetTimeout ? setTimeout(preload, interval) : preload();
            //
        })();
        /** @todo Thinks of a way to eliminate the inner function memory leak */
    }; // _PR._runPreloadAudioQueue

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {Param} param - The name of the parameter of audios in folder
     */
    _PR._onFinishPreloadAudios = function(param) {
        console.info("All audios specified in " + param + " are preloaded.");
        this._isAudioParamPreloaded[param] = true;
        if (!_PR._areAllAudioParamsPreloaded.call(this)) return;
        DataManager.onFinishPreload("IsPreloadAudio");
    }; // _PR._onFinishPreloadAudios

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @returns {Boolean} The check result
     */
    _PR._areAllAudioParamsPreloaded = function() {
        var preloadAudioParams = _PR._PRELOAD_AUDIO_PARAMS;
        return preloadAudioParams.every(_PR._isAudioParamPreloaded, this);
    }; // _PR._areAllAudioParamsPreloaded

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {Param} param - The name of the parameter of audios in folder
     * @returns {Boolean} The check result
     */
    _PR._isAudioParamPreloaded = function(param) {
        return this._isAudioParamPreloaded[param];
    }; // _PR._isAudioParamPreloaded

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {String} preloadedMiscAudio - The misc audio file to be preloaded
     */
    _PR._preloadMiscAudio = function(preloadedMiscAudio) {
        var args = preloadedMiscAudio.split("/");
        _PR._preloadAudio.call(this, args[0], args[1]);
    }; // _PR._preloadMiscAudio

    /**
     * The this pointer is AudioManager
     * Idempotent
     * @since v1.00a @version v1.00a
     * @param {String} folder - The name of the folder under the audio folder
     * @param {String} name - The name of the audio to be preloaded
     */
    _PR._preloadAudio = function(folder, name) {
        // Users might input raw values or empty audios directly
        if (folder && name) this.createBuffer(folder, name);
        //
    }; // _PR._preloadAudio

})(DoubleX_RMMV.Preloaded_Resources); // AudioManager