Go Back   The PokéCommunity Forums > ROM Hacking > Research & Development
Reload this Page Research Fire Red save data structure

For all updates, view the main page.

Research & Development Got a well-founded knack with ROM hacking? Love reverse-engineering the Pokémon games? Or perhaps you love your assembly language. This is the spot for polling and gathering your ideas, and then implementing them! Share your hypothesis, get ideas from others, and collaborate to create!
Research & Development programs in this forum are subject to moderator approval before they are displayed.

Thread Tools
Old June 1st, 2015 (02:51 PM). Edited June 7th, 2015 by JPAN.
JPAN JPAN is offline
pokemon rom researcher
Join Date: Dec 2008
Posts: 104
This post is about the RAM layout of the three DMA protected blocks, the same ones that are saved in the flash. We shall call them block 8, block C and block 10 after the location of their access address (0x3005008, 0x300500C and 0x3005010). Here are the IDA structures that represent them:
00000000 SaveBlock8      struc ; (sizeof=0x3D68)
00000000 player_map_x    DCW ?                
00000002 Player_map_y    DCW ?
00000004 currentMap      Warp_struct ?
0000000C field_C         Warp_struct ?
00000014 last_used_empty_teleporter Warp_struct ? ; used for doors such as the trade center ones, to determine where
00000014                                         ; the warp will go
0000001C last_healing_spot Warp_struct ?         ; used to determine where teleport and escape rope will lead you
0000001C                                         ; (may be useful to create alternate teleport locations)
00000024 Last_used_warp  Warp_struct ?           ; last warp that caused a transition
0000002C map_song        DCW ?
0000002E field_2E        DCB ?
0000002F current_weather DCB ?
00000030 used_flash?     DCB ?
00000031 field_31        DCB ?
00000032 map_footer_no   DCW ?
00000034 party_size      DCD ?
00000038 Poke1           Poke100Bytes ?
0000009C Poke2           Poke100Bytes ?
00000100 Poke3           Poke100Bytes ?
00000164 Poke4           Poke100Bytes ?
000001C8 Poke5           Poke100Bytes ?
0000022C Poke6           Poke100Bytes ?
00000290 money           DCD ?
00000294 coins           DCW ?
00000296 registered_item DCW ?
00000298 Item_PC_storage Item_entry 30 dup(?)    ; Only set of items that is not encrypted
00000310 General_items   Item_entry 40 dup(?)    ; Items are encrypted with the other block 0xf20 key
000003B0 key_Item        Item_entry 32 dup(?)
00000430 pokeBalls       Item_entry 13 dup(?)
00000464 TMs             Item_entry 58 dup(?)
0000054C Berries         Item_entry 43 dup(?)
000005F8 pokedex_seen_flags_1 DCB 52 dup(?)      ; also on 28 and 5c of 300500c, and on 3a18 of this block
0000062C unknown         DCB 12 dup(?)
00000638 VS_seeker_step_counter DCW ?
0000063A rebattle_counter DCB 100 dup(?)         ; if = 0, trainer is not rebattled. 1 = rebattle first time, 3=
0000063A                                         ; rebattle later times.
0000063A                                         ; Based on person number (not OW event number, from map structure),
0000063A                                         ; seem capable of up 100 people events on map
0000069E field_69E       DCW ?
000006A0 OW_ram          Ram_OW_struct 16 dup(?)
000008E0 map_OW_copy     MapOwData 64 dup(?)     ; beggining of data structure holding current map OWs
000008E0                                         ; (same structure as map, 20bytes per person, at least support
000008E0                                         ; for 15 characters)
00000EE0 flags           DCB 288 dup(?)          ; 0x900 flags
00001000 variables       DCW 256 dup(?)          ; 0x4000->0x407f are all available variables
00001200 encrypted_Counters DCD 64 dup(?)        ; Encrypted counters. 64 word-sized encrypted counters.
00001200                                         ; Count stuff such as number of saves, or splashes used
00001300 previously_array Previously_save_block 4 dup(?)
00002CA0 field_2CA0      DCB 48 dup(?)           ; Quick chat words for the link function
00002CA0                                         ; 2ca0 = 6 hwords (Default "I am a Pokemon friend!")
00002CA0                                         ; 2cac = 6 hwords (Default "Are you ready? Here I come!")
00002CA0                                         ; 2cb8 = 6 hwords (default empty)
00002CA0                                         ; 2cc4 = 6 hwords (default empty)
00002CA0                                         ; as extracted from 80BDD34
00002CD0 party_mail      mail 6 dup(?)
00002DA8 pc_mail         mail 10 dup(?)
00002F10 field_2F10      DCB 112 dup(?)          ; 2f10 = 40 bytes
00002F10                                         ; 2f38+ = ??
00002F80 breeding_center pokemon_daycare ?
0000309C field_309C      DCB 11 dup(?)           ; no idea, but is 11 bytes, as used in some link function
000030A7                 DCB ? ; undefined
000030A8 field_30A8      DCB 40 dup(?)           ; unkown- not found
000030D0 field_30D0      Roaming_legend ?        ; a block containing information on the roaming legend.
000030D0                                         ; C holds its level
000030EC eReaderBerryStruct berry_struct ?
00003108 field_3108      DCB 18 dup(?)
0000311A e_berry_special DCB ?                   ; =26, allows enigma replacement to stone-evolve pokes
0000311B field_311B      DCB ?
0000311C e_berry_checksum DCD ?
00003120 field_3120      DCD ?
00003124 field_3124      DCB 444 dup(?)
000032E0 field_32E0      DCD ?
000032E4 field_32E4      DCB 332 dup(?)
00003430 field_3430      DCD ?
00003434 field_3434      DCB 36 dup(?)
00003458 field_3458      DCW 4 dup(?)
00003460 field_3460      DCD ?
00003464 field_3464      DCB 20 dup(?)           ; see 8144790
00003478 field_3478      DCD ?
0000347C field_347C      DCB 416 dup(?)          ; unknown
0000361C field_361C      DCD ?
00003620 field_3620      DCB 1000 dup(?)
00003A08 field_3A08      DCB 16 dup(?)           ; not found
00003A18 pokedex_seen_flags_2 DCB 52 dup(?)
00003A4C rival_name      DCB 8 dup(?)
00003A54 fame_checker_flags DCD 16 dup(?)
00003A94 field_3A94      DCB 64 dup(?)           ; unkonwn-not found
00003AD4 field_3AD4      Greetings ?             ; 21 byte strings *10
00003BA6 field_3BA6      DCW ?                   ; padding?
00003BA8 field_3BA8      DCB 240 dup(?)          ; 12*20
00003BA8                                         ; Seems to be related to the union room.
00003C98 old_daycare     daycare_pkmn ?
00003D24 field_3D24      DCB 16 dup(?)           ; seem unused
00003D34 field_3D34      DCD ?                   ; used by trainer tower
00003D38 key_struct_array key_struct 4 dup(?)
00003D68 SaveBlock8      ends
00000000 ; ---------------------------------------------------------------------------
00000000 SaveBlockC      struc ; (sizeof=0xF24)
00000000 PlayerName      DCB 8 dup(?)            ; FF terminated, so 7 character
00000008 playerGender    DCB ?                   ; 0 for male, 1,2,3 = female, >4 = null
00000009 field_9         DCB ?                   ; used for someting, seems like a bitfield. bits 0,1,2,3 are
00000009                                         ; used in some functions
0000000A ID              DCW ?
0000000C SecretID        DCW ?
0000000E time            Time ?
00000013 LR_function     DCB ?                   ; 0 = help, 1 = L=A , 2 = L = left
00000014 Options         DCW ?                   ; bit 0-1 = text speed (3 invalid)
00000014                                         ; bit 2-6 = border num (border = options>>2&7f), valid only to 13
00000014                                         ; bit 7 invalid
00000014                                         ; bit 8 = sound channel (0= mono, 1 = stereo)
00000014                                         ; bit 9 = battle switch (0 = switch, 1 = set)
00000014                                         ; bit 10 = battle anim (0= on, 1 = off)
00000014                                         ; bit 11-16 = unused
00000016 field_16        DCB ?
00000017 field_17        DCB ?
00000018 field_18        DCB ?
00000019 field_19        DCB ?
0000001A field_1A        DCB ?                   ; set as DA when a new game is started
0000001B field_1B        DCB ?                   ; value = b9 while var 0x404e = 0x6258 and flag 0x840 is set
0000001B                                         ; makes national dex active
0000001C first_unown_PID DCD ?
00000020 first_spinda_ID DCD ?
00000024 field_24        DCD ?
00000028 caught_flags    DCB 52 dup(?)
0000005C seen_flags      DCB 52 dup(?)
00000090                 DCB ? ; undefined
00000091                 DCB ? ; undefined
00000092                 DCB ? ; undefined
00000093                 DCB ? ; undefined
00000094                 DCB ? ; undefined
00000095                 DCB ? ; undefined
00000096                 DCB ? ; undefined
00000097                 DCB ? ; undefined
00000098                 DCB ? ; undefined
00000099                 DCB ? ; undefined
0000009A                 DCB ? ; undefined
0000009B                 DCB ? ; undefined
0000009C                 DCB ? ; undefined
0000009D                 DCB ? ; undefined
0000009E                 DCB ? ; undefined
0000009F                 DCB ? ; undefined
000000A0                 DCB ? ; undefined
000000A1                 DCB ? ; undefined
000000A2                 DCB ? ; undefined
000000A3                 DCB ? ; undefined
000000A4                 DCB ? ; undefined
000000A5                 DCB ? ; undefined
000000A6                 DCB ? ; undefined
000000A7                 DCB ? ; undefined
000000A8 field_A8        DCD ?
000000AC field_AC        DCB ?
000000AD field_AD        DCB ?
000000AE                 DCB ? ; undefined
000000AF                 DCB ? ; undefined
000000B0 field_B0        DCB 1012 dup(?)         ; cleaned at start, 1012 bytes
000004A4 field_4A4       DCB 7 dup(?)
000004AB field_4AB       DCB ?
000004AC field_4AC       DCB 1604 dup(?)         ; unknown
00000AF0 field_AF0       DCB 32 dup(?)           ; cleaned on start
00000B10 field_B10       DCB 32 dup(?)           ; cleaned on start
00000B30 field_B30       DCB 1008 dup(?)
00000F20 encryption_key  DCD ?
00000F24 SaveBlockC      ends
00000000 ; ---------------------------------------------------------------------------
00000000 SaveBlock10     struc ; (sizeof=0x83D0)
00000000 current_box     DCD ?
00000004 box_data        box 14 dup(?)           ; 30*80-byte pokemon each box
00008344 box_names       DCB 126 dup(?)          ; 9 bytes name * 14 boxes
000083C2 box_wallpapers  DCB 14 dup(?)
000083D0 SaveBlock10     ends

