• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Forum moderator applications are now open! Click here for details.
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Advanced Over World Sprite Editing: Part 2

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
After some discoveries, I asked Darthatron if I could finish his old tutorial on Advanced OW Sprite Editing and he said yes. I recently fully discovered how the routine works which controls how many OWs you can have and I plan on sharing with you how to increase this limit.

However, first, here is the original tutorial who's thread was closed a while back with a little updated commentary from me. I will also include the offsets for the main english roms Ruby and Emerald. If you need more offsets and you can't find them on your own, just let me know.

Darthatron said:
Okay, in this tutorial I will teach you how to repoint, resize and increase the amount of OWS (Over World Sprites) in Pokemon FireRed. Sounds fun, right? :p

I haven't tested this in the other Advance Gen Games, but I'm sure it will work just the same. :)

karatekid552- Confirmed. It does work for all Advance Gen games.

For this Tutorial you will need...
  • An English FireRed ROM
  • A Hex Editor
  • The latest version of VBA
  • A Free Space Finder
  • A Brain

Lesson 01: Understanding the Data.

Ok, let's take a quick look at the Layout of the Sprite Data, before we go any further. Here is what the first Sprites Data will look like in FireRed:

Code:
FFFF001102110002100020001001000010373A089C373A0870343A08A0003A08FC1C2308
Now, let's break it down, so you can all understand:
Code:
FFFF		= Starter Byte
00		= Palette Number
11 02 11	= Unknown Data 1
0002		= Unknown Data Size
10		= Width
00		= Unknown Byte 1
20		= Height
00		= Unknown Byte 1
10 01 0000	= Unknown Data 2
10373A08	= Unknown Pointer 1
9C373A08	= Unknown Pointer 2
70343A08	= Unknown Pointer 3
A0003A08	= Sprite Pointer
FC1C2308	= Unknown Pointer 4

karatekid552- Due to some new knowledge from JPAN's Hacked Engine guide and NSE Classic, we know more about those unknown pointers:

Here is a pic from JPAN's guide:
Spoiler:

Following the "Sprite Pointer" will lead you to this Data:

Code:
68BB350800010000

This is another pointer to where the actual Sprite Hex Art is, don't worry about looking at it, it's pointless unless you look at it in an OWE. Here's the broken up version of the Sprite Data:

Code:
68BB3508	= Hex Art Pointer
0001		= Data Size
0000		= Unknown Data
The Data Size is always equal to this algorithm:
Code:
Data Size	= (Width x Height) / 2

That's about it for this lesson, next we will learn how to resize the OW Sprite! YAY! *Cheers*

Lesson 02: Resizing an Over World Sprite.

Right, so if you remember correctly, before we looked at the Sprite Data, and it had the "Height" and "Width" Bytes stored there, so... Let's just change them, and see what happens. Why don't we make it a 32 x 32 Sprite now?

Code:
FFFF		= Starter Byte
00		= Palette Number
11 02 11	= Unknown Data 1
0002		= Unknown Data Size
20		= Width
00		= Unknown Byte 1
20		= Height
00		= Unknown Byte 1
10 01 0000	= Unknown Data 2
10373A08	= Unknown Pointer 1
9C373A08	= Unknown Pointer 2
70343A08	= Unknown Pointer 3
A0003A08	= Sprite Pointer
FC1C2308	= Unknown Pointer 4

Now, let's put it back together.

Code:
FFFF001102110002100020001001000010373A089C373A0870343A08A0003A08FC1C2308

...And put it back into our Hex Editor. Next we will open up the OWS in our OWE.
0.png


Oh dear! Frame 0 and 1 seemed to have melded together! This means we have to repoint the Frames, YAY!
Ok, so all you have to do is follow the "Sprite Pointer", which is "A0003A08", or "0x003A00A0" when it's flipped. SO now, goto the offset "0x003A00A0" in your Hex Editor and look at the data. It should look something like this:

Code:
68BB350800010000

Now, we need to work out how many frames the OWS has. The Hero Sprite has 20 Frames, so open up your Free Space Finder and search for the Value of this Sum:

Code:
Value = (Height x Width) / 2 x Frames
So, in this case it would be:
Code:
Value = (16 x 16) / 2 x 20
Value = 256 / 2 x 20
Value = 128 x 20
Value = 2560

So, we will be searching for 2560 Bytes! YAY! Searching sure is fun.

*Searches*

Ok, I found the Space I need at the offset: "0x00720A00" Lucky me. Now, I'm going to start Repointing all the Pointers.

Back to the Offset "0x003A00A0" in your Hex Editor and it's time to start the fun!

Alright, so replace the First Pointer with "000A7208", which now lead to the Free Space we found earlier.

Now, view that Frame and Sprite in your OWE. And see how it turns out.
1.png


Great! We now have a clear Sprite! Next we are going to want to do the same for every frame, so back at the Offset "0x003A00A0" we are going to move 8 more Bytes into the File and Repoint this Frame aswell!

So with the Free Space we found earlier, which was "0x00720A00", we want to add 128 Bytes, because that is the Value of the Sum we did before:

Code:
Value = (Height x Width) / 2
So, the new Offset will be: "0x00720A80"
And the new Pointer will be: "800A7208"

So, what we want to do it replace the Pointer at the Offset "0x003A00A0" with our new pointer, in my case: "800A7208".


