[WIP] FF9 Save editor. Memory card and save offset stuff.

  • Thread starter Thread starter gjoerulv
  • Start date Start date
Status
Not open for further replies.
G

gjoerulv

Guest
I'm working on a FF9 savegame editor (anyone got a good idea for a name  :P). I need some help understanding how the psx memorycard works and where the data is. I've tried some searching with some luck. But lets see if I've gotten the gist of things. I've worked on a .mcr file.


PART 1. MEMORY CARD HEADERS

When I open a .mcr file with a hex-editor, the header -0x80 bytes- looks like this:

Code: [Select]
Code:
?? ?? ?? ?? ?? ?? .... ?? ?? ?? CS4D 43 00 00 00 00 .... 00 00 00 0E
Question1: What do the "??" represent? Are they even important when making a save editor (pointers etc)?

The last one being a checksum, the bytes are XORed 'til the end of the header.

Then the header for each slot follows, 0x80 bytes each (if I got it down right). The checksum is on the last byte and is calculated the same way. Here are the 1st FF9 saveslot header on my card:
Code: [Select]
Code:
?? ?? ?? ?? ?? ?? ?? ?? ?? ?? [<---           Region/DiscNr code           --->] [SlotNr]51 00 00 00 00 20 00 00 FF FF 42 45 53 4C 45 53 2D 30 32 39 36 35 30 30 30 30 30 2D 30 30 00 00?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? CS00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 77
Question2: What are the "??" here? Specially the ones before Region/DiscNr code. Nuber of slots to use?

Region/DiscNr code + SlotNr are read like this as a string:

Code: [Select]
Code:
BESLES-0296500000-00
I'm guessing this means PAL disc1 code stuff, and that it is slot nr 1 (read as 0. The 3 last bytes here are slot nr, so no need to include 'em further).

Below is what I've read testing saves from all discs. And I'm pretty sure I'm correct.

Code: [Select]
Code:
PAL disc 1 = BESLES-0296500000PAL disc 2 = BESLES-1296500000PAL disc 3 = BESLES-2296500000PAL disc 4 = BESLES-3296500000
Question 3: How do the NTSC codes look like, and are there other versions (Spanish, German, etc)?

It would be great if there only were 2 versions of this: NTSC and PAL.  :-D


PART 2. SAVE MAP OFFSETS

Here I could use much help. I dunno what the stuff from after the last slot 'til the beginning of save-data is (offset 0x800 - 0x1FFF). Before the 1st save-data, starting at 0x2000, there seems to be another header equal to the 1st one in the file. I guess it doesn't matter much though, as it's mostly just 0x00 bytes.  :roll: I'm guessing it might be something to do with games which use multiple slots. Or not...

Anyway, here are the data I've found by searching the web and analyzing saves. Each save block are 2000h bytes long.

