WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
I am attempting to create a plugin that will suit my needs very well, but I am running into trouble as I have never dealt with creating a plugin that can read a notetag, or in this particular case, part of the data that does not have a notetag (Animations).

What I am attempting to do is have a notetag that the user will put at the end of the Animation's name, and have it read back two to four values in it, separated by comma.

JavaScript:
<test:w,x,y,z>

Those values would be integers.

The error I keep getting so far, trying to get it to read just one value in that tag, is this:

Code:
Invalid regular expression: Nothing to repeat

This is the code so far, I am just trying to get it to print back to the console any Animations which have the tag in their name, to start. I used 7 in the slice part because "name" is the 7th value in the array in the Animations.json data file. I have also used 6 in the event that the first value (id) is actually 0 and not 1. Same result.

Any insight into where I am going wrong here would be awesome, so I can continue to try to figure the rest of this out on my own.

JavaScript:
'use strict';
/<test:*\d*>/;

$dataAnimations.slice(7).forEach(function(name) {
    'use strict';
    let note = /<test:*\d*>/.exec(name);
    if(note !== null) {
    console.log(note);
    }
});
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,824
Reaction score
2,162
First Language
EN
Primarily Uses
RMMZ
A few pointers:
  1. The database is not loaded at the point when plugins first load. I recommend hooking into a method that runs after the database is loaded, e.g. Scene_Boot#start:
    JavaScript:
    (function() {
    'use strict';
      let alias = Scene_Boot.prototype.start;    // <- store original method
      Scene_Boot.prototype.start = function() {  // <- redefine method
        // put/call your code here
        alias.apply(this, arguments);            // <- invoke original method
      };
    })();

  2. $dataAnimations is an array of objects, but you're treating them as strings. To iterate through and parse tags from each animation's name, try something like this:
    JavaScript:
    $dataAnimations.forEach(function(obj) {
      let note = /regular expression/.exec(obj.name);
      // etc
    });

  3. * in regular expressions means "repeat previous item 0+ times"; it is not a space/wildcard. More details here:
    You could adapt the core script expression used to parse tags from note fields (cf DataManager.extractMetadata, rpg_managers.js), e.g.
    JavaScript:
    /<test:([^>]*)>/
    If necessary, String#split and/or parseInt can be used for type conversion after matching.

    Alternatively...there's probably a shorter way to write it, but I think this regular expression should match exactly 2~4 comma-separated numbers:
    JavaScript:
    /<test:\s*(\d+),\s*(\d+),?\s*(\d+)?,?\s*(\d+)?>/
    I.e.
    • <test: - just some text
    • \s* - 0+ spaces
    • (\d+) - 1 capture group of 1+ numerical digits
    • , - a comma
    • (\d+)? and ,? - optional capture group/comma
    • > - some more text
 

WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
OK, so I've got this for now, and this returns no errors, but also is not printing anything to the console in regards to which animations, by name, have this tag (I've only put the tag at the end of one animation name for now, for testing). I only put two values for numbers there for testing, I can up it to 3 or 4 after, I still have that notetag you posted in there commented out.


JavaScript:
 (function() {
     'use strict';
     let alias = Scene_Boot.prototype.start;
     Scene_Boot.prototype.start = function() {
     $dataAnimations.forEach(function(obj) {
         'use strict';
         let note = /<test:(\d+),(\d+)>/.exec(obj.name);
         if(note !== null) {
             console.log(note);
        }
        alias.apply(this, arguments);
     });
     };
});

My question is, is it not printing to the console because it is returning it as null or something else? I think I can test that by adding an else case there and printing something completely random there.... which I did and it still didn't log anything to the console to show it was able to read the note.
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,824
Reaction score
2,162
First Language
EN
Primarily Uses
RMMZ
I see! Try this instead:
JavaScript:
(function() {
'use strict';
    const alias = Scene_Boot.prototype.start;
    Scene_Boot.prototype.start = function() {
        $dataAnimations.forEach(function(obj, id) {
            if (obj) {
                const note = /<test:(\d+),(\d+)>/.exec(obj.name);
                if (note !== null) {
                    console.log('animation ' + id + ':', note);
                }
            }
        });
        alias.apply(this, arguments);
    };
})();
I made a few changes:
  • Added () to the end of the function expression, so that it evaluates. More details here:
  • Moved the alias call outside the loop, because it should only be called once!
  • Added a check to see if the animation is defined before trying to get its name, because ID 0 of each database list is null.
  • Added animation ID to the console message, through the second argument of forEach:
  • Swapped let for const because those values aren't getting changed.
  • Removed the extra 'use strict' statement: the top-level one applies to all sub-scopes.