karatekid552- Some people find pointers confusing so here is a way to remember it: take the 6 figure long offset, and swap the first and the last bytes (the first pair of two numbers and the last pair of two numbers) then put 08 on the end. Also, here is a visual representation:

AX BY CZ -> CZ BY AX 08​


Great! The second Frame is now clear as well! Do that for the other 18 Frames, and then you can start painting your new OWS! YAY!

Lesson 03: Adding for OWS to the game.

Finally, we can learn how to repoint the OWS and add more into out game! YAY! *Cheers*

Ok, what we are going to do it open our ROM in our Hex Editor...

*Opens ROM*

Right, now Goto the offset: "0x0039FDB0" And you will see a whole bunch of Pointers, right? They should look something... like... this:

Code:
B03B3A08D43B3A08F83B3A081C3C3A0858483A08A0483A08C4483A0864453A08
88453A08AC453A08D0453A087C483A08E8483A080C493A08643C3A08883C3A08
AC3C3A08D03C3A083C3D3A08A83D3A08F03D3A08F43C3A08183D3A08603D3A08
CC3D3A0890433A08B4433A08143E3A085C3E3A08EC3E3A08383E3A08843D3A08
803E3A08343F3A0820443A08583F3A084C423A0828423A0870423A087C3F3A08
A03F3A08C43F3A08E83F3A0878403A089C403A08C0403A08E4403A08A43E3A08
C83E3A0818463A0854403A0878493A080C403A08B8423A0808413A082C413A08
94423A08BC413A0830403A08103F3A08403C3A0850413A0874413A0898413A08
00433A08D4443A08F8443A0824433A0868443A088C443A08B0443A086C433A08
34483A08A4473A0810483A0860463A08C8473A08EC473A08D8433A08FC433A08
84463A08A8463A08CC463A08F0463A0814473A0880473A085C473A0838473A08
EC503A083C463A08E0413A08DC423A0848433A0830493A0854493A0844443A08
1C453A0840453A08C0493A08E4493A08084A3A082C4A3A08504A3A08744A3A08
984A3A08BC4A3A08E04A3A08044B3A0810513A089C493A08284B3A08844F3A08
F04F3A08C8503A0814503A0880503A08A4503A0838503A084C4B3A08704B3A08
5C503A08944B3A08B84B3A08DC4B3A08004C3A08244C3A08484C3A086C4C3A08
904C3A08B44C3A08D84C3A08FC4C3A08204D3A08444D3A08A84F3A08684D3A08
8C4D3A08B04D3A08D44D3A08644E3A08884E3A08AC4E3A08F44E3A08D04E3A08
184F3A083C4F3A08604F3A08CC4F3A08F84D3A081C4E3A08404E3A08
They look fun... NOT! Ok, so I'll show you what each pointer means...

Code:
B03B3A08	= Pointer to OWS 0
D43B3A08	= Pointer to OWS 1
F83B3A08	= Pointer to OWS 2
1C3C3A08	= Pointer to OWS 3
58483A08	= Pointer to OWS 4
A0483A08	= Pointer to OWS 5
C4483A08	= Pointer to OWS 6
64453A08	= Pointer to OWS 7
88453A08	= Pointer to OWS 8
AC453A08	= Pointer to OWS 9
D0453A08	= Pointer to OWS 10
7C483A08	= Pointer to OWS 11
E8483A08	= Pointer to OWS 12
0C493A08	= Pointer to OWS 13
643C3A08	= Pointer to OWS 14
883C3A08	= Pointer to OWS 15
AC3C3A08	= Pointer to OWS 16
D03C3A08	= Pointer to OWS 17
3C3D3A08	= Pointer to OWS 18
...
404E3A08	= Pointer to OWS 150

Yes, that's right. Following one of those points will take you to the "Sprite Data", we looked at that data before (Lesson 01 & 02), cool huh? This is the location where AMap reads from, however, this isn't as far back as we can go...

Now, in your Hex Editor we are going to goto the location that points to this Table, and change it. So, goto this location: "0x0005F2F4", this should have a pointer to the table we just looked at, correct?

Ok, now open up your ROM in your FSF and search for this number of bytes:
Code:
[Center]Value = Number x 4[/center]
"Number" is how many Sprites you want to have in your game. For this example we will use 151, Which is 1 extra Sprite to the average 151 FireRed has.