Code: [Select]
Code:
0x0105: BYTE    Level;          // Party leader level0x0106: BYTE    Name[8];        // Party leader name0x010E: BYTE    Unknown;        // ???0x010F: BYTE    Unknown;        // ???0x0106: BYTE    Location[28];   // Name of current location0x012C: BYTE    Gametime;       // Gametime (expressed in tenth of a second)0x0130: BYTE    Gil;            // Total amount of Gil0x0ee8 | 00 00 00 00 = 0         // Number of Gil// ============================================================================// Final Fantasy IX | Savegame | Character Stats// Start Pointer: 0x09d0// End Pointer: 0x0EDF// Block Count: 9// Block Size: 144 bytes// Total Size: 1296 bytes// ============================================================================0x0000: BYTE    Name[8];        // Character name0x0008: BYTE    Unknown;        // ???0x0009: BYTE    Unknown;        // ???0x000A: BYTE    Unknown;        // ???0x000B: BYTE    Level;          // Character level0x000C: DWORD   Experience;     // Total amount of experience ?0x0010: WORD    CurrentHP;      // Current amount of HP0x0012: WORD    CurrentMP;      // Current amount of MP0x0014: BYTE    Unknown;        // ???0x0015: BYTE    Unknown;        // ???0x0016: BYTE    Unknown;        // ???0x0017: BYTE    CurrentMS;      // Current amount of magical stones0x0018: BYTE    MaxHP;          // Max amount of HP0x001A: BYTE    MaxMP;          // Max amount of MP0x001C: BYTE    Unknown;        // ???0x001D: BYTE    Unknown;        // ???0x001E: BYTE    Unknown;        // ???0x001F: BYTE    MaxMS;          // Max amount of magical stones0x0020: BYTE    TranceLevel;    // Trance Level0x0021: BYTE    Unknown;        // ???0x0022: BYTE    Unknown;        // ???0x0023: BYTE    Unknown;        // ???0x0024: BYTE    Speed;          // Speed (total value incl. gear bonuses)0x0025: BYTE    Strength;       // Strength (total value incl. gear bonuses)0x0026: BYTE    Magic;          // Magic (total value incl. gear bonuses)0x0027: BYTE    Spirit;         // Spirit (total value incl. gear bonuses)0x0028: BYTE    Defence;        // Defence0x0029: BYTE    Evade;          // Evade0x002A: BYTE    MagicDefence;   // Magic defence0x002B: BYTE    MagicEvade;     // Magic evade0x002C: WORD    2nd HP max;     // Max HP with Bonus0x002E: WORD    2nd MP max;     // Max MP with Bonus0x0030: BYTE    BaseSpeed;      // Base speed (excl. gear bonuses)0x0031: BYTE    BaseStrength;   // Base strength (excl. gear bonuses)0x0032: BYTE    BaseMagic;      // Base magic (excl. gear bonuses)0x0033: BYTE    BaseSpirit;     // Base spirit (excl. gear bonuses)0x0034: BYTE    Unknown;        // ???0x0035: BYTE    Unknown;        // ???0x0036: BYTE    Unknown;        // ???0x0037: BYTE    Unknown;        // ???0x0038: BYTE    Status;         // Status bits.0x0039: BYTE    Weapon;         // Equiped weapon0x003A: BYTE    Headgear;       // Equiped head gear0x003B: BYTE    Armgear;        // Equiped arm gear0x003C: BYTE    Armor;          // Equiped armor0x003D: BYTE    Addon;          // Equiped add-on0x003E: BYTE    Unknown;        // ???0x003F: BYTE    Unknown;        // ???0x0040: BYTE    Unknown;        // ???0x0041: BYTE    Unknown;        // ???0x0042: BYTE    Unknown;        // ???0x0043: BYTE    Unknown;        // ???0x0044: BYTE    Unknown;        // ???0x0045: BYTE    Unknown;        // ???0x0046: BYTE    Unknown;        // ???0x0047: BYTE    Unknown;        // ???0x0048: BYTE    Unknown;        // ???0x0049: BYTE    Unknown;        // ???0x004A: BYTE    Unknown;        // ???0x004B: BYTE    Unknown;        // ???0x004C: BYTE    Unknown;        // ???0x004D: BYTE    Unknown;        // ???0x004E: BYTE    Unknown;        // ???0x004F: BYTE    Unknown;        // ???0x0050: BYTE    Unknown;        // ???0x0051: BYTE    Unknown;        // ???0x0052: BYTE    Unknown;        // ???0x0053: BYTE    Unknown;        // ???0x0054: BYTE    Unknown;        // ???0x0055: BYTE    Unknown;        // ???0x0056: BYTE    Unknown;        // ???0x0057: BYTE    Unknown;        // ???0x0058: BYTE    Unknown;        // ???0x0058: BYTE    AbilityAP[48];  // AP for action/support abilities0x0088: BYTE    Support[8];     // Support abilities equiped// ============================================================================// Final Fantasy IX | Savegame | Item List// Start Pointer: 0x0F20// End Pointer: 0x111F// Block Count: 256// Block Size: 2 bytes// Total Size: 512 bytes// ============================================================================0x0000: BYTE    ID;              // Item ID0x0001: BYTE    Count;           // Item Count CARDS:0x1178: WORD    WINS?0x117A: WORD    LOSSES?0x117C: WORD    DRAWS?0x119A: BYTE    Card Count?      // Number of cards in stock0x119B: BYTE    Type Count?      // Number of card types// ============================================================================// Final Fantasy IX | Savegame | Cards// Start Pointer: 0x119C// End Pointer: 0x13F3// Block Count: 100// Block Size: 6 bytes// Total Size: 600 bytes// ============================================================================ 0x0000: BYTE    ID? ;             // Type ID  (FFh = empty block)?0x0001: BYTE    Arrow bits?;      // Bitmap representing arrows?0x0002: BYTE    Attack type?;     // Type of attack (physical, magical etch.)?0x0003: BYTE    Attack?;          // Atack Power?0x0004: BYTE    P.Def?;           // Physical defence power?0x0005: BYTE    M.Def?;           // Magical defence power?
I see there are some errors here (BYTE instead of WORD etc), but I'm too lazy to correct 'em. The bit length should be obvious in most cases.
 
