’Cause all games were better on the GBC

You are not logged in.

#1 1970-01-01 00:33:30

Registered: 2010-10-16
Post 1/156

Town Map (arangement data)

The town map in RBGY is stored using RLE(Run Lenth Encoding) compression,

So for example you want to lay down 4 land tiles you would with out RLE
compression: 06 06 06 06, which RLE compression you write the Hexadecimal
number of the Tile down then the number of times you would like to lay it
down on the screen, e.g. 64.

I recomend repointing your maps data for saftey purposes as you may run out of
room and not realise that you are writing over important data.

The maps pointer is at:

Kanto's Map is between:

0 - Blank Tile (DONT USE!)
1 - Alternate Land Route Across
2 - Alternate Land Route Up
3 - Alternate Land mark
4 - Water
5 - Town
6 - Land
7 - White Title/Path
8 - North East Lands end
9 - North West Lands End
A - South West Lands End
B - South East Lands End
C - Land mark
D - One Sea Route Dot
E - Sea Dot Across
F - Sea Dot Up

I recomend doing your map in GSC first which uses no compression with its town
map, then use it as a guide to create your RBGY version, iv found it is easiest
to do it line by line, then when you have typed in each line indicate that you
have somehow so you know where you are, like I did with Crion for my Red hack
'Pokemon Violet':

Line One - 48 91 61 81 44 A1 64 - Yes
Line Two - 41 91 61 81 42 91 61 51 62 45 64 - Yes
Line Three - 41 61 C1 61 41 91 62 71 61 51 81 44 A1 63 - Yes
Line Four - 41 A1 71 B1 41 61 73 61 71 B1 45 63 - Yes
Line Five - 42 C1 41 91 61 51 63 71 B1 45 A1 62 - Yes
Line Six - 42 71 91 75 61 51 61 81 45 62 - Yes
Line Seven - 42 71 61 71 61 51 61 71 61 71 62 45 A1 61 - Yes
Line Eight - 91 81 71 61 71 B1 F1 A1 71 61 C1 61 B1 47 - Yes
Line Nine - 72 51 72 41 F1 41 71 63 (49:Last tile 1st tile on L.10) - Yes
Line Ten - A1 61 B1 41 F1 91 71 51 71 C1 81 41 91 61 81 (47:Last 4 tiles
1st on line 11)
- Yes
Line Eleven - 91 61 71 62 71 66 B1 42 91 - Yes
Line Twelve - 44 A1 61 C1 62 71 65 B1 42 91 61 - Yes
Line Thirteen - B1 61 A1 42 64 51 73 51 71 E3 C1 61 - Yes
Line Forteen - 61 51 71 E2 C1 62 B1 F1 A1 64 81 42 A1 61 - Yes
Line Fifteen - A1 62 81 41 A1 B1 42 F1 42 A1 B1 A1 B1 (45:Last tile 1st tile on
L.16) - Yes
Line Sixteen - A1 61 B1 45 F1 4F:Last 5 tiles 1st tiles on L.17) - Yes
Line Seventeen - 44 F1 4A - Yes

A big thankyou has to go out to a guy called Hyperhacker who first found the
maps location in the first place and how it is stored.


#2 2013-03-29 01:02:25

Registered: 2013-02-20
Post 1/95

Re: Town Map (arangement data)

I can't answer your question, 80C, but I would like to expand on what Cartmic posted, since I just worked on the town map the other day.

Here is some more information about the town map:

To change the locations of the towns and routes, and possible re-point them if you change the names:

This was taken from the disassembly project:

