DMV Core
This plugin is a requirement for almost all of my other RPG Maker MV plugins. You should ensure this plugin is also loaded before all other DMV plugins. It is advised that you check to ensure you have the latest version whenever you install a new DMV Engine Plugin.
Plugin Code
/*: ==========================================================================
* ############################################################################
*
* Plug-in: dmv-core.js
* Version: 2.0.1
* Author: DekitaRPG [ www.dekitarpg.com ]
* MailTo: dekitarpg@gmail.com
*
* ############################################################################
* ============================================================================
*
* @author DekitaRPG [ www.dekitarpg.com ]
*
* @plugindesc DMV_Core contains functions that are used within some of
* the more advanced RPG Maker MV plugins of mine.
*
* @help
* ============================================================================
* ■ System Information:
* ============================================================================
*
* This plugin is required to use ALL of my other RPG Maker MV plugins.
* Ensure that this plugin is also loaded before all other DMV plugins.
*
*
* ============================================================================
* ■ Script Calls:
* ============================================================================
*
* ... N/A
*
*
* ============================================================================
* ■ Plugin Commands:
* ============================================================================
*
* ... N/A
*
*
* ============================================================================
* ■ Terms && Conditions:
* ============================================================================
*
* This plugin is authorized for use in NON-COMMERCIAL projects ONLY!!
* Copyright (C) DekitaRPG - All Rights Reversed!
*
* You are not allowed to redistribute this plugin directly.
* Instead, provide a link to www.dekitarpg.com.
*
*
* ============================================================================
* ■ Stay Up To Date:
* ============================================================================
*
* I advise that you check regularly to see if any of the plugins you use
* have been updated. The plugin updates will include things like bugfixes
* and new features, so it is highly recommended.
*
* Get the latest plugin versions at www.dekitarpg.com/dmv
*
*
* ============================================================================
* ■ Change Log:
* ============================================================================
*
* v.2.0.1 - Added DMV.Emitter class,
* - Added DMV.HTTP basic error and timeout features,
* v.2.0.0 - Rewrote using es6 features,
* - Dropped MVC Requirement,
* v.1.0.1 - Added Function: DMV.isScene(sceneClass),
* v.1.0.0 - Initial Release,
*
*
* ============================================================================
* Visit www.dekitarpg.com for more!
* ============================================================================
*/
const DMV = Object.create(Object);
(function dmv_kore_setup(dmv_kore){"use strict";
// use strict mode to enforce typing standards:..
/**
* DMV.version
* returns the overall version number for the DMV Plugins engine.
*/
dmv_kore.version = '2.0.1';
/**
* DMV.author
* Returns object containing information about system author
*/
dmv_kore.author = {
mail: "dekitarpg@gmail.com",
name: "David Bow [DekitaRPG]",
site: "https://www.dekitarpg.com",
};
/**
* plugins_loaded
* stores all loaded dmv plugin names and versions
*/
let plugins_loaded = Object.create(Object);
/**
* defaultGetter(name)
* @param name {string} The name of the property.
* @return {function} that can be used as a getter.
* @private
*
* Generates a getter function based on a name
* See dmv_kore.reader() for information about the default getter.
*/
function defaultGetter(name){
return function defaultGetter(){
return this['_' + name];
};
}
/**
* defaultSetter(name)
* @param name {string} The name of the property.
* @return {function} that can be used as a setter.
* @private
*
* Generates a setter based on a name
* See dmv_kore.writer() for information about the default setter.
*/
function defaultSetter(name){
const property = '_' + name;
return function defaultSetter(v) {
if (!this[property] || this[property] !== v){
this[property] = v;
if (this._refresh){
this._refresh(property);
}
}
};
}
/**
* defaultContructor(parent)
* @param parent {object} The parent class of the object.
* @return {function} that can be used as a contructor.
* @private
*
* Generates a constructor function that automatically
* calls the parent object constructor within it.
*/
function defaultContructor(parent){
return function defaultContructor(/** arguments **/){
parent.apply(this, arguments);
if(!parent.prototype.initialize && this.initialize) {
this.initialize.apply(this, arguments);
}
};
}
/**
* dmv_kore.reader(obj, name, getter);
* {}.attr_reader(name, getter); (< if object was extended with dmv_kore.createClass())
* @param obj The object to add the reader property onto
* @param name The name of the reader porperty
* @param getter [optional] The Getter function
*
* Makes an easy way to make a reader (a variable you can read)
* By default it gets the value of this['_' + name]
*/
dmv_kore.reader = function(objekt, name, getter) {
Object.defineProperty(objekt, name, {
get: getter || defaultGetter(name),
configurable: true
});
};
/**
* dmv_kore.writer(obj, name, setter);
* {}.attr_writer(name, setter); (< if object was extended with dmv_kore.createClass())
* @param obj The object to add the property
* @param name The property name
* @param setter [optional] The setter function
*
* Makes an easy way to define a writer (a setter to a variable)
* By default it sets the function of the property this['_' + name] = value
* It also calls a method this._refresh() if that method exists
*/
dmv_kore.writer = function(objekt, name, setter) {
Object.defineProperty(objekt, name, {
set: setter || defaultSetter(name),
configurable: true
});
};
/**
* dmv_kore.accessor(obj, name, setter, getter);
* {}.attr_accessor(name, setter, getter); (< if object was extended with dmv_kore.createClass())
* @param obj The object to add the accessor
* @param name The property name
* @param setter [optional] The setter function
* @param getter [optional] The getter function
* @see dmv_kore.reader
* @see dmv_kore.writer
*
* Makes an accessor (both getter and setter) of an object easily
* See writer() and reader() for information about default values.
*/
dmv_kore.accessor = function(objekt, name, setter, getter) {
Object.defineProperty(objekt, name, {
get: getter || defaultGetter(name),
set: setter || defaultSetter(name),
configurable: true
});
};
/**
* dmv_kore.rand(max, min)
* @param max the maximum value that can be returned
* @param min [optional] same as max, but minimum value
* @return a random value between min (0 if not given) and max
*/
dmv_kore.rand = function(max, min) {
let rmin = min ? min : 0;
return Math.floor(Math.random()*(max-rmin+1)+rmin);
};
/**
* dmv_kore.
* @param {*} setParent
*/
dmv_kore.createStaticClass = function(setParent) {
let klass = Object.create(setParent || Object);
dmv_kore._addClassFunctions(klass);
return klass;
};
/**
* dmv_kore.
* @param {*} setParent
*/
dmv_kore.createClass = function(setParent, konstructor) {
let parent = setParent || Object;
let klass = konstructor || defaultContructor(parent);
klass.prototype = Object.create(parent.prototype);
klass.prototype.constructor = klass;
if (!klass.prototype.attr_accessor){
dmv_kore._addClassFunctions(klass, true);
}
return klass;
};
/**
* dmv_kore.
* @param {*} setParent
*/
dmv_kore._addClassFunctions = function(klass, instancable){
klass.attr_accessor = function(name,setter,getter){
dmv_kore.accessor(this, name, setter, getter);
};
klass.attr_reader = function(name,getter){
dmv_kore.reader(this, name, getter);
};
klass.attr_writer = function(name,getter){
dmv_kore.writer(this, name, getter);
};
if (instancable){
klass.prototype.attr_accessor = klass.attr_accessor;
klass.prototype.attr_reader = klass.attr_reader;
klass.prototype.attr_writer = klass.attr_writer;
}
};
/**
* dmv_kore.
* @param {*} setParent
*/
dmv_kore.toMinMax = function(number, max, min){
let rmin = min ? min : 1;
let rmax = max ? max : number;
return Math.min(Math.max(number,rmin),rmax);
};
/**
* dmv_kore.map2n(array)
* @param array the array to map into a number array
* @return the number array that has been mapped
*/
dmv_kore.map2n = function(array){
return array.map(element => Number(element));
};
/**
* dmv_kore.mapParams2n(paramstring, splitter)
* @param paramstring the paramter string to map to a number array
* @param splitter [optional] the character to use to delimit the string
* @return the number array that has been mapped
*/
dmv_kore.mapParams2n = function(paramstring /*, splitter */){
if (!paramstring) return [];
let spl = (arguments[1] ? arguments[1] : ',');
return dmv_kore.map2n(paramstring.split(spl));
};
/**
* dmv_kore.mapMeta2n(object, metaid, splitter)
* @param object the meta object to extract data from
* @param metaid the meta identifier string value
* @param splitter [optional] the character to use to split meta
* @return an integer array containing the required meta information
*/
dmv_kore.mapMeta2n = function(object, metaid, splitter){
let meta = dmv_kore.extractMetaData(object, metaid);
return dmv_kore.mapParams2n(meta, splitter);
};
/**
* dmv_kore.extractMetaData(object, metaid)
* @param object the meta object to extract data from
* @param metaid the meta identifier to return if found
* @return the meta id information or null if not found
*/
dmv_kore.extractMetaData = function(object, metaid){
let meta = object.meta[metaid];
return meta !== undefined ? meta : null;
};
/**
* dmv_kore.reduceMeta(array, vname)
* @param array the array of database object, such as equips().
* @param vname the variable name to scan meta data for
* @return the total value gained from all vname notetags, or 0.
*/
dmv_kore.reduceMeta = function(array, vname){
return array.reduce(function(prev, curr, i, obj){
return (obj[i] ? (prev + curr[vname]) : prev);
}, 0);
};
/**
* dmv_kore.reduceMetaID(array, vname, id)
* @param array the array of database object, such as equips().
* @param vname the variable name to scan meta data for
* @param id the array index to use for adding values..
* @return the total value gained from all vname notetags, or 0.
* @note this function is used when scanning meta that is an array
*/
dmv_kore.reduceMetaID = function(array, vname, id){
return array.reduce(function(prev, curr, i, obj){
return (obj[i] ? (prev + curr[vname][id]) : prev);
}, 0);
};
/**
* dmv_kore.extractFunkString(objekt, funkName, defaultFunkString)
* @param objekt the object to scan the meta for funkName
* @param funkName the function name to get from meta
* @param defaultFunkString the default function string
* @return a string that can be used to create functions
*/
dmv_kore.extractFunkString = function(objekt, funkName, defaultFunkString){
let meta = dmv_kore.extractMetaData(objekt, funkName);
return "return " + (meta ? meta : defaultFunkString);
};
/**
* dmv_kore.extractFunkStringF(objekt, funkName, defaultFunkString)
* @param objekt the object to scan the meta for funkName
* @param funkName the function name to get from meta
* @param defaultFunkString the default function string
* @return a function that is bound to the objekt
*/
dmv_kore.extractFunkStringF = function(objekt, funkName, defaultFunkString){
let str = dmv_kore.extractFunkString(objekt, funkName, defaultFunkString);
return Function(str).bind(objekt);
};
/**
* dmv_kore.register(pluginName, pluginVer, date, reqr, exit)
* @param pluginName the plugin name to br registered
* @param pluginVer the plugin version to be registered
* @param params the parameters the plugin was uses
* @return PluginManagers parameters for the specific plugin
*/
dmv_kore.register = function(pluginName, pluginVer, params){
const dmv_name = 'dmv-' + pluginName;
if (plugins_loaded[pluginName]){
return alert("You are trying to load more than one version of: " + dmv_name);
}
plugins_loaded[pluginName] = {version:pluginVer, params};
console.log("Loaded:", dmv_name, "v" + pluginVer);
return PluginManager.parameters(dmv_name);
};
/**
* dmv_kore.isRegistered(pluginName, pluginVer)
* @param pluginName the name of plugin to check for
* @param pluginVer the version of plugin to check for
* @return boolean value based on if plugin available
*/
dmv_kore.isRegistered = function(pluginName, pluginVer){
let plugin = plugins_loaded[pluginName];
if (plugin !== undefined){
let version = plugin.version;
return dmv_kore.compver(version, pluginVer) >= 0;
}
return false;
};
/**
* dmv_kore.compver(a, b) [compares version strings- '1.0.1']
* @param {String} a
* @param {String} b
* @return {Number}
* if a < b number is < 0
* if a > b number is > 0
* if a == b number is 0
*/
dmv_kore.compver = function(a, b) {
let regExStrip0 = /(\.0+)+$/;
let segmentsA = a.replace(regExStrip0, '').split('.');
let segmentsB = b.replace(regExStrip0, '').split('.');
let l = Math.min(segmentsA.length, segmentsB.length);
for (var i = 0; i < l; i++) {
let sega = parseInt(segmentsA[i], 10);
let segb = parseInt(segmentsB[i], 10);
let diff = sega - segb;
if (diff) return diff;
}
return segmentsA.length - segmentsB.length;
};
/**
* dmv_kore.STATIC_CLASS_ERROR
* Holds string for base static error, to save retyping..
*/
dmv_kore.STATIC_CLASS_ERROR = " is a static class, cannot create instance!";
/**
* dmv_kore.current_spriteset
* @return the current scenes spriteset if available.
*/
dmv_kore.reader(dmv_kore, 'current_spriteset', function(){
return this.current_scene ? this.current_scene._spriteset : null;
});
/**
* dmv_kore.current_scene
* @return the current scene if available.
*/
dmv_kore.reader(dmv_kore, 'current_scene', function(){
return SceneManager._scene ? SceneManager._scene : null;
});
/**
* dmv_kore.createIconButton(icon1, icon2, parent)
* @param icon1 the icon to show for buttons cold frame
* @param icon2 the icon to show for buttons hot frame
* @param parent [optional] if given will call addChild
* to add the button into the parents child list
* @return new button
*/
dmv_kore.createIconButton = function(icon1, icon2, parent) {
let bw = 32, bh = 32, button = new Sprite_Button();
button.bitmap = ImageManager.loadSystem('IconSet');
button.setColdFrame(icon1%16*bw, Math.floor(icon1/16)*bh, bw, bh);
button.setHotFrame(icon2%16*bw, Math.floor(icon2/16)*bh ,bw, bh);
if (parent != undefined && parent.addChild){
parent.addChild(button);
}
button.visible = true;
return button;
};
/**
* Setup metadata helper functions
* Game_BattlerBase.prototype.meta
* Game_Actor.prototype.meta
* Game_Enemy.prototype.meta
*/
dmv_kore.reader(Game_BattlerBase.prototype,'meta',function(){
return {};
});
dmv_kore.reader(Game_Actor.prototype,'meta',function(){
return this.actor() ? this.actor().meta : {};
});
dmv_kore.reader(Game_Enemy.prototype,'meta',function(){
return this.enemy() ? this.enemy().meta : {};
});
/**\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
* DMV HTTP Variables && Functions
**///////////////////////////////
/**
* HTTP::KnownErrors
* Cross-Origin Request Blocked: The Same Origin Policy disallows reading the
* remote resource at http://www.dekyde.com/BasicHTTPDemo/BasicPost.php5
* (Reason: CORS header 'Access-Control-Allow-Origin' missing).
* ^CORS header was available and this only happens 1/100 times...
* I suspect some other underlying cause - continuing to research...
*/
dmv_kore.HTTP = function() {
throw new Error('DMV.HTTP' + dmv_kore.STATIC_CLASS_ERROR);
};
/**
* DMV.HTTP functions
*/
(function(http){
/**
* DMV.HTTP.FORM_ENCODE
* Content-type used when performing post requests
*/
http.FORM_ENCODE = "application/x-www-form-urlencoded";
/**
* [ private ] aSyncRequest(cbk)
* @param cbk The main callback function
* @param obj The object to perform the cbk on
* @return an asyncronous request
*/
function aSyncRequest(cbk, thisobj){
let request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200){
cbk.apply(thisobj, [request.responseText]);
}
};
request.ontimeout = function() {
cbk.apply(thisobj, ['timeout']);
};
request.onerror = function(error) {
cbk.apply(thisobj, ['error', error]);
};
return request;
}
/**
* DMV.HTTP.getAsync(url, str, cbk, obj)
* @param url URL to send request to
* @param str string to pass with url
* @param cbk Callback function
* @param obj The object to perform the cbk on
*/
http.getAsync = function(url, str, cbk, obj){
let request = aSyncRequest(cbk, obj);
request.open("GET", url, true);
this._sendRequest(request, str);
};
/**
* DMV.HTTP.postAsync(url, str, cbk)
* @param url URL to send request to
* @param str string to pass with url
* @param cbk Callback function
* @param obj The object to perform the cbk on
*/
http.postAsync = function(url, str, cbk, obj){
let request = aSyncRequest(cbk, obj);
request.open("POST", url, true);
request.setRequestHeader("Content-type", http.FORM_ENCODE);
this._sendRequest(request, str);
};
/**
* DMV.HTTP._sendRequest(url, str, cbk)
* @param request XMLHttpRequest object
* @param string string to pass with url call
*/
http._sendRequest = function(request, string){
request.timeout = 5000;
request.send(string);
};
/**
* End HTTP Declarations
*/
})(dmv_kore.HTTP);
/**\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
* DMV Scene Related Variables && Functions
**////////////////////////////////////////
/**
* DMV.isScene(sceneClass)
* @param sceneClass the class to check for
* @return true if the current class is sceneClass
*/
dmv_kore.isScene = function(sceneClass){
let scene = SceneManager._scene;
return scene && scene.constructor === sceneClass;
};
/**
* DMV.Sprite
* Container to hold my custom sprite classes
*/
dmv_kore.Sprite = function() {
throw new Error('DMV.Sprite'+dmv_kore.STATIC_CLASS_ERROR)
};
/**
* DMV.Window
* Container to hold my custom window classes
*/
dmv_kore.Window = function() {
throw new Error('DMV.Window'+dmv_kore.STATIC_CLASS_ERROR)
};
/**
* DMV.Scene
* Container to hold my custom scene classes
*/
dmv_kore.Scene = function() {
throw new Error('DMV.Scene'+dmv_kore.STATIC_CLASS_ERROR)
};
/**
* DMV.Emitter
* Basic clone of PIXI.utils.EventEmitter
*/
dmv_kore.Emitter = dmv_kore.createClass(PIXI.utils.EventEmitter);
/**
* DMV.Sprite.TogButton
* Sprite_Button class with dedicated toggled state
*/
dmv_kore.Sprite.TogButton = dmv_kore.createClass(Sprite_Button);
/**
* DMV.Sprite.TogButton.prototype functions
*/
(function($this_class, parent){
/**
* DMV.Sprite.TogButton.prototype.initialize(bitmap)
* Initiailizes toggle button sprite.
* @param bitmap [optional] the bitmap image to use for the button
*/
$this_class.initialize = function(/* bitmap */){
parent.initialize.call(this);
if (arguments[0]){
this.bitmap = arguments[0];
}
this._dmv_toggled = false;
//this.update();
};
/**
* DMV.Sprite.TogButton.prototype.updateFrame()
* Overwrite parent function to allow for toggle state
*/
$this_class.updateFrame = function() {
let frame = null, touch = this._touching;
if (this._dmv_toggled){
frame = touch ? this._dmv_tog_hotFrame : this._dmv_tog_coldFrame;
} else {
frame = touch ? this._hotFrame : this._coldFrame;
}
if (frame) {
this.setFrame(frame.x, frame.y, frame.width, frame.height);
}
};
/**
* DMV.Sprite.TogButton.prototype.setTogColdFrame(x, y, w, h)
* Sets the button sprites cold frame for toggled state.
* @param x the x position to use for this frame
* @param y the y position to use for this frame
* @param w the width to use for this frame
* @param h the height to use for this frame
*/
$this_class.setTogColdFrame = function(x, y, width, height) {
this._dmv_tog_coldFrame = new Rectangle(x, y, width, height);
};
/**
* DMV.Sprite.TogButton.prototype.setTogHotFrame(x, y, w, h)
* Sets the button sprites hot frame for toggled state.
* @param x the x position to use for this frame
* @param y the y position to use for this frame
* @param w the width to use for this frame
* @param h the height to use for this frame
*/
$this_class.setTogHotFrame = function(x, y, width, height) {
this._dmv_tog_hotFrame = new Rectangle(x, y, width, height);
};
/**
* DMV.Sprite.TogButton.prototype.setRegularFrames(coldArray, hotArray)
* Sets the regular state hot and cold frames for this button.
* @param coldArray the array of [x,y,w,h] to use for the cold frame
* @param hotArray the array of [x,y,w,h] to use for the hot frame
*/
$this_class.setRegularFrames = function(coldArray, hotArray) {
$this_class.setColdFrame.apply(this,coldArray);
$this_class.setHotFrame.apply(this,hotArray);
};
/**
* DMV.Sprite.TogButton.prototype.setToggledFrames(coldArray, hotArray)
* Sets the toggled state hot and cold frames for this button.
* @param coldArray the array of [x,y,w,h] to use for the cold frame
* @param hotArray the array of [x,y,w,h] to use for the hot frame
*/
$this_class.setToggledFrames = function(coldArray, hotArray) {
$this_class.setTogColdFrame.apply(this,coldArray);
$this_class.setTogHotFrame.apply(this,hotArray);
};
/**
* DMV.Sprite.TogButton.prototype.callClickHandler()
* Calls the handler that processes when the button is clicked,
* if it is available, and also toggles the toggle state flag.
*/
$this_class.callClickHandler = function() {
if (this._clickHandler) {
this._dmv_toggled = !this._dmv_toggled;
this._clickHandler();
}
};
/**
* End DMV.Sprite.TogButton.prototype declarations
*/
})(dmv_kore.Sprite.TogButton.prototype, Sprite_Button.prototype);
/**
* $this_class: Number.prototype
* parent: undefined
* This wrapper function contains enhancements to the Number class
*/
(function($this_class, parent){ // Number
/**
* Number.prototype.fix()
* Drops anything after the 12th decimal place of the number, thus,
* fixing javascript's issue with decimal operations.
* Examples:
* Math.ceil((0.2 + 0.1) * 10) == 4
* Math.ceil((0.2 + 0.1).fix() * 10) == 3
* @return the fixed number.
*/
if (!$this_class.fix){
$this_class.fix = function(){
return parseFloat(this.toPrecision(12));
};
}
/**
* Number.prototype.floor()
* @return the largest integer less than or equal to the number.
*/
if (!$this_class.floor){
$this_class.floor = function(){
return Math.floor(this.fix());
};
}
/**
* Number.prototype.ceil()
* @return the smallest integer greater than or equal to the number.
*/
if (!$this_class.ceil){
$this_class.ceil = function(){
return Math.ceil(this.fix());
};
}
/**
* Number.prototype.round()
* @return the value of the number rounded to the nearest integer.
*/
if (!$this_class.round){
$this_class.round = function(){
return Math.round(this.fix());
};
}
/**
* Number.prototype.abs()
* @return the absolute value
*/
if (!$this_class.abs){
$this_class.abs = function(){
return Math.abs(this);
};
}
/**
* End Number.prototype wrapper
*/
})(Number.prototype, undefined);
/**
* $this_class: Bitmap.prototype
* parent: undefined
* Enhancement to the Bitmap class
*/
(function($this_class, parent){
/**
* Bitmap.prototype.copySection(x,y,w,h)
* @param x The x position to begin copying from
* @param y The y position to begin copying from
* @param w The width to copy onto the new bitmap
* @param h The height to copy onto the new bitmap
* @return A new bitmap created from the region specified.
*/
$this_class.copySection = function(x, y, w, h) {
let newbitmap = new Bitmap(w, h);
newbitmap.blt(this,x,y,w,h,0,0,w,h);
return newbitmap;
};
/**
* End Bitmap.prototype wrapper
*/
})(Bitmap.prototype, undefined);
/**
* $this_class: ImageManager
* parent: undefined
* Enhancement to the ImageManager class
*/
(function($){
/**
* ImageManager.loadIcon(index)
* @param index The icon index to return as a single bitmap
* @return A new bitmap containing only the icon specified
*/
$.loadIcon = function(index) {
let ic = this.loadSystem("IconSet");
let pw = Window_Base._iconWidth;
let ph = Window_Base._iconHeight;
let sx = index % 16 * pw;
let sy = Math.floor(index / 16) * ph;
return ic.copySection(sx, sy, pw, ph);
};
/**
* End ImageManager wrapper
*/
})(ImageManager, undefined);
/**
*
* $this_class: Array.prototype
* parent: undefined
* This brings back the min and max functions used often
* on arrays to quickly clamp a set of data. Sure, we
* have the clamp function, but that only works on 2
* numbers at a time. This works on arrays!
*
*/
(function($this_class, parent) {
/**
* [1,2,3].min()
* => 1
*/
$this_class.min = function() {
return Math.min.apply(null, this);
};
/**
* [1,2,3].max()
* => 3
*/
$this_class.max = function() {
return Math.max.apply(null, this);
};
/**
* End Array.prototype wrapper
*/
})(Array.prototype, undefined);
/**
* End Declarations
*/
})(DMV);
/**
* ------------ End Of Plugin ------------
* Visit https://www.dekitarpg.com for more!
*/