How to create respawning resource nodes using a single variable and a common event.

● ARCHIVED · READ-ONLY
Started by Trihan 48 posts Page 1 of 3 View original ↗
  1. Tutorial Title: How to create respawning resource nodes

    Brief Description: This tutorial will teach you how to implement a system of harvestable resource nodes which replenish themselves on a timer without the need for many game variables or huge nests of conditional branches.

    Requirements: None, though a basic familiarity with Javascript would be a bonus for understanding the script we'll be writing.

    Tutorial Body:
    We're going to look at how to create mining nodes for stone, but these concepts can be modified to apply to basically anything harvestable; plants, ore, fish, you name it. Due to how the data will be stored, it may not be entirely suitable for a full-on farming system where you'll have a lot of crops growing at once, but for all I know it'll work for that too. Feel free to experiment.

    IMPORTANT: Any time I refer to "variable" in the tutorial, if it's prefaced with "[JS]" I mean a JavaScript variable (the kind you create in a script command) and it it's prefaced with "[RM]" I mean the built-in RPG Maker game variables (the ones you manipulate with the Control Variables command, which can also be manipulated in code using $gameVariables.value(x) to get a variable's value, and $gameVariables.setValue(x, value) to set it)

    So first things first, let's create a rock event. The main contents of the event, such as animations, text, item gain etc. can be anything you want; the only important part is the script at the end, and turning on self switch A to activate page 2, which has the graphic of the empty node. My event looks like this:
    1642821540132.png
    1642821560687.png
    Let's break down that script and look at what it's doing:

    JavaScript:
    if ($gameVariables.value(1) === 0) $gameVariables.setValue(1, []);
    $gameVariables.value(1).push([this._mapId, this._eventId, 500]);

    If [RM]variable 1 is equal to 0, set it to an empty array.
    Then push to that array another array consisting of the current map ID, the current event ID, and the value 500.

    The first line is to ensure that the [RM]variable we're using becomes an array before we try to store multiple values in it, otherwise we'll get an error. The second line is storing an array of data identifying this particular node event and the number of frames it'll take to respawn. So in this case, 500 frames, or just over 8 seconds.

    this._mapId and this._eventId will already return whatever the current map is, and the ID of the event the code is running inside, so you don't need to change this, it'll work as-is with any event you paste it into.

    It should hopefully go without saying, but the [RM]variable ID used must be one you're not using elsewhere in the game.

    And now, let's look at our common event (these are created in the "Common Events" tab of the database):

    1642821780943.png
    This will be a parallel process event. Parallel process events never just run by themselves with no input; they always require a specified switch to be turned on before they'll start, so you'll need to make sure its activation switch is turned on at some point. Usually for things like this I have an autorun event at the start of the game which does setup like this and then either erases itself or turns on a self switch to move to a non-autorun page, but the exact method of turning on the switch is up to you.

    Note from this point that any time I refer to the "1" in $gameVariables.value or $gameVariables.setValue, you must ensure that you use the same [RM]variable ID as you used for the event step above. Everything else can be copied as-is.

    The conditional branch script condition, $gameVariables.value(1) !== 0, is just making sure the [RM]variable's value is not 0. This is to ensure that we don't waste time running the inner code if the player has never interacted with a node. As soon as they do, the line from the event which turns the [RM]variable into an array and then pushes an array into it will cause this condition to be true, and start running the rest of the code:

    JavaScript:
    for (const oreData of $gameVariables.value(1)) {
      oreData[2]--;
      if (oreData[2] === 0) {
        $gameSelfSwitches.setValue([oreData[0], oreData[1], 'A'], false);
        $gameVariables.value(1).remove(oreData);
      }
    }

    So what's happening here is that we're running a loop that goes through each element of [RM]variable 1's value, which as mentioned before is an array of arrays (an array just being a [JS]variable that can hold more than one value inside it). Each time we loop, we'll store the current element in a [JS]variable called oreData. It doesn't have to be oreData, you can call it anything you like as long as it starts with a letter, underscore or dollar sign. The important thing is that every occurrence here of "oreData" must be exactly the same name or the script won't work.

    First, we reduce the value of oreData's third element (index 2) by 1. Then, if that value is equal to 0, we turn off a self switch, using oreData's first element as the map ID, its second element as the event ID, and 'A' as the self switch letter. Finally, we remove the oreData element from the [RM]variable.

    Let's work through this with an example which will hopefully make the mechanism clearer. Let's say I've mined a stone node that's on map 2, event 9.

    The code in that event is going to change [RM]variable 1's value from 0 to [], and then push [2, 9, 500] to it. So variable 1 now contains [[2, 9, 500]].

    The common event now sees that [RM]variable 1 is not equal to 0, so it starts the loop. In the first iteration, oreData is [2, 9, 500]. oreData[2] is 500, and it's reduced by 1 to become 499. Its value is not 0, so that's all the loop does for now.

    Once the loop has run 500 times, the value of that oreData[2] will be 0. At that point, we'll set the value of the self switch with key [2, 9, 'A'] to false, which turns off self switch A for event 9 on map 2. And then oreData will be removed from the array, meaning it will now have a value of [].

    Now that self switch A is off for that event, it will turn back to page 1, allowing the player to harvest from it again and starting the process over.

    And that's all there is to it! You can copy that event around as many locations and maps as you wish. There shouldn't be much if any lag from the common event, as it only ever needs to run through the nodes the player has harvested from which haven't respawned yet, and as soon as they do respawn the event stops looking at them.



    Please feel free to post any thoughts, feedback or suggestions you have below, and I wish you all happy harvesting!
  2. while it work on MV as well, I got 1 question,

    if you set variable 1 (in this tutorial), and 500 frames, does it work
    on a similair selfVariable? for each mine you set (basic), I know you
    need to use variable2 for an higher frame), or is a self variable plugin
    required?
  3. This is really neat. More importantly I learned something new in the form of For(of) statements. It's also nice that each resource point can be individually set to their own respawn times and still use the same common event.
  4. ShadowDragon said:
    while it work on MV as well, I got 1 question,

    if you set variable 1 (in this tutorial), and 500 frames, does it work
    on a similair selfVariable? for each mine you set (basic), I know you
    need to use variable2 for an higher frame), or is a self variable plugin
    required?
    They are effectively self variables using this method because all node information is held in a single game variable. You could probably tweak it to work with a self variables plugin.
  5. I see, the reason I ask is because YEP_SelfSwVar plugin can have
    each event their own variable.

    just to make sure if you set this event on 4 events on common event,
    that not all spawn all at the same time as a "reset".

    I try to learn alot and the ins and out like this which is also a new
    approch I didn't know off, but if it's count as a self variable,
    it's a really clever idea :) (I save it, can come in handy).
  6. It shouldn't be affected by a self variables plugin since it's not actually giving events their own variables, it's just using one variable to store a collection of data relating to the node events.
  7. Thank you so much for taking the time to create this tutorial and actually explaining what the scripts are doing! This was very helpful and I learned some more about how scripts work and more about arrays. You did an awesome job explaining the scripting.

    I am completely new so I take the small victories and am happy!

    I was able to successfully recreate this after a few mistakes because I didn't notice a couple of things, the events defaulted to below character instead of same as character.

    One small piece of feedback from a person who now trains adults full time. Most of whom don't have any experience with the subject matter. If you want to be extra helpful for complete beginners, like me, it might be helpful to break it down just a tad further.

    For instance, it wasn't exactly clear, at least to me, what I should name the variable. I ended up thinking that you used oreData, but I wasn't sure. I saw it in the Common Event script but I didn't know if that was something else and it was different from the variable 1.

    Also, based on the limited scripts I have seen and used, I initially thought that I would have to change data in the script for map ID and event ID until I thought that maybe "this._" in the script would take care of that. Which it apparently does. Which is very cool to know.

    Probably a complete newbie confusion, but that little bit of extra clarity can be helpful for the absolute beginner.

    I forget this all the time when I am teaching my new students because I think something is so basic that everyone already knows it. Then, low and behold, someone asks me a question and I'm like, oh yeah, I didn't really mention that did I? Sorry about that. And I will try to remember for the next class of new students.

    Anyway, this was a fantastic tutorial, it taught me multiple new things, it didn't take me that long to recreate in game, and it worked great!


    Again, fantastic job and thanks for helping out a newbie!
  8. kvngreeley said:
    Thank you so much for taking the time to create this tutorial and actually explaining what the scripts are doing! This was very helpful and I learned some more about how scripts work and more about arrays. You did an awesome job explaining the scripting.

    I am completely new so I take the small victories and am happy!

    I was able to successfully recreate this after a few mistakes because I didn't notice a couple of things, the events defaulted to below character instead of same as character.

    One small piece of feedback from a person who now trains adults full time. Most of whom don't have any experience with the subject matter. If you want to be extra helpful for complete beginners, like me, it might be helpful to break it down just a tad further.

    For instance, it wasn't exactly clear, at least to me, what I should name the variable. I ended up thinking that you used oreData, but I wasn't sure. I saw it in the Common Event script but I didn't know if that was something else and it was different from the variable 1.

    Also, based on the limited scripts I have seen and used, I initially thought that I would have to change data in the script for map ID and event ID until I thought that maybe "this._" in the script would take care of that. Which it apparently does. Which is very cool to know.

    Probably a complete newbie confusion, but that little bit of extra clarity can be helpful for the absolute beginner.

    I forget this all the time when I am teaching my new students because I think something is so basic that everyone already knows it. Then, low and behold, someone asks me a question and I'm like, oh yeah, I didn't really mention that did I? Sorry about that. And I will try to remember for the next class of new students.

    Anyway, this was a fantastic tutorial, it taught me multiple new things, it didn't take me that long to recreate in game, and it worked great!


    Again, fantastic job and thanks for helping out a newbie!
    Those are good suggestions, I'll definitely edit the topic to include further breakdowns.

    Edit: That's those changes in, does that address your points?
  9. Trihan said:
    Those are good suggestions, I'll definitely edit the topic to include further breakdowns.

    Edit: That's those changes in, does that address your points?
    I think those edits are very helpful! And I am updating this entire tutorial again into my research notes so I have everything in one place for ease of reference.

    Again, thank you so much for creating this and for being willing to provide clarity!
  10. Are there any other things you'd like to see a tutorial for?
  11. Trihan said:
    Are there any other things you'd like to see a tutorial for?
    Unfortunately, I wouldn't know where to start! I am still neck deep in watching and reading tutorials and recreating them. I still don't have a good idea of what exactly is already out there compared to what I want to learn how to do.

    But if you are still game later, I might post for help when I can't find something or can't figure something out. There is so much to learn and I am having a blast, quite frankly!
  12. kvngreeley said:
    Unfortunately, I wouldn't know where to start! I am still neck deep in watching and reading tutorials and recreating them. I still don't have a good idea of what exactly is already out there compared to what I want to learn how to do.

    But if you are still game later, I might post for help when I can't find something or can't figure something out. There is so much to learn and I am having a blast, quite frankly!
    Yeah, I'm basically asking for something from your list of things you want to learn how to do, and I'll think about writing a tutorial for it. :)
  13. Well, the only thing that comes to mind right now is whether there is a way to display information about characters on the map screen without a plugin.

    For instance, if a party member takes damage outside of battle processing from say a state or a trap or a damage floor or something, is it possible to briefly display the amount of damage above the character? Or display a state icon or indicator until it is removed?

    Actually, now that I think about it, would it be possible to display small portraits of the party members on the screen and display information over/around/near the portrait?

    I think that is possible because I made an event where the party could get poisoned from lock picking a trap and I could make a small portrait of the party member appear on the screen and tinted green until they were healed. Then I made it go away.

    I just am not sure how to make the portraits always show or maybe only show for a short time where there is something important to display, such as damage, healing, states/statuses, etc. and how to display that information. Or a portrait area that can be turned on and off.

    In case you can't tell, I am fond of the older games that show the character portraits along with information like name, HP, MP, states/statuses, and held weapons.

    I am sure there are probably plugins that make a party portrait area like that, but I am wondering if you can do it without a plug in.

    I haven't found anything on doing any of those things yet.
  14. Hmm, that would be a pretty fun thing to event. I'll certainly consider that as my next tutorial subject. :)
  15. Hey man, thanks for the tutorial.
    I did a video explainer on my YT channel of it and credited you for it, however my MV viewers are having an issue saying that .remove is not a function.
    Would you have any idea why this would be?
  16. Greetings!
    A question: Is this kind of script also possible with a little tewak so it doesn't automatically respawn a ore node?
    I don't have JS skills myself, but do understand some of it. But I simply don't know all the commands possible.

    My current mining system is using a "Call common even: Node Respawn" and that calls for a randomizer to give the node a chance to repawn. Instead of always recurring.

    Also, I'm at work at the moment, so can't really give insight how I've set it up at the moment. But out of my head it's somehting like this:

    The Node is being mined. Turns on self switch A and disappears.
    I've a Day/Night system running and every night it also runs some commons events. 1 of them is Node Respawn. It calls for a randomizer and if value is >76 (25% chance) Node x respawns.

    But this common event is currently filled with each Node seperately. So more nodes, means more typing :)

    I was hoping with this script I could simplify the common event.
  17. Draegon said:
    A question: Is this kind of script also possible with a little tewak so it doesn't automatically respawn a ore node?

    My current mining system is using a "Call common even: Node Respawn" and that calls for a randomizer to give the node a change to repawn. Instead of always recurring.
    In Trihan's common event, change:
    Code:
      if (oreData[2] === 0) {

    to read:
    Code:
      if (oreData[2] <= 0 && Math.random()<.25) {
  18. ATT_Turan said:
    In Trihan's common event, change:
    Code:
      if (oreData[2] === 0) {

    to read:
    Code:
      if (oreData[2] <= 0 && Math.random()<.25) {
    Thanks, will give this a try!

    And just so I understand what you're saying:

    This code replaces the auto respawn and will install that randomizer.
    So if I don't run the Node Respawn common event as a Parallel event, but still as a command to run the common event, it will check if oredata <= 0 (It'll become negative probably) and then runs the randomizer. ?
  19. Draegon said:
    This code replaces the auto respawn and will install that randomizer.
    So if I don't run the Node Respawn common event as a Parallel event, but still as a command to run the common event, it will check if oredata <= 0 (It'll become negative probably) and then runs the randomizer. ?
    Sorry, now it's my turn to not really understand what you're saying :guffaw:

    I'm not sure what "runs the randomizer" means. This does exactly what you asked - once the respawn timer on the ore node runs out, instead of respawning immediately, it will have a 25% chance to respawn every...frame, currently.

    You should modify the event so that it's not just sitting there running every frame (that's kinda pointless, because you'll be almost guaranteed to have it respawn within a second anyway).

    I would change the script on page 1 of the map event so that instead of the number 500 (representing 500 frames for 8 seconds), you push the number of actual minutes you want to be the minimum amount of time for the ore to respawn.

    So if you want it to appear at least 8 seconds from now, put in the number 8 instead of 500.

    Then, in the common event, add at the bottom event commands
    Wait: 60
    That will make the event only run once every second. So it will count down from 8 seconds, and starting then it will have a 25% chance every second of respawning. Adjust the numbers however you like.
  20. OK, I think I understand now. Was in a bit of a hurry earlier when I replied. :)

    I'm now behind my PC at home and can look at the common events I already created (Before changing to this possible solution.

    1) The Ore Node calls Common Event: Mining.
    2) Common Event: Mining adjusts a couple of Variables (Time, Hunger, Thirst, etc) and then calls for Common Event: Mining Reward.
    3) Common Event: Mining Reward gives a reward depending on skill level and a random change. Turns on Self Switch A of the Ore Node Event.
    4) Ore Node disappears.

    5) TIME HUD Common Event: After calculating hours and setting next day, my Node Re-spawn Common Event is called.

    6) Common Event Node Re-spawn: Checks if Self Switch A is on from Ore Node Event X and start a Randomizer. If >= 76 the Ore Node re-spawns.

    This is all working, but when creating more nodes in other places, more and more must be filled into the Node Re-spawn common event.
    So I was hoping to combine this solution in this topic with my current setup.

    Maybe not using the array? But still pushing the MapID and EventID to the events in a variable?
    So that my Node Re-spawn common event is this checked manually.

    I do not want ore nodes (or maybe other resources) to re-appear the same day in game.

    Hopefully this clarifies my intent a bit :D
    1658781615161.png

    ATT_Turan said:
    Sorry, now it's my turn to not really understand what you're saying :guffaw:

    I'm not sure what "runs the randomizer" means. This does exactly what you asked - once the respawn timer on the ore node runs out, instead of respawning immediately, it will have a 25% chance to respawn every...frame, currently.

    You should modify the event so that it's not just sitting there running every frame (that's kinda pointless, because you'll be almost guaranteed to have it respawn within a second anyway).

    I would change the script on page 1 of the map event so that instead of the number 500 (representing 500 frames for 8 seconds), you push the number of actual minutes you want to be the minimum amount of time for the ore to respawn.

    So if you want it to appear at least 8 seconds from now, put in the number 8 instead of 500.

    Then, in the common event, add at the bottom event commands
    Wait: 60
    That will make the event only run once every second. So it will count down from 8 seconds, and starting then it will have a 25% chance every second of respawning. Adjust the numbers however you like.
    ink