Script [Resolved] What is the offset location of the Rival's name? Trying to nickname a Pokémon after the Rival.
Binary ROM HackingNeed 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.
So I have tried the best I could to figure this out by myself, but unfortunately to no avail. What started as a relatively simple XSE script has made me delve into the depths of RAM memory - which I, admittedly, do not fully understand. Help would be highly appreciated!
In short, I want the player to receive a Pokémon, which carries the (nick)name the player gave to the Rival in the introduction. (I won't go into detail exactly why, but let's just say the Rival naming sequence becomes the starter nicknaming sequence.) As I do not master ASM yet, I would like to try to do this fully in XSE. This post shows how to rename an obtained Pokémon to the Player's name through a simple XSE script. It does so by copying the bytes of the Pokémon's OT to the Pokémon's nickname.
Spoiler:
Quote:
Originally Posted by DrFuji
Changing a Pokemon's nickname to the player's name is pretty simple to do through copying bytes in the the game's memory and easily be done in XSE. Here's a script that will give the player two Bulbasaurs and change the first one's name to the player's name:
In this script I'm copying the original trainer name from the Pokemon's data and overwriting the nickname data. As the trainer name can only be a maximum of seven letters we then need to pad the last three letters with 0xFF just in case the Pokemon's name is longer that that. If the Pokemon was traded it will have the trader's trainer name but it should be fine in 99% of cases. If the Pokemon you're trying to assign the name to isn't the first one in your party you will have to add 0x64 to each of the pointers for each Pokemon until you reach the party member you want to nickname. You could also give a Pokemon a static name just by using the writebytetooffset command if you wanted a Pokemon to have a specific name that wasn't the trainer's.
This script is designed for FireRed but it can be ported over to Emerald like this though I haven't tested it:
This seems to work fine. I would like to do the same, but instead of the Player's (OT's) name, it would copy the Rival's name. I thought I could achieve this by finding the location of the Rival's name and replacing the offsets referring to the OT (in bold in the spoiler above) in the script with the offsets of the Rival's name. However, it does not seem to be that easy. I don't know which offsets to copy the bytes from.
This post contains a list/map of the RAM offsets, including the Rival's name. It explains that it is stored in the so-called Dynamic Memory Allocation (DMA) and that the actual offsets change all the time. An excerpt of the post is included below. A simple addition of 0x03005008 + 0x000039D4 = 0x030089DC is not succesful because the actual DMA pointers change while the game is running.
Here's the DMA structures. The memory positions are relative to the memory addresses that are saved at those DMA save pointer locations above. The DMA pointers change while the game is running, often when leaving buildings or exiting certain menus.
Sav1
Code:
...
0x000039D4 rivals_name: .byte 8 dup(?)
...
...
But perhaps there is a much easier solution. In this post, the user has a similar question but suggests it can be bypassed using "copyvar to 0x8005 or something" in XSE. But for this I still need to know the location of the variable containing the Rival's name...
Spoiler:
Quote:
I have ASM code that needs to access a certain variable in the DMA, namely 0x4011, but as you probably know the actual location of this variable in the RAM changes all the time. I could (probably) get around this by using copyvar to 0x8005 or something before callasm-ing (as XSE script is evidently able to bypass this BS), but as this might not be an option in the future I wanted to know how seasoned ASM coders got around this, and the location of the IWRAM DMA cache (which contains pointers to each variable protected by DMA).
I am pretty confused at this point. Is there an accessible point where the Rival's name is stored, which can be identified and copied? Given the frequency with which the name is invoked throughout the game, and with [rival] in message boxes, I would be surprised if this wasn't somehow possible. Many thanks in advance, and apologies if I missed something obvious!
---
PS: Other posts I used and thought could be relevant, but didn't want to go through in this post:
This post by FBI which mentions the Rival's name is located in the EWRAM, which has offsets ranging from 0x02000000 to 0x0203FFFF.
Spoiler:
First of all, you'll notice that there are two sections of WRAM, which have been labeled. One is 32KB and the other is 256 KB. The 256KB of EWRAM is what's available for your game to use for its RAM data. For example: the save structures, player name, rival name, NPC states, malloc calls ect are all placed in this 256 KB RAM slot we call EWRAM.
This post contains an ASM script on renaming the Rival in the overworld. I can't read ASM, but it doesn't seem like any of the mentioned offsets can be used in the script. I have tried it with 0x03005008 which was unsuccesful.
Since the rival's name is at a DMA address, there's a few ways you can go about getting it. Firstly, you could use ASM to get it, but since you want to use a script, that's out. Secondly, you could use eval to dynamically load the DMA pointer and manipulate it to extract your needed bytes, but that's overly complicated and would take a long time to explain. The third and best way to get the rival's name is to have it be moved to another point in the RAM that isn't dynamic.
A good way to move the rival name's into a non-DMA part of the RAM is to have it occupy the displayed text as that will always start at 0x02021D18. You can use the command 'preparemsg' to load a prepared text string without actually having a msgbox appear on screen, ruining the immersion. Here's what a script based off the one you quoted earlier with this in mind:
This script will rename the first Pokemon in your party to your rival's name. One interesting thing about this is that your Pokemon will most likely have some random letters at the end of their name in the RAM that will never be loaded in-game as a 0xFF terminator will always be copied to it's nickname after the rival's name is finished. I hope this is what you're looking for.
Since the rival's name is at a DMA address, there's a few ways you can go about getting it. Firstly, you could use ASM to get it, but since you want to use a script, that's out. Secondly, you could use eval to dynamically load the DMA pointer and manipulate it to extract your needed bytes, but that's overly complicated and would take a long time to explain. The third and best way to get the rival's name is to have it be moved to another point in the RAM that isn't dynamic.
A good way to move the rival name's into a non-DMA part of the RAM is to have it occupy the displayed text as that will always start at 0x02021D18. You can use the command 'preparemsg' to load a prepared text string without actually having a msgbox appear on screen, ruining the immersion. Here's what a script based off the one you quoted earlier with this in mind:
This script will rename the first Pokemon in your party to your rival's name. One interesting thing about this is that your Pokemon will most likely have some random letters at the end of their name in the RAM that will never be loaded in-game as a 0xFF terminator will always be copied to it's nickname after the rival's name is finished. I hope this is what you're looking for.
This seems to be exactly what I'm looking for! Thanks alot, I did not know about the preparemsg command, but it makes a lot of sense. I will test it out tomorrow. :-)
Edit: I have tested DrFuji's script and it works exactly as intended. Thank you once again very much!