JS Snippets Thread

● ARCHIVED · READ-ONLY
Started by mlogan 38 posts Page 2 of 2 View original ↗
  1. bblizzard said:
    Here are a few useful extra methods for the array class. Nothing fancy, just makes code look cleaner when you use then instead of manually writing the code.

    PHP:
    //=============================================================================
    // Array_util
    //=============================================================================
    
    (function() {
      
    //=============================================================================
    
    Array.prototype.includes = function(value)
    {
        return (this.indexOf(value) >= 0);
    };
    
    Array.prototype.remove = function(value)
    {
        this.splice(this.indexOf(value), 1);
    };
    
    Array.prototype.tryRemove = function(value)
    {
        var index = this.indexOf(value);
        if (index >= 0)
        {
            this.splice(index, 1);
            return true;
        }
        return false;
    };
    
    //=============================================================================
    
    })();

    Adding new methods to standard classes is a very bad practice

    The includes method already exists in the array: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
  2. bblizzard said:
    I know, but it doesn't exist in MV. Try calling it and see for yourself.
    This function appeared in rpg maker with version 1.5 (when support for es6 appeared). Also, developers added their similar function, which is called contains (see rpg_core.js). It was from version 1.0.
    It is also important to know that the functions includes and indexOf work differently. It seems that indexOf does not work with NaN.
  3. That's quite weird, I kept getting errors when I tried using it. I think I started with 1.5.1 or 1.5.2 so it should have been there (last year in November or so). Oh well. ¯\_(ツ)_/¯ I'll switch out my own code.
  4. load multi fonts example without api or plugin.
    We use here the native method `document.fonts.check()`
    ` this.load();` it for continue after all fonts are succeed to load.
    PHP:
        load_fonts(){
            const fonts = [ // your fonts reference here
                {name:"ArchitectsDaughter", url:"fonts/ArchitectsDaughter.ttf"},
                {name:"zBirdyGame", url:"fonts/zBirdyGame.ttf"},
            ];
            fonts.forEach(font => { // for each fonts create @font-face rules
                const style = document.createElement('style');
                style.appendChild(document.createTextNode(`
                    @font-face {
                        font-family: '${font.name}';
                        font-style: normal;
                        font-weight: 700;
                        src: url("${font.url}");
                    }
                `));
                document.getElementsByTagName('head').item(0).appendChild(style);
                const div = document.createElement('div'); // create a div for each fonts rule (yes it weird but it how web fonts are loaded)
                div.style.fontFamily = font.name;
                document.body.appendChild(div);/* Initiates download in Firefox, IE 9+ */
                div.innerHTML = 'Content.';/* Initiates download in WebKit/Blink */
            });
            let checkFonts =  setInterval(()=>{// check every ticks if fonts are available in cache
                if( fonts.every(e => document.fonts.check(`12px ${e.name}`) )){
                    this.fonts = fonts;
                    clearInterval(checkFonts);
                    this.load();
                }
            },60);
        };

    ps: you can also remove div used for load fonts after, they take memory for nothing.
    PHP:
    function removeElement(id) {
        var elem = document.getElementById(id);
        return elem.parentNode.removeChild(elem);
    }
  5. This snippet allow you to: Add hashing method to your `String` for versioning or other purpose.


    PHP:
    String.prototype.hashCode = function() {
      var hash = 0, i, chr;
      if (this.length === 0) return hash;
      for (i = 0; i < this.length; i++) {
        chr   = this.charCodeAt(i);
        hash  = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
      }
      return hash;
    };

    example, let versioning this obj data {a:123456, b:'abcde'}
    PHP:
    JSON.stringify({a:123456,b:'abcde'}, null, '\t').hashCode(); // return alway 1776027141
  6. This snippet allow you to: Compute memory your code take with nwjs

    PHP:
    var befor = process.memoryUsage().heapUsed / 1024 / 1024;
          // your code
    var after = process.memoryUsage().heapUsed / 1024 / 1024;
    var r = `code consume ~${after-befor} MB in memory`;
    console.log(r)
  7. Aloe Guvner said:
    Autosave:
    (replace X with the save file ID #)
    Code:
    $gameSystem.onBeforeSave();
    if(DataManager.saveGame(X)) {
       StorageManager.cleanBackup(X);
    }

    Autoload:
    (replace X with the save file ID #)
    Code:
    if(DataManager.loadGame(X)) {
       SoundManager.playLoad();
       SceneManager._scene.fadeOutAll();
       $gamePlayer.reserveTransfer($gameMap.mapId(), $gamePlayer.x, $gamePlayer.y);
       $gamePlayer.requestMapReload();
       SceneManager.goto(Scene_Map);
       $gameSystem.onAfterLoad();
    }

    @Kvothe A useful thing to know with RPG Maker MV v1.6.0+ and the new NW.js we can use the ** operator now - no more Math.pow() !!
    (a.x - (b.x - (1)) ) ** 2

    @bblizzard Worth noting that we already have a native 'Array.prototype.includes' with the new NW.js version, it would be wise to not overwrite the native prototype.
    Thanks So much.
    I have looked for a long time like this.
  8. Public Service Announcement: you can use meta data in Lunatic code snippets, just like you can use it in plugins.

    As an example, I'll post my Lunatic snippet for a final attack / death counter attack. This assumes you have Yanfly's battle core and Buffs and States core. If you don't use Yanfly Battle Core, remove the spriteReturnHome() line.

    Code:
    <Custom Battle Effect>
    target.addState(3);
    </Custom Battle Effect>
    
    <Custom Respond Effect>
    if (target.hp == 0) {
    BattleManager._subject.spriteReturnHome();
    var skillid = parseInt($dataEnemies[target._enemyId].meta.deathcounter);
    var index = BattleManager._subject.index();
    target.forceAction(skillid, index);
    BattleManager.forceAction(target);
    }
    </Custom Respond Effect>
    
    <Custom Conclude Effect>
    if (user.hp == 0) {
    user.removeState(3);
    user.refresh();
    user.die();
    }
    </Custom Conclude Effect>

    As you can see, it's one state for all death-countering enemies. In the notetags of individual enemies, I put <deathcounter: id>, and the snippet processes it and applies the correct final attack for the enemy. State 3 is the default immortal state.
  9. A quick snippet that I decided to research for adding, changing or removing input keys (e.g. changing movement to WASD, or to use start/pause as a secondary menu button). I haven't been able to use the default scripts to achieve the former without a plugin, however the following does work for modifying the controller behavior for the latter case:

    Code:
    Input.gamepadMapper = {
        0: 'ok',        // A
        1: 'cancel',    // B
        2: 'shift',     // X
        3: 'menu',      // Y
        4: 'pageup',    // LB
        5: 'pagedown',  // RB
        9: 'menu',      // Start/Pause <-- the added input is here
        12: 'up',       // D-pad up
        13: 'down',     // D-pad down
        14: 'left',     // D-pad left
        15: 'right',    // D-pad right
    };
  10. Script to add to events and characters the ability to go walking to a specific position, without the need of creating the entire path manually

    Works for MV and MZ

    Captura de pantalla -2023-08-07 09-34-13.png

    JavaScript:
            /**
             * To be used in route commands, keeps repeating until character reaches x,y
             * @param x
             * @param y
            */
            Game_Character.prototype.goto = function(x,y){
                if (!((this.x == x)&&(this.y == y))){
                    let direction = this.findDirectionTo(x, y);
                    this.setDirection(direction);
                    this.moveForward()
                    if (this.isMovementSucceeded()) {
                        this._moveRouteIndex = this._moveRouteIndex - 1;
                    }
                }
            }
  11. Stop wasting tiles for passability!
    Captura de pantalla -2023-11-30 18-15-11.png

    Do you want to use regions to define directional passability?

    With this script you get this:
    Region 48: Direction 2 Blocked
    Region 49: Direction 4 Blocked
    Region 50: Direction 6 Blocked
    Region 51: Direction 8 Blocked
    Region 52: Direction 2,4 Blocked
    Region 53: Direction 2,6 Blocked
    Region 54: Direction 2,8 Blocked
    Region 55: Direction 4,6 Blocked
    Region 56: Direction 4,8 Blocked
    Region 57: Direction 6,8 Blocked
    Region 58: Direction 4,8,6 Blocked
    Region 59: Direction 8,6,2 Blocked
    Region 60: Direction 6,2,4 Blocked
    Region 61: All Directions Blocked

    JavaScript:
    //Directional passability based on regions
    Game_Map.prototype.isPassableByTile = Game_Map.prototype.isPassable
    Game_Map.prototype.isPassable = function(x, y, d) {
        let region = this.regionId(x,y);
        let br = 48;
    
        if (region==br+14){return false;}
        if ((d==2)&&([br,br+4,br+5,br+6,br+11,br+12,br+13].includes(region))){ return false;}
        if ((d==4)&&([br+1,br+4,br+7,br+8,br+10,br+12,br+13].includes(region))){ return false;}
        if ((d==6)&&([br+2,br+5,br+7,br+9,br+10,br+11,br+12].includes(region))){ return false;}
        if ((d==8)&&([br+3,br+6,br+8,br+9,br+10,br+11,br+13].includes(region))){ return false;}
    
       return this.isPassableByTile(x,y,d);
    };

    If you don't want to start on region 48, just change let br = 48; for the number you want to be the first region of the list, and you are done.
    And remember: If you don't remember what number is which direction, just look at your numpad!
  12. Most flexible way of generating a random integer number I think of.

    * Preface:
    So I was looking at other people's plugin's codes, and seen plenty different ways used for generating random number when required. Some of which looked a bit cumersome for what they are, like some conditional checking, and complicated solutions.
    Therefore, I'm presenting the most reduced solution for this very common necessity I could come up with.

    JavaScript:
    function rand(a = 1, b = 0) {
        return Math.round(Math.random() * (b - a) + a);
    }

    It's benefits include:
    • Shortest memorable name = Easy to type and remember.
    • Works with 0, 1 or 2 arguments input (see examples below).
    • Can input the lower and upper ends in both orders = Now you won't have to remember if it was rand(min, max) or rand(max, min)
    • Shortest formula: No need to add or substract or use flooring or ceiling.
    • Cannot get wrong bounds (e.g., random between 3 (minimum) and 1 (maximum), or same minimum and maximum, causing unexpected results).
    • Works on negative numbers.

    Example usages:
    JavaScript:
    console.log(rand()) // Random integer between 0 and 1 is printed.
    console.log(rand(2)) // Random integer between 0 and 2 is printed.
    console.log(rand(1, 3)) // Random integer between 1 and 3 is printed.
    console.log(rand(3, 1)) // Random integer between 1 and 3 is printed!
    console.log(rand(2, 2)) // Random integer between 2 and 2 is always 2!
    console.log(rand(2, -1)) // Random integer between -1 and 2 is printed!

    Hope this helps people.
    Best regards.
  13. -J- said:
    JavaScript:
    function rand(a = 1, b = 0) {
    return Math.round(Math.random() * (b - a) + a);
    }
    A notable disadvantage of that approach is that numbers are not uniformly random because of round, e.g. rand(1,3) has a 50% chance of returning 2, a 25% chance of returning 1 and 25% chance of returning 3. This is because all values between 1.5 and 2.5 will get rounded to 2, while only values between 1 and 1.5 will get rounded down to 1.

    A simple fix is to use Math.floor instead, like so:
    JavaScript:
    function rand(a = 1, b = 0) {
        return Math.floor(Math.random() * (b - a + 1) + a);
    }
  14. Do you need help debugging your events, and even more, your events paths?

    debug.gif

    I made this script for that:

    Put this script in your custom plugin or as a only once executing event and then in the console
    click the "eye" icon and there write "$gameMap.event(1).debug();" where 1 is the number event you want to see

    You can also just write in the console $gameMap.event(1).debug(); if you don't want to keep live tracking

    JavaScript:
    Game_Character.prototype.debug = function () {
          console.log("Event:" + this._eventId + "    Name:" + (this.event ? this.event().name : "GamePlayer") + "\n" +
            " X: " + this._x + " Y:" + this._y + "\n" +
            " Page:" + (this._pageIndex + 1) + " Route Line:" + (this._moveRouteIndex)+"\n\n"+
            this.routeToText());
    
      }
     
      Game_Character.prototype.routeToText = function(){
    
            let text="";
            let maxSize = 20;
            let len = this._moveRoute.list.length;
    
            let start = 0;
            let end = len;
    
            let tprefix="";
            let tsufix="";
            let prefix="";
    
            if (len > maxSize){
                start = this._moveRouteIndex - maxSize/2;
                end = this._moveRouteIndex + maxSize/2;
    
                if (start < 0){ end=end+(-start); start=0; }
                if (end > len){ start=start-(end-len); end=len;}
                if (start < 0){ start=0; }
    
                if (start > 0){ tprefix="...\n"  }
                if (end < len){ tsufix="..."  }
    
            }
    
    
    
            for (let i = start; i < end; i++) {
    
                let exec = "";
                if (i==this._moveRouteIndex){exec=" >> ";}
    
                let prefix = i+ " ";
    
                const gc = Game_Character;
                let params = this._moveRoute.list[i].parameters;
                switch (this._moveRoute.list[i].code) {
                    case gc.ROUTE_END:
                        break;
                    case gc.ROUTE_MOVE_DOWN:
                        text+=prefix+exec+"Move Down \n";
                        break;
                    case gc.ROUTE_MOVE_LEFT:
                        text+=prefix+exec+"Move Left \n";
                        break;
                    case gc.ROUTE_MOVE_RIGHT:
                        text+=prefix+exec+"Move Right \n";
                        break;
                    case gc.ROUTE_MOVE_UP:
                        text+=prefix+exec+"Move Up \n";
                        break;
                    case gc.ROUTE_MOVE_LOWER_L:
                        text+=prefix+exec+"Move Lower Left \n";
                        break;
                    case gc.ROUTE_MOVE_LOWER_R:
                        text+=prefix+exec+"Move Lower Right \n";
                        break;
                    case gc.ROUTE_MOVE_UPPER_L:
                        text+=prefix+exec+"Move Upper Left \n";
                        break;
                    case gc.ROUTE_MOVE_UPPER_R:
                        text+=prefix+exec+"Move Upper Right \n";
                        break;
                    case gc.ROUTE_MOVE_RANDOM:
                        text+=prefix+exec+"Move at Random \n";
                        break;
                    case gc.ROUTE_MOVE_TOWARD:
                        text+=prefix+exec+"Move toward Player \n";
                        break;
                    case gc.ROUTE_MOVE_AWAY:
                        text+=prefix+exec+"Move away From Player \n";
                        break;
                    case gc.ROUTE_MOVE_FORWARD:
                        text+=prefix+exec+"1 Step Forward \n";
                        break;
                    case gc.ROUTE_MOVE_BACKWARD:
                        text+=prefix+exec+"1 Step Backward \n";
                        break;
                    case gc.ROUTE_JUMP:
                        text+=prefix+exec+"Jump: X:"+params[0]+" Y:"+params[1]+" \n";
                        break;
                    case gc.ROUTE_WAIT:
                        text+=prefix+exec+"Wait: "+params[0]+" frames \n";
                        break;
                    case gc.ROUTE_TURN_DOWN:
                        text+=prefix+exec+"Turn Down \n";
                        break;
                    case gc.ROUTE_TURN_LEFT:
                        text+=prefix+exec+"Turn Left \n";
                        break;
                    case gc.ROUTE_TURN_RIGHT:
                        text+=prefix+exec+"Turn Right \n";
                        break;
                    case gc.ROUTE_TURN_UP:
                        text+=prefix+exec+"Turn Up \n";
                        break;
                    case gc.ROUTE_TURN_90D_R:
                        text+=prefix+exec+"Turn 90º Right \n";
                        break;
                    case gc.ROUTE_TURN_90D_L:
                        text+=prefix+exec+"Turn 90º Left \n";
                        break;
                    case gc.ROUTE_TURN_180D:
                        text+=prefix+exec+"Turn 180º \n";
                        break;
                    case gc.ROUTE_TURN_90D_R_L:
                        text+=prefix+exec+"Turn 90º Right or Left \n";
                        break;
                    case gc.ROUTE_TURN_RANDOM:
                        text+=prefix+exec+"Turn at Random \n";
                        break;
                    case gc.ROUTE_TURN_TOWARD:
                        text+=prefix+exec+"Turn toward Player \n";
                        break;
                    case gc.ROUTE_TURN_AWAY:
                        text+=prefix+exec+"Turn away from Player \n";
                        break;
                    case gc.ROUTE_SWITCH_ON:
                        text+=prefix+exec+"Switch ON: "+params[0]+"\n";
                        break;
                    case gc.ROUTE_SWITCH_OFF:
                        text+=prefix+exec+"Switch OFF: "+params[0]+"\n";
                        break;
                    case gc.ROUTE_CHANGE_SPEED:
                        text+=prefix+exec+"Speed: "+params[0]+"\n";
                        break;
                    case gc.ROUTE_CHANGE_FREQ:
                        text+=prefix+exec+"Frequency: "+params[0]+"\n";
                        break;
                    case gc.ROUTE_WALK_ANIME_ON:
                        text+=prefix+exec+"Walking Animation ON \n";
                        break;
                    case gc.ROUTE_WALK_ANIME_OFF:
                        text+=prefix+exec+"Walking Animation OFF \n";
                        break;
                    case gc.ROUTE_STEP_ANIME_ON:
                        text+=prefix+exec+"Stepping Animation ON \n";
                        break;
                    case gc.ROUTE_STEP_ANIME_OFF:
                        text+=prefix+exec+"Stepping Animation OFF \n";
                        break;
                    case gc.ROUTE_DIR_FIX_ON:
                        text+=prefix+exec+"Direction Fix ON \n";
                        break;
                    case gc.ROUTE_DIR_FIX_OFF:
                        text+=prefix+exec+"Direction Fix OFF \n";
                        break;
                    case gc.ROUTE_THROUGH_ON:
                        text+=prefix+exec+"Through ON \n";
                        break;
                    case gc.ROUTE_THROUGH_OFF:
                        text+=prefix+exec+"Through OFF \n";
                        break;
                    case gc.ROUTE_TRANSPARENT_ON:
                        text+=prefix+exec+"Transparent ON \n";
                        break;
                    case gc.ROUTE_TRANSPARENT_OFF:
                        text+=prefix+exec+"Transparent OFF \n";
                        break;
                    case gc.ROUTE_CHANGE_IMAGE:
                        text+=prefix+exec+"Image: "+params[0]+"("+params[1]+") \n";
                        break;
                    case gc.ROUTE_CHANGE_OPACITY:
                        text+=prefix+exec+"Opacity: "+params[0]+"\n";
                        break;
                    case gc.ROUTE_CHANGE_BLEND_MODE:
                        text+=prefix+exec+"Blend Mode: "+params[0]+"\n";
                        break;
                    case gc.ROUTE_PLAY_SE:
                        text+=prefix+exec+"SE: "+params[0].name+" (Volume: "+params[0].volume+", Pitch:"+params[0].pitch+", Pan:"+params[0].pan+")\n";
                        break;
                    case gc.ROUTE_SCRIPT:
                        text+=prefix+exec+"Script: "+params[0]+"\n";
                        break;
                }
            }
            text = tprefix+text+tsufix;
            this._routeText = text;
            return text;
        }
  15. Here is a snippet that sets a switch whenever a save file is loaded

    JavaScript:
        var baseOnLoad = Game_System.prototype.onAfterLoad;
        Game_System.prototype.onAfterLoad = function() {
            baseOnLoad.call(this);
            $gameSwitches.setValue(switchId, true);
        };
    (Replace the switchId with the ID of the switch you're going to use)

    Or if you want it as a plugin

    JavaScript:
    //=============================================================================
    // ILB_SetSwitchAtLoad.js
    //=============================================================================
    
    /*:
     * @plugindesc Sets the switch from Switch ID parameter to the specified value after a save game is loaded
     * @author I_LIKE_BREAD7
     *
     * @param Switch ID
     * @desc Switch to be set to the value
     * @default 1
     *
     * @param Value
     * @desc Value to be set (true/false)
     * @default true
     *
     * @help This plugin does not provide plugin commands.
     */
    
    (function() {
    
        var parameters = PluginManager.parameters('ILB_SetSwitchAtLoad');
        var switchId = Number(parameters['Switch ID'] || 1);
        var value = JSON.parse(parameters['Value']);
    
        var baseOnLoad = Game_System.prototype.onAfterLoad;
        Game_System.prototype.onAfterLoad = function() {
            baseOnLoad.call(this);
            $gameSwitches.setValue(switchId, value);
        };
    
    })();

    It can be used to make "Save and quit to title" functionality, like this
    1721060481130.png
    Otherwise, if you do "Open Save Screen" and then "Return to Title Screen" immediately after the game will always return to the title screen after being loaded.
    In this situation, the switch will be off after saving, which will allow the game to return to the title screen, but will be on after loading the game and will not allow the game to do that again.
  16. Use this function to get an event, by id, name or tag, or by 'this' variable.
    JavaScript:
    function $E(n){
      if(n instanceof Game_Event) return n;
      if(typeof n.eventId=='function') n = n.eventId();
      return $gameMap._events[n]||$gameMap._events.find(function(e){return e&&e.event().name==n;})||$gameMap._events.find(function(e){return e&&e.event().note.contains(n);})||null;
    }

    This function gets the sprite of an event.
    JavaScript:
    function $spr(c){
      if(c instanceof Game_Character == false){
        c = $E(c);
      }
      if(!c) return null;
      return SceneManager._scene._spriteset._characterSprites.find(function(s){return s._character==c;});
    }

    And this function turns an event into a map layer. Which uses the entie character picture(so you don't have to make a picture 12 times bigger if you want to add some map decoration).
    You can change it's position by setting its layerX and layerY property.
    You can also change its z value directly.
    You can clip the picture using frameX, frameY, frameWidth, and frameHeight properties.
    And since it is an event, it can move and jump like a normal one.
    Spoiler
    1722561546870.png1722562485804.png
    JavaScript:
    function makeEventLayer(e){
      e = $E(e);
      var spr = $spr(e);
    
      if(spr._madeEventLayerSprite) return;
    
      e.screenX = function(){
        var tw = $gameMap.tileWidth();
        return Math.round(this.scrolledX() * tw+(this.layerX||0));
      };
      e.screenY = function() {
          var th = $gameMap.tileHeight();
          return Math.round(this.scrolledY() * th - this.jumpHeight() + (this.layerY||0));
      };
    
      e.screenZ = function() {
          return this.z==undefined?(this._priorityType * 2 + 1):this.z;
      };
    
      spr._madeEventLayerSprite = true;
      spr.anchor.set(0,0);
      spr.updateCharacterFrame = function(){
        var c = this._character;
        if(c.frameX!=undefined){
          this.setFrame(c.frameX,c.frameY,c.frameWidth,c.frameHeight);
        }else{
          this.setFrame(0,0,this.bitmap.width,this.bitmap.height);
        }
      };
    }
  17. if you need to change actor appearance a lot or for party members for the actor.
    this snippet remove 3 lines to be called into a single line (just a slight more efficient).
    JavaScript:
    function changeActorImage(fileName, index) {
        //=> Image file in character folder
        $gameActors.actor(id).setCharacterImage(fileName, index);
        //=> Image file in faces folder
        $gameActors.actor(id).setFaceImage(fileName, index);
        $gamePlayer.refresh();
    };

    Just make sure that the file name in character folder and faces folder are equal
    in order this to work.

    file names are in "string" to grab the file name.

    you can change the function name if you like.