00000000 ; ---------------------------------------------------------------------------
00000000 Warp_struct     struc ; (sizeof=0x8)
00000000 map_bank        DCB ?
00000001 map_number      DCB ?
00000002 warp_number     DCB ?                   ; FF = warp to given coordinates, regardless of warp
00000003 padding         DCB ?
00000004 x_coord         DCW ?
00000006 y_coord         DCW ?
00000008 Warp_struct     ends
00000000 ; ---------------------------------------------------------------------------
00000000 Item_entry      struc ; (sizeof=0x4)
00000000 item_ID         DCW ?
00000002 item_quantity   DCW ?
00000004 Item_entry      ends
00000000 ; ---------------------------------------------------------------------------
00000000 Previously_save_block struc ; (sizeof=0x668)
00000000 is_present_marker DCB ?                 ; 1 if present, 0 if not present
00000000                                         ; Also affects camera position
00000001 old_map_entry   DCB ?
00000002 old_map_bank    DCB ?
00000003 warp_no         DCB ?
00000004 map_x_pos       DCW ?
00000006 map_y_pos       DCW ?
00000008 person_resume_array DCB 320 dup(?)      ; each person OW is stored in 20 bytes (total 20*16 = 320 bytes)
00000148 old_flag_save_data DCB 144 dup(?)       ; saves 144 bytes worth of flags, from flag 0 to flag 1152
000001D8 field_1D8       DCB 144 dup(?)
00000268 old_var_save_data DCB 256 dup(?)        ; saves 256 bytes worth of variables, or variables 0x4000 to 0x407f
00000368 field_368       DCB 256 dup(?)
00000468 not_found       DCW ?
0000046A field_46A       DCB ?
0000046B not_yet_found_2 DCB ?
0000046C not_yet_found   DCB 252 dup(?)
00000568 OW_movements    DCB 256 dup(?)          ; 8 bytes each, 32 slots total, sum for player and other npc movement
00000668 Previously_save_block ends
00000000 ; ---------------------------------------------------------------------------
00000000 pokemon_daycare struc ; (sizeof=0x11C)
00000000 slot_1          daycare_pkmn ?
0000008C slot_2          daycare_pkmn ?
00000118 egg_structure   DCW ?
0000011A Egg_steps_counter DCW ?
0000011C pokemon_daycare ends
00000000 ; ---------------------------------------------------------------------------
00000000 daycare_pkmn    struc ; (sizeof=0x8C)
00000000 pokemon         Poke80Bytes ?
00000050 poke_mail       mail ?
00000074 OT_Name         DCB 8 dup(?)
0000007C Poke_name       DCB 12 dup(?)
00000088 exp_counter     DCD ?
0000008C daycare_pkmn    ends
00000000 ; ---------------------------------------------------------------------------
00000000 mail            struc ; (sizeof=0x24)
00000000 words           DCW 9 dup(?)
00000012 sender_Name     DCB 8 dup(?)
0000001A OTID            DCD ?
0000001E species_ID      DCW ?                   ; used for special mail that prints a pokemon icon below the mail
00000020 itemID          DCW ?
00000022 padding         DCW ?
00000024 mail            ends
00000000 ; ---------------------------------------------------------------------------
00000000 Roaming_legend  struc ; (sizeof=0x1C)
00000000 IVs             DCD ?
00000004 PID             DCD ?
00000008 legend_species  DCW ?
0000000A current_hp      DCW ?
0000000C legend_level    DCB ?
0000000D status          DCB ?
0000000E contest_stats   DCB 5 dup(?)
00000013 exists          DCB ?
00000014 field_14        DCB 8 dup(?)
0000001C Roaming_legend  ends
00000000 ; ---------------------------------------------------------------------------
00000000 berry_struct    struc ; (sizeof=0x1C)
00000000 name            DCB 7 dup(?)
00000007 Hardness        DCB ?                   ; 1= super soft, 5 = super hard
00000008 size            DCB ?                   ; in cm. 1 = 0.1 cm
00000009 field_9         DCB ?
0000000A field_A         DCB ?
0000000B field_B         DCB ?
0000000C field_C         DCD ?                   ; offset (00000000)
00000010 field_10        DCD ?                   ; offset (00000000)
00000014 growth_time     DCB ?                   ; hours per stage. 3 = 3h per stage = 12h total
00000015 flavor          DCB 5 dup(?)            ; spicy, dry, sweet, bitter, sour
0000001A feel            DCB ?
0000001B field_1B        DCB ?
0000001C berry_struct    ends
00000000 ; ---------------------------------------------------------------------------
00000000 Greetings       struc ; (sizeof=0xD2)
00000000 hello           DCB 21 dup(?)
00000015 pokemon         DCB 21 dup(?)
0000002A trade           DCB 21 dup(?)
0000003F battle          DCB 21 dup(?)
00000054 lets            DCB 21 dup(?)
00000069 ok              DCB 21 dup(?)
0000007E sorry           DCB 21 dup(?)
00000093 yay             DCB 21 dup(?)
000000A8 thank_you       DCB 21 dup(?)
000000BD bye_bye         DCB 21 dup(?)
000000D2 Greetings       ends
00000000 ; ---------------------------------------------------------------------------
00000000 key_struct      struc ; (sizeof=0xC)
00000000 field_0         DCD ?
00000004 key             DCD ?
00000008 field_8         DCD ?
0000000C key_struct      ends
00000000 ; ---------------------------------------------------------------------------
00000000 Time            struc ; (sizeof=0x5)
00000000 hours           DCW ?
00000002 minutes         DCB ?
00000003 seconds         DCB ?
00000004 ticks           DCB ?
00000005 Time            ends
Block 10, the biggest block, is the simplest one to explain. It starts with one 32bit word tracking the last open pokemon box, followed by 14*30 pokemon in 80-byte format and ending with the box names and wallpapers. Block 10 can also be called the Box block.

