Converting a Script into a Plug-In

Discussion in 'Javascript/Plugin Support' started by p0_boy, Apr 12, 2019.

  1. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    Hey, folks-

    I have been using RPG Maker MV for little over a month now and am at the point where I am trying to add a HUD to my game.

    I adapted an RPG Maker VX ACE tutorial by a user named Pixii, and came up with the following, simple script:

    Code:
    Number.prototype.roundTo = function(num) {
        var xBuff = this%num;
        if (xBuff <= (num/2)) {
            return this-xBuff;
        } else {
            return this+num-xBuff;
        }
    }
    var calcHP = ($gameActors.actor(1).hp * 112) / $gameActors.actor(1).mhp;
    var pSuffix = calcHP.roundTo(4);
    var pName = "zhud_hp_" + pSuffix;
    var xTopRight = (Graphics.boxWidth * 0.75);
    $gameScreen.showPicture(1, pName, 0, xTopRight, 3, 100, 100, 255, 0);
    
    I am currently running it as a Parallel Process using a plug-in written by Pivoo called Pv_Scriptlets, but I fear that this method is very heavy on the computer's processor and may cause lag in gameplay.

    Is there any way that this can be adapted to work as its own plug-in? Would doing so mean better game performance?

    I tried to figure it out for myself, watching SRDude's How to Make a Plugin in RPG Maker MV YT tutorials, but even after referencing the RPGMakerMV Library- I cannot figure out which pre-existing function I should manipulate and override (is it Scene_Base.update()?).

    In, my mind-

    1. I need to find the Library function that initially draws everything in the scene, as well as the function that monitors the character's HP.
    2. I also need to modify the script that I have to find the dimensions (width/height) of the image that I am displaying as the HUD, so that it's position on the screen can be determined in relation to those measurements.

    I am using an ABS system so I do not need any information about a Battle HUD, just one that appears on the map.

    I was excited to find a Google search result called RMMV Plugin Scripting Tutorials (Beginner to Advanced): Tutorial 34 - Variable HUD by Soulpour777, only to find that the video is unavailable because " the uploader has closed their YouTube account".

    So, I am wondering if anybody could help and/or point me in the right direction?

    Thanks in advance!
     
    Last edited: Apr 12, 2019
    #1
  2. caethyril

    caethyril ^_^ Veteran

    Messages:
    1,162
    Likes Received:
    718
    Location:
    UK
    First Language:
    English
    Primarily Uses:
    RMMV
    Parallel events only run on the map, so to mimic that you'd add it to Scene_Map's update routine. Then again, like you mention, if it's representing the character's HP then that only needs to update when their HP does (which is probably less often than once per frame). That means you could instead opt for an alias of the scene's start method and the actor's gainHp method. :)

    Here's an example of the possible structure:
    Code:
    /*:
     * @plugindesc Description!
     * @author Author!
     * @help Help!
     */
    
    var p0_boy = p0_boy || {};  // author namespace
    p0_boy.HUD = p0_boy.HUD || {};  // plugin namespace
    
    (function($) {  // $ corresponds to input argument (see parentheses at end of function block)
    
      Number.prototype.roundTo = function(num) {
        // roundTo stuff here
      };
    
      $.refreshHUD = function() {
        // your calculation / show picture stuff here
      };
    
      var _Scene_Map_start = Scene_Map.prototype.start;  // local alias
      Scene_Map.prototype.start = function() {
        _Scene_Map_start.call(this);  // callback for original behaviour
        $.refreshHUD();  // call your code
      };
    
      var _Game_Actor_gainHp = Game_Actor.prototype.gainHp;  // local alias
      Game_Actor.prototype.gainHp = function(value) {
        _Game_Actor_gainHp.call(this, value);  // callback
        $.refreshHUD();
      };
    
    })(p0_boy.HUD);  // use plugin namespace
    The plugin/author namespaces and general setup with the (function($) {...})(input) stuff (a.k.a. IIFE) is optional, but good for staying organised and reducing the risk of conflicts with other plugins.

    Not sure how much of a performance improvement you'll see, but it should technically be faster as its own plugin! I think the heaviest part of this is the showPicture part and the time it takes to load a new picture. Suggestion: remember the calcHP value last calculated, and if it's the same as before then don't do anything this time around, e.g.
    Code:
      $.lastHP = 0;
      $.refreshHP = function() {
        var calcHP = whatever;
        if ($.lastHP === calcHP) return;  // stop here if same as before
        $.lastHP = calcHP;  // else remember new value
        // then do the pName & showPicture stuff
      };
    If you're still having performance issues it may be worth showing all relevant pictures with opacity zero, then simply adjusting the picture opacities. That way they're all loaded into memory, but only one is visible at a time~

    Getting picture dimensions: plugin parameters may be a better option, assuming all HUD elements have fixed dimensions during play. Otherwise I think you'll either need to load, check, then show the picture, or show, check, then immediately reposition it. I think I'd try the latter, but that would still involve searching for the matching sprite from the spriteset (no predefined functions for going from Game_Picture to Sprite_Picture). :kaoback:
     
    #2
    p0_boy likes this.
  3. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    Caethyril-

    Thank you so much! This is fantastic.

    Using your code, this is what I came up with:

    Code:
    /*:
    *
    * zHUD.js
    * @plugindesc (v0.4)
    * A Zelda-esque Head-Up Display.
    *
    * @author dismal_science__, caethyril
    *
    * @help
    *
    * Place Images in IMG/PICTURES folder.
    *
    * File format: Prefix_Suffix.png
    *
    * @param Prefix
    * @desc Filename prefix, ex. "zhud_hp_"
    * @default zhud_hp_
    *
    * @param ImgWidth
    * @desc Width of Image
    * @default 192
    *
    * @param ImgMax
    * @desc Total number of Images
    * @default 28
    *
    * @param LastImgSuffix
    * @desc Suffix of last image in group.
    * @default 112
    *
    */
    
    var dismal_sci = dismal_sci || {};
    dismal_sci.zHUD = dismal_sci.zHUD || {};
    
    (function() {
      
        dismal_sci.zHUD = {
            Parameters: PluginManager.parameters('zHUD'),
        };
      
        dismal_sci.Param = dismal_sci.Param || {};
        dismal_sci.Param.zHUD = dismal_sci.Param.zHUD || {};
        dismal_sci.Param.zHUD.Prefix = dismal_sci.zHUD.parameters['Prefix'];
        dismal_sci.Param.zHUD.ImgWidth = dismal_sci.zHUD.parameters['ImgWidth'];
        dismal_sci.Param.zHUD.ImgMax = dismal_sci.zHUD.parameters['ImgMax'];
        dismal_sci.Param.zHUD.LastImgSuffix = dismal_sci.zHUD.parameters['LastImgSuffix'];
      
    }) ();
    
    (function($) {
          
        Number.prototype.roundTo = function(num) {
            var xBuff = this%num;
            if (xBuff <= (num/2)) {
                return this-xBuff;
            } else {
                return this+num-xBuff;
            };
      
        $.lastHP = 0;
        $.xRight = (Graphics.boxWidth - (dismal_sci.Param.zHUD.ImgWidth + 24));
        $.xRound = (dismal_sci.Param.zHUD.LastImgSuffix / dismal_sci.Param.zHUD.ImgMax);
          
        $.refreshHUD = function() {
            var calcHP = ($gameActors.actor(1).hp * dismal_sci.Param.zHUD.LastImgSuffix) / $gameActors.actor(1).mhp;
            if ($.lastHP === calcHP) return;
            $.lastHP = calcHP;
            var pSuffix = calcHP.roundTo($.xRound);
            var pName = dismal_sci.Param.zHUD.Prefix + pSuffix;
            $gameScreen.showPicture(1, pName, 0, $.xRight, 3, 100, 100, 255, 0);
        };
      
        var _Scene_Map_start = Scene.Map.prototype.start;
      
        Scene_Map.prototype.start = function() {
            _Scene_Map_start.call(this);
            $.refreshHUD();
        };
      
        var _Game_Actor_gainHP = Game_Actor.prototype.gainHP;
      
        Game_Actor.prototype.gainHp = function(value) {
            _Game_Actor_gainHp.call(this, value);
            $.refreshHUD();
        };
      
      
                  
    }) (dismal_sci.zHUD);
    
    
    
    I added parameters, so a few things can be modified, including manually inputting the Image Width rather than having the script figure it out. Am I doing this correct?

    Also, when I run the game- the HUD doesn't pop up. I don't get any errors though. Do I need to call the plugin somehow?

    [​IMG]

    [​IMG]

    Thank you again!
     
    Last edited: Apr 12, 2019
    #3
  4. caethyril

    caethyril ^_^ Veteran

    Messages:
    1,162
    Likes Received:
    718
    Location:
    UK
    First Language:
    English
    Primarily Uses:
    RMMV
    I think the problem is this part. First you define your plugin namespace as a new object with a single property, Parameters. This means that you're storing your plugin's parameters in dismal_sci.zHUD.Parameters. Unfortunately JS is case-sensitive, so all the following lines see is an attempt to access some unknown property parameters. It's probably causing an error ("cannot read property of undefined") and making your plugin fail to load. Try pressing F8 during play-test to open the console window, where errors will appear in red text; if a plugin throws an error when it's loading, that plugin gets ignored. :kaoswt:

    You could try something like this for your parameters instead:
    Code:
    dismal_sci.Param = dismal_sci.Param || {};  // your parameter namespace
    dismal_sci.Param.zHUD = dismal_sci.Param.zHUD || {};  // this plugin's parameters
    
    (function($) {  // <- in here, $ = dismal_sci.Param.zHUD, because that's what we passed in as the function input
    
      dismal_sci.zHUD.parameters = PluginManager.parameters('zHUD');  // get parameters from plugin file named "zHUD.js"
    
      $.Prefix = $.parameters['Prefix'];
      $.ImgWidth = Number($.parameters['ImgWidth']);  // convert to number since all parameters are retrieved as text
      $.ImgMax = Number($.parameters['ImgMax']);
      $.LastImgSuffix = Number($.parameters['LastImgSuffix']);
    
    })(dismal_sci.Param.zHUD);  // <- "function input" I mentioned previously, basically just lets you define a shorthand
    I personally prefer to just add my parameters directly as properties of the plugin namespace, but to each their own~

    Oh, and you forgot a closing brace on your Number.prototype.roundTo function. :)
     
    #4
  5. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    Thanks!

    OK- so I replaced the parameters in question, and closed the .roundTo function and the script now looks like this:

    Code:
    /*:
    *
    * zHUD.js
    * @plugindesc (v0.4)
    * A Zelda-esque Head-Up Display.
    * 
    * @author dismal_science__, caethyril
    *
    * @help
    *
    * Place Images in IMG/PICTURES folder.
    *
    * File format: Prefix_Suffix.png 
    *
    * @param Prefix
    * @desc Filename prefix, ex. "zhud_hp_"
    * @default zhud_hp_
    *
    * @param ImgWidth
    * @desc Width of Image
    * @default 192
    *
    * @param ImgMax
    * @desc Total number of Images
    * @default 28
    *
    * @param LastImgSuffix
    * @desc Suffix of last image in group.
    * @default 112
    *
    */
    
    var dismal_sci = dismal_sci || {};
    dismal_sci.zHUD = dismal_sci.zHUD || {};
    
    dismal_sci.Param = dismal_sci.Param || {};  // your parameter namespace
    dismal_sci.Param.zHUD = dismal_sci.Param.zHUD || {};  // this plugin's parameters
    
    (function($) {  // <- in here, $ = dismal_sci.Param.zHUD, because that's what we passed in as the function input
    
      dismal_sci.zHUD.parameters = PluginManager.parameters('zHUD');  // get parameters from plugin file named "zHUD.js"
    
      $.Prefix = $.parameters['Prefix'];
      $.ImgWidth = Number($.parameters['ImgWidth']);  // convert to number since all parameters are retrieved as text
      $.ImgMax = Number($.parameters['ImgMax']);
      $.LastImgSuffix = Number($.parameters['LastImgSuffix']);
    
    })(dismal_sci.Param.zHUD);  // <- "function input" I mentioned previously, basically just lets you define a shorthand
    
    (function($) {
           
        Number.prototype.roundTo = function(num) {
            var xBuff = this%num;
            if (xBuff <= (num/2)) {
                return this-xBuff;
            } else {
                return this+num-xBuff;
            }
        };
       
        $.lastHP = 0;
        $.xRight = (Graphics.boxWidth - (dismal_sci.Param.zHUD.ImgWidth + 24));
        $.xRound = (dismal_sci.Param.zHUD.LastImgSuffix / dismal_sci.Param.zHUD.ImgMax);
           
        $.refreshHUD = function() {
            var calcHP = ($gameActors.actor(1).hp * dismal_sci.Param.zHUD.LastImgSuffix) / $gameActors.actor(1).mhp;
            if ($.lastHP === calcHP) return;
            $.lastHP = calcHP;
            var pSuffix = calcHP.roundTo($.xRound);
            var pName = dismal_sci.Param.zHUD.Prefix + pSuffix;
            $gameScreen.showPicture(1, pName, 0, $.xRight, 3, 100, 100, 255, 0);
        };
       
        var _Scene_Map_start = Scene.Map.prototype.start;
       
        Scene_Map.prototype.start = function() {
            _Scene_Map_start.call(this);
            $.refreshHUD();
        };
       
        var _Game_Actor_gainHP = Game_Actor.prototype.gainHP;
       
        Game_Actor.prototype.gainHp = function(value) {
            _Game_Actor_gainHp.call(this, value);
            $.refreshHUD();
        };
       
       
                   
    }) (dismal_sci.zHUD);
    
    
    It still isn't popping up though, and the console window reveals this error:

    [​IMG]

    [​IMG]

    I'm sorry for asking so many questions, I have limited grasp of JavaScript still- but I am trying to learn.

    I appreciate your help very much.

    Thanks!
     
    #5
  6. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    Caethyril-

    I stripped the code down back to its minimum:

    Code:
    /*:
    *
    * zHUD.js
    * @plugindesc (v0.4s)
    * A Zelda-esque Head-Up Display.
    * 
    * @author dismal_science__, caethyril
    *
    * @help
    *
    *
    */
    
    var dismal_sci = dismal_sci || {};
    dismal_sci.zHUD = dismal_sci.zHUD || {};
    
    (function($) {
           
        Number.prototype.roundTo = function(num) {
            var xBuff = this%num;
            if (xBuff <= (num/2)) {
                return this-xBuff;
            } else {
                return this+num-xBuff;
            }
        };
       
        $.lastHP = 0;
        $.xRight = (Graphics.boxWidth - (192 + 24));
        $.xRound = 4;
           
        $.refreshHUD = function() {
            var calcHP = ($gameActors.actor(1).hp * 112) / $gameActors.actor(1).mhp;
            if ($.lastHP === calcHP) return;
            $.lastHP = calcHP;
            var pSuffix = calcHP.roundTo($.xRound);
            var pName = "zhud_hp_" + pSuffix;
            $gameScreen.showPicture(1, pName, 0, $.xRight, 3, 100, 100, 255, 0);
        };
       
       
        var _SB_start = Scene_Map.prototype.start;
       
        Scene_Map.prototype.start = function() {
            _SB_start.call(this);
           
            $.refreshHUD();
        };
       
        var _Game_Actor_gainHP = Game_Actor.prototype.gainHP;
       
        Game_Actor.prototype.gainHp = function(value) {
            _Game_Actor_gainHp.call(this, value);
            $.refreshHUD();
        };
       
       
                   
    }) (dismal_sci.zHUD);
    
    And for some reason the HUD still does not pop up.

    There are no errors in the console:

    [​IMG]

    Any idea what I am doing wrong?

    I really appreciate your help. Thank you in advance!
     
    #6
  7. caethyril

    caethyril ^_^ Veteran

    Messages:
    1,162
    Likes Received:
    718
    Location:
    UK
    First Language:
    English
    Primarily Uses:
    RMMV
    OK sorry for the delay but I've had a chance to test it out now and figure out what was going wrong.
    1. Your roundTo function was getting rounding errors (0.999 sorta thing); I've replaced it with num * Math.round(this/num). :kaojoy:
    2. Graphics.boxWidth isn't defined when the plugin script loads, so the x coordinate of the picture was undefined, causing it to fail to display. I've changed xRight to xOffset and simply subtracted it from the boxWidth in the refreshHUD routine. :kaoswt2:
    3. I changed the gainHp alias to reference setHp instead; gainHp calls setHp, so this way it'll simply catch more cases. :kaothx:
    4. Just because it makes so much tidier from my perspective: I merged the parameter stuff to the plugin namespace. :kaoslp:
    I tried with three images (0, 1, 2) and it seemed to work as expected for me! Incidentally, the ImgMax parameter may be misleading, since you always need one more image for 0 HP. Not sure how to clarify that beyond stating it in the plugin help (it's fine mechanically if the picture is there). :kaoswt:

    Oh yea, here's the code~ :kaopride:
    Code:
    /*:
     * zHUD.js
     *
     * @plugindesc (v0.5)
     * A Zelda-esque Head-Up Display.
     * 
     * @author dismal_science__, caethyril
     *
     * @help
     *
     * Place Images in IMG/PICTURES folder.
     *
     * File format: Prefix_Suffix.png 
     *
     * @param Prefix
     * @type text
     * @desc Filename prefix, ex. "zhud_hp_"
     * @default zhud_hp_
     *
     * @param ImgWidth
     * @type number
     * @desc Width of Image
     * @default 192
     *
     * @param ImgMax
     * @type number
     * @desc Total number of Images, excluding 0
     * @default 28
     *
     * @param LastImgSuffix
     * @type number
     * @desc Suffix of last image in group.
     * @default 112
     */
    
    var dismal_sci = dismal_sci || {};		// Author namespace
    dismal_sci.zHUD = dismal_sci.zHUD || {};	// Plugin namespace
    
    (function($) {
    
    	// Get parameters
    	$.params = PluginManager.parameters('zHUD');
    	if ($.params === undefined) throw new Error('zHUD parameters not found! Check the plugin is named correctly and try again.');
    
    	// Define parameter variables on plugin namespace
    	$.Prefix = $.params['Prefix'];
    	$.ImgWidth = Number($.params['ImgWidth']);
    	$.ImgMax = Number($.params['ImgMax']);
    	$.LastImgSuffix = Number($.params['LastImgSuffix']);
    
    	// Other plugin variables
    	$.lastHP = 0;
    //	$.xRight = Graphics.boxWidth - ($.ImgWidth + 24);	// boxWidth is not set yet!
    	$.xOffset = $.ImgWidth + 24;				// Alternative approach
    	$.xRound = $.LastImgSuffix / $.ImgMax;
    
    	// Round to nearest multiple of integer num
    	Number.prototype.roundTo = function(num) {
    		return Math.ceil(this/num) * num;
    	};
    
    	// Display appropriate picture for HUD, via showPicture
    	$.refreshHUD = function() {
    		console.log('Refreshing HUD!');
    		var actor = $gameActors.actor(1);
    		var calcHP = ($.LastImgSuffix * actor.hp / actor.mhp).roundTo($.xRound);
    		if ($.lastHP === calcHP) return;	// Only continue if changed
    		$.lastHP = calcHP;			// Remember HP
    		var id = 1;
    		var name = $.Prefix + String(calcHP);
    		var origin = 0, x = Graphics.boxWidth - $.xOffset, y = 3;
    		var scaleX = 100, scaleY = 100, opacity = 255, blend = 0;
    		$gameScreen.showPicture(id, name, origin, x, y, scaleX, scaleY, opacity, blend);
    	};
    
    	// Refresh HUD when Scene_Map loads
    	var _Scene_Map_start = Scene_Map.prototype.start;
    	Scene_Map.prototype.start = function() {
    		_Scene_Map_start.call(this);
    		console.log('Scene_Map has started!');
    		$.refreshHUD();
    	};
    
    	// Refresh HUD when actor gains/loses HP
    	var _Game_Actor_setHp = Game_Actor.prototype.setHp;
    	Game_Actor.prototype.setHp = function(value) {
    		_Game_Actor_setHp.call(this, value);
    		console.log('Actor HP changed!');
    		$.refreshHUD();
    	};
    
    })(dismal_sci.zHUD);
    (Hope it works out this time!)
     
    #7
    p0_boy likes this.
  8. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    Caethyril- WOO!

    Thanks so much!

     
    #8
    caethyril likes this.
  9. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    Caethyril-

    Sorry to bother you again, but I was trying to be slick and add a beeping sound when the HP reaches a low value. So I modified the script:

    Code:
    /*:
     * zHUD.js
     *
     * @plugindesc (v0.6)
     * A Zelda-esque Head-Up Display.
     *
     * @author dismal_science__, caethyril
     *
     * @help
     *
     * Place Images in IMG/PICTURES folder.
     *
     * File format: Prefix_Suffix.png
     *
     * @param Prefix
     * @type text
     * @desc Filename prefix, ex. "zhud_hp_"
     * @default zhud_hp_
     *
     * @param ImgWidth
     * @type number
     * @desc Width of Image
     * @default 192
     *
     * @param ImgMax
     * @type number
     * @desc Total number of Images (excluding 0).
     * @default 28
     *
     * @param LastImgSuffix
     * @type number
     * @desc Suffix of last image in group.
     * @default 112
     *
     * @param LowHealthSE
     * @type text
     * @desc Low HP Sound Effect, place in AUDIO/SE folder.
     * @default LowHealth
     */
    
    var dismal_sci = dismal_sci || {};        // Author namespace
    dismal_sci.zHUD = dismal_sci.zHUD || {};    // Plugin namespace
    
    (function($) {
    
        // Get parameters
        $.params = PluginManager.parameters('zHUD');
        if ($.params === undefined) throw new Error('zHUD parameters not found! Check the plugin is named correctly and try again.');
    
        // Define parameter variables on plugin namespace
        $.Prefix = $.params['Prefix'];
        $.ImgWidth = Number($.params['ImgWidth']);
        $.ImgMax = Number($.params['ImgMax']);
        $.LastImgSuffix = Number($.params['LastImgSuffix']);
        $.LowHealthSE = $.params['LowHealthSE'];
    
        // Other plugin variables
        $.lastHP = 0;
    //    $.xRight = Graphics.boxWidth - ($.ImgWidth + 24);    // boxWidth is not set yet!
        $.xOffset = $.ImgWidth + 24;                // Alternative approach
        $.xRound = $.LastImgSuffix / $.ImgMax;
    
        // Round to nearest multiple of integer num
        Number.prototype.roundTo = function(num) {
            return Math.ceil(this/num) * num;
        };
     
        $.lowHP = Math.pow($.xRound,2);
        $.lowHP_SND = {name: $.LowHealthSE, volume: 90, pitch: 100, pan: 0};
    
        // Display appropriate picture for HUD, via showPicture
        $.refreshHUD = function() {
            console.log('Refreshing HUD!');
            console.log($.lowHP);
            var actor = $gameActors.actor(1);
            var calcHP = ($.LastImgSuffix * actor.hp / actor.mhp).roundTo($.xRound);
            if (calcHP < $.lowHP) AudioManager.playSe($.lowHP_SND);
            if ($.lastHP === calcHP) return;    // Only continue if changed
            $.lastHP = calcHP;            // Remember HP
            var id = 1;
            var name = $.Prefix + String(calcHP);
            var origin = 0, x = Graphics.boxWidth - $.xOffset, y = 3;
            var scaleX = 100, scaleY = 100, opacity = 255, blend = 0;
            $gameScreen.showPicture(id, name, origin, x, y, scaleX, scaleY, opacity, blend);
        };
    
        // Refresh HUD when Scene_Map loads
        var _Scene_Map_start = Scene_Map.prototype.start;
        Scene_Map.prototype.start = function() {
            _Scene_Map_start.call(this);
            console.log('Scene_Map has started!');
            $.refreshHUD();
        };
    
        // Refresh HUD when actor gains/loses HP
        var _Game_Actor_setHp = Game_Actor.prototype.setHp;
        Game_Actor.prototype.setHp = function(value) {
            _Game_Actor_setHp.call(this, value);
            console.log('Actor HP changed!');
            $.refreshHUD();
        };
    
    })(dismal_sci.zHUD);
    
    But of course, since the HUD only refreshes when HP is lost or gained, this means that the sound only beeps once when it reaches that low HP value. Is there any way to make it beep constantly without demanding too much from the computer's processor? Do I need to attach it to another function?

    Sorry for being such a bother. I appreciate all your help.

    Thanks!
     
    Last edited: Apr 14, 2019
    #9
  10. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    I kinda figured it out (using setInterval)-

    Code:
    /*:
     * zHUD.js
     *
     * @plugindesc (v0.6)
     * A Zelda-esque Head-Up Display.
     * 
     * @author dismal_science__, caethyril
     *
     * @help
     *
     * Place Images in IMG/PICTURES folder.
     *
     * File format: Prefix_Suffix.png 
     *
     * @param Prefix
     * @type text
     * @desc Filename prefix, ex. "zhud_hp_"
     * @default zhud_hp_
     *
     * @param ImgWidth
     * @type number
     * @desc Width of Image (in pixels).
     * @default 192
     *
     * @param ImgMax
     * @type number
     * @desc Total number of Images.
     * @default 29
     *
     * @param LastImgSuffix
     * @type number
     * @desc Suffix of last image in group.
     * @default 112
     *
     * @param LowHealthSE
     * @type text
     * @desc Low HP Sound Effect, place in AUDIO/SE folder.
     * @default LowHealth
     * 
     * @param SE_Interval
     * @type number
     * @desc Interval between Low HP Sound Effect beeps, in milliseconds.
     * @default 500
     *
     */
    
    var dismal_sci = dismal_sci || {};        // Author namespace
    dismal_sci.zHUD = dismal_sci.zHUD || {};    // Plugin namespace
    
    (function($) {
    
        // Get parameters
        $.params = PluginManager.parameters('zHUD');
        if ($.params === undefined) throw new Error('zHUD parameters not found! Check the plugin is named correctly and try again.');
    
        // Define parameter variables on plugin namespace
        $.Prefix = $.params['Prefix'];
        $.ImgWidth = Number($.params['ImgWidth']);
        $.ImgMax = Number($.params['ImgMax']) - 1;
        $.LastImgSuffix = Number($.params['LastImgSuffix']);
        $.LowHealthSE = $.params['LowHealthSE'];
        $.SE_Interval = Number($.params['SE_Interval']);
    
        // Other plugin variables
        $.lastHP = 0;
    //    $.xRight = Graphics.boxWidth - ($.ImgWidth + 24);    // boxWidth is not set yet!
        $.xOffset = $.ImgWidth + 24;                // Alternative approach
        $.xRound = $.LastImgSuffix / $.ImgMax;
    
        // Round to nearest multiple of integer num
        Number.prototype.roundTo = function(num) {
            return Math.ceil(this/num) * num;
        };
       
        $.lowHP = Math.pow($.xRound,2);
        $.lowHP_SND = {name: $.LowHealthSE, volume: 90, pitch: 100, pan: 0};
       
        $.lowHP_beep = function() {
            if ($.beepInterval === undefined) {
                $.beepInterval = setInterval(function(){
                    AudioManager.playSe($.lowHP_SND);
                }, $.SE_Interval);
            }
        };
       
        $.lowHP_beep_kill = function() {
            if ($.beepInterval != undefined) {
                clearInterval(this.beepInterval);
                delete this.beepInterval;
            }
        };
       
        // Display appropriate picture for HUD, via showPicture
        $.refreshHUD = function() {
            console.log('Refreshing HUD!');
            console.log($.lowHP);
            var actor = $gameActors.actor(1);
            var calcHP = ($.LastImgSuffix * actor.hp / actor.mhp).roundTo($.xRound);
            if (calcHP < $.lowHP) {
                $.lowHP_beep();
            } else if (calcHP > $.lowHP) {
                $.lowHP_beep_kill();
            };
            if ($.lastHP === calcHP) return;    // Only continue if changed
            $.lastHP = calcHP;            // Remember HP
            var id = 1;
            var name = $.Prefix + String(calcHP);
            var origin = 0, x = Graphics.boxWidth - $.xOffset, y = 3;
            var scaleX = 100, scaleY = 100, opacity = 255, blend = 0;
            $gameScreen.showPicture(id, name, origin, x, y, scaleX, scaleY, opacity, blend);
        };
       
        // Refresh HUD when Scene_Map loads
        var _Scene_Map_start = Scene_Map.prototype.start;
        Scene_Map.prototype.start = function() {
            _Scene_Map_start.call(this);
            console.log('Scene_Map has started!');
            $.refreshHUD();
        };
    
        // Refresh HUD when actor gains/loses HP
        var _Game_Actor_setHp = Game_Actor.prototype.setHp;
        Game_Actor.prototype.setHp = function(value) {
            _Game_Actor_setHp.call(this, value);
            console.log('Actor HP changed!');
            $.refreshHUD();
        };
    
    })(dismal_sci.zHUD);
    
    I just can't get it to stop beeping. Any clue what I might be doing wrong?

    Also, am I placing the code in the optimal position in the script or am I just causing the processing to slow down?

    Thanks again!
     
    Last edited: Apr 14, 2019
    #10
  11. caethyril

    caethyril ^_^ Veteran

    Messages:
    1,162
    Likes Received:
    718
    Location:
    UK
    First Language:
    English
    Primarily Uses:
    RMMV
    Ooh, fancy! :kaopride:

    The setInterval and clearInterval stuff looks OK to me... I notice that if calcHP equals lowHP, neither of the beep methods will be called, maybe that's what you're seeing? :kaoswt:

    I think it's working for me after rearranging the refreshHUD routine a little:
    Code:
        $.refreshHUD = function() {
            console.log('Refreshing HUD!');
            var actor = $gameActors.actor(1);
            var calcHP = ($.LastImgSuffix * actor.hp / actor.mhp).roundTo($.xRound);
            if ($.lastHP === calcHP) return;    // Only continue if changed
            $.lastHP = calcHP;            // Remember HP
            console.log('calculated:', calcHP, '\nlow:', $.lowHP);
            if (calcHP <= $.lowHP && calcHP > 0) {  // at or below low HP, and not dead
                $.lowHP_beep();
            } else {   // end beep in all other cases
                $.lowHP_beep_kill();
    	};
            var id = 1;
            var name = $.Prefix + String(calcHP);
            var origin = 0, x = Graphics.boxWidth - $.xOffset, y = 3;
            var scaleX = 100, scaleY = 100, opacity = 255, blend = 0;
            $gameScreen.showPicture(id, name, origin, x, y, scaleX, scaleY, opacity, blend);
        };
    You may also want to double-check the lowHP value calculation; with the default values I think it's about 14.9 (square of 112/29).

    Also, for the sound name parameter you can use the v1.5.0+ @type and @dir directives if you like~
    Code:
     * @param LowHealthSE
     * @type file
     * @dir audio/se
     * @require 1
     * @desc Low HP Sound Effect, place in AUDIO/SE folder.
     * @default LowHealth
    (PS: I didn't reply previously, but your game video looks fantastic! :kaojoy:)
     
    #11
  12. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    Thank you- I am finishing about a room a week juggling between graphics and code, and I have 12 more rooms to go before i'll have something I'm happy with.

    I really am grateful for your help. I replaced the refreshHUD routine with your new code. But the main way that I restore HP for the character right now is through a common event:

    Code:
    ◆Comment:SleepEvent ON - Call Common Event specified by SleepEventID
    :Comment:SleepEventID (Variable 19) - Common Event #
    ◆Set Movement Route:Player
    :Set Movement Route:◇Turn 180°
    ◆Control Variables:#0011 CharPose = 2
    ◆Common Event:CharImage
    ◆Script:Galv.Mstyle.img(0,'WindowArrow1');
    ◆Text:None, Window, Bottom
    :Text:\pop[0]#{snooze.0}
    ◆Show Choices:Yes, No (Window, Right, #1, -)
    :When Yes 
      ◆Fadeout Screen
      ◆Play ME:sleep (45, 100, 0)
      ◆Wait:570 frames
      ◆Recover All:Entire Party
      ◆Plugin Command:zHUD refreshHUD
      ◆If:SleepEvent is ON
        ◆Script:var commonEvent = $dataCommonEvents[$gameVariables.value(19)];
        :Script:if (commonEvent) {
        :Script:var eventId = this.isOnCurrentMap() ? this._eventId : 0;
        :Script:this.setupChild(commonEvent.list, eventId);
        :Script:}
        ◆
      :End
      ◆Fadein Screen
      ◆Control Switches:#0020 Bool_BalloonTail = OFF
      ◆Control Variables:#0014 EventId = 0
      ◆Control Variables:#0015 Balloon_Msg = "snooze.1"
      ◆Common Event:BalloonTxt
      ◆
    :When No 
      ◆
    :End
    ◆Control Switches:#0018 SleepEvent = OFF
    ◆Common Event:CharImage
    ◆Set Movement Route:Player (Wait)
    :Set Movement Route:◇Move Down
    :Set Movement Route:◇Move Down
    
    But when I do, the HUD is not refreshed and the beeping has not stopped until I hit the {esc} key, pull up the menu, and then exit out of the menu.

    I try to call the zHUD refreshHUD function manually:

    Code:
    ◆Recover All:Entire Party
      ◆Plugin Command:zHUD refreshHUD
    
    But I might be using the wrong syntax.
     
    #12
  13. caethyril

    caethyril ^_^ Veteran

    Messages:
    1,162
    Likes Received:
    718
    Location:
    UK
    First Language:
    English
    Primarily Uses:
    RMMV
    Oh, I see. Yes, for some reason Recover All seems to set the HP (and MP) directly, bypassing the designated methods for it. :kaoslp:

    One option is to add a refresh call to the recoverAll routine:
    Code:
      var _Game_Actor_recoverAll = Game_Actor.prototype.recoverAll;
      Game_Actor.prototype.recoverAll = function() {
        _Game_Actor_recoverAll.call(this);
        $.refreshHUD();
      };
    Alternatively you could call the refresh manually with a script call:
    Code:
    dismal_sci.zHUD.refreshHUD();
    Plugin Commands need additional setup in the plugin code: they're basically script calls in fancy dress, text split by spaces into a command name and arguments. You'd need to alias Game_Interpreter.prototype.pluginCommand, check the command/args, and invoke script calls as appropriate. Too much bother here, I think. :kaoswt:
     
    #13
    p0_boy likes this.
  14. p0_boy

    p0_boy anti-kumbaya Veteran

    Messages:
    64
    Likes Received:
    26
    Location:
    quezon city
    First Language:
    English
    Primarily Uses:
    RMMV
    Caethyril- thank you, yet again!

    Here's the final version of the code, for now:

    Code:
    /*:
     * zHUD.js
     *
     * @plugindesc (v0.8)
     * A Zelda-esque Head-Up Display.
     *
     * @author dismal_science__, caethyril
     *
     * @help
     *
     * zHUD is a very rudimentary HP HUD, reminiscent to the style used in the
     * Zelda series.
     *
     * zHUD is designed for use with single-actor games.
     *
     * zHUD uses a set of image files to indicate HP status.
     *
     *
     * =[ U S A G E ]===========================================================
     *
     * zHUD's filename must remain "zHUD.js" in order to work properly.
     *
     * The example includes 33 image files, all named similarly with the
     * prefix "zhud_x_hp_" and bearing the same width of "237" pixels.
     *
     * The first image file- "zhud_x_hp_0.png"- represents the image shown when
     * HP is at its lowest.
     *
     * The second image file- "zhud_x_hp_128.png"- represents the image shown
     * when HP is full.
     *
     * The 31 images in-between represent the various possible HP states, in this
     * case, increasing/reducing in increments of 4.
     *
     * The example uses 33 images, but the plug-in can use any number of files.
     * The plug-in adjusts depending on the ImgMax and LastImgSuffix parameters.
     *
     * For the included example, the parameter ImgMax should be set to "33" and
     * LastImgSuffix should be set to "128".
     *
     * For this example, the ImgWidth parameter should be set to "237".
     * This may be adjusted depending on the size of the image used.
     *
     * Place image files in your project's IMG/PICTURES folder.
     *
     * During gameplay, when HP reaches a critical low, zHUD activates an
     * audible warning- specified in the LowHealthSE parameter.
     *
     * For the example- LowHealthSE is set to "LowHPBeep", which represents the
     * audio files "LowHPBeep.ogg" and "LowHPBeep.m4a".
     *
     * Place audio files in the project's AUDIO/SE folder.
     *
     * SE_Interval represents the amount of time in milliseconds between beeping.
     * It is set to "700" by default but may need to be adjusted depending on the
     * length of the audio file that is used.
     *
     * Finally, the zActorID parameter is the number of the Actor whose HP will be
     * displayed.
     *
     * zHUD usually updates its display automatically, but in cases where this
     * doesn't happen, you may need to use a script call to do it manually.
     *
     * Script call: dismal_sci.zHUD.refreshHUD();
     *
     *
     * =[ E T C . ]===========================================================
     *
     * zHUD is written by dismal_science__ and caethyril.
     *
     * zHUD is free for use in both commercial and non-commercial projects,
     * as long as both authors are credited accordingly.
     *
     *
     *
     * @param Prefix
     * @type text
     * @desc Filename prefix, ex. "zhud_x_hp_"
     * @default zhud_x_hp_
     *
     * @param ImgWidth
     * @type number
     * @desc Width of image (in pixels).
     * @default 237
     *
     * @param ImgMax
     * @type number
     * @desc Total number of images.
     * @default 33
     *
     * @param LastImgSuffix
     * @type number
     * @desc Suffix of last image in group.
     * @default 128
     *
     * @param LowHealthSE
     * @type file
     * @dir audio/se
     * @require 1
     * @desc Low HP Sound Effect, place in AUDIO/SE folder.
     * @default LowHPBeep
     *
     * @param SE_Interval
     * @type number
     * @desc Interval between Low HP Sound Effect beeps (in milliseconds).
     * @default 700
     *
     * @param zActorID
     * @type number
     * @desc ID of Actor whose HP will be displayed.
     * @default 1
     *
     */
    
    var dismal_sci = dismal_sci || {};        // Author namespace
    dismal_sci.zHUD = dismal_sci.zHUD || {};    // Plugin namespace
    
    (function($) {
    
        // Get parameters
        $.params = PluginManager.parameters('zHUD');
        if ($.params === undefined) throw new Error('zHUD parameters not found! Check the plugin is named correctly and try again.');
    
        // Define parameter variables on plugin namespace
        $.Prefix = $.params['Prefix'];
        $.ImgWidth = Number($.params['ImgWidth']);
        $.ImgMax = Number($.params['ImgMax']) - 1;
        $.LastImgSuffix = Number($.params['LastImgSuffix']);
        $.LowHealthSE = $.params['LowHealthSE'];
        $.SE_Interval = Number($.params['SE_Interval']);
        $.zActorID = Number($.params['zActorID']);
    
        // Other plugin variables
        $.lastHP = 0;
    //    $.xRight = Graphics.boxWidth - ($.ImgWidth + 24);    // boxWidth is not set yet!
        $.xOffset = $.ImgWidth + 24;                // Alternative approach
        $.xRound = $.LastImgSuffix / $.ImgMax;
    
        // Round to nearest multiple of integer num
        Number.prototype.roundTo = function(num) {
            return Math.ceil(this/num) * num;
        };
      
        $.lowHP = Math.pow($.xRound,2);
        $.lowHP_SND = {name: $.LowHealthSE, volume: 90, pitch: 100, pan: 0};
      
        $.lowHP_beep = function() {
            if ($.beepInterval === undefined) {
                $.beepInterval = setInterval(function(){
                    AudioManager.playSe($.lowHP_SND);
                }, $.SE_Interval);
            }
        };
      
        $.lowHP_beep_kill = function() {
            if ($.beepInterval != undefined) {
                clearInterval(this.beepInterval);
                delete this.beepInterval;
            }
        };
      
        // Display appropriate picture for HUD, via showPicture
        $.refreshHUD = function() {
                console.log('Refreshing HUD!');
                var actor = $gameActors.actor($.zActorID);
                var calcHP = ($.LastImgSuffix * actor.hp / actor.mhp).roundTo($.xRound);
                if ($.lastHP === calcHP) return;    // Only continue if changed
                $.lastHP = calcHP;            // Remember HP
                console.log('calculated:', calcHP, '\nlow:', $.lowHP);
                if (calcHP <= $.lowHP && calcHP > 0) {  // at or below low HP, and not dead
                    $.lowHP_beep();
                } else {   // end beep in all other cases
                    $.lowHP_beep_kill();
            };
                var id = 1;
                var name = $.Prefix + String(calcHP);
                var origin = 0, x = Graphics.boxWidth - $.xOffset, y = 3;
                var scaleX = 100, scaleY = 100, opacity = 255, blend = 0;
                $gameScreen.showPicture(id, name, origin, x, y, scaleX, scaleY, opacity, blend);
            };
      
        // Refresh HUD when Scene_Map loads
        var _Scene_Map_start = Scene_Map.prototype.start;
        Scene_Map.prototype.start = function() {
            _Scene_Map_start.call(this);
            // console.log('Scene_Map has started!');
            $.refreshHUD();
        };
      
        // Refresh HUD when actor gains/loses HP
        var _Game_Actor_setHp = Game_Actor.prototype.setHp;
        Game_Actor.prototype.setHp = function(value) {
            _Game_Actor_setHp.call(this, value);
            // console.log('Actor HP changed!');
            $.refreshHUD();
        };
      
    })(dismal_sci.zHUD);
    
    zHUD.js (ZIP w/ example images and audio, 76 kb)

    Would you mind if I posted it in the JS PLUGINS RELEASES forum?
     
    Last edited: Apr 15, 2019
    #14
    caethyril likes this.
  15. caethyril

    caethyril ^_^ Veteran

    Messages:
    1,162
    Likes Received:
    718
    Location:
    UK
    First Language:
    English
    Primarily Uses:
    RMMV
    Happy to help! And sure, post it wherever you like, you did most of the work. =P
     
    #15
    p0_boy likes this.

Share This Page