PokeHacking

Join our Discord community

Simplifying collisions in Gen IV by removing the hit layer and characterizing the sound collisions in HeartGold and SoulSilver

Mikelan98, AdAstra/LD3005

Target games:


Introduction

With the arrival of Pokémon Diamond and Pearl, maps were introduced a second layer for move permissions that -potentially- allowed a more flexible collision editing for maps, since it allowed combining the hit properties with every other collision type in the map. In practice, however, cases where an unusual hit property is needed for a collision type in a tile are very rare, rendering the two-layer system pointless. Furthermore, this system may suppose an additional effort to the ROM hacker when it comes to mapping.


DS Pokémon ROM Editor (DSPRE) showing the two collision layers of a Pokémon Platinum map.

In Pokémon HeartGold and SoulSilver, a third layer was added for triggering sounds when the player steps over a tile. In this case, though, the system is useful since the combinations of the different sounds with different collision types are very frequent, allowing plenty of graphical effects (shallow water, footprints) followed by sound effects, and thus enriching the game experience.

In this tutorial we will research the game code that handles the hit collision, so the second move permissions layer from the game maps can be removed. The default hit collision will be implemented at collision type 01, and a method for assigning hittable/walkable properties for every collision type in the game code will be implemented. Additionally, for this purpose, a small tool will be developed to analyse and convert the original maps collisions into the new collision system with the hit layer removed. Finally, the different sounds collisions in HeartGold and SoulSilver will be listed and researched to identify the different sounds that are triggered by each.


Research

The easiest strategy for searching the game subroutine that handles the hit collisions is to find and trace the map data in the RAM memory. In this case, we took New Bark Town as an example, and disassembled the game while the player was present in the mentioned map. The whole map collision data of New Bark Town was searched in the RAM memory so it could be traced. Optionally, the emulator DeSmuME allows dumping the RAM memory, so the map data can also be searched in an external hex editor. In both cases, we got the memory address of New Bark Town collisions.


New Bark Town collision data in the RAM memory, at address 0x0231F748.

By enabling a trace breakpoint in a specific collision, we can check the subroutines that read the collision data by stepping over that tile. We found that, for HeartGold, subroutine sub_20547D8 was the only one that accessed this data, and this function returned the complete 2 bytes collision without processing it. Researching a bit further, we found that four subroutines called this mentioned subroutine: sub_20548C0 (processed hit collisions), sub_20548EC (processed sound collisions), sub_2054918 (processed collision types) and sub_2054940 (returned the complete collision). The first subroutine, sub_20548C0, was the one that had to be researched and edited for our purpose.

The subroutine sub_20548C0 takes the complete 2 bytes collision and checks the most significant bit. If the bit is set, it returns 1 (meaning that it is a hit). However, if the most significant bit is clear, it returns 0 (standing for no hit). The most significant bit is represented in the maps by the value 80 of the second collision layer in SDSME and DSPRE -although the second layer should be a single bit value, boolean array, not a byte array as it is represented in those tools- forming the halfword 0x8000, or 0b1000000000000000. We will modify this subroutine, so it returns 0 or 1 depending on a custom check.


Collision data scheme for Gen IV maps. H: Hit, S: Sound, T: Type. Every part is processed by a different subroutine. The sound part is only processed in HeartGold and SoulSilver.

Researching a bit more, we found that a collision type properties array can be found in 0x020FCA74. This array is 256 bytes long (one byte per collision type), and in this array, every collision type has two possible bitflags assigned: 1 for surfable collisions and 2 for collisions that trigger wild encounters. In our case, a third bitflag (with value 4) can be added to represent a hittable/walkable property, so we edited the subroutine sub_20548C0 for this goal. To determine whether a collision type had to have this bitflag set or clear, we developed a tool to mass-analyse the hit-type combinations in the original game maps. This tool was eventually also used to convert the map collision data into the new single-layer format.

To identify the sounds triggered by the different sound collisions in HeartGold and SoulSilver, we researched the calls to the subroutine sub_20548EC, eventually finding a table in 0x20FCB98 that handles the played sounds.