Block C is the most "mysterious" block, as most of its data is still undocumented. It starts with the player data such as name and IDs, followed by the in-game timer and options.It also stores the ID of the first seen spinda and unown, so the pokedex displays the same one every time, followed by the seen and caught flags. While the caught flags are the only set, the seen flags are also present in two locations on block 8. The remainder of the data is yet undiscovered, with the searching method for unknown fields yielding only the sizes of the memory areas, and not its function.

Block 8 is the one with more to talk about, being almost completely documented. It can be roughly divided into several smaller blocks, starting with a Map block.
The map sub block that contains the player position, the current map, last used warps, map information such as music being played and current weather, ending with the map footer id.
The next sub block is the party sub block, containing a party count and 6 100bytes pokemon slots.
The next sub block is the player belongings sub block. This block stores money, coins, items, the first of the pokedex seen flags and the data used by the VS Seeker.
The next sub block is the OW sub block, containing the RAM structure of OWs for the maximum of 16 on-screen, and up to 64 OW in the same format as found in Advance Map.
The next sub block is the story records sub block, containing 0x900 flags, 128 variables and 64 encrypted counters. Encrypted counters are used by the game to keep metrics, such as the ones shared via record mixing.
The next sub block is the "Previously" sub block, containing 4 slides that store information needed to replicate the map event during the Previously slide show. Each slide contains the map, location, OWs present, a copy of the flags and variables section and 32 movements used during the cutscene, that is shared between NPCs and player.
The next sub block is the quickchat sub block, containing some words that should be used by the link function and the mail storage for both party and PC.
The next sub block is the breeding sub block, containing the breeding daycare center data, such as the 80 byte pokemon, held mail, nickname, OT name and a counter for experience earned. It also contains an egg seed and an egg step counter.
The next sub block is unnamed, and ends with the data for creating and maintaining Roaming Legendary pokemon.
The next sub block is tentatively called the E-reader sub block, since it contains the E-reader berry data and seems to keep the E-reader Trainer data for the battle tower. This block is big and mostly undocumented.
The final sub block is also unnamed, and contains the second set of seen flags, the rival name, the Fame checker flags, a set of 20-character greetings and the Cerulean daycare data.