ExternalMapEntries: ; 1c:5313
    EMAP $2,$B,PalletTownName
    EMAP $2,$8,ViridianCityName
    EMAP $2,$3,PewterCityName
    EMAP $A,$2,CeruleanCityName
    EMAP $E,$5,LavenderTownName
    EMAP $A,$9,VermilionCityName
    EMAP $7,$5,CeladonCityName
    EMAP $8,$D,FuchsiaCityName
    EMAP $2,$F,CinnabarIslandName
    EMAP $0,$2,IndigoPlateauName
    EMAP $A,$5,SaffronCityName
    EMAP $0,$0,PalletTownName ; unused
    EMAP $2,$A,Route1Name
    EMAP $2,$6,Route2Name
    EMAP $4,$3,Route3Name
    EMAP $8,$2,Route4Name
    EMAP $A,$3,Route5Name
    EMAP $A,$8,Route6Name
    EMAP $8,$5,Route7Name
    EMAP $D,$5,Route8Name
    EMAP $D,$2,Route9Name
    EMAP $E,$4,Route10Name
    EMAP $C,$9,Route11Name
    EMAP $E,$9,Route12Name
    EMAP $D,$B,Route13Name
    EMAP $B,$C,Route14Name
    EMAP $A,$D,Route15Name
    EMAP $5,$5,Route16Name
    EMAP $4,$8,Route17Name
    EMAP $6,$D,Route18Name
    EMAP $6,$F,Route19Name
    EMAP $4,$F,Route20Name
    EMAP $2,$D,Route21Name
    EMAP $0,$8,Route22Name
    EMAP $0,$6,Route23Name
    EMAP $A,$1,Route24Name
    EMAP $B,$0,Route25Name

InternalMapEntries: ; 1c:5382
    IMAP $29,$2,$B,PalletTownName
    IMAP $2E,$2,$8,ViridianCityName
    IMAP $33,$2,$6,Route2Name
    IMAP $34,$2,$4,ViridianForestName
    IMAP $3B,$2,$3,PewterCityName
    IMAP $3E,$6,$2,MountMoonName
    IMAP $44,$A,$2,CeruleanCityName
    IMAP $45,$5,$2,Route4Name
    IMAP $46,$A,$2,CeruleanCityName
    IMAP $49,$A,$4,Route5Name
    IMAP $4C,$A,$6,Route6Name
    IMAP $4F,$9,$5,Route7Name
    IMAP $51,$B,$5,Route8Name
    IMAP $53,$E,$3,RockTunnelName
    IMAP $54,$F,$4,PowerPlantName
    IMAP $57,$D,$9,Route11Name
    IMAP $58,$E,$7,Route12Name
    IMAP $59,$C,$0,SeaCottageName
    IMAP $5F,$A,$9,VermilionCityName
    IMAP $69,$9,$A,SSAnneName
    IMAP $6D,$0,$4,VictoryRoadName
    IMAP $77,$0,$2,PokemonLeagueName
    IMAP $78,$A,$5,UndergroundPathName
    IMAP $79,$0,$2,PokemonLeagueName
    IMAP $7A,$A,$5,UndergroundPathName
    IMAP $8D,$7,$5,CeladonCityName
    IMAP $8E,$E,$5,LavenderTownName
    IMAP $95,$F,$5,PokemonTowerName
    IMAP $98,$E,$5,LavenderTownName
    IMAP $9C,$8,$D,FuchsiaCityName
    IMAP $9D,$8,$C,SafariZoneName
    IMAP $9F,$8,$D,FuchsiaCityName
    IMAP $A3,$5,$F,SeafoamIslandsName
    IMAP $A4,$A,$9,VermilionCityName
    IMAP $A5,$8,$D,FuchsiaCityName
    IMAP $A6,$2,$F,PokemonMansionName
    IMAP $AE,$2,$F,CinnabarIslandName
    IMAP $AF,$0,$2,IndigoPlateauName
    IMAP $B8,$A,$5,SaffronCityName
    IMAP $BA,$9,$D,Route15Name
    IMAP $BD,$4,$5,Route16Name
    IMAP $BE,$E,$A,Route12Name
    IMAP $C0,$7,$D,Route18Name
    IMAP $C1,$5,$F,SeafoamIslandsName
    IMAP $C2,$0,$7,Route22Name
    IMAP $C3,$0,$4,VictoryRoadName
    IMAP $C4,$E,$7,Route12Name
    IMAP $C5,$A,$9,VermilionCityName
    IMAP $C6,$3,$4,DiglettsCaveName
    IMAP $C7,$0,$4,VictoryRoadName
    IMAP $CF,$7,$5,RocketHQName
    IMAP $D6,$A,$5,SilphCoName
    IMAP $D9,$2,$F,PokemonMansionName
    IMAP $E2,$8,$C,SafariZoneName
    IMAP $E5,$9,$1,CeruleanCaveName
    IMAP $E6,$E,$5,LavenderTownName
    IMAP $E7,$A,$2,CeruleanCityName
    IMAP $E9,$E,$3,RockTunnelName
    IMAP $ED,$A,$5,SilphCoName
    IMAP $F8,$0,$2,PokemonLeagueName
    db $FF