karatekid552- After a lot of experimentation with overworlds, I have found that this is not the case. FireRed actually has 152 total OWs (I will prove this later), Ruby has 218, and Emerald has 246. This is due to some people forgetting about OW number 00 and, in FR's case, 151, the S.S. Anne, which doesn't show up in A-map. So, keep in mind these new totals as you continue on.:) Darthatron will continue to use the A-map number of 151 for FireRed but it is 152. (Unless you don't like the S.S. Anne:p)

So.... In my FSF I will search for....
Code:
Value		= Number x 4
Value		= 152 x 4
Value		= 608
...608 Bytes. However, due to my vast amount of laziness, and my really slow computer, I will just use the offset "0x00801000", write that offset down somewhere, alright so... Asuming we are still at the offset "0x0005F2F4", I will set the Pointer there to... "00108008".

Now, we have copy/paste the Table at the Location "0x0039FDB0", ONLY THE FIRST 151 POINTERS (604 Bytes), to the Location we just found, in my case "0x00801000". Now, if you did everything correctly, there should be at least 4 Free Bytes after the table has been pasted. With this free space we are going to add a new pointer to some free space where we will put our new Sprite Data...

Once again, open up FSF and search for some free space, this time search for 36 Bytes. Once again, due my huge amount of laziness, I will be using the offset "0x00802000". Back at the 4 Bytes that we have free after pasting the Pointer Table, we are going to add out new pointer. In my case: "00208008".

Now, in your Hex Editor we are going to look at the Hero's Sprite Data, located at "0x003A3BB0", and we are going to copy it all (36 Bytes). Then we will go back to our new free space, in my case "0x00802000", and we are going to paste the data we just stole from the Hero's Sprite Data.

Open your ROM up in a Map Editor and make a Sprite with the Picture Number of "151" and you will notice that the Map Editor doesn't appear to show any Sprite. However, opening the ROM in your emulator and looking at the Sprite it will look like the Hero.

Alright, now you just have to follow Lesson 02, using this Sprite Data instead of the First, and all should be fine. I think... I kind of lost track of where I was up to. If for whatever reason it doesn't work, post and I'll see if I missed anything... xD

Here is my table of equivalent offsets between games. I can expand this table fairly easily if needed:
0a64141c92eb4b52523365e88120d5ed_zps7f7d54de.jpg

[I would like to apologize for this being an image. I wanted code it as a table, but it appears the table system for PC has a few bugs, so I couldn't.]

I would also like to note that to use the increased OWs with an OW editor, I would suggest using NSE Classic since it reads from the table we just repointed, and not the secondary sprite table that OWERE uses. To use your new sprites, create an .ini file (instructions for this are in the NSE readme file) and point it to your new table. Then, open NSE and under options choose "Advanced Mode". From there, go back under options and turn the boundaries off. This was a major feature lacking from OWERE. Instead of this, it just gave the "subscript out of range" error.


Part 2.


Now that you know how to increase the amount of overworlds by repointing that nice big table, we need to take a look at what I like to call "OW limiters". In all Advance Gen games, there is a special routine that is carried out when an overworld is loaded onto the screen. This routine checks to make sure that the OW is a part of the table. If not, instead of letting the game crash, it just reroutes the loading routine to use OWs from earlier on in the table.

For those of you ASM enthusiasts, here is the routine that runs said checks in Ruby and FireRed. they are almost identical but Emerald is a little different, so we will discuss it later on:
Ruby
Code:
ROM:0805BC10 sub_805BC10
ROM:0805BC10                 PUSH    {LR}
ROM:0805BC12                 LSLS    R0, R0, #0x18
ROM:0805BC14                 LSRS    R1, R0, #0x18
[COLOR="Red"][B]ROM:0805BC16                 CMP     R1, #239[/B][/COLOR]
ROM:0805BC18                 BLS     loc_805BC28
ROM:0805BC1A                 MOVS    R0, R1
ROM:0805BC1C                 ADDS    R0, #0x10
ROM:0805BC1E                 LSLS    R0, R0, #0x18
ROM:0805BC20                 LSRS    R0, R0, #0x18
ROM:0805BC22                 BL      sub_8069290
ROM:0805BC26                 ADDS    R1, R0, #0
ROM:0805BC28
ROM:0805BC28 loc_805BC28                             ; CODE XREF: sub_805BC10+8j
[B][COLOR="red"]ROM:0805BC28                 CMP     R1, #217[/COLOR][/B]
ROM:0805BC2A                 BLS     loc_805BC2E
ROM:0805BC2C                 MOVS    R1, #5
ROM:0805BC2E
ROM:0805BC2E loc_805BC2E                             ; CODE XREF: sub_805BC10+1Aj
ROM:0805BC2E                 LDR     R0, =unk_836DC58
ROM:0805BC30                 LSLS    R1, R1, #2
ROM:0805BC32                 ADDS    R1, R1, R0
ROM:0805BC34                 LDR     R0, [R1]
ROM:0805BC36                 POP     {R1}
ROM:0805BC38                 BX      R1
ROM:0805BC38 ; End of function sub_805BC10
ROM:0805BC38
ROM:0805BC38 ; ---------------------------------------------------------------------------
ROM:0805BC3A                 DCB    0
ROM:0805BC3B                 DCB    0
ROM:0805BC3C off_805BC3C     DCD unk_836DC58         ; DATA XREF: sub_805BC10:loc_805BC2Er

ROM:0805BC40 sub_805BC40
ROM:0805BC40                 PUSH    {R4,LR}
ROM:0805BC42                 MOVS    R4, R0
ROM:0805BC44                 LDRB    R0, [R4,#5]
[COLOR="Red"][B]ROM:0805BC46                 CMP     R0, #239[/B][/COLOR]
ROM:0805BC48                 BLS     loc_805BC56
ROM:0805BC4A                 ADDS    R0, #0x10
ROM:0805BC4C                 LSLS    R0, R0, #0x18
ROM:0805BC4E                 LSRS    R0, R0, #0x18
ROM:0805BC50                 BL      sub_8069290
ROM:0805BC54                 STRB    R0, [R4,#5]
ROM:0805BC56
ROM:0805BC56 loc_805BC56                             ; CODE XREF: sub_805BC40+8j
ROM:0805BC56                 POP     {R4}
ROM:0805BC58                 POP     {R0}
ROM:0805BC5A                 BX      R0
ROM:0805BC5A ; End of function sub_805BC40

FireRed
Code:
0805F2C8 sub_0805F2C8:                           @ CODE XREF: sub_0805E510+8p
0805F2C8                                         @ npc_to_oam_pre_buffer_maybe+48p ...
0805F2C8                 PUSH    {LR}
0805F2CA                 LSLS    R0, R0, #0x18
0805F2CC                 LSRS    R1, R0, #0x18
[COLOR="red"][B]0805F2CE                 CMP     R1, #239[/B][/COLOR]
0805F2D0                 BLS     loc_0805F2E0
0805F2D2                 MOVS    R0, R1
0805F2D4                 ADDS    R0, #16
0805F2D6                 LSLS    R0, R0, #0x18
0805F2D8                 LSRS    R0, R0, #0x18
0805F2DA                 BL      sub_0806E5A4
0805F2DE                 ADDS    R1, R0, #0
0805F2E0
0805F2E0 loc_0805F2E0:                           @ CODE XREF: npc_get_type+8j
[COLOR="red"][B]0805F2E0                 CMP     R1, #151[/B][/COLOR]
0805F2E2                 BLS     loc_0805F2E6
0805F2E4                 MOVS    R1, #16
0805F2E6
0805F2E6 loc_0805F2E6:                           @ CODE XREF: npc_get_type+1Aj
0805F2E6                 LDR     R0, =unk_0839FDB0
0805F2E8                 LSLS    R1, R1, #2
0805F2EA                 ADDS    R1, R1, R0
0805F2EC                 LDR     R0, [R1]
0805F2EE                 POP     {R1}
0805F2F0                 BX      R1
0805F2F0 @ End of function sub_0805F2C8
0805F2F0
0805F2F0 @ ---------------------------------------------------------------------------
0805F2F2                 .byte    0
0805F2F3                 .byte    0
0805F2F4 off_0805F2F4:   .long unk_0839FDB0         @ DATA XREF: npc_get_type:loc_0805F2E6r

0805F2F8 sub_0805F2F8:                           @ CODE XREF: rom_npc_to_npc_state+158p
0805F2F8                 PUSH    {R4,LR}
0805F2FA                 MOVS    R4, R0
0805F2FC                 LDRB    R0, [R4,#5]
[COLOR="red"][B]0805F2FE                 CMP     R0, #239[/B][/COLOR]
0805F300                 BLS     loc_0805F30E
0805F302                 ADDS    R0, #0x10
0805F304                 LSLS    R0, R0, #0x18
0805F306                 LSRS    R0, R0, #0x18
0805F308                 BL      sub_0806E5A4
0805F30C                 STRB    R0, [R4,#5]
0805F30E
0805F30E loc_0805F30E:                           @ CODE XREF: sub_0805F2F8+8j
0805F30E                 POP     {R4}
0805F310                 POP     {R0}
0805F312                 BX      R0
0805F312 @ End of function sub_0805F2F8


In Ruby, there is a total of 218 OWs (counting #00). If you notice, the second cmp command checks if the number in r1 (which is the OW number currently being loading loaded onto the screen using the hex equivalents for the numbers in NSE) is less than or equal to 0xD9 or decimal 217. In FireRed, this cmp is to 0x97 or decimal 151 and will branch only if less than or equal. This proves what I commented earlier being that there are 152 OWs because it is comparing to the numbers in NSE, in which the S.S. Anne is #151.

So, as you can see, that check was pretty basic. It was just the maximum number of OWs. But what about those other two? They both cmp for 0xEF (240) in both Ruby and FireRed, but what could they possibly do? After a lot of research, I finally understand how these are used. They allow for Dynamic OWs; OWs that can be placed on the map and then later modified to be something different. These checks make it so that OWs #240+ are dynamic in nature. Some main examples of how these are used would be the sprites in the Union Room in FR and how secret bases are done in RSE. I will discuss how we can use these to our advantage in Part 2.5.

So, what if you don't know all of this fancy ASM stuff? What do you do? It is actually pretty simple.

Open up our trusty Hex editor and change the following three offsets to the hex value of the number of OWs you want to have up to 239. If you want anything higher, you will have to deal with Part 2.5.

Ruby(AXVE)
•0x5BC28

FireRed(BPRE)
•0x5F2E0

*If you need offsets for different versions, just let me know. I will get them.


Now you have done it! You've successfully increased the amount of OWs in Ruby and FireRed. Yay!


But what if you have Emerald? I never want to leave any hackers in the cold, which is why I try to write my tutorials to support as many games as possible. In Emerald, the routine is fairly the same. However there is an extra ripple I want to make you aware of.

Here is the routine:
Emerald:
Code:
ROM:0808E694 sub_808E694                             ; CODE XREF: sub_808D90C+8p
ROM:0808E694                                         ; sub_808D98C+4Ap ...
ROM:0808E694                 PUSH    {LR}
ROM:0808E696                 LSLS    R0, R0, #0x18
ROM:0808E698                 LSRS    R1, R0, #0x18
[COLOR="red"][B]ROM:0808E69A                 CMP     R1, #239[/B][/COLOR]
ROM:0808E69C                 BLS     loc_808E6AC
ROM:0808E69E                 MOVS    R0, R1
ROM:0808E6A0                 ADDS    R0, #0x10
ROM:0808E6A2                 LSLS    R0, R0, #0x18
ROM:0808E6A4                 LSRS    R0, R0, #0x18
ROM:0808E6A6                 BL      sub_809D6D0
ROM:0808E6AA                 ADDS    R1, R0, #0
ROM:0808E6AC
ROM:0808E6AC loc_808E6AC                             ; CODE XREF: sub_808E694+8j
[B][COLOR="red"]ROM:0808E6AC                 CMP     R1, #69[/COLOR][/B]
ROM:0808E6AE                 BNE     loc_808E6C4
ROM:0808E6B0                 BL      sub_81201C8
ROM:0808E6B4                 LSLS    R0, R0, #0x18
ROM:0808E6B6                 LDR     R1, =off_85059DC
ROM:0808E6B8                 LSRS    R0, R0, #0x16
ROM:0808E6BA                 ADDS    R0, R0, R1
ROM:0808E6BC                 LDR     R0, [R0]
ROM:0808E6BE                 B       loc_808E6D2
ROM:0808E6BE ; ---------------------------------------------------------------------------
ROM:0808E6C0 off_808E6C0     DCD off_85059DC         ; DATA XREF: sub_808E694+22r
ROM:0808E6C4 ; ---------------------------------------------------------------------------
ROM:0808E6C4
ROM:0808E6C4 loc_808E6C4                             ; CODE XREF: sub_808E694+1Aj
[B][COLOR="red"]ROM:0808E6C4                 CMP     R1, #238[/COLOR][/B]
ROM:0808E6C6                 BLS     loc_808E6CA
ROM:0808E6C8                 MOVS    R1, #5
ROM:0808E6CA
ROM:0808E6CA loc_808E6CA                             ; CODE XREF: sub_808E694+32j
ROM:0808E6CA                 LDR     R0, =off_8505620
ROM:0808E6CC                 LSLS    R1, R1, #2
ROM:0808E6CE                 ADDS    R1, R1, R0
ROM:0808E6D0                 LDR     R0, [R1]
ROM:0808E6D2
ROM:0808E6D2 loc_808E6D2                             ; CODE XREF: sub_808E694+2Aj
ROM:0808E6D2                 POP     {R1}
ROM:0808E6D4                 BX      R1
ROM:0808E6D4 ; End of function sub_808E694
ROM:0808E6D4
ROM:0808E6D4 ; ---------------------------------------------------------------------------
ROM:0808E6D6                 DCB    0
ROM:0808E6D7                 DCB    0
ROM:0808E6D8 off_808E6D8     DCD off_8505620         ; DATA XREF: sub_808E694:loc_808E6CAr

ROM:0808E6DC sub_808E6DC                             ; CODE XREF: sub_808D644+D6p
ROM:0808E6DC                 PUSH    {R4,LR}
ROM:0808E6DE                 MOVS    R4, R0
ROM:0808E6E0                 LDRB    R0, [R4,#5]
[B][COLOR="red"]ROM:0808E6E2                 CMP     R0, #239[/COLOR][/B]
ROM:0808E6E4                 BLS     loc_808E6F2
ROM:0808E6E6                 ADDS    R0, #0x10
ROM:0808E6E8                 LSLS    R0, R0, #0x18
ROM:0808E6EA                 LSRS    R0, R0, #0x18
ROM:0808E6EC                 BL      sub_809D6D0
ROM:0808E6F0                 STRB    R0, [R4,#5]
ROM:0808E6F2
ROM:0808E6F2 loc_808E6F2                             ; CODE XREF: sub_808E6DC+8j
ROM:0808E6F2                 POP     {R4}
ROM:0808E6F4                 POP     {R0}
ROM:0808E6F6                 BX      R0
ROM:0808E6F6 ; End of function sub_808E6DC


As you have probably noticed by now, this routine has four checks. I can tell you that the 1st, 3rd, and 4th checks match up in the same order that they do in Ruby and FireRed.

But what about that second check? After some guessing and playing, I figured it out. It checks specifically for this guy's sprite:

69_0_zpse8bb40f7.png


In all of the other games in which he appears, his sprites were kept together. However in Emerald, there is only one usable sprite: #69.

The other ones are at the end of the table, above the old limits, and auto default to other sprites when used in game. When you use sprite number 69, it activates a section of the OW loading routine that allows the sprite shown on screen to be changed (to one of his other colors at the end of the table) depending on certain conditions such as his location in the game (bank and map number) and the data of your save file.

In theory, this check could be used to create OWs that could be randomized, and ideally, unique, per game save. I don't know if it can be done, but it definitely would be a cool feature.

So, when you are expanding your OWs in Emerald, keep this guy in mind and try to leave his sprites in order and when you change one, change them all. He is the only NPC sprite to vary like he does, so it is kind of cool.:)

As I said before, the other three checks work exactly as they do in Ruby and FireRed so here are the offsets that need to be changed in Emerald to the number of OWs you want to have. Since Emerald has 246 OWs already, your best bet is to just go straight for 255 and change the main limit locations to 0xFF, but remember, since this goes over 239, you will have to deal with Part 2.5:

Emerald(BPEE):
•0x8E6C4

Now you know how to get the most OWs possible without having problems with the dynamic ones in the major Advance Gen games.:D Have fun!



Part 2.5: Dealing with Dynamic Over Worlds

Above you learned that in RSE, OWs 240+ are used for secret bases. If we change their checks, then it prevents your dolls and cusions from being used in your secret bases. So, Darthatron and I worked out a way to fix this. I suggested just checking if you were in a secret base and then running the original routine if that was true. He found where the secret base byte was and I tried writing a nice routine. I failed miserably after 2 hours of hard work, lol. Then, Darth wrote up a routine in 10 minutes to fix it. (I guess I need some more practice, haha) What his routine does is it just skips the checks used for secret bases when you are not in them. After we worked out the bugs in Ruby, I ported it over to Emerald. Simple, but effective. There are only 3 problems (2 of which I provide a fix for):

1) Outside of S.B.s, sprite 240 is the always the opposite gender of the player making it the rival sprite. I don't have a fix for this yet. You can still do it the old fashion way by having two different sprites on the map and only showing the relevant one.

2) A-map loads the OWs by searching for the routine that comes just before the pointer. This fix changes that routine, which means A-map won't be able to load the OWs without a change to the .ini file. I will provide this change attached at the end of this post. My best suggestion is to make a second copy of A-map that will use this .ini so that you won'thave to keep switching them out.

3) This one is really simple; your player's rooms are not secret bases, so the decorations won't be diplayed correctly. Just change the map type in A-map to "Secret Base" for those 2 rooms and you should be fine.


With the above mentioned, let's move on to how to apply this hack. If you are decent with ASM, then feel free to do it yourself. Here is the source code:

Spoiler:



However, most of you will look at the above and go, "Say what?" So, I will simplify it for you.



~Ruby Fix (AXVE)~

1) Paste both of these lines of code somewhere in the free space of the rom using a hex editor:

Routine prt1:
Code:
01 1C 04 48 00 78 09 28 01 D0 04 48 00 47 02 48 00 47 C0 46 3F E8 02 02 17 BC 05 08 29 BC 05 08

Routine prt2:
Code:
04 1C 04 48 00 78 09 28 01 D0 04 48 00 47 60 79 01 49 08 47 3F E8 02 02 47 BC 05 08 57 BC 05 08

2)Those were the main routines. Now, we must branch to them. So, go to offset 5BC10 in your rom.

3)Now, we shall make these changes:

----------------------------
@5BC12-> change "00 06 01 0E" to "09 49 08 47".

@5BC36-> change "02 BC 08 47 00 00" to "00 BD XX XX XX XX" where XX XX XX XX is the pointer to the location where you placed "Routine prt1 + 1".

@5BC42-> change "04 1C 60 79" to "18 4C 20 47".

@5BCA2-> change "01 BC 00 47 00 00" to "00 BD XX XX XX XX" where XX XX XX XX is the pointer to the location where you placed "Routine prt2 + 1".
----------------------------




~Emerald Fix (BPEE)~

(yeah, I just copied and pasted the Ruby part and changed the offsets and data;p)

1) Paste both of these lines of code somewhere in the free space of the rom using a hex editor:

Routine prt1:
Code:
01 1C 04 48 00 78 09 28 01 D0 04 48 00 47 02 48 00 47 C0 46 2F 73 03 02 9B E6 08 08 C5 E6 08 08

Routine prt2:
Code:
04 1C 04 48 00 78 09 28 01 D0 04 48 00 47 60 79 01 49 08 47 2F 73 03 02 E3 E6 08 08 F3 E6 08 08

2)Those were the main routines. Now, we must branch to them. So, go to offset 8E694 in your rom.