May I suggest Freya as the name for this program? Assuming its not already taken by some other tool.
 
I would personally recommend Blank as the name of the editor, not a main character, but he is the first to truly save Zidane, Steiner and Garnet by sacrificing himself to keep them alive.
 
I would personally recommend Blank as the name of the editor, not a main character, but he is the first to truly save Zidane, Steiner and Garnet by sacrificing himself to keep them alive.
Actually that's not a bad idea.

Dibs on calling the FF9 Enemy Editor Garland.
As a long term plan I was planing on making one myself. Are you making one? Anyway, Garland would be THE perfect name for one.  :-D

Obviously, you should call it Kefka_Leonhart37. Just sayin'.
Consider it done!  ;D

EDIT:

Actually I found out each slot header has a game ID and a product code. And, yay, I revealed the NTCS codes.

Code: [Select]
Code:
PAL disc 1 = BESLES-02965PAL disc 2 = BESLES-12965PAL disc 3 = BESLES-22965PAL disc 4 = BESLES-32965NTSC disc 1 = BASLUS-01251NTSC disc 2 = BASLUS-01295NTSC disc 3 = BASLUS-01296NTSC disc 4 = BASLUS-01297Game ID = 00000-[saveNr on memcard]
If someone has any info. on the psx memcard structure I would be glad.
 
Last edited:
Question 3: How do the NTSC codes look like, and are there other versions (Spanish, German, etc)?

It would be great if there only were 2 versions of this: NTSC and PAL.  :-D
There's seven different versions of the game, here's the disc ID's for them all:

Code: [Select]
Code:
Japanese      SLPS_020.00, SLPS_020.01, SLPS_020.02, SLPS_020.03English (USA) SLUS_012.51, SLUS_012.95, SLUS_012.96, SLUS_012.97English (EU)  SLES_029.65, SLES_129.65, SLES_229.65, SLES_329.65French        SLES_029.66, SLES_129.66, SLES_229.66, SLES_329.66German        SLES_029.67, SLES_129.67, SLES_229.67, SLES_329.67Italian       SLES_029.68, SLES_129.68, SLES_229.68, SLES_329.68Spanish       SLES_029.69, SLES_129.69, SLES_229.69, SLES_329.69
For the savefiles, the first 2 characters (region code?) in the ID is BE for all european discs (eg. BESLES-02965), BA for the USA ones (eg. BASLUS-01251), and BI for the japanese ones (eg. BISLPS-02000). And they all use the same save file format structure (but the japanese version uses a different character table for strings of course), which is probably also the reason サラマンダー wasn't called Salamander (but Amarant) outside of Japan as it doesn't fit the 8 byte character name limit.
 
Thanks Zande, this'll help. I figured those BEs and BAs where regional stuff. The stuff you listed are the product codes, while the rest of the header info (I know of) are the game-IDs (the end is not slot# as I typed in the opening post, but part of the game id).

EDIT:

ok, so I've compared some saves and figured out the bitmap at the end of the character data. Each ability equipped has a flag, and it looks like this (must not be read as memory, but like you would see it in an hex editor):

