The PokéCommunity Forums  

Go Back   The PokéCommunity Forums > Fan Games > Binary ROM Hacking
Reload this Page Script Fixing the PokeMart clerk glitch in Pokemon Ruby

Notices
For all updates, view the main page.

Binary ROM Hacking Need a helping hand or just want to talk about binary ROM hacks? Get comments and answers to any ROM Hacking-related problems, questions or thoughts you have here.

Ad Content
Reply
 
Thread Tools
  #1   Link to this post, but load the entire thread.  
Old August 12th, 2021 (12:37 PM). Edited August 24th, 2021 by ShinyIksbat.
ShinyIksbat's Avatar
ShinyIksbat ShinyIksbat is offline
 
Join Date: Aug 2021
Posts: 12
Hello everyone,

I got back into playing Pokemon Ruby a few weeks ago and enjoyed it ever since.
Now that I 100%ed it, I wanted to get into ROM hacking of said game.
I have set myself a little challenge of fixing as many glitches in the game as I possibly can.

For now I did some minor corrections using Advance Map 1.92 to edit NPC properties or moving/removing tiles.
Yesterday I finally hit my first roadblock: I want to fix the PokeMart clerk in Oldale Town.
It's a well known glitch where they run into a tree, if you didn't have enough space in your inventory to receive the potion.
Spoiler:


I have already set up XSE 1.1.1 to edit scripts, but I still have questions left, which hopefully one of the gurus here can answer :)

#1 What is the correct way to edit existing code?
From what I understood so far, XSE is able to dynamically use the ROMs available addresses to store data.
Take for example the existing PokeMart clerk:
* do I have to move all the existing code with my new additions to a new address and change the sprites script to the new offset address?
* or can I simply start adding, and XSE will change the offsets of all subsequent existing things (even data outside of the current sprite script) on it's own, without me overwriting stuff?
My goal is to fix the behaviour, but keeping everything as close to vanilla as possible.

#2 Are the flags simple Bits, or are they Bytes?
Just for understanding the concept behind them, I would like to know what the flags are actually.
They get accessed by something that looks like it could be a RAM address, but I would assume from my gut feeling that they actually are just Bits, not whole Bytes.
Some of those flags seem to be implicitly set by routine calls - the lower ones I assume, like 0x0 or 0x1 for example when doing a checkflag.

#3 Why does the script for the PokeMart clerk not work?
The sprites script starts at 0x14DDDC:
Spoiler:

The Map Script of Oldale starts at 0x14DD88:
Spoiler:

