redriders180
Mastermind of Pokemon Glazed
- 314
- Posts
- 14
- Years
- Path of Victory, Tunod
- Seen Dec 17, 2016
Over the last few weeks, I started investigating Battle Platforms, how they work, and how one might be able to increase the amount of them, for custom platforms such as a lava one, or basically to add a little creative touch to a hack that has special platforms.
I hit a brick wall, however, and only managed to decipher what happens about halfway. I'm posting all my findings here, in the hope that someone else might be able to use this information to their advantage, and be able to find out more about it.
First, the table that stores entries for all the battle platforms begins at 24EE34, and each entry is made of five pointers. The first is a pointer to the tiles that make up the platform itself. The second is a pointer to the platform's tilemap. The third is a pointer to the tiles that make up the secondary animation (Waves splashing, grass waving, etc.). The fourth is a pointer to the tileset of the secondary animation, usually it's a strip of something that scrolls to the left, and then drops down and disappears. And the fifth appears to be a pointer to the compressed palette. This table seems to be repointable, and I did so successfully, although there's no way to access the platforms conventionally.
There's a very easy-to-understand (relatively speaking) routine that loads up the platform required at 0800F260, and it looks as such:
This code, quite simply, gets the value of R0, finds that r0'th entry in the above table, and then goes to the image decompression function at 0800EBC0. Midway, it checks if the value of R0 is greater than 0x13, and if it is, load up slot nine instead, probably as a sort of error-checker.
I have images for what each value of r0 will boot up. Firered has built-in support for twenty battle platforms already, although six are basically the same, with small palette changes. Here are the images, in a spoiler:
(Normal tall grass) r0 = 0:
(High Grass, never used in-game) r0 = 1:
(Sand) r0 = 2:
(Underwater, also never used in-game) r0 = 3:
(Sea) r0 = 4:
(Pond) r0 = 5:
(Not sure) r0 = 6:
(Cave) r0 = 7:
(Interior 1) r0 = 8:
(Default platform; this one is loaded if r0 > 0x13) r0 = 9:
(Interior 2) r0 = 0xA:
(Interior 3) r0 = 0xB:
(Interior 4) r0 = 0xC:
(Interior 5) r0 = 0xD:
(Interior 6) r0 = 0xE:
(Elite Four 1 [Blue]) r0 = 0xF:
(Elite Four 2 [Brown]) r0 = 0x10:
(Elite Four 3 [Purple]) r0 = 0x11:
(Elite Four 4 [Teal]) r0 = 0x12:
(Champion Room) r0 = 0x13:
Sadly, I wasn't able to find out how the value of r0 is determined. For most of the platforms, they seem to be based on behavior byte of the tile you're on; for instance, standing on a tile with "Very Tall Grass" animation will yield the very tall grass platform, no matter what. The four Elite Four platforms are controlled by a header setting in the map, under "Fight Type". Sonic1 was able to determine that the header setting takes precedence to the behavior byte. And still others, such as the underwater and (I believe) cave and indoor tiles depend on the "Type" value in the header, which can be set to underwater, underground, or inside, respectively.
I managed to develop a routine which would function similarly to Mastermind_X's music hack, allowing me to choose which platform appears in a script, depending on the value of variable 0x800A (chosen because it's hardly used). This routine was successful, for the most part, except it had two key bugs. The first, it would load the wrong tiles and tilemaps for the secondary animation. For example, I would turn all the platforms to sand, but walking on a tall grass tile would make sand-colored tall grass appear behind the player. Secondly, whenever a Pokemon's attack would display a background, such as the move Psybeam, the screen would flash in an infinite loop, I assume trying to load the correct platform, but it not being able to.
The main routine, not the one I added, is called in a rather inconvenient way, using the "relative to PC" branch command, instead of a normal goto, meaning that any sort of custom routine would need to be located in a very specific range of free space. The location of the branch is at 0800F416. Sonic1 was able to help in this regard, since I'd never "hooked" a routine before, and said that the routine must be between 0x8000000 and 0x83FFFFF. The custom routine I added was such:
The main limitation on this code is that it won't accept the standard tall grass platform (0x0), just because I chose 0x0 to mean "don't change". The second limitation is that this change forces all platforms to instead load the one specified in the variable. If I were to do a rewrite of the code, I'd make it so a specific platform would be replaced by another platform, to avoid "water battle sand platform" issues.
One final note: I was able to deduce a few things about the routines that load these platforms. The first is that the palettes are loaded after the platforms are, which I know because the platforms that were switched had the correct palette, secondary animation aside. Secondly, I suspect there might be more to that palette block. All wild battles used two palettes that are somewhat identical in color, one for the platforms, and one for the secondary animation. I'm not 100% sure where this second palette comes from...perhaps another table? And finally, the secondary animation must be loaded from another routine prior to this, because of the aforementioned problems.
I hope this is enough info to get the minds of Pokecommunity turning; I haven't seen any hacks that go much farther then replacing the platform pictures with more awesome and less plain ones, or custom platforms at all, so this might be a neat area to tap into.
I hit a brick wall, however, and only managed to decipher what happens about halfway. I'm posting all my findings here, in the hope that someone else might be able to use this information to their advantage, and be able to find out more about it.
First, the table that stores entries for all the battle platforms begins at 24EE34, and each entry is made of five pointers. The first is a pointer to the tiles that make up the platform itself. The second is a pointer to the platform's tilemap. The third is a pointer to the tiles that make up the secondary animation (Waves splashing, grass waving, etc.). The fourth is a pointer to the tileset of the secondary animation, usually it's a strip of something that scrolls to the left, and then drops down and disappears. And the fifth appears to be a pointer to the compressed palette. This table seems to be repointable, and I did so successfully, although there's no way to access the platforms conventionally.
There's a very easy-to-understand (relatively speaking) routine that loads up the platform required at 0800F260, and it looks as such:
Code:
0800F260 - push {r4,r5,r14}
0800F262 - lsl r0, r0, #0x10
0800F264 -lsr r0, r0, #0x10
0800F266 - cmp r0, #0x13
0800F268 - bls #0x800F26C
0800F26A - mov r0, #0x9
0800F26C -ldr r5,=#0x824EE34
0800F26E - lsl r4, r0, #0x2
0800F270 - add r4, r4, r0
0800F272 - lsl r4, r4, #0x2
0800F274 - add r0, r4, r5
0800F276 - ldr r0, [r0]
0800F278 - ldr r1,=#0x6008000
0800F27A - bl #0x800EBC0
I have images for what each value of r0 will boot up. Firered has built-in support for twenty battle platforms already, although six are basically the same, with small palette changes. Here are the images, in a spoiler:
Spoiler:
(Normal tall grass) r0 = 0:
Spoiler:
(High Grass, never used in-game) r0 = 1:
Spoiler:
(Sand) r0 = 2:
Spoiler:
(Underwater, also never used in-game) r0 = 3:
Spoiler:
(Sea) r0 = 4:
Spoiler:
(Pond) r0 = 5:
Spoiler:
(Not sure) r0 = 6:
Spoiler:
(Cave) r0 = 7:
Spoiler:
(Interior 1) r0 = 8:
Spoiler:
(Default platform; this one is loaded if r0 > 0x13) r0 = 9:
Spoiler:
(Interior 2) r0 = 0xA:
Spoiler:
(Interior 3) r0 = 0xB:
Spoiler:
(Interior 4) r0 = 0xC:
Spoiler:
(Interior 5) r0 = 0xD:
Spoiler:
(Interior 6) r0 = 0xE:
Spoiler:
(Elite Four 1 [Blue]) r0 = 0xF:
Spoiler:
(Elite Four 2 [Brown]) r0 = 0x10:
Spoiler:
(Elite Four 3 [Purple]) r0 = 0x11:
Spoiler:
(Elite Four 4 [Teal]) r0 = 0x12:
Spoiler:
(Champion Room) r0 = 0x13:
Spoiler:
Sadly, I wasn't able to find out how the value of r0 is determined. For most of the platforms, they seem to be based on behavior byte of the tile you're on; for instance, standing on a tile with "Very Tall Grass" animation will yield the very tall grass platform, no matter what. The four Elite Four platforms are controlled by a header setting in the map, under "Fight Type". Sonic1 was able to determine that the header setting takes precedence to the behavior byte. And still others, such as the underwater and (I believe) cave and indoor tiles depend on the "Type" value in the header, which can be set to underwater, underground, or inside, respectively.
I managed to develop a routine which would function similarly to Mastermind_X's music hack, allowing me to choose which platform appears in a script, depending on the value of variable 0x800A (chosen because it's hardly used). This routine was successful, for the most part, except it had two key bugs. The first, it would load the wrong tiles and tilemaps for the secondary animation. For example, I would turn all the platforms to sand, but walking on a tall grass tile would make sand-colored tall grass appear behind the player. Secondly, whenever a Pokemon's attack would display a background, such as the move Psybeam, the screen would flash in an infinite loop, I assume trying to load the correct platform, but it not being able to.
The main routine, not the one I added, is called in a rather inconvenient way, using the "relative to PC" branch command, instead of a normal goto, meaning that any sort of custom routine would need to be located in a very specific range of free space. The location of the branch is at 0800F416. Sonic1 was able to help in this regard, since I'd never "hooked" a routine before, and said that the routine must be between 0x8000000 and 0x83FFFFF. The custom routine I added was such:
Code:
.align 2
.thumb
Main:
ldr r6, .VAR_800A
ldrh r6, [r6]
cmp r6, #0x0
bne replace
ldr r6, .NEXT_INST
bx r6
replace:
add r0, r6, #0x0
ldr r6, .RETURN
bx r6
.hword 0x0000
.VAR_800A: .word 0x020370CC
.RETURN: .word 0x0800F261
The main limitation on this code is that it won't accept the standard tall grass platform (0x0), just because I chose 0x0 to mean "don't change". The second limitation is that this change forces all platforms to instead load the one specified in the variable. If I were to do a rewrite of the code, I'd make it so a specific platform would be replaced by another platform, to avoid "water battle sand platform" issues.
One final note: I was able to deduce a few things about the routines that load these platforms. The first is that the palettes are loaded after the platforms are, which I know because the platforms that were switched had the correct palette, secondary animation aside. Secondly, I suspect there might be more to that palette block. All wild battles used two palettes that are somewhat identical in color, one for the platforms, and one for the secondary animation. I'm not 100% sure where this second palette comes from...perhaps another table? And finally, the secondary animation must be loaded from another routine prior to this, because of the aforementioned problems.
I hope this is enough info to get the minds of Pokecommunity turning; I haven't seen any hacks that go much farther then replacing the platform pictures with more awesome and less plain ones, or custom platforms at all, so this might be a neat area to tap into.