Code: [Select]
Code:
Auto-Potion     00 00 00 00 00 00 00 01Locomotion      00 00 00 00 00 00 00 02Clear Headed    00 00 00 00 00 00 00 04Boost           00 00 00 00 00 00 00 08Odin's Sword    00 00 00 00 00 00 00 10Mug             00 00 00 00 00 00 00 20Bandit          00 00 00 00 00 00 00 40??????          00 00 00 00 00 00 00 80Insomniac       00 00 00 00 00 00 01 00Antibody        00 00 00 00 00 00 02 00Bright Eyes     00 00 00 00 00 00 04 00Loudmouth       00 00 00 00 00 00 08 00Restore HP      00 00 00 00 00 00 10 00Jelly           00 00 00 00 00 00 20 00Return Magic    00 00 00 00 00 00 40 00Absorb MP       00 00 00 00 00 00 80 00Body Temp       00 00 00 00 00 01 00 00Alert           00 00 00 00 00 02 00 00Initiative      00 00 00 00 00 04 00 00Level Up        00 00 00 00 00 08 00 00Ability Up      00 00 00 00 00 10 00 00Millionaire     00 00 00 00 00 20 00 00Flee-Gil        00 00 00 00 00 40 00 00Guardian Mog    00 00 00 00 00 80 00 00Mag Elem Null   00 00 00 00 01 00 00 00Concentrate     00 00 00 00 02 00 00 00Half MP         00 00 00 00 04 00 00 00High Tide       00 00 00 00 08 00 00 00Counter         00 00 00 00 10 00 00 00Cover           00 00 00 00 20 00 00 00Protect Girls   00 00 00 00 40 00 00 00Eye 4 Eye       00 00 00 00 80 00 00 00Healer          00 00 00 01 00 00 00 00Add Status      00 00 00 02 00 00 00 00Gamble Defence  00 00 00 04 00 00 00 00??????          00 00 00 08 00 00 00 00Power Throw     00 00 00 10 00 00 00 00Power Up        00 00 00 20 00 00 00 00Reflect-Null    00 00 00 40 00 00 00 00Reflectx2       00 00 00 80 00 00 00 00Undead Killer   00 00 01 00 00 00 00 00Dragon Killer   00 00 02 00 00 00 00 00Devil Killer    00 00 04 00 00 00 00 00Beast killer    00 00 08 00 00 00 00 00Man Eater       00 00 10 00 00 00 00 00High Jump       00 00 20 00 00 00 00 00Master Thief    00 00 40 00 00 00 00 00Steal Gil       00 00 80 00 00 00 00 00MP+20%          00 01 00 00 00 00 00 00Accuracy+       00 02 00 00 00 00 00 00Distract        00 04 00 00 00 00 00 00Long Reach      00 08 00 00 00 00 00 00MP Attack       00 10 00 00 00 00 00 00Bird Killer     00 20 00 00 00 00 00 00Bug Killer      00 40 00 00 00 00 00 00Stone Killer    00 80 00 00 00 00 00 00Auto-Reflect    01 00 00 00 00 00 00 00Auto-Float      02 00 00 00 00 00 00 00Auto-Haste      04 00 00 00 00 00 00 00Auto-Regen      08 00 00 00 00 00 00 00Auto-Life       10 00 00 00 00 00 00 00HP+10%          20 00 00 00 00 00 00 00HP+20%          40 00 00 00 00 00 00 00MP+10%          80 00 00 00 00 00 00 00??????          00 00 00 00 00 00 00 80??????          00 00 00 08 00 00 00 00
Can someone see what abilities I've might forgotten (the ? ?? ?? ?, 2 of 'em). Or maybe they're dummied out? I can't check 'em be setting these flags 'cause then I get a bad checksum. sigh, I gotta figure out that checksum out too. As I see it, it's not a crc, but a 2 byte checksum at offset 0x13FE. As far as I'm concerned, FF9 doesn't use any space from 0x1400 and out.
 
Last edited:
Those are all abilities in file 08_04a.txt.... (dont ask what the hell that name means!)
this is how they are sorted in data file
Code: [Select]
Code:
Ability UpAbsorb MPAccuracy+Add StatusAlertAntibodyAuto-FloatAuto-HasteAuto-LifeAuto-PotionAuto-ReflectAuto-RegenBanditBeast KillerBird KillerBody TempBoostBright EyesBug KillerChemistClear HeadedConcentrateCounterCoverDevil KillerDistractDragon KillerEye 4 EyeFlee-GilGamble DefenseGuardian MogHP+10%HP+20%Half MPHealerHigh JumpHigh TideInitiativeInsomniacJellyLevel UpLocomotionLong ReachLoudmouthMP AttackMP+10%MP+20%Mag Elem NullMan EaterMaster ThiefMillionaireMugOdin’s SwordPower ThrowPower UpProtect GirlsReflect-NullReflectx2Restore HPReturn MagicSteal GilStone KillerUndead KillerVoid
Missing
Code: [Select]
Code:
ChemistVoid
Supposing that Void is not ability, but void place..... (played only start of FF9)
In mine NTSC version is 'Gamble Defense'  (you have CE in end:P)