So far I understand that in the Map Script (which is executed when you enter the town) the clerk is moved to his starting position next to the bottom right house, if the flag 0x84 (promo potion received) is NOT set.
That way the walk can properly be played.
When you speak to the clerk and the walk is performed, the flax 0x1 gets set (line #9 of clerk script) - this way the game keeps track if you already have spoken to him (and thus walked up).
If you immediately talk to them again but didn't receive the promotion because of a full bag, the walk will not be performed.
---
To my understanding the bug occurs when you leave the map and enter again, because the Map Script executes and 0x1 is overwritten because of other calls in it.
And when you talk to the clerk again (while 0x84 still being false), the walk will be played.

This in itself wouldn't be an issue, but somehow the Map Script with the movesprite2 call does not execute (properly?) - the clerk still stands just before the PokeMart.
If I would have to guess, I would say that sprites can't be moved if they are considered to be on screen.
That guy isn't on screen when I just barely leave the town and come back, but maybe the game handles sprites up to X tiles outside of the viewable area as "still on screen" - veterans could maybe answer that question :)
Spoiler:

Edit: if you walk far enough away from the town and then back in, the clerk will be reset at the correct position again.

#4 is RAM saved to the save file?
So my question is if ALL the flags and variables (or all the RAM for that matter) is stored in the save file.
I would assume so, because when I save the game and reload while something is temporarely changed, the change still exists when reloading.
Be it either the clerk standing next to the PokeMart even when 0x84 is false, or a tile existing near me, even when I changed it with Advance Map (will be corrected once you enter again though) - this at least would make me think certain stuff gets saved.


Kind regards
Reply With Quote
  #2   Link to this post, but load the entire thread.  
Old August 13th, 2021 (3:55 AM).
Anon822 Anon822 is offline
 
Join Date: Nov 2017
Posts: 326
Quote:
Originally Posted by ShinyIksbat View Post
#1 What is the correct way to edit existing code?
From what I understood so far, XSE is able to dynamically use the ROMs available addresses to store data.
Take for example the existing PokeMart clerk:
* do I have to move all the existing code with my new additions to a new address and change the sprites script to the new offset address?
* or can I simply start adding, and XSE will change the offsets of all subsequent existing things (even data outside of the current sprite script) on it's own, without me overwriting stuff?
XSE can automatically find free space but only if you're using the "#dynamic" directive. You should move everything you edit to free space and editing the script to use #dynamic is a good way to do that.

Quote:
Originally Posted by ShinyIksbat View Post
#2 Are the flags simple Bits, or are they Bytes?
Each flag is represented by a single bit in an array of bytes.

Quote:
Originally Posted by ShinyIksbat View Post
#3 Why does the script for the PokeMart clerk not work?
...
If I would have to guess, I would say that sprites can't be moved if they are considered to be on screen.
That would be my guess too. I believe movesprite2 command is used to move off-screen sprites while movesprite is used to move on-screen sprites.

Quote:
Originally Posted by ShinyIksbat View Post
#4 is RAM saved to the save file?
So my question is if ALL the flags and variables (or all the RAM for that matter) is stored in the save file.
The save file contains specific parts of ram (often referred to as saveblock1, saveblock2 and saveblock3/PokemonStorage), which includes all flags and most variables (I believe the 0x8000+ vars aren't saved).
Reply With Quote
  #3   Link to this post, but load the entire thread.  
Old August 13th, 2021 (10:28 AM). Edited August 13th, 2021 by ShinyIksbat.
ShinyIksbat's Avatar
ShinyIksbat ShinyIksbat is offline
 
Join Date: Aug 2021
Posts: 12
Thanks mate, that was already a big help :)
I think I found an elegant solution and was able to fix the glitch.
Before I want to show my solution, I need some more answers to very specific questions 😅

#1
As far as I know all the variables are unsigned WORDs (16 Bits).
In my solution an underflow can happen because of "subvar" -> the variable might become a big positive number (which is intended), but I am not sure if the overflowing part will affect the variable next to the intended one in memory.
My gut feeling says it might/will do so, because this is programming on a very low level... still I tested it by underflowing variable 0x4001 -> 0x4000/0x4002 seem to not have been affected... but maybe I just tested it wrong.
Maybe someone who has a lot of experience can tell me how the hardware (or emulation in this case) behaves exactly.

#2
I used the #dynamic directive now for the existing code that has been patched by me.
This causes the existing code to be pushed to a new free offset, but the previous bytes that have been used are not freed (set to FF).
Is there a way to automatically (or at least on demand) reset that space?

#3
So there is "call" and "goto" which both enable me to execute code from another pointer.
The difference is that the code from call can jump back with the "return" directive.
My question is now if call behaves like goto if I never run into a return directive, or if it does an implicit return at the end of the code.
Intention behind this question is that I conditionally want to return to the previous point.
Also... can I run into a stack overflow when I do not return in a call (I mean after doing that MANY times... I would assume "call" creates a stack entry).

Kind regards
Reply With Quote
  #4   Link to this post, but load the entire thread.  
Old August 14th, 2021 (3:44 AM).
Anon822 Anon822 is offline
 
Join Date: Nov 2017
Posts: 326
Quote:
Originally Posted by ShinyIksbat View Post
#1
As far as I know all the variables are unsigned WORDs (16 Bits).
In my solution an underflow can happen because of "subvar" -> the variable might become a big positive number (which is intended), but I am not sure if the overflowing part will affect the variable next to the intended one in memory.
Yes, variables are 16 bits and overflowing them does not affect other variables.

Quote:
Originally Posted by ShinyIksbat View Post
#2
I used the #dynamic directive now for the existing code that has been patched by me.
This causes the existing code to be pushed to a new free offset, but the previous bytes that have been used are not freed (set to FF).
Is there a way to automatically (or at least on demand) reset that space?
Apparently there are some directives for deleting scripts, but I don't think freeing a few bytes is really worth it when you have megabytes of free space available. You also typically look for free space at the end of the rom so you wouldn't end up reusing that space unless you made conscious effort to do so.

Quote:
Originally Posted by ShinyIksbat View Post
#3
My question is now if call behaves like goto if I never run into a return directive, or if it does an implicit return at the end of the code.
There is no implicit return, you can just end the script after a call.

Quote:
Originally Posted by ShinyIksbat View Post
can I run into a stack overflow when I do not return in a call (I mean after doing that MANY times... I would assume "call" creates a stack entry).
Just don't do more than 20 calls.
Reply With Quote
  #5   Link to this post, but load the entire thread.  
Old August 22nd, 2021 (11:24 AM).
ShinyIksbat's Avatar
ShinyIksbat ShinyIksbat is offline
 
Join Date: Aug 2021
Posts: 12
I finally was able to completely understand the issue with this glitch and how to fix it with just 12 existing bytes fixed, and 11 new bytes introduced.
The issue was that the sprite of the PokeMart clerk potentially doesn't unload if you just bearly leave and reenter the town, and also flag 0x1 gets reset, because it is part of the temporary ones, which implicitly get cleared when you enter a new map.
A detailed explanation can be seen here - took me quite some time to bring it all into video form ^^

Reply With Quote
Reply

Quick Reply

Join the conversation!

Create an account to post a reply in this thread, participate in other discussions, and more!

Create a PokéCommunity Account
Ad Content
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -8. The time now is 9:15 AM.