Did a quick test and this seemed to work for me~ :kaohi:
 

WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
Alright, updated the code with this, and I'm now seeing it in the console log. So, just trying to understand what I'm actually seeing here (still new at notetags).

Code:
animation 196:
Array(3)
0: "<test:1,2>"
1: "1"
2: "2"
groups: undefined
index: 11
input: "TestAnim<test:1,2>"
length: 3

I guess my next step is to understand how to use the information being sent to the console in an actual function based on the notetags. I assume that the "1" and "2" are the things I need to store in some variables or something, then use them in a function?

Is that done via $RegExp1 and $RegExp2, or something similar. I've seen something like that in a few YEP plugins to take information from a notetag with multiple entries in one notetag.
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,824
Reaction score
2,162
First Language
EN
Primarily Uses
RMMZ
As you can see, RegExp#exec returns an array of results. For your test case:
  • 0 - Full match - "<test:1,2>"
  • 1 - Capture group 1 - "1"
  • 2 - Capture group 2 - "2"
More details here:
The values are right there: you can convert them to another type, store them somewhere, whatever you like. The tag parsing is all done at this point.

Here's an example that you can paste into the console:
JavaScript:
(function() {
'use strict';
  const match = /<test:(\d+),(\d+)>/.exec("blabla<test:4,50>abcdefg");
  if (match) {
    let fullMatch = match[0];
    let capture1 = match[1];
    let capture2 = match[2];
    console.log("matched tag:", fullMatch);
    console.log("value 1:", capture1);
    console.log("value 2:", capture2);
  }
})();
[Edit: swapped the a for a 4, what was that doing there.]

Edit: here's some documentation on the RegExp.$n notation you mentioned:
This notation has been deprecated, so it shouldn't be used.
 
Last edited:

WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
I am still completely lost on how I get these values that are printing to the console to be used in the function I want to use it in. Not your fault, of course. I'm just having trouble understanding how to get from A to B.

We know the tag is working, and the information is being displayed in the console, so it can then be used elsewhere with the right syntax. How to use it, I have no idea.

Any time I try to apply any of this to the function I actually want to use it in, it returns errors citing things being undefined, but they should have been defined at Scene_Boot, since that's where all the notetag code was?

Do I need to forget Scene_Boot and put the notetag code in the actual function I want to use it in?

JavaScript:
Sprite_Animation.prototype.updateCellSprite

That is the function I want to use the tagged information in.
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,824
Reaction score
2,162
First Language
EN
Primarily Uses
RMMZ
It sounds like you may be having trouble with scope:
A common approach here is to define a property on the parent object, e.g. expanding on my previous example:
JavaScript:
(function() {
'use strict';
    const alias = Scene_Boot.prototype.start;
    Scene_Boot.prototype.start = function() {
        $dataAnimations.forEach(function(obj, id) {
            if (obj) {
                const note = /<test:(\d+),(\d+)>/.exec(obj.name);
                if (note !== null) {
                    // define meta property on this object if it doesn't already exist
                    obj.meta || (obj.meta = {});
                    // store captured values in a "test" sub-property on this "meta" property
                    obj.meta.test = [note[1], note[2]];
                }
            }
        });
        alias.apply(this, arguments);
    };
})();
Then you can check an animation's value directly, e.g. if animation ID 196 has <test:1,2> in its name, I think this would return the array ["1", "2"]:
JavaScript:
$dataAnimations[196].meta ? $dataAnimations[196].meta.test : undefined

Alternatively you can just do all the parse-from-string stuff when you need the value(s), but that can have a notable impact on framerate if you need to reference the values frequently.
 

WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
OK, let me explain exactly what I'm trying to accomplish, because I don't think I am understanding how the above examples can be used in a function outside of
Code:
Scene_Boot
and nothing I have tired seems to work.

As I'm understanding it, and this could be totally wrong, but placing the code to determine the tag's values in Scene_Boot is what allows it to do so AFTER plugins are loaded.

So here is what I am trying to do at the end of all of this.

I am trying to get an Animation's name to be checked for the following tag:
Code:
<test:n,n>
where
Code:
n
is an integer, and it will never be anything but an integer. So you got that part down and working, in the test only the one Animation in the game with that tag printed to the console, with those two values split up into "1" and "2", respectively.