header file  in SLUS_012.51
0x5D92A  0x5DB2A, format 2B pointer 6B other chaos, maybe useful for something...
data file in file 0008  (9th file in first folder....:P)  0x8640 0x88D4
 
Missing
Code: [Select]
Code:
ChemistVoid
Supposing that Void is not ability, but void place..... (played only start of FF9)
In mine NTSC version is 'Gamble Defense'  (you have CE in end:P)
Thanks! I thought I had chemist... Must've forgotten. And, yes, it's defenCE in the PAL version. British English vs US English.

header file  in SLUS_012.51
0x5D92A  0x5DB2A, format 2B pointer 6B other chaos, maybe useful for something...
data file in file 0008  (9th file in first folder....:P)  0x8640 0x88D4
I'm not sure what you mean here. Inside the .img file on that disc?

oh, and anyone got any intel (lol) on how the checksum/crc?
 
Great, great stuff ! And might I suggest 'Memoria' for its name ? I think it'd be fitting for a FFIX save editor.
 
So, the save wasn't compressed / encrypted? I just assuned it'd be a complete arseache to decode.

I may be able to help with this.
 
Great, great stuff ! And might I suggest 'Memoria' for its name ? I think it'd be fitting for a FFIX save editor.
Best suggestion so far imo. Using an app called memoria sounds epic in some way...

So, the save wasn't compressed / encrypted? I just assuned it'd be a complete arseache to decode.

I may be able to help with this.
No, as far as I'm concerned there's no compression. At least not the parts I've figured out. Besides, FF9 don't use any space after offset 0x13FF. I have downloaded some saves that have some data after this point, but when I erase this data (zero it to hell), the save is still 100% usable with no difference in-game, no error message when loading the game etc.
I dunno how anybody got data here, 'cause when I play with these saves, and overwrite 'em, I only get zeroes after 0x13FF.
Even when you slightly alter the block's title you get an error (not the header, but the title inside the actual save data), thus I highly doubt FF9 use any space after 0x13FF. Which leads to my conclusion that there is no reason for compression.

I must admit the card-section of the savemap seems encrypted. Either that or the cards are stored in a different order in the savemap. I'm yet to figure it out, but it would help to get the checksum right first. Then It'll be way easier to see differences when I save with my editor and play the game.
 
Hunch? I'd guess there were a set of "Seen card?" flags and then data for the quantities.

I'd like to see how that data changes when you pick up and lose cards.
 
header file  in SLUS_012.51
0x5D92A  0x5DB2A, format 2B pointer 6B other chaos, maybe useful for something...
data file in file 0008  (9th file in first folder....:P)  0x8640 0x88D4
I'm not sure what you mean here. Inside the .img file on that disc?
Yeah, that's inside .img file.
I thought that .img file structure is 'common' knowledge since it was long time ago posted here by someone (maybe in wiki too).
Its structure is something like 'folders and files' - that's why I refer to '9th file in first folder'.
There was some extractor of .img file posted here, seen in q-gears svn if I am not wrong.
(But it lack import, which I needed, so I made one myself:P)
 
I just wanted to say good luck on the save file editor.  If you get far enough that it can change an attribute and save back to a useable save file, maybe we can get an alpha/beta to play with? I think the hardest part of these type of editors is always checksum related.  Some other game I was reading about stored the checksum twice, and it was a checksum of only part of the save file.  I think 90% of the developement time was checksum related.
 
ff9se-k2ltu.jpg


Ok, a small update as I've started working on it again.
I implemented a "CRC16 assuming checksum finder" (lol). As you can see on the status strip on the form it goes through every polynomial, starting at offset 0 - 256, with every possible initial values on 2 different savegames (block 11 and 12). No need to say it's gonna take hours. And even if I find enough matches it's based on certain assumptions. May very well be a waste of time.  :-\
 
Looking really nice gjoerulv :)
Would it be possible to make a 'hard mode' by modding the save files in any way?
I ask because I did this with FFX, by lowing the stats you earn as you progress.
Obviously FFIX has a totally different system, but I would so love to make it more difficult!
Any ideas?
 
The savemap (parts of it) is basically the only knowledge I have 'bout the "inner workings of FF9" lol, so besides lowering stats, level, etch, nothing else pops out from the top of my head.

I would love to have a hard mod for FF9. Any FF needs a hard mode. If I am to make a FF9 enemy editor it's name will certainly be Garland.  :evil:
 
Status
Not open for further replies.
Back
Top