3)Now, we shall make these changes:

----------------------------
@8E696-> change "00 06 01 0E" to "0F 49 08 47".

@8E6D2-> change "02 BC 08 47 00 00" to "00 BD XX XX XX XX" where XX XX XX XX is the pointer to the location where you placed "Routine prt1 + 1".

@8E6DE-> change "04 1C 60 79" to "18 4C 20 47".

@8E73E-> change "01 BC 00 47 00 00" to "00 BD XX XX XX XX" where XX XX XX XX is the pointer to the location where you placed "Routine prt2 + 1".
----------------------------



And now, you're done! Not so bad huh?

Remember to change your A-map .ini (best to just create a second copy of A-map to use it), that the rival sprite won't work (Maybe I'll find a fix:D), and to change your rooms' map type to Secret Base.


Dealing with FireRed

In FireRed, I mistakenly assumed (you know what they say about assuming:p) that we wouldn't have any problems because we don't have secret bases. I was very wrong. The Union Room definitely uses dynamic OWs and it is most likely also the case when it comes to the trainer tower. So, I have created another port of the Ruby routine for FR. This routine, like the others will only allow the dynamic OWs to be dynamic on maps whose type is 09 (secret base). On any other map, these OWs will act like regular OWs, just showing up like you see them in NSE.