That's it for the broad view of the save data RAM structure. I'll post more detailed information in subsequent posts.

Two main methods were used to find this information: Breakpoints in VBA debugger and search the ROM for mov/ldr instructions for the block offsets. In order to do so, I developed a tool that searches the ROM for references to a given number, which might be an address or any other number. This tool can search for bl calls, byte references and, when selected, mov/shift combos that load the value onto the registers.
I shall provide the tool as-is in order to facilitate this same research for Emerald.
To start the tool, choose a rom by clicking the ... button. The tool remembers the last open ROM file.
To search for an address, enter it in the "Offset to search for" box and press "Search". The address may be in the 0x80000000-0x9fffffff range or, if the "No offset Correct" box is not ticked, the address can be in the 0x0 to 0x1ffffff range and the program will shift it to the GBA address.
To search for a number that is not an address, the "No offset Correct" must be ticked. If the "Mov/Shift Combo" is ticked, results will include mov/shift load combos.
The tool also includes a jump calculator, that given two addresses, compiles the jump instruction that leads from the start to the finish.

We start the in-depth analyzis by addressing the DMA. Disabling the DMA shifting will provide several advantages:
- Making the blocks static allow for breaks on read/write by the debugger;
- Static blocks can be easily acessed from scripts;
- Stopping the shift means the empty RAM space needed to cushion the changes can be used for storing custom data.
To make the blocks static, in Fire Fed, go to 0x4C062 and change the byte to 0. In Emerald, change the byte at 0x76BEC to 0. This will make the blocks static, but not disable the DMA copy functions. The DMA will simply copy the blocks back to the same space.
At the end of each block lies 0x80 bytes of free RAM. With a bit of work, these 3*0x80 bytes can be saved to the Flash. In Fire Red, simply go to 0x3FEC96 and write 0xA4 0xf, at 0x3FECa6 write 0x68 0x0f and at 0x3FECCA write 0x50 0x08.