Sound Collision Triggered Sound Description
002156 - SEQ_SE_GS_ASHIOTO_A_WALKStep (walking)
012157 - SEQ_SE_GS_ASHIOTO_AStep (running)
022154 - SEQ_SE_GS_OCHIBAFallen leaves (used in Azalea Gym and Bellchime Trail)
032166 - SEQ_SE_GS_EDAPAKICracking branches (Ilex Forest Farfetch'd puzzle)
042167 - SEQ_SE_GS_KUSA2Grass
052158 - SEQ_SE_GS_ASHIOTO_B*Sand
062160 - SEQ_SE_GS_ASHIOTO_D*Step (used in entrances)
072161 - SEQ_SE_GS_ASHIOTO_D_2Metal
082162 - SEQ_SE_GS_ASHIOTO_EUnknown (not used)
092158 - SEQ_SE_GS_ASHIOTO_B*Straw (used in Moo-moo Farm)
0A2163 - SEQ_SE_GS_ASHIOTO_F*Rock (used in some caves)
0B2160 - SEQ_SE_GS_ASHIOTO_DStep (used in Olivine/Vermilion ports)
0C2165 - SEQ_SE_GS_ASHIOTO_HUnknown (not used)
0D2164 - SEQ_SE_GS_ASHIOTO_GCracking wood
0E1515 - SEQ_SE_DP_BOX02Unknown (not used)
0F1514 - SEQ_SE_DP_BOX01Unknown (not used)

Sound collision 00 will trigger SEQ_SE_GS_ASHIOTO_A if the player is running instead of walking. Sounds marked with an asterisk will be forced to use the sound bank of the current sound player.

Although 128 possible values fit into a sound collision (7 bits), only values 0 to 15 should be used. If more values were to be used, the table should be repointed (changing the addresses written at 0x0205CE5C and 0x0205CE64) and expanded with the new sound IDs, and the limit written at 0x0205CE16 should be increased with the table size.


Tutorial

The source code of the program for both analysing and converting the maps collisions can be downloaded with the following link: CollisionMerger.zip

It requires the original maps binary files, that will be modified. An output text file will be generated after the conversion. The modified map files must be reinserted in the ROM after that.

To modify the game code, we will need to edit the sub_20548C0 subroutine (or its analogue in other game versions) and the collision properties table. The table below shows the offset (in the arm9.bin) and the new data for both, and for every game version.

Game Code Hit Check Subroutine Offset Hit Check Subroutine Code Collision Properties Offset Collision Properties Data
ADAE 0x4A6B4 18 B5 81 B0 84 6D 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 14 5C 0F 02 0xF5C14 adae_data.bin
APAE 0x4A6B4 18 B5 81 B0 84 6D 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 14 5C 0F 02 0xF5C14 apae_data.bin
CPUE 0x54F68 18 B5 81 B0 C4 6D 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD C4 D8 0E 02 0xED8C4 cpue_data.bin
IPKE 0x548C0 18 B5 81 B0 04 6E 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 74 CA 0F 02 0xFCA74 ipke_data.bin
IPGE 0x548C0 18 B5 81 B0 04 6E 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 74 CA 0F 02 0xFCA74 ipge_data.bin
ADAS 0x4A724 18 B5 81 B0 84 6D 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 64 5C 0F 02 0xF5C64 adas_data.bin
APAS 0x4A724 18 B5 81 B0 84 6D 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 64 5C 0F 02 0xF5C64 apas_data.bin
CPUS 0x55038 18 B5 81 B0 C4 6D 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 58 D9 0E 02 0xED958 cpus_data.bin
IPKS 0x548B8 18 B5 81 B0 04 6E 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 5C CA 0F 02 0xFCA5C ipks_data.bin
IPGS 0x548C0 18 B5 81 B0 04 6E 00 AB 64 68 A0 47 00 28 08 D0 00 A8 00 78 04 49 09 5C 04 20 08 42 01 D0 01 20 00 E0 00 20 01 B0 18 BD 74 CA 0F 02 0xFCA74 ipgs_data.bin

After the changes are successfully applied, map collisions for new maps made in PDSMS, DSPRE or SDSME must use collision 01 in the type layer (instead of the old collision 80 in the hit layer). The hit layer should be ignored and left empty (in Diamond, Pearl and Platinum) or used for sound collisions only (HeartGold and SoulSilver). We recommend updating PDSMS and DSPRE, so the collision type 01 is depicted as the new hit collision. After this, you won’t have to paint your map collisions twice when making new maps!


Demanded credits

If you are planning to use this research on your project, credits for Mikelan98 and AdAstra/LD3005 are needed. You can cite this research by copying the following reference in the credits section of your project's thread or webpage:

Mikelan98, AdAstra/LD3005: Map Collision Layers Merge (pokehacking.com/r/24061300)

Total or partial reproduction of this research in other site is forbidden without prior authorization of the authors.






© 2024 PokeHacking

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.