Now that we know that information is being called, I want to store and use that information ("1" and "2" value of that Animation) on the following function
Code:
Sprite_Animation.prototype.updateCellSprite
in order to change the width and height of that specific Animation's cells when it is played. I am assuming this is the function that handles that process as that is where the default cell size is defined in
Code:
Sprite_Animation
and nowhere else. Normally, cells are 192 x 192 pixels, and Animations without the tag should stick to that. The ones with the tag should use the first integer as the width of the cell, and the second integer as the height of the cell.

When the Animation plays on the map or in battle, it should use the customized cell dimensions, as defined by the notetag in the Animation's name. Otherwise, it should use the default cell size.

Animation named
Code:
Fire
would not use customized dimensions
Animation named
Code:
Thunder<test:236,360>
would use customized dimensions

I understand that the editor cannot tell that the cell size is bigger or smaller and a lot of trial and error on my part will be needed to make sure the bigger or smaller animations play the way they are supposed to. That won't be an issue for me.

At the same time, I don't want someone to just write this plugin for me, I want to learn how to do this, so I can do it again for other plugins I might want to create. I am just having a hard time understanding how to store the information that is being called in
Code:
Scene_Boot
from the note tag and then use it elsewhere.

So after a while of trying different things, I got it to where it was functioning normally, no errors or issues, but the animations were all invisible. I am lost on what to do to get this working.

Another idea would be to completely disregard the notetag functionality in favor of editing the function to simply auto-determine the Animation image file's dimensions.