In Block 8, there are 5 warp structures. Each has its own meaning.
At 0x4, currentMap indicates what the entrance taken into the current map. Positions of 0xffff indicate the entry point was a connection and not a warp.
At 0x14, last_used_empty_teleporter is the structure that saves the destination for 0x7f warps, such as the one on the elevator and one the trading center. This field is modified by the setwarpplace command.
At 0x1c, last_healing_spot is the structure that saves the destination for Teleport and where you go when you lose all pokemon. This field is set by the SethealingPlace command. Changing this field allows control over the destination of Teleport, but might break the fainting script.
At 0x24, last_used_warp stores the last warp from where the player transitioned from an outside map to an indoors/cave map. It is set each time such transition occurs, and is used by Dig and Escape Rope to determine where to go. Changing this field allows control over the destination of Dig and Escape Rope.

In order to expand the player maximum money to 999999999, the first change is allowing the money to add to that amount. at 0x9fdd4, place 0xFF 0xc9 0x9a 0x3b. Then we need to change the money display. At 0x09FE52 place 0x9 At 0x09FE62 place 0x9. This makes the showMoneyBox command display the full number. At 0x08A006 place 9. This makes the trainer card display the correct amount.
The money paid after losing a battle is calculated at 0x054C04, using a table at 0x26D294. The table contains one entry per number of badges collected. Each entry is multiplied by 4 and then multiplied by the highest pokemon level in your party. For example, if you have 6 badges and the highest pokemon level is 60, the money to pay out is 60*4*20 = 4800.