The external maps work just as you'd expect, if you are in any of those towns/routes, it will look at that table and get the location and text string from the row that corresponds to the map you are in.
The first nibble (half-byte) is the Y location (from the top) [0-F]
The second nibble is the X location (from the left) [0-F]
Those are both combined into byte, so for pallet town, they combine and is displayed as $2B
The following word (2 bytes) is the pointer to the name of the location (in bank 1C, the names start at 1C:5473)

The internal maps are slightly different.  The idea is that if you are not in one of the routes or towns, then you are in a building or a cave.  Since these are not necessary shown on the map, the game looks through this table to determine which location (on the map) it should indicate you are at and which name it should display.
The first byte indicates the hexadecimal ID number for the map. (I'll get back to this)
The following byte is the Y/X location. (combined, as above)
The end word is the text pointer to the name of the location.

The game determines which row from the table to use by comparing to the ID of the map to the first byte in the row.  If the map value is BELOW the value indicated, it will use that line.  If not, it will check the next line.

For example, Viridian Forest is ID $33
The following lines are in the table:

IMAP $2E,$2,$8,ViridianCityName
IMAP $33,$2,$6,Route2Name
IMAP $34,$2,$4,ViridianForestName

The game compares the map id ($33) to the ID in the ID stored in the top line.  $33 is not below $2E, so it checks the next line.
Again, $33 is not below $33 (they are equal), so it checks the value against the next line.
In this case, the map ID ($33) IS below the value in the row ($34), so it uses that row to display the location and name of Viridian Forest on the map.

As you can see, this allowed the for multiple buildings / caves to be grouped together to a single location and text pointer.  For example, the SS Anne maps are from $5F-$68.  The code in the game reads:

IMAP $5F,$A,$9,VermilionCityName
IMAP $69,$9,$A,SSAnneName

In this case, all of the maps for the SS Anne will fail the check on the top line, but pass the check for the next line (they are all >= $5F and <$69).


To change the order that the towns/routes appear when you cycle through the map:

To do this, simply replace the values from 1C:4F11 - 4F41 to the ID's of the maps that you want to appear on the map, in order.  If you don't want to use all of the spaces, replace the remaining ones with FE (when the game see an FE, it will skip to the next location)


To change the order that the towns appear when you cycle through the map while using FLY:

This starts are 1c:5070.

This one is a bit tricky, but I'll try to explain how it works:
First off, know that the bytes in ram that indicate which towns you can fly to are stored in D70B-D70C.
Second, know that the game stores the flyable map IDs in CD3D-CD49.
hl is then set to CD3D.
The first step is to set (hl) [this means the value stored at the pointer saved in hl] to FF, to indicate that it is the beginning of the list.
It then increments hl, so it now points to the first item in the list.
The game then checks each bit (starting with bit 0 of D70B, up to bit 2 of D70C) to see if it is set or not.
If it is set, it places the number of the bit [from 0-0B, where bit 0 if D70B = 0, and bit 2 of D70C = 2b] at the location that hl points to.
If it is not set, it places FE are the location that hl points to. [FE means skip to the next item]
It then increments hl to have it point to the next item in the list.
(it then loops and checks the next bit)
Finally, after it checks through all of the bits, it places FF at the location that hl points to, which is CD49.  This shows that it is the end of the list.

Now, this code is hard to modify because it is a single loop and the map ID that is saved is simply one higher than the previous.
I recommend simply writing your own routine to check each town bit in the order that you want it to display.  To do this, you first have to repoint the call to your custom script.

The call for this script is at 1c:4fb4.
At this location, you want to replace

call 5070


call LocationOfNewScript

Here is the example of the script that I have for my game.  I have changed the order of the town appearances in the game, and the script checks each map in the order that I want them to appear in the flyable map list.

Script starts at 1c:7cd0:

ld hl,cd3d        ;load start location
ld (hl),ff        ;place beginning ff and increase hl
inc hl
ld bc,000c        ;number of towns [I ADDED A TOWN, IF YOU ARE TO COPY THIS SCRIPT, USE ld bc,000b]

;this loop pre-sets every value in the array of towns (from CD3D-CD49, not inclusive) to FE
ld (hl),fe        ;place SKIP
inc hl
dec c
jr nz,7cd9        ;loop if not at 0

ld (hl),ff        ;place finisher
ld hl,cd3e        ;load first town location

7CE4: [TOWN1]
ld a,(d70b)        ;load Flyable Maps bit high into a
bit 0,a        ;town 1?
jr z,7CEE        ;jump to town 2 if not
ld (hl),00        ;otherwise, load town 1 into hl and increase
inc hl

bit 1,a        ;town 2?
jr z,7Cf5        ;jump to town3 if not
ld (hl),01        ;otherwise, load town 2 into hl and increase
inc hl

7CF5: [TOWN3]
bit 2,a        ;town 3?
jr z,7CFC        ;jump to town4 if not
ld (hl),02        ;otherwise, load town 3 into hl and increase
inc hl

;the following town is the first one that is out of place when compared to the original map order
;as you can see, I am checking for bit 0 of d70c.  This corresponds to a map id of $08
;The original function would be checking bit 3 of d70b, which corresponds to map id of $08
ld a,(d70c)        ;load Flyable Maps bit low into a
bit 0,a        ;town 4?
jr z,7D06        ;jump to town5 if not
ld (hl),08        ;otherwise, load town 4 into hl and increase
inc hl

7D06: [TOWN5]
bit 2,a        ;town 5?
jr z,7D0D        ;jump to town4 if not
ld (hl),0a        ;otherwise, load town 5 into hl and increase
inc hl

;starting here, the map bits are now located back in byte D70B, so I have to load that back into a
7D0D: [TOWN6]
ld a,(d70b)        ;load Flyable Maps bit high into a
bit 4,a        ;town 6?
jr z,7D17        ;jump to town7 if not
ld (hl),04        ;otherwise, load town 6 into hl and increase
inc hl

;This is the town I added (originally Route 16, map ID $1b)
;this location bit is never checked in the original routine, and is never set unless you change the script that sets the bits
7D17: [TOWN7]
ld a,(d70c)        ;load Flyable Maps bit low into a
bit 3,a        ;town 7?
jr z,7D21        ;jump to town8 if not
ld (hl),1b        ;otherwise, load town 7 into hl and increase
inc hl

;again, switch back to the first byte of the flyable maps
7D21: [TOWN8]
ld a,(d70b)        ;load Flyable Maps bit high into a
bit 5,a        ;town 8?
jr z,7D2B        ;jump to town9 if not
ld (hl),05        ;otherwise, load town 8 into hl and increase
inc hl

7D2B: [TOWN9]
bit 6,a        ;town 9?
jr z,7D32        ;jump to town10 if not
ld (hl),06        ;otherwise, load town 9 into hl and increase
inc hl

7D32: [TOWN10]
bit 3,a        ;town 10?
jr z,7D39        ;jump to town11 if not
ld (hl),03        ;otherwise, load town10 into hl and increase
inc hl

7D39: [TOWN11]
bit 7,a        ;town 11?
jr z,7D40        ;jump to town12 if not
ld (hl),07        ;otherwise, load town11 into hl and increase
inc hl

;Unless you added a town, there should only be 11!!!
7D40: [TOWN12]
ld a,(d70c)        ;load Flyable Maps bit low into a
bit 1,a        ;town 12?
ret z            ;return if not
ld (hl),09        ;otherwise, load town 12 into hl and increase

It's not necessarily the most efficient script, but it gets the job done.  I hope that all made sense!

Last edited by pokeglitch (2013-03-29 04:45:44)


#3 2013-03-29 02:36:17

Registered: 2013-02-20
Post 2/95

Re: Town Map (arangement data)

The code that calls the location of the map information starts at 1C:50CD:

1C:50CD:        ld hl,C3A0            ;this is the top left corner of the visible screen
1C:50D0:        ld de,5100            ;this is the start of the map table

If you want to be careful about not overwriting anything important, you can repoint it by replacing line at 1C:50D0 with

ld hl,PtrToNewMap

as long as the new map is in the same bank.  There is more than enough free space at the end of bank 1C to fit your map.

BUT, you probably don't have to.

The map takes up the space from 1C:5100 to 1C:51AA.  You can see this is the case because there is a 00 at 1C:51AA, and if you look at line 1C:50D3, the map is drawn until it reaches a 00

1C:50D3:        ld a,(de)        ;this loads the next byte of map information
1C:50D4:        and a            ;the AND operation always returns true unless a is 00, in which case it will return a 0
1C:50D5:        jr z,50E9        ;if it returned a 0, then exit the loop

Good luck!

Last edited by pokeglitch (2013-03-29 04:44:15)


#4 2013-03-29 18:32:13

Registered: 2012-04-09
Post 177/679

Re: Town Map (arangement data)

16-bit values are usually read in reverse. You would put in 90 6E in a hex editor.


#5 2013-03-29 21:45:23

Registered: 2012-04-09
Post 180/679

Re: Town Map (arangement data)

You wanted to put it in at 0x710d1.

Last edited by comet (2013-03-29 21:45:41)


#6 2013-03-30 03:31:24

Registered: 2013-02-20
Post 3/95

Re: Town Map (arangement data)

Looks, glad I could help.  Did you manage to change the order of towns when viewing the town map or flying?


#7 2013-03-30 16:14:13

Registered: 2013-02-20
Post 4/95

Re: Town Map (arangement data)

it will be simple to add the map to when you are navigating through the town map, but adding it to the map when flying might be tricky.  In the example I posted for reodering the towns when flying, I added a new town, but I also had to expand the field in the RAM that the game reads from when navigating the map.  So far, it hasn't caused any issues,but it might have overwritten something important.  Still not sure.

but if you do do that, you also want to do the following:

at 1c:5068   [$071068]

replace:    ld hl,cd49
with:        ld hl,cd4a    ;one town was added, so the field got expanded by one byte

That line of code gets run when you reach you are at the beginning of the map and want try to move up the list.  Since you are at the begining, it repoints you to the end and then moves up the list from there.  This change repoints it to one byte further, because the list is one byte longer.

Last edited by pokeglitch (2013-03-30 16:14:40)


#8 2013-06-20 18:48:19

Registered: 2013-03-16
Post 772/1,257

Re: Town Map (arangement data)

I simply had to replace $0B with $0C in the original location of the flight towns order located at 1c:5068, but I've got a very small bug that is identical of one of Pokemon Brown:

When I scroll the locations, if I return back with the reversed order (Pallet town, saffron, indigo etc.) the new town isn't showed, it is showed only if you scroll the locations in the right order.

PS: The Town Map location Order changes worked, thanks a lot.

I left this forum.


Board footer

Powered by FluxBB