JavaScript:
Sprite_Animation.prototype.updateCellSprite = function(sprite, cell) {
    var pattern = cell[0];
    if (pattern >= 0) {
        var sx = pattern % 5 * Animation Image File Width;
        var sy = Math.floor(pattern % 100 / 5) * Animation Image File Height;
        ...
        ...

Since the default size is 192 x 192, then I suppose it wouldn't break any existing animations.

The question here would be how do we get the dimensions of the image file used in the animation, and since each animation can have two images to use for an animation, how do we make sure one doesn't break the other?
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,824
Reaction score
2,162
First Language
EN
Primarily Uses
RMMZ
If you store the data on a global object like $dataAnimations, then you can reference it in any method you like, because it is in the global scope (see my previous post for link to scope article).


You can define and reference Array elements like this:
JavaScript:
var testArray = ["A", "B", "C"];
var firstValue = testArray[0];   // "A", because array indices start at 0
var secondValue = testArray[1];   // "B"
// etc
More info on Arrays here:


Inside my example's forEach loop (see this post for example/link), obj is a variable set to each element of $dataAnimations in turn. So this line:
JavaScript:
obj.meta.test = [note[1], note[2]];
...says "store an array of two values in the test property of the meta property of this entry of the $dataAnimations array". The two values are the two captured groups yielded by exec, e.g. for a name tag "<test:1,2>", these values are "1" and "2". I didn't do any type conversion here, but it would be fairly simple to add, e.g.
JavaScript:
obj.meta.test = [parseInt(note[1], 10), parseInt(note[2], 10)];
So now, the $dataAnimations[id].meta.test array should hold two integer values. (For more information on parseInt, check out the link in my original response.)


In the setup method of Sprite_Animation, the associated $dataAnimations record is stored in the sprite's _animation property. I'm guessing this was what you were stuck on?


In a Sprite_Animation method you can get the current sprite instance using the this keyword. this is a reference to the current scope, more info here:
Therefore you can write this._animation in your updateCellSprite override in order to access the sprite's database data, e.g.
JavaScript:
Sprite_Animation.prototype.updateCellSprite = function(sprite, cell) {
    var pattern = cell[0];
    // -----------------------------------
    var x, y;
    // does meta.test property exist on this animation?
    if (this._animation.meta && this._animation.meta.test) {
        // store values in local variables x & y
        x = this._animation.meta.test[0];
        y = this._animation.meta.test[1];
    }
    // -----------------------------------
    // rest of method goes here
}


If you want separate dimensions for each animation sheet, just add more [potential] values to the tag.


Also: the width/height of the animation cel is determined by this line of the updateCellSprite method:
JavaScript:
sprite.setFrame(sx, sy, 192, 192);   // width 192, height 192
The sx and sy values affect the x & y coordinates of the top-left of the frame. I'm guessing you're aware of that since you were originally talking about a notetag with [up to] 4 values, but I figured I should mention it just in case. :kaohi:
 

WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
Alright, so I made a little bit of progress from your last reply, and was able to get the normal, untagged animations to still show, as normal, but the ones with the tags are still not showing, and here's why.

It's returning the height as I defined it as "undefined." No crash, so it's just saying it doesn't exist (mind you, the width is returning as the number in the tag), so I have one more thing I am going to try now.

2 hours later...

So, interestingly, it's actually outputting the width as the number that is supposed to be the height in that console.log call.

So let's say the tag is <iad:400,300>, the console is outputting the WIDTH as 300 and the height as 'undefined' instead. So I changed those numbers to [0], [1] and bam, it works. I don't know WHY that works, but it works.

I also wanted to ask, what is the 10 for in the parseInt line? Is that the maximum length of the parsed integer?
 
Last edited:

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,824
Reaction score
2,162
First Language
EN
Primarily Uses
RMMZ
So let's say the tag is <iad:400,300>, the console is outputting the WIDTH as 300 and the height as 'undefined' instead. So I changed those numbers to [0], [1] and bam, it works. I don't know WHY that works, but it works.
Edit: actually, I'm not sure what happened there, but good to hear you solved it? :kaoswt:

I also wanted to ask, what is the 10 for in the parseInt line? Is that the maximum length of the parsed integer?
The second argument of parseInt is the radix, a.k.a. base, of the number. More details here:
 

WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
Edit: actually, I'm not sure what happened there, but good to hear you solved it? :kaoswt:


The second argument of parseInt is the radix, a.k.a. base, of the number. More details here:
Ah, OK! Thank you for all of your assistance (and patience)!
 

WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
OK so, sorry for the double post, but I am coming across a little issue with adding the 3rd and 4th digit to the notetag.

All of it works fine, and what I want to do with them also works half-fine, lol.

I need the 3rd and 4th digit in the notetag to be able to accept a positive or negative integer. I dunno if that requires something to parse a "+" or a "-" before those integers.

Positive integers work fine as is, but negative ones all return as 0.
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,824
Reaction score
2,162
First Language
EN
Primarily Uses
RMMZ
Currently, you are matching only a string of digits. To include an optional plus or minus sign beforehand, you can add a suitable character class, e.g.
  • /([+-]?\d+)/
Captures:
  • Optional? + or - character
  • Followed by 1+ numerical digits
Be careful about using hyphens in character classes: if they are not the first or last character in the class, then they are treated as a control character. More details on character classes can be found here:
Some control characters can be \escaped to ensure they are treated literally, e.g. \- or \..

A similar approach can be used to match decimals: match an optional \. and follow-up string of digits. :kaophew:
 

WCouillard

Veteran
Veteran
Joined
Nov 24, 2013
Messages
77
Reaction score
21
First Language
English
Primarily Uses
Currently, you are matching only a string of digits. To include an optional plus or minus sign beforehand, you can add a suitable character class, e.g.
  • /([+-]?\d+)/
Captures:
  • Optional? + or - character
  • Followed by 1+ numerical digits
Be careful about using hyphens in character classes: if they are not the first or last character in the class, then they are treated as a control character. More details on character classes can be found here:
Some control characters can be \escaped to ensure they are treated literally, e.g. \- or \..

A similar approach can be used to match decimals: match an optional \. and follow-up string of digits. :kaophew:
Got it working now.

So the notetag is structured like so:

<iad:w,h,+/-x,+/-y>

x/y are acting as offsets added to the normal X and Y position of the Animation when it is played.

I guess the only thing I could do to finish this is make the 3rd and 4th digits optional on the tag. Any way to do that without completely rewriting most of it?

Right now, it's required to use the 3rd and 4th tag, either with a + or a - before them, which isn't the end of the world, as someone could just use +0 or -0 in those spots if they don't need the offset.
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
2,824
Reaction score
2,162
First Language
EN
Primarily Uses
RMMZ
Consider having two regular expressions. Then when parsing tag values, if the 2-value expression doesn't match, try the 4-value one.
 

Latest Threads

Latest Profile Posts

What the writer wrote: "The curtain is blue."
The readers: "There must be a hidden meaning behind this, perhaps to convey the character emotions ...".
What the writer has in mind: "The curtain is frickin' blue".
Time to share something!
hmZFwQe.png

I made these a while ago for my game. I took reference from various huts in Africa.
Have a great night! :D
I really need to buy a new mouse. Mine's keeps double-clicking and makes me waste A LOT of time eventing
How come there's no spooktober game jam? I thought horror maker games were some of the most popular genre out there...
"I didn't know X song was about that!" Uh... why? Do you not listen to the lyrics? I mean, I guess that makes sense. We live in a world where nobody listens, but everyone wants to be heard.

Forum statistics

Threads
115,843
Messages
1,093,354
Members
151,031
Latest member
Florian973
Top