PC Items are the only set that is not encrypted. 0809A2A4 clears that space. 0809A304 gets the first free slot on the PC. 0809A33C countes the number of slots occupied. 0809A374 checks if an item (R0) exists with at least R1 quantity. This function is used by the checkPCItem command. 0809A3C8 adds R1 items R0 to the PC. 0809A460 removes r1 items r0 from the PC, if they exist. 0809A4E8 compacts the PC items, moving items into the empty slots above them.
The bags are usually acessed from a table at 0203988C. Each entry consists of the bag address in the block and one word size of the bag. The entire bag is cleared by 0809A2DC.

There are three sets of pokedex Seen flags, all of which must be set for a pokemon to be considered seen. The function that accesses and modifies the data is at 08104AB0, and receives r0 as the pokemon number, r1= 0 for get seen flag, 1 for get caught flag, 2 for set seem flag amd 3 for set capture flag, r2 = 0 if the pokemon number is not the dex number

Field OW_ram contains 16 entries of Ram OW structure. Most of this structure is still undocumented, but is one of the three essential structures to display OWs on the map. OWs loaded in this structure are the ones to be displayed on screen. This field is a copy of the one really used at 02036E38. The 16 entry limitation makes it so that only 16 sprites (including player) can be displayed at once on screen.
The field map_OW_copy contains an array copied from the Map OW structure. This is not just a copy, however. It is here that most OW functions fetch the Map OW structure, not from the ROM. Commands such as spriteBehave that modify OW behavior alter them on this field. This field size also determines the maximum number of OW on a single map, 64.
The third important structure is the OAM RAM structure at 0202063C. This structure is used by the game engine to display sprite images such as the OWs or the battle HUD and battle sprites. It includes a direct copy of the OAM structure for that sprite, as well as pointers to images and animations. This structure (which is not included in the save files) also needs further study.
Attached Files
File Type: zip codeRefFinder.zip‎ (115.3 KB, 9 views) (Save to Dropbox)
Here are the links for my work