Here is the source code:
Spoiler:



-Just as a side note, when I was porting this routine, I noticed that, besides offsets, both routines are exactly the same. Just a little bit more proof for the argument that FR is a heavily modified version of Ruby.:p-

Once again, I know you probably don't understand much of that fix, so I will dumb it down a lot:


~FireRed Fix (BPRE)~

-Just as a fair warning, I did not test this routine since it was all just offset changes from Ruby. I have double-checked all of the offsets, so it should work. If you have a single problem, be sure to let me know.

1) Paste both of these lines of code somewhere in the free space of the rom using a hex editor:

Routine prt1:
Code:
01 1C 04 48 00 78 09 28 01 D0 04 48 00 47 02 48 00 47 C0 46 3F 13 6E 03 CF F2 05 08 E1 F2 05 08

Routine prt2:
Code:
04 1C 04 48 00 78 09 28 01 D0 04 48 00 47 60 79 01 49 08 47 3F 13 6E 03 FF F2 05 08 0F F3 05 08

2)Those were the main routines. Now, we must branch to them. So, go to offset 5F2C8 in your rom.

3)Now, we shall make these changes:

----------------------------
@5F2CA-> change "00 06 01 0E" to "09 49 08 47".

@5F2EE-> change "02 BC 08 47 00 00" to "00 BD XX XX XX XX" where XX XX XX XX is the pointer to the location where you placed "Routine prt1 + 1".

