Vis_Mage

Wisp Charmer
Regular
Joined
Jul 28, 2013
Messages
779
Reaction score
281
First Language
English
Primarily Uses
RMMV
Hello! :kaohi:

Would someone be able to help me with figuring out how to use arrays with variables? I'm hoping that learning how to use them will cut down on a lot of cumbersome chains of conditional branches needed in complex eventing.

There are three different systems that I am looking to set up using arrays, which I'm hoping should give me a pretty good understanding on how to use arrays between them.

1. I'm looking to check if an array contains a string (such as "Swamp"). If it does, than the conditional branch is TRUE and nothing happens, but if it doesn't, then it is FALSE and that string is added onto the array, and I add 1 to a different variable. Also, I do want this array to be saved even after the save file is reloaded, so from what I understand this array would have to be stored in an actual variable itself, right? (The context is that I'm keeping track of the names of "random" dungeons the player beats.)

2. Set up an array to contain numbers 1-40. Then, pick a random number between 1-40. If the array has that number in it, than the conditional branch is TRUE and removes that number from the array, otherwise it is FALSE, and loops back to choose another random number. (The context is a card game, in which you have a 40 card deck. I want to make sure once you draw a certain card, you don't draw that same card again.)

3. This last one if a slightly different version of the one above. Still sets up an array with 1-40, but instead it will directly pick a random number from the array itself, skipping the step of choosing a random number from 1-40 to check if it's still in the array.

Thank you!
 

Drakkonis

Regular
Regular
Joined
Mar 5, 2021
Messages
267
Reaction score
242
First Language
English
Primarily Uses
RMMZ
I assume you're talking about scripting instead of eventing? If you want to have data included in a save file you'd need scripting if you DON'T store the data into variables.

I haven't dealt with saving custom data myself, but I've seen how some other plugins do it. Basically, they have their data stored as an object, and add that object to the contents object that gets saved. Then when the save is loaded, they have the plugin search the save for their data object and reload it into memory.

I don't have time right now to answer the rest, I'll come back tonight and finish my answer if nobody else does by then. (Time to go to work.... bleh....)
 

Trihan

Speedy Scripter
Regular
Joined
Apr 12, 2012
Messages
6,860
Reaction score
7,913
First Language
English
Primarily Uses
RMMZ
Okay, so the first thing to understand about MV's game variables is that even though the editor only supports storing single integer values in them, under the hood they're objects like any other and can take any value you store in them, from values to strings to entire functions.

Armed with this knowledge, $gameVariables.setValue becomes your new best friend.

I like to think of a variable like a box big enough to hold one item. You can put one of your items into it, and then when you talk about the box you're really talking about the item inside it, but if you want to talk about a different item you need to take the current one out of the box and put the new one in.

An array is like you've partitioned the box with dividers, so each compartment can hold a different item. You can still talk about the items using the same box, but you also have to specify which compartment so that the person you're talking to knows which item is being referenced.

To wit: $gameVariables.setValue(1, 5) will store the integer number 5 inside game variable 1. Simple enough. To reference its value, you use $gameVariables.value(1).
$gameVariables.setValue(1, [1, 2, 3, 4, 5]) will store an array containing the numbers 1-5 inside game variable 1. So now, you can still use $gameVariables.value(1) but you need to tell it which "compartment" to access, starting the indexing at 0. So if I wanted to access the value 3, I'd do $gameVariables.value(1)[2].

So with that in mind, let's look at what you're trying to do:

1. The first thing you need to do here is store an empty array inside the variable you're working with, otherwise what follows won't work. So $gameVariables.setValue(1, []).

Then, whenever you want to check this, you'd create a conditional branch with a script condition reading: !$gameVariables.value(1).contains("your string here"). Inside the success branch, put $gameVariables.setValue(1, $gameVariables.value(1).push("your string"))

Doing it like this with a negative condition is better because it means you don't even need an "else".

2. As long as you don't mind dealing with 0-indexes, you can do the setup for this fairly simply with

$gameVariables.setValue(id, [...Array(40).keys()])

This will give you an array containing the values 0 to 39.

To pick a random one, first with just a random number from 1-40 and then using the array itself:

var random = Math.randomInt(40) + 1
var random = $gameVariables.value(id)[Math.randomInt($gameVariables.value(id).length)]

To remove an entry, you can use the splice() function.

You'd have to use script for your conditional here too, but hopefully that should be enough to get you started and you can ask if you have further questions about it.

3. This is covered by 2.
 

 Masked 

Assistant
Regular
Joined
Oct 28, 2015
Messages
114
Reaction score
310
First Language
Portuguese
Primarily Uses
RMMZ
1. I'm looking to check if an array contains a string (such as "Swamp"). If it does, than the conditional branch is TRUE and nothing happens, but if it doesn't, then it is FALSE and that string is added onto the array, and I add 1 to a different variable.

This is pretty straightforward to do in a single script call:
JavaScript:
const array = $gameVariables.value(ARRAY_ID);

if (!array.contains("Swamp")) {
    $gameVariables.setValue(OTHER_ID, $gameVariables.value(OTHER_ID) + 1);
}

(you may replace ARRAY_ID and OTHER_ID as you need)

Also, I do want this array to be saved even after the save file is reloaded, so from what I understand this array would have to be stored in an actual variable itself, right? (The context is that I'm keeping track of the names of "random" dungeons the player beats.)

AFAIK, you might as well just go full savage and shove it into another global variable that you know is stored on saves, like $gameTemp:

JavaScript:
$gameTemp.MY_ARRAY = []

And then:

JavaScript:
if (!$gameTemp.MY_ARRAY.contains("Swamp")) {
    $gameVariables.setValue(OTHER_ID, $gameVariables.getValue(OTHER_ID) + 1);
}

This way at least you're not wasting an event variable.

And by the way, if all you need is to check whether a given string is in the array, you probably want a Set:

JavaScript:
$gameTemp.MY_SET = new Set()

JavaScript:
if (!$gameTemp.MY_SET.has("Swamp")) {
    $gameVariables.setValue(OTHER_ID, $gameVariables.getValue(OTHER_ID) + 1);
}

2. Set up an array to contain numbers 1-40. Then, pick a random number between 1-40. If the array has that number in it, than the conditional branch is TRUE and removes that number from the array, otherwise it is FALSE, and loops back to choose another random number. (The context is a card game, in which you have a 40 card deck. I want to make sure once you draw a certain card, you don't draw that same card again.)

You essentially described an algorithm for shuffling. My recommendation is that you use a different algorithm, called Fisher Yates shuffle, to shuffle the deck beforehand. Then, instead of removing numbers from the array, you simply keep an index to the first card still on the deck (this index will be sequential, so you only have to increment it; the actual shuffling is done beforehand, so you know the picks are random). This guarantees an uniformly random distribution of card permutations, which the algorithm you described does not (at least I think it doesn't, I didn't properly analyse it to say for sure, just following my intuition here xd).

Generating an array with elements 1-40 is pretty simple too:

JavaScript:
Array.from({ length: 40 }, (_, i) => i + 1)

All you have to do then is combine this with the shuffling algorithm and you're good to go.

3. This last one if a slightly different version of the one above. Still sets up an array with 1-40, but instead it will directly pick a random number from the array itself, skipping the step of choosing a random number from 1-40 to check if it's still in the array.

If you follow what I said on 2, this won't be necessary.
 

Wavelength

MSD Strong
Global Mod
Joined
Jul 22, 2014
Messages
6,114
Reaction score
5,911
First Language
English
Primarily Uses
RMVXA
Arrays are a little different in JavaScript (which I believe is considered a weakly-typed language) than they are in more strongly-typed languages, and act more like an object that simply has index-value associations rather than being a true list. For purposes like you're describing, that doesn't matter too much, although you may have to do slightly more inconvenient checks for matches than you might have to do in another language (or you could start with prebuilt utility methods that do things like find an index of a value in an array).

1. I'm looking to check if an array contains a string (such as "Swamp"). If it does, than the conditional branch is TRUE and nothing happens, but if it doesn't, then it is FALSE and that string is added onto the array, and I add 1 to a different variable.
Code:
var found_swamp = false; // Define this BEFORE the loop begins so it's not reset
for (var sw = 0; sw < array_being_checked.length; sw++) {
    if (array_being_checked[sw] === "swamp") {
        found_swamp = true;
        break; // This breaks the for loop, as there's no need to keep looking anymore
    }
}
if (found_swamp === false) { // Only do this if it's STILL false after the loop
    array_being_checked.push("swamp"); // Adds new value at end of array
    $gameVariables.setValue(18, $gameVariables.value(18) + 1); // Adds 1 to Var #18
}

To just make the check "is swamp in there?" inside an RPG Maker conditional branch, I think you would use (but not sure):
Code:
var found_swamp = false; for (var sw = 0; sw < array_being_checked.length; sw++) { if (array_being_checked[sw] === "swamp") { found_swamp = true } }; found_swamp

Also, I do want this array to be saved even after the save file is reloaded, so from what I understand this array would have to be stored in an actual variable itself, right? (The context is that I'm keeping track of the names of "random" dungeons the player beats.)
Best way to do this IMO is to make sure your data is part of an existing game object that is already being saved to save files. For example, you want to save that array - create the array as a property of $gameParty (a great object to use for most new properties that need to be saved, since you can be very confident that, even with most other scripts, there will be one and exactly one instance of it that's present throughout the entire game):
$gameParty.swampy_array = [];
or, inside any method of $gameParty (particularly its initialize or initMembers method):
this.swampy_array = [];

((EDIT: @Masked above gives a pretty good explanation of this but I think that $gameTemp is one of the few global objects that is NOT saved and loaded, as $gameTemp is designed to hold data that won't need to be carried across sessions! I could be wrong, though - haven't checked that part of the code for a couple months.))

2. Set up an array to contain numbers 1-40.
JavaScript:
$gameParty.cards_array = [];

for (var ca = 1; ca <= 40; ca++) {

    $gameParty.cards_array.push(ca);

}

Then, pick a random number between 1-40. If the array has that number in it, than the conditional branch is TRUE and removes that number from the array, otherwise it is FALSE, and loops back to choose another random number. (The context is a card game, in which you have a 40 card deck. I want to make sure once you draw a certain card, you don't draw that same card again.)
While you could do a similar loop to found_swamp above, continually picking a random number from 1 to 40 using Math.ceil(Math.random(40)) until a match is found (use a while loop), for your purpose there's no reason to go through that. Instead, do it like you're imagining for Scenario #3: simply pick one of the indexes of your existing array, which we know will hold a "valid value", and then delete the selected entry from the array:
JavaScript:
var chosen_index = Math.floor(Math.random($gameParty.cards_array.length)); // For example,
                        // if there are 28 cards left, this picks a value from 0 to 27

var my_card = cards_array[chosen_index]; // Could also do $gameVariables.setValue(18, cards_array[chosen_index]);

cards_array.splice(chosen_index, 1); // Deletes the card at the position you picked from cards_array

If there's a reason you want to see the roundabout way of picking a random number that may or may not be in the array, then checking to see if it's in the array, let me know and I can give you the code for that. Just know upfront it will be like 15 lines long instead of 3, and no less technical.

Hope this helps! Definitely call me out if any of this code doesn't work.
 
Last edited:

Trihan

Speedy Scripter
Regular
Joined
Apr 12, 2012
Messages
6,860
Reaction score
7,913
First Language
English
Primarily Uses
RMMZ
It's interesting how different developers give such different answers on the same subject. Cool stuff. :)

And you're right, Wavelength; $gameTemp isn't saved.
 

 Masked 

Assistant
Regular
Joined
Oct 28, 2015
Messages
114
Reaction score
310
First Language
Portuguese
Primarily Uses
RMMZ
((EDIT: @Masked above gives a pretty good explanation of this but I think that $gameTemp is one of the few global objects that is NOT saved and loaded, as $gameTemp is designed to hold data that won't need to be carried across sessions! I could be wrong, though - haven't checked that part of the code for a couple months.))

You're right, my bad xd
There's even a remark on that here: https://github.com/rpgtkoolmv/corescript/blob/master/js/rpg_managers/DataManager.js#L432

That being said, anything else works: $gameSystem might be a good candidate, and even $gameVariables.MY_ARRAY would do.

Arrays are a little different in JavaScript (which I believe is considered a weakly-typed language) than they are in more strongly-typed languages, and act more like an object that simply has index-value associations rather than being a true list

Just for curiosity's sake, this is also not quite right. At least from what I know, in V8 (which is arguably the most used JS engine out there) arrays are actual arrays (read: sequential data in memory) underneath, as long as you don't mess with them (by adding extra properties and other mischievous stuff like that). This is why simple arrays are actually faster to iterate and index than objects in most cases, as this benchmark demonstrates: https://jsben.ch/CAHDP

Either way, looking up a string on an array by scanning through it (which contains does too, btw) is almost always slower than looking it up on a set, so I think a set should be preferred in this case.
 
Last edited:

Vis_Mage

Wisp Charmer
Regular
Joined
Jul 28, 2013
Messages
779
Reaction score
281
First Language
English
Primarily Uses
RMMV
Thank you very much everyone for giving me such detailed responses! :kaothx: It's really interesting seeing how many different ways there are to reach the same goal.

I'm going to try out the different methods you've all given so far, and hopefully make sense of it all. I'll let you know if I run into any problems.
 

Wavelength

MSD Strong
Global Mod
Joined
Jul 22, 2014
Messages
6,114
Reaction score
5,911
First Language
English
Primarily Uses
RMVXA
Just for curiosity's sake, this is also not quite right. At least from what I know, in V8 (which is arguably the most used JS engine out there) arrays are actual arrays (read: sequential data in memory) underneath, as long as you don't mess with them (by adding extra properties and other mischievous stuff like that). This is why simple arrays are actually faster to iterate and index than objects in most cases, as this benchmark demonstrates: https://jsben.ch/CAHDP

Either way, looking up a string on an array by scanning through it (which contains does too, btw) is almost always slower than looking it up on a set, so I think a set should be preferred in this case.
Good point! Most of my JS background is self-taught (or at least Google-search-taught :kaoblush:) so there are definitely some holes in my conceptual understanding of things.

I also forgot about the includes() method of arrays, which would handle the Swamp example a lot easier, as you pointed out. Usually, I need to know which index a given entry is at, which would require a loop like I wrote out (or a prebuilt method which does the same), but for the purposes of simply determining whether swamp is present anywhere in the array, array_being_checked.includes("swamp") would work just fine and return true or false as needed.
 

Latest Threads

Latest Profile Posts

Arrr me mateys, have ye seen the new Advent pirates? Wouldn't want to cross paths with those scallywags.
Is there a clinical term for the disorder wherein you always have way too many Internet browser tabs open?
Kokoro Reflections is my favorite tileset maker. I absolutely love their work. I have bought quite a bit from them. Best RPG Maker tileset creator ever imo.
Me working on a deadline, "don't make the baseline and chords too funky, don't over compose it... remember, you have to finish it." Touches MIDI controller...instant funk.
TGA are coming up, and I'm still mad Lies of P didn't get nominated.
Like, they chose a remake of a 20 year old game and a vanilla 2D Mario game over it?

Bah, humbug!
I'll be there for the trailers and whatever weird mistakes are made.

Forum statistics

Threads
136,785
Messages
1,269,962
Members
180,539
Latest member
z_juice
Top