Currently working on:
Battle Script Documentation
Another large project
Reply With Quote
Old June 3rd, 2015 (04:25 PM).
GoGoJJTech's Avatar
GoGoJJTech GoGoJJTech is offline
http://GoGoJJTech.com (WIP!)
Gold Tier
Join Date: Nov 2012
Location: Earth
Age: 16
Gender: Female
Nature: Jolly
Posts: 2,186
JPAN, glad to see you back.

The Save Block Structure has always been iffy since most of the data is used a lot, then some you rarely see get accessed or written to, such as the Spinda and Unown PIDs. Thanks for looking into it more deeply.

However, this forum doesn't consist of many people willing to contribute or do ASM/research at all, which is why you should come to the romhacking chat at http://chat.linkandzelda.com:9090/?channels=rhm so we can collab and work on stuff and things.
I believe in Jesus Christ my Savior. If you do too, and aren't scared to admit it, then copy and paste this into your signature.
The HGSS Music Patch - The BW/2 Music Patch - ASM: Switch Music Based on Seasons
Romhack.me Profile - Pokecommunity Profile - Pokemonhackersonline Profile - Youtube Channel

Join us in the romhacking chat
Pokémon Platinum Red and Blue
Reply With Quote
Old June 3rd, 2015 (05:16 PM). Edited June 3rd, 2015 by Team Fail.
Team Fail's Avatar
Team Fail Team Fail is online now
fun in the sun
Platinum Tier
Join Date: May 2009
Age: 20
Gender: Male
Nature: Brave
Posts: 10,727
I know that bulbapedia has some info on the save data format, and I also know that in the Japanese version at least there's a chunk of save data that's used for storing Mystery Events scanned e-Reader e-Card data for the house on Seven Island. I think this save data area still exists in the international copies, but is just kept empty. I'll have to check where that is saved in the data though, although the data structure behind it is almost fully documented (Although, I think some of it is incorrect) on bulbapedia as well. I do know as well, like you mentioned, that it has Battle Tower data, that of which I haven't worked on yet. That leads me to think that FRLG stores two chunks of e-Card data, totalling four trainers since the Battle Tower cards hold three trainers and the battle-e cards hold only one. I do have at least a start on the trainer battle-e card format for Ruby/Sapphire, and I think the data format is almost the exact same as those used for FRLG, so you may want to peek in here and see about this.