@5F2FA-> chnage "04 1C 60 79" to "18 4C 20 47".

@5F35A-> change "01 BC 00 47 00 00" to "00 BD XX XX XX XX" where XX XX XX XX is the pointer to the location where you placed "Routine prt2 + 1".
----------------------------






Also, if you notice any other areas where the sprites do not appear correctly, try changing that map type to 09 (secret base) in A-map. Places like the Battle Tower/Frontier most likely use dynamic OWs. If you find a location not listed here, feel free to comment with it. I will try and make a list of all of the locations.



--On a final note, Advance Map was never designed to support expanded OWs, therefore, it is highly likely that your sprites will not show up properly in A-map.--


Well, that should be it,

Good Luck!



~Credits:~
  • Darthatron- For putting up with my many, many questions and providing the original main OW limiter in FR. Also for his original Advanced OW tutorial which was the main reason I downloaded a hex editor!
  • Shinyquagsire- For also putting up with my many questions and his ASM tutorial.:)
  • Jambo51- Once again, answering my many questions, and helping me with my grammar.:D
  • Bela, ShinyDragonHunter, and MrAPT1- For listening to me for hours on IRC and constantly throwing out suggestions on what each check could mean and how they relate. Bela especially for forcing me to take a closer look at the S.S. Anne and SDH for making me look into Emerald.
  • HackMew- For his ASM tutorial which got me started on learning ASM. It took me three tries to finally work up the courage to read the whole thing:p.



