![]() |
Berry system for Fire Red with RTC
From a request that started on the hacked engine thread came a question: "Now that we have a RTC system in Fire Red\Leaf Green, can we port the berry growth system from Ruby?" My answer to that was "Why not build one from scratch?" In this thread I will introduce the solution I came up with, but I feel can be somewhat improved. Also, as of the posting of this message, the berry system seems to work ok on the two-week trial it went through, but I would appreciate any help debugging and replacing problematic areas of code.
First of all, I must say this code is built on top of a normal US Fire Red ROM with only the Day Night System by Interdpth & ZodiacDaGreat, using the Real Time Clock that comes with it. I would like to give credit to them for this great hack, and without which this would not be possible. I also use the code base for the hacked engine on the key-inserting and the OW hacks, and this latest is required for the correct working of this tool. Starting from the top: What is a berry tree? Berry trees are Overworld sprites, similar to any other, except they change with time. That time may pass by in-game or outside of the game, as the RTC will keep the game updated in either cases. Besides this outside look, they also need to store somewhere information about them, such as time since planted or watered, or what kind of berry tree it is. So, we can define a berry tree as an OW that changes with time and user interaction, and gives the player an item after a number of conditions are met. Where do we store that information? Variables are good, since they keep memory after the game is shut down. But can all information needed to be kept stored in a variable? Unfortunately, no. We need at least two variables for each tree. How is a berry tree made? This is the creative part. The official R/S/E berry tree is stored differently from the other OW's, and has its own sets of rules. They keep a memory area reserved for them, that the OW loader accesses direclty, and use a script with specials to obtain which area they are using, the berry growing there and the berry growth stage. In this approach, we will consider an hybrid model between R/S/E and D/P/Pt. Basically, a berry tree has two variables(with bit 0 being the least significant): Code:
Code:
Another think to note is the timespan. The time passed cannot be big enough to make one note a difference (one hour-apart updates would make a berry that was just planted to grow at the same time one that was planted 50 minutes ago) but not small enough to take much space (if in seconds, one day was too long for one variable). For this implementation, the timespan is one minute, that allows for a maximum livespan of 45 days and a half (0xfff0). As it seems impratical for such a long time, and because it's hard to make compares with this value, the day limit was set at 32 (0xb400). The berry information, shown in the first variable, is one byte long, too small to be the berry item number. Also, up until now we talked numbers, but what about the graphics? How does the game displays the correct berry tree? Once again, the official solution would do us no good. it involves some maths with the frame to display on the sole tree OW data, and some more maths to find the correct palette, and all of this using the data from the special memory area that we don't have. The solution for this is the use of a Dynamic OW hack to display the tree we need. But how does it know the correct image and when to display it? The solution is the creation of a Berry table, where the berry information byte is the index. That table is composed as this: Code:
So, as an example, let's assume you have an oran berry tree's sprites stored (in order) in the positions 0-4 of your sprite table 0x5, and the ones for a sitrus berry tree in 5-7 (last three stages only). We assume that one oran tree gives 2-8 berries and sitrus gives 1-4 berries. We want the same times as the original version and we want oran as the first one and sitrus as the second. the table would look like this (| indicates end of berry): Code:
So, after all this long explanation on the ways this new berry system will work, it's time to put it into practice. All this code is useless if it is never used. So first of all, we need a function that, in game, runs at least once every minute, even if the player stays still. For that role, I chose the key reader. The key reader function is a special function that runs since the game begins to the moment you turn the power off. The keyboard may be pressed at any time, and as such, this function needs to read it frequently. More than once a minute. So, we take advantage of it, and place a small hack when it is called so that if a minute has passed since it last ran, a code is executed, and if not, simply carry on, with as little delay as possible. For that, I used a small memory room, not managed, at the position 0x0203f3f0. This code is the same as the one used for the key-pressing changes, so I'll only highlight the important piece of code in it, but will post it completely for testing purposes. Code:
The RTC doesn't run the game code to make sure berries are updated, so we need to create a system that allows the player to leave his game unattended for a large period of time without losing its berries. For that the next routine was created. A first problem encountered is that, to my knowledge, the clock time from the last save is not stored anwywhere. For that, I used two variables (0x4090 and 0x4091) to store the time. Also, as room was lacking, I saved only month, day, hour and minute of the last save. That means that if you played a hack using this system a year after you put it down, everything would be the same as when you left. Another problem was where to put it. It is expensive, so ideally we should run it only once, but what routines run only once just as soon the game loads? First attempt was made with the routine at 0xcc94, responsible for the fadescreen after the game is loaded in the starting screen, both for "continue" and "new game". But another problem ensued. When that routine is called, it loads the game, but uses the variable's space to determine the "last on" scene when it continues. at the end of that, another routine loads the variables again, and that routine is called through the WRAM Stack area, making it almost untraceable. So, as an alternative, I went with the collision detector. The function is located at 0x0806d698, and handles all movement. It doesn't, however, run until you move. So this is a somewhat poor replacement function, but since we believe that every person that plays the game will eventually walk around it, it's not that bad. All this code is relevant to the subject at hand Code:
There is a limit of 256 different berry slots, each identified in the person id by the table number 0xfe. The game, when loading the OW, checks its table number, and in the same way Dynamic OWs were created, he also checks to see what it should print. It goes to the Plant variable, checks for the table index of that entry, calculates the current time on that variable to get its stage, and finally prints the corresponding OW. The code is as follows: (what matters in BOLD) Code:
Another problem present is how to keep the time the game was last updated. The out-game updating routine takes care of updating the time it was executed, but there was no need to save every minute. All we need is for the variable to be up-to-date as we save the game. So, I created this save hack that saves the variable when the save screen is shown: Code:
I finished a routine that gets the planted item, as well as the quantity produced. The formula to the number of items was previously mentioned, but there is a special case that when it's 0, it will give 2 if always watered and 1 otherwise. It uses variables 0x8004 and 0x8005, and returns to 0x8004 and to r0 the item and to 0x8005 returns the number of items. This code is supposed to be used with a callasm or included in an empty special. Code:
planting routine; add mulch routine; watering routine; Check tree state routine; Check watered time routine; Berry script. So, before I leave, I have some questions I need to raise. First, how do you thing the planting should be done? It's two simple setvars, one for the plant and one for the timer, but how will we find the item the player wants to plant, and its position on the table? Second, do you think it would be more appropriate to change the OW hack to instead of reading of a variable, reading a set of variables concerning where it is? For instance, its not var sprite 0x0, table 0xfe = var 0x7d00 plant, but rather sprite 0x0, table 0xfe = a fixed variable that contains the plant variable. Having regional variables can increase the number of berries possible, but is it really necessary to have more than 256 berry plants? And if so, what would be a good number of variables to set apart for a map script to change? Third, do you think the item number should be determined by the given formula, or would you prefer something more like the 0 case (the byte only represents a mode)? |
Wow, great job I had to read it twice to fully understand. :P But on your questions do you think it is possible to make a routine that when they click on the dirt path, you then they can click on a berry you want to plant, and the berry chosen gets placed into a var. Then the other routine checks the var.
Or make a routine kinda similar to the special the makes the player chose 3 pokemon, but insted of choosing 3 pokemon you chose one berry. |
how to install this?
i dont see how |
Quote:
|
Some routines should be complied with gas, or goldroad while others should be complied with devkitpro. He specified what code was in devkitpro. Once it is complied you have the hex code.
|
maybe someone make a ips?
or aps? |
I would much more prefer to see this implemented into jpans program, if not keep it like this. Anybody can apply an ips patch, this way makes it so that only the decent hackers can reap the benefits.
|
Quote:
And before you even think about, please don't pull the "it'll get overused and make it less special" argument. I saw that a lot with the release of Mastermind_X's Day/Night System and I'm getting pretty sick of it. |
Quote:
If something's overused or less special, then work hard and pull of something even better than the existing version of a cool hack. Otherwise don't complain ^^ |
its just that i never understand what JPAN is explaining
and i hack already a long time |
Quote:
Anyone who understands the information he has given is able to implement this in their own hack, and those who don't should learn what it means instead of blindly patching their ROM. |
no
he was reacting to someone elses post he wants that ppl share their discoveries |
There not discovering anything throw a patch or learning anything. They will just be using the system for them self. It wouldn't be knowledge it would just be a new feature for them.
|
Quote:
|
Well then you most of miss understood me. I am all for sharing discoveries, I don't care how long you hack, but I like it when discoveries are not just patches; because then you actually learn something.
|
>__< in other words u two are saying the same thing
colcolstyles wants things to be open to everyone, and narutoactor wants it to be available to those who know how to use it, stop fighting about stupid stuff >__> anyways, really liken this interdepth xD before long u are prob gonna have the entire ROM hacked xD |
I don't think you should make a patch, people should know how something works before they attempt to put it in their hack. It will just create more problems later.
Quote:
|
Quote:
|
Quote:
|
Quote:
|
I'm pretty sure the revival limit doesn't apply here...
OK, so I've followed through on this tutorial, inserted all of the routines and such, I've even written a water checker, waterer, and mulch adders. But, how exactly does the game know which overworld is a tree? Is it the person ID that's set to the variable? Or is it something different? |
Yo, JPAN, don't know if you got all the info you wanted from this thread(esp. with all the offtopic) and have carried on development, but thought I would throw in my two cents.
Planting berries could be done two ways that I can see. The first would be writing a routine from the use option in the item menu(checking if you're standing in front of a dirt patch, if not goto the regular berry use) which seems difficult as to my knowledge items are not completely understood yet. The second would be using a special command to select a berry(either by going to the item menu or your dynamic listboxes). Your second question is worded somewhat ambiguously, so I'll answer both options. 256 is more than enough for types of berry plants. You might want to go up 1000(1024?) for number of berry plants that can be placed around the world map. By your third question, I assume you mean number of berries received? I would just use a random number generator between 2 and 6. Saves space and time. One more thought I had when reading your work was how you saved and recalled time. Your solution works, but it looks like a lot of effort only to fail if there is a one year gap, or February 29th pops up. My suggestion to this point is to store time in minutes and calculate the rtc value in minutes. It would save space both in asm code and in variables(one year in minutes can be expressed in twenty bits), won't break on February 29th and fixes the one year exploit/loophole/glitch/whatever. And to everyone arguing about releasing this in a patch,see this spoilered rant. Spoiler:
|
Man, how come whenever I ask a question, I always answer it myself? (I was pretty sleepy last night doing this, maybe that's why...)
Anyways, I found my answer. Quote:
|
Do I have to hex edit and which portion of hex codes?
|
Sorry to resurrect an old topic, but I needed to ask, is there a way to get the time of the RTC clock? If so it would be pretty easily to script the entire GSC berry system(no planting/watering or moving icons involved, just pick a tree OW sprite, and give it a script to check the time, and if so use the giveitem command to give the person a berry once per day.
|
| All times are GMT -8. The time now is 8:40 AM. |
![]()
© 2002 - 2018 The PokéCommunity™, pokecommunity.com.
Pokémon characters and images belong to The Pokémon Company International and Nintendo. This website is in no way affiliated with or endorsed by Nintendo, Creatures, GAMEFREAK, The Pokémon Company or The Pokémon Company International. We just love Pokémon.
All forum styles, their images (unless noted otherwise) and site designs are © 2002 - 2016 The PokéCommunity / PokéCommunity.com.
PokéCommunity™ is a trademark of The PokéCommunity. All rights reserved. Sponsor advertisements do not imply our endorsement of that product or service. User generated content remains the property of its creator.
Acknowledgements
Use of PokéCommunity Assets
vB Optimise by DragonByte Technologies Ltd © 2023.