voler avec moi
Reply With Quote
Old June 12th, 2015 (04:02 PM). Edited June 13th, 2015 by JPAN.
JPAN JPAN is offline
pokemon rom researcher
Join Date: Dec 2008
Posts: 104
The "Previously" system is the collection of functions related to saving, loading and displaying the slide show that appears when continuing a saved game in Fire Red. Each scene in the show (and the data saved that generate it) is a slide.
To save a slide, the function at 0x08110AEC is called. The function will write on the slide indicated by 0x0203ADF8, or on 0 if the slide indicated by 0x0203ADF8 is greater than 3. It begins by clearing the space on that slide slot, and then stores the map warp, the OWs present, map Footer, a copy of the variables and flags, and finally the 32 last movements the OWs (including player) made.
The function at 0x08110F14 is in charge of loading the slides to show in the slide show. The function at 0x08111914 is responsible for determining the next slide to be loaded. If no more slides exist, prepares the game for normal load.
Much is yet unknown about how the slides are generated and displayed. It is ingrained in the normal overworld loading routines, and it seems like the previously slide show is handled like the normal overworld.

While interesting to study, it is a feature (much like the help system) that many wouldn't miss if it was gone. Disabling the previously system would allow us to use the memory associated with it in any way we wanted. The most tempting part is that this memory is acessible to flags and variables without altering the loading code. Flags from 0x2100 to 0x3fff and variables from 0x4180 to 0x4e4f fall within the previously slides range.
To disable the previouly system, we need to disable both load and save functions. At 0x110f24, place 0x28 0xe0. This will cause a jump to 0x08110f78, skipping the loading function. The second loading function should now never be called, but better safe than sorry. At 0811192A place 0x04 0x20 (mov r0, 4) to trick it into thinking the slides were already loaded.
At 08110AEC. Place a "bx lr" (0x70 0x47) to skip the save function entirely. The function at 81123BC, which moves the slides up if any was erased, is also problematic. Place "bx lr" (0x70 0x47) at that address to prevent the cleanup.

You should now have safe access to thousands of new flags and variables. The new flags and variables have a slight overlap, so it would be recommended that certain variables wouldn't be used if using the flags. This small table shows what values are safe.
Flag                |Total Flags  |Variables        |Total Variables
0x2100 - 0x27ff     |2048         |0x4200 - 0x4e4f  |3152
0x2100 - 0x30ff     |4096         |0x4280 - 0x4e4f  |3024
0x2100 - 0x37ff     |6144         |0x4300 - 0x4e4f  |2944
0x2100 - 0x3fff     |7936         |0x4370 - 0x4e4f  |2784
Each quickword is composed of two parts: quickword & 0x1ff is the entry number, quickword>>9 is the table number. Tables 13 and 15 are special, as they load the names of moves and pokemon respectively straight from the source. The table at 083ECED4 contains the table for the quickword entries. Each entry in that table points to a list of entries containing the actual words. The entries at the 083ECED4 table represent a category of words (the ones presented during mail writing).
0841E093 contains the default string for when a quickword is invalid ("???"). The function that translate quickwords to actual strings is at 0x080BD7F8, and takes the quickword already split into category(r0) and entry(r1).
Mail contains fields to store trainer name and OTID. While the name storing is obvious, the OTID being stored is not, as the mail doesn't seem to show it. The species of the pokemon holding the mail (or last holding the mail in the pc case) is stored for the mails that contain a small pokemon icon on the frame.
The function at 080BD89C is responsible for loading the mail into display format.

@TeamFail Your research is very interesting, and finding out where the E-reader data is hidden is only natural in its progression. Wish you luck with that research.
Here are the links for my work

Currently working on:
Battle Script Documentation
Another large project
Reply With Quote
Old June 12th, 2015 (06:20 PM).
azurile13 azurile13 is offline
Join Date: Mar 2015
Posts: 115
Wait, seriously? Those simple steps open up all of those flags and vars? That's pretty damn incredible, especially since most people find the previously feature annoying anyways. I had no idea how much memory it was eating up; awesome findings!
Reply With Quote
Quick Reply

Sponsored Links

You may also like.. (Beta)
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

All times are UTC -8. The time now is 04:03 PM.