Locations that need to be changed to map type Secret Base:

Ruby:
-Your Room
-Your Rival's Room
-Battle Tower
-Pokemon Contests
-Southern Island
-Locations which show Team Aqua and Team Magma (they do it this way to save space between Ruby and Saphire)


Emerald
-Your Room
-Your Rival's Room
-All of the Battle Frontier
-Pokemon Contests
-Southern Island


FireRed
-Trainer Tower
-Union Room


~Please note that most of these do not need to be done if you are removing/modifying that feature from your hack, such as Team Aqua/Magma, Union Room, Southern Island, ect~


? => need confirmation.

 
Last edited:

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
why dont you use the tool overworld changer?

The original tutorial was written about 6 months before NSE Classic was released and I believe before even OW changer. Darthatron did a lot of work with learning the structure of OWs and many people, like JPAN and myself, learned how to hex edit them and work with them from his original tutorial.

That being said, I included the original tutorial becuase Part 2 makes a lot more sense when you have Part 1 right in front of you. The is no tool, or even documentation, that people can find on what is covered in Part 2.



--------

I would like to say that last night me and Darthatron began working on a branch from the original routine in order to allow the use of OWs over 240 with secret bases. Hopefully we can get it done, and then you can have both.:)
 
265
Posts
11
Years
But the overworld changer tool is much quicker and better to resize the overworld sprites.
 

Darthatron

巨大なトロール。
1,152
Posts
18
Years
But the overworld changer tool is much quicker and better to resize the overworld sprites.

Sometimes people like to know how and why things work. It's called "learning." And what karatekid552 has done is what we call "ROM hacking." It's what you are supposed to do in the "ROM Hacking" section.

Might I ask why that tool is better? Quicker, sure. But why better?
 

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
Sometimes people like to know how and why things work. It's called "learning." And what karatekid552 has done is what we call "ROM hacking." It's what you are supposed to do in the "ROM Hacking" section.

Might I ask why that tool is better? Quicker, sure. But why better?

I would also like to add, that at least on my copy of OW changer, I have noticed several bugs. It refuses to let me type in the dynamic option box, so I have to type in the static and then change my options. From there, it refuses to accept the offset I give it, instead going to the first free space it finds before the offset I selected. This means I really have absolutely no control, whatsoever where the images are placed.

Finally, this is the biggest kicker. You can't repoint more than one OW at a time, otherwise it just overwrites the image space you used for the last one. This is definitely not good if you need to get a large number of OWs resized at once.



Also, did you even read my post???? Daratron's tutorial is in there so that Part 2 fits with Part 1. I know there are tools for it. But his was written before them. It also teaches you how OWs are stored and work, which is extremely important for knowing how to make things go the way you want when you start thinking outside the box, for example making huge OWs like the S.S. Anne which you cannot do in a tool. None of them will let an OW exceed 64x64, but yet some have to be.

