Z_Core: Game & JavaScript Utilities for Devs

Discussion in 'JS Plugins In Development' started by sagebrushfire, Jun 16, 2016.

  1. sagebrushfire

    sagebrushfire Villager Member

    Messages:
    25
    Likes Received:
    12
    First Language:
    English
    Note: I'm a member of other RPG Maker MV forums so this is largely copy/pasted from my first time posting it. I usually choose the same username so it's pretty obvious. 


    Preface:


    Plugins and scripting are what I like best about RMMV so here I'd like to share my core plugin. This plugin started out really being more for internal use as it is 99.9% for Developer use but I think it's worth sharing and it will grow a LOT as I work on other plugins.


    I chose the name Z so it would show up at the bottom of my plugin list and I hadn't seen others do the same yet. I will happily rename if someone already had the same idea.


    Terms:


    This is free to use and modify as you see fit. I only ask that if you make a huge improvement you share it with me so I can update my code too!


    User-Oriented Features:


    Right now there is only one feature you can mess with from the RMMV app in the Plugin Manager menu: Touch Enable/Disable. You can now dynamically disable/enable touch input in-game and you can decide whether it's on or off at the beginning with the parameter in the touch menu. To turn it off in-game you simply have to run a simple script from an event that changes a JavaScript variable to true or false.


    Developer Features:
    This is the bulk of this plugin. These are features intended to help other plugin designers with their code.

    • Conversion Utilities: I've added some simple utilities for converting "XX%" strings into decimals (e.g. "10%" becomes 0.10), grabbing an element's ID or Name using one or the other, converting values to booleans (e.g. 1, "on", "yes", true", etc. become true, anything else becomes false) and merging/cloning JavaScript objects. 
       
    • Extension Utilities: I have also written a few functions that allow you to extend the core RMMV objects without having to copy/paste their native code into your plugin. You can write a function that runs before or after the core function you're extending or you can even write a function that returns true or false and only allows the core function to run if it evaluates to true. Not everything can be extended this way but it's especially useful when you just want to tack on functionality to existing core functions. 
       
    • Metadata Upgrade: I discovered that the Data Manager actually attempts to store note tags in a "meta" object by default. Unfortunately it was horribly rudimentary and didn't match a lot of the popular paradigms I see plugin makers use. I upgraded this feature so that it could process more advanced notes AND I added a meta() function to the Game_Actor and Game_Enemy classes so you can also access metadata (notes) in the damage formula.





    Metadata Upgrade Screenshots & Examples


    I wrote documentation in the help section of the plugin and above the functions themselves but I also created a few screenshots so you can see just what the Metadata Upgrade actually does. This Imgur Gallery gives you a step-by-step example:


    http://imgur.com/a/xFFos


    Additional Info


    This plugin is a precursor to a Battle Math plugin that's far more developed and relies on this for some of it's functionality as well as an HTML Event Wizard plugin that is useful for asynchronous stuff and HTML Events. I'll post those soon (I'm currently looking into getting rid of my jQuery dependency on the Event Wizard since it's a big file to make people use in their game).


    Download


    I will be maintaining this on the MV Plugins Page. 


    Z_Core.js Stand-Alone


    Z_BattleMath + Z_Core + Z_HtmlEventWizard + jQuery (My whole plugin package at the moment)


    Code:


    Since this is an "In Progress" thread and the file isn't too large, I will also post the code for you to look at so you don't necessarily have to download the zip: 


    (EDIT: This code block is huge, I was kind of hoping for a scroll bar. If anyone knows how to fix this that'd be great, unless nobody minds the huge amount of space it takes up.)

    Code:
    /// <reference path="../libs/jquery.js" />
    /// <reference path="../libs/pixi.js" />
    /// <reference path="../libs/fpsmeter.js" />
    /// <reference path="../libs/lz-string.js" />
    /// <reference path="../rpg_core.js" />
    /// <reference path="../rpg_managers.js" />
    /// <reference path="../rpg_objects.js" />
    /// <reference path="../rpg_scenes.js" />
    /// <reference path="../rpg_sprites.js" />
    /// <reference path="../rpg_windows.js" />
    //=============================================================================
    // SLC Z Plugin: Core Plugin
    // Z_Core.js
    //=============================================================================
    var Imported = Imported || {};
    var Z = Z || {};
    var Z$ = window.jQuery;
    Z.ExtendedFunctions = [];
    Imported.Z_Core = true;
    //=============================================================================
    /*:
    * @plugindesc v1.1  Core Utilities & Developer Features
    * parameters:
    * @author SLC
    *
    *
    * @param Enable Touch Input
    * @desc Disable Touch Input on Startup (Toggle via Z.Settings.TouchEnabled true/false)
    * @default true
    *
    * @help
    * ============================================================================
    * Introduction
    * ============================================================================
    *
    * This is a generic plugin with utility functions like prototype extensions, etc.
    * The formatting was derrived from Yanfly's awesome YEP Plugins, thanks for inspiring!
    *
    *
    * ============================================================================
    * USER FEATURES
    * ============================================================================
    *
    * DYNAMIC TOUCH ENABLE/DISABLE
    *
    *   You can set the default touch to be enabled/disabled by default by adjusting
    *   that parameter in the Plugin Manager. You can also, however, change it later
    *   in-game! Simply use an event to run a script that changes the value of the
    *   Z.Settings.TouchEnabled variable.
    *
    *   Example 1:  Z.Settings.TouchEnabled = true;
    *
    *   Example 2:   Z.Settings.TouchEnabled = !Z.Settings.TouchEnabled;
    *
    *   Example 1 directly enables touch input. Example 2 toggles it, making it
    *   whatever it wasn't before!
    *
    * ============================================================================
    * DEVELOPER FEATURES
    * ============================================================================
    *
    * All developer features have documentation above the actual code so make sure
    * to check out the source code for even more information.
    *
    * Z_Core Utility Functions
    *
    *   These are javascript functions that are available to plugins and scripts
    *   as long as they're loaded AFTER the Z_Core.js plugin. They include functions
    *   for merging and cloning JS objects, converting percentage-style strings to
    *   decimal format and quickly nabbing an element's ID or Name from game data.
    *
    * RMMV Extensions
    *
    *   These are extensions and rewrites to core RMMV scripts. They extend or
    *   modify the base classes and add new functions and functionality to them.
    *
    *   [Metadata Upgrade]
    *
    *   By default RMMV actually tries to store XML-formatted
    *   tags in Note properties as a javascript object in the relavent $data object.
    *   Unfortunately the default version is very basic and is pretty much only
    *   useful for using stuff like <info: somevalue> or <IsBoss>, etc.
    *   This upgrade does two things: It allows the script to process more complex
    *   note tags and it makes the meta object available in the Game_Actor and
    *   Game_Enemy classes, which in turn makes it available in damage formulas!
    *
    *   Here is an example of an actor #1's note tag and what it will produce:
    *
    *   <IsRoyalty>
    *   <zodiac: scorpio>
    *   <AttackBonus: 20>
    *   <CustomPlugin: param1=5>
    *   <CustomPlugin: param2=foo>
    *   <ComplexProperty>
    *   some value here
    *   23
    *   another value here
    *   </ComplexProperty>
    *
    *   After processing, $dataActors[1].meta will be the following:
    *
    *   {
    *       IsRoyalty: true,
    *       zodiac: "scorpio",
    *       AttackBonus: 20,
    *       CustomPlugin: {
    *           param1: 5,
    *           param2: "foo"
    *       },
    *       ComplexProperty: [
    *           "some value here",
    *           23,
    *           "another value here"
    *       ]
    *   }
    *
    *   In the damage formula you could access this info with a or b like so:
    *
    *       a.atk * a.meta("AttackBonus")
    *
    *   OR
    *
    *       a.atk * a.meta().AttackBonus
    *
    *   These are not [currently] saved properties, they're perpetual properties
    *   so this would not replace a plugin such as BOB_CustomStats.js but it can
    *   definitely be used in conjunction with those types of plugins.
    *
    * That's it for now. More updates are planned soon!
    *
    * Happy modding!
    *
    * ============================================================================
    */
    /*
    * =============
    *  Z_CORE UTILITIES
    * =============
    */
    // Simple Merging function for combining simple objects.
    // Original object gets extended & merged with input object.
    Z.mergeIntoFirst = function (a, b) {
        b = b || {};
        for (var key in b) {
            if (b.hasOwnProperty(key)) {
                a[key] = b[key];
            }
        }
        return a;
    };
    // Simple merging function that returns a brand new clone object
    // which is the result of the source object & input object.
    Z.mergeResult = function (a, b) {
        var result = {};
        result.mergeWith(a);
        result.mergeWith(b);
        return result;
    };
    // This utility allows you to run extra functions before the function
    // you're extending. It's mostly useful for making the extended function trigger
    // events as it does not modify the extended function directly.
    Z.PrependFunction = function (base, extra) {
        Z.ExtendedFunctions.push(base);
        var clone = eval(base + ";");
        eval(base + "=function(){extra.apply(this,[this].concat(arguments)); return clone.apply(this,arguments);};");
    };
    // This utility is for providing a function extension that returns  true or false
    // The extended function only runs if your extension evaluates to true.
    Z.ConditionFunction = function (base, condition) {
        Z.ExtendedFunctions.push(base);
        var clone = eval(base + ";");
        var es = base + "=function(){if(condition.apply(this,[this].concat(arguments))){return clone.apply(this,arguments);}};";
        eval(es);
    };
    // This is the same as PrependFunction but the extra code is executed AFTER the function in question, not before!
    Z.AppendFunction = function (base, extra) {
        Z.ExtendedFunctions.push(base);
        var clone = eval(base + ";");
        eval(base + "=function(){var result = clone.apply(this,arguments); extra.apply(this,[this].concat(arguments)); return result;};");
    };
    // A simple method to convert values into booleans (true|false).
    // Mostly unique as it errs on the side of false instead of true.
    Z.toBool = function (input) {
        input = (input + "").toLowerCase();
        if (input === "yes") { return true; }
        if (input === "1") { return true; }
        if (input === "true") { return true; }
        if (input === "on") { return true; }
        return false;
    };
    Z.PercentToDecimal = function (input) {
        input = input + "";
        var result = Number(input);
        if (input.contains("%")) {
            result = input.replace("%", "");
            result = Number(result);
            if (!isNaN(result)) {
                result = result / 100;
            }
        }
        if (!isNaN(result)) {
            return result;
        }
        return -1;
    };
    Z.getElementId = function (name) {
        var quick = Number(name);
        if (!isNaN(quick) && quick in $dataSystem.elements) {
            return quick;
        }
        var result = $dataSystem.elements.indexOf(name);
        if (result >= 0) {
            return result;
        }
        return -1;
    };
    Z.getElementName = function (id) {
        if (id in $dataSystem.elements) {
            return $dataSystem.elements[id];
        }
        return "NULL";
    };
    /*
    * =============
    *  SETUP
    * =============
    */
    Z.Params = PluginManager.parameters("Z_Core");
    Z.Settings = {};
    Z.Settings.TouchEnabled = Z.toBool(Z.Params["Enable Touch Input"]);
    
    /*
    * =============
    *  RMMV EXTENSIONS
    * =============
    */
    // This extension makes much better use of the data manager's meta functionality
    // It handles a wide variety of inputs in your note tags.
    DataManager.extractMetadata = function (data) {
        var re = /<([^<>:]+)(:?)([^>]*)>/g;
        data.meta = {};
        for (; ;) {
            var match = re.exec(data.note);
            if (match) {
                var m1 = match[1] || "",
                    m2 = match[2] || "",
                    m3 = match[3] || "",
                    dm = data.meta || {};
                if (match[2] === ':') {
                    if (match[3].contains("=")) {
                        dm[m1] = dm[m1] || {};
                        var sub = m3.trim().split("="),
                            subkey = sub[0] || "error",
                            subval = sub[1] || "error";
                        dm[m1][subkey] = subval;
                    }
                    else {
                        dm[m1] = m3.trim();
                    }
                } else {
                    var specialReg = "<" + m1 + ">(.*)</" + m1 + ">",
                        find = new RegExp(specialReg, "gi"),
                        trimNote = data.note.replace(/(\r\n|\n|\r)/gm, "!LB!"),
                        result = find.exec(trimNote) || ["", ""],
                        values = result[1].split("!LB!").filter(function (n) { return n !== ""; });
                    if (values.length > 0) {
                        dm[m1] = values;
                    } else {
                        if (m1[0] !== "/") {
                            dm[m1] = true;
                        }
                    }
                }
            } else {
                break;
            }
        }
    };
    // This new function makes the meta properties available for
    // the Game_Enemy object and also damage formulas.
    Game_Enemy.prototype.meta = function (key) {
        key = key || false;
        var data = $dataEnemies[this.enemyId()] || false;
        if (data !== false && data.meta) {
            if (data.meta[key]) {
                return data.meta[key];
            }
            return data.meta;
        }
        return false;
    };
    // This new function makes the meta properties available for
    // the Game_Actor object and also damage formulas.
    Game_Actor.prototype.meta = function (key) {
        key = key || false;
        var data = $dataActors[this.actorId()] || false;
        if (data !== false && data.meta) {
            if (data.meta[key]) {
                return data.meta[key];
            }
            return data.meta;
        }
        return false;
    };
    // Applies a condition to the TouchInput._onMouseDown property
    // So it won't fire if a variable is set to false.
    Z.ConditionFunction("TouchInput._onMouseDown", function (context) {
        context = context || window.Event;
        return (function (context) {
            return Z.Settings.TouchEnabled;
        })(context);
    });
     
    Last edited by a moderator: Jun 17, 2016
    #1
    Marian likes this.

Share This Page