My tutorial is about changing the number of OWs in total, something that not a single tool can do, (except JPAN's hacked engine, but that is only for FR 1.0).

If you think I'm being a jerk, you'll understand when, as Darth stated, you actually dig into the code and do some real hacking. Tools are how you start off, but the best parts of hacking, the ones that take you over the top, there is no tool for. Take this lesson to heart. It is one that took me a while to learn, but it is amazing what can be done once you leave the "blockyness" of tools behind. I love them, don't get me wrong, but if they are all you use, your hack will never excell.



Now Darthatron, let's get that secret base routine patched up. First we need to find where the map header is stored. I'm thinking of saving the RAM and searching it for the header that is found in the rom. Good idea?
 
Last edited:

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
bUT Karatekid this turiotial is hard!!!! please try and make a tool as soon as possible


On a scale of 1-10, my programing skill is a 0.1. I just started.

I know it is hard, but real rom hacking is hard. Here are two quotes I really want you to ponder on:

Rarely do we find men who willingly engage in hard, solid thinking. There is an almost universal quest for easy answers and half-baked solutions. Nothing pains some people more than having to think.

-Martin Luther King, Jr.


Happiness does not come from doing easy work but from the afterglow of satisfaction that comes after the achievement of a difficult task that demanded our best.

-Theodore Isaac Rubin
 

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
Now that that is over, I bring great news!!!!!! Me and Darth (96% Darth actually:p) have solved the problem of secret bases in Ruby. I have a completely running copy with 256 OWs and fully functional secret bases sitting on my desktop right now!!:D As soon as I port it over to Emerald, I will edit the tutorial to teach you how to fix it!

Edit: I finished porting the routine today. I haven't had a chance test it, but once it is confirmed, I will update this tutorial.
 
Last edited:

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
On other news, I am testing the ported routine right now!

Edit: It appears to work well, however, I forgot that you can place decorations in your room...... I wonder if we can just change your room to secret base and have it work fine....

Edit2: yup, that is a fix. But I found one more problem:/. With this hack aplied, A-map gives the error: The position SpriteHeader could not be found!

Any ideas? I didn't move the location of the pointer to the sprite bank....

Edit3: Searching through the .ini I found that it appears to search for the routine which I just edited, which allows it to know where to load sprites from:/. I'll find a fix for this, I just hope I don't have to edit the .ini because then clean roms won't work of any kind due to the fact searches for the same SpriteHeader in all of the games, it is just one line in the ini:(
 
Last edited by a moderator:

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
UPDATED!!!!!

I finally finished part 2.5 which will allow people to fix the Secret Base issue in RSE. Maybe I will get around to looking into a fix for the rival sprite issue, but it isn't a priority. I will see what I can do. Have fun maxing things out!


Lastly, in case anyone is wondering, me and HackStar worked everything out.
 

thizzman

PKMN rom maker and hacker
32
Posts
11
Years
  • Age 33
  • Seen Jun 9, 2022
Nice Job Karatekid!!! And I'm glad you figured out the secret bases in r/s/e.
I really love reading advanced tutorials like this, as they help understand things in detail rather than using some tool, in this case OW changer. Hoping for some more tutorials like this (:
 

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
Is there a way to add more OW-palettes without JPANs hacked engine?

Yes, you can just repoint the table. I don't know if there are any limiter bytes that would prevent this though. Also, there is a certain amount of ow palettes that are allowed on screen at once, which is why the game had such a low number to begin with. I don't know the exact number though.

Nice Job Karatekid!!! And I'm glad you figured out the secret bases in r/s/e.
I really love reading advanced tutorials like this, as they help understand things in detail rather than using some tool, in this case OW changer. Hoping for some more tutorials like this (:

Thanks:p I'm looking into making one for Trainer Sprites. So far I know that there are about 6 different routines which reference the table, all of which have limiter bytes.

------

I also just learned, that while FR doesn't have secret bases, it does have the union room, which won't work properly (I think) with my (Darth's, lol) routine as it uses the variable sprites over 240. This needs more research though, and I don't know if anybody really needs the union room... Lol


Edit: Due to the above and some more thoughts about the OWs over 240, I am going to need to rework a lot of my tutorial to account for it. Please keep an eye out for it.
 
Last edited:

karatekid552

What happens if I push it?....
1,771
Posts
11
Years
oh!!!then what will happen if i incase dont follow part 2.5

If you can avoid it, don't expand over 240. I have to rework everything so that the Dynamic OWs used in the Trainer Tower and the Union Room don't have problems. What was addressed in Part 2.5 will soon have to worked into FR for similar issues but in different areas, when I find the time.

edit: I am in the proccess of redoing Part 2 and 2.5 in an effort to completely prevent any problems with the dynamic OWs. I just need to finish porting the routine to FR. What could really help me is a list of maps in Ruby, Emerald, and FR that have OWs which use sprites 240+ as these will be dynamic.


~~~~~~~~~~~~~~~

Updated! I redid most of Part 2 to flow better into 2.5 and added a section for FR and a list of possible locations for dynamic OWs in all of the games. I also posted an updated A-Map Ini to support FR.
 
Last edited:
Back
Top