Author Topic: FF7 PSX save format information and region of CRC gen  (Read 4258 times)

Cyberman

  • *
  • Posts: 1572
    • View Profile
Warning this contains CODE :)
These are the record structures.. almost verbatum save a few small changes.
Code: [Select]

typedef struct  { // [0x0044] Descriptions; no actual game data
BYTE level; // [0x0000] Lead character's level
BYTE party[3]; // [0x0001] Party
char name[16]; // [0x0004] Lead character's name (ff7 text)
USHORT curHP; // [0x0014] Lead character's current HP
USHORT maxHP; // [0x0016] Lead character's base HP
USHORT curMP; // [0x0018] Lead character's current MP
USHORT maxMP; // [0x001A] Lead character's base MP
UINT gil; // [0x001C] Amount of gil
UINT time; // [0x0020] Total number of seconds played
char location[32]; // [0x0024] Save location (ff7 text)
} FF7DESC;

typedef struct  { // [0x0084] Character info
BYTE id; // [0x0000] Character id (used by Sephiroth/Vincent slot)
BYTE level; // [0x0001] Level (0-99)
BYTE strength; // [0x0002] Strength (0-255)
BYTE vitality; // [0x0003] Vitality (0-255)
BYTE magic; // [0x0004] Magic (0-255)
BYTE spirit; // [0x0005] Spirit (0-255)
BYTE dexterity; // [0x0006] Dexterity (0-255)
BYTE luck; // [0x0007] Luck (0-255)
_UNKNOWN z_1[6];
BYTE limitlevel; // [0x000E] Current limit level (1-4)
BYTE limitbar; // [0x000F] Current limit bar (0xFF = limit break)
char name[12]; // [0x0010] Name (ff7 text)
BYTE weapon; // [0x001C] Equipped weapon
BYTE armor; // [0x001D] Equipped armor
BYTE accessory; // [0x001E] Equipped accessory
BYTE flags[3]; // [0x001F] Character flags
// [0:0x10] 1: Sadness
// [0:0x20] 1: Fury
// [1:0x01] 1: Front row  0: Back row
USHORT limits; // [0x0022] Learned limit skills
USHORT kills; // [0x0024]
USHORT timesused; // [0x0026]
_UNKNOWN z_3[4];
USHORT curHP; // [0x002C] Current HP
USHORT baseHP; // [0x002E] Base HP (before materia alterations)
USHORT curMP; // [0x0030] Current MP
USHORT baseMP; // [0x0032] Base MP (before materia alterations)
_UNKNOWN z_4[4];
USHORT maxHP; // [0x0038] Maximum HP (after materia alterations)
USHORT maxMP; // [0x003A] Maximum MP (after materia alterations)
UINT exp; // [0x003C] Current EXP
UINT materia[16]; // [0x0040] Materia slots (0-7=weapon,8-15=armor)
UINT expNext; // [0x0080] EXP to next level
}  FF7CHAR;


typedef struct  { // [0x0010] Chocobo
USHORT speed; // [0x0000] Sprint speed
USHORT maxspeed; // [0x0002] Max Sprint speed
USHORT sprintspd; // [0x0004] Speed
USHORT maxsprintspd; // [0x0006] Max Speed
_UNKNOWN z_1[2];
BYTE intelligence; // [0x000A] Intelligence
_UNKNOWN z_2[2];
BYTE raceswon; // [0x000D] Number of races won
BYTE sex; // [0x000E] Sex (0=male,1=female)
BYTE type; // [0x000F] Type (Yellow,Green,Blue,Black,Gold)
} FF7CHOCOBO;


typedef struct  {
USHORT x;
USHORT y;
USHORT z;
} FF7XYZ;




typedef struct
{
   char  UNUSED[0x200];
USHORT checksum; // [0x0200] Checksum
_UNKNOWN z_1[2];
FF7DESC desc; // [0x0204:44] Slot description
BYTE colors[4][3]; // [0x0248] Window colors (RGB)

FF7CHAR chars[9]; // [0x0254:84] The nine characters (Cl,Ba,Ti,Ae,Re,Yu,Ca,Vi,Ci)
BYTE party[3]; // [0x06F8] Party members
_UNKNOWN z_2;
USHORT items[320]; // [0x06FC] Items (320 slots)
UINT materia[200]; // [0x097C] Materia (200 slots)
_UNKNOWN z_3[224];
UINT gil; // [0x0D7C] Party gil
UINT time; // [0x0D80] Total number of seconds played
_UNKNOWN z_4[16];    // [0x0D82]
USHORT mapid; // [0x0D92] Current map
USHORT locationid; // [0x0D94] Current location
_UNKNOWN z_5[2];     // [0x0D96]
FF7XYZ coord; // [0x0D98] Current coordinates (world map)
_UNKNOWN z_6[7];     // [0x0D9E]
struct {   // [0X0DA5] Love points
BYTE aeris;
BYTE tifa;
BYTE yuffie;
BYTE barret;
} love;
_UNKNOWN z_7[5];     // [0x0DA9]
USHORT battles; // [0x0DAE] Number of battles fought
USHORT runs; // [0x0DB2] Number of escapes
BYTE timer[4]; // [0x0BB4] Game timer (HH:MM:SS:TT)
_UNKNOWN z_8[44];
// [0x0BBC] Number of times used (Curse Ring)
BYTE keyitems[8]; // [0x0BE4] Key items
_UNKNOWN z_9[258];
USHORT gp; // [0x0CEE] Party GP (0-10000)
_UNKNOWN z_10[12];
BYTE stables; // [0x0CFC] Number of chocobo stables owned
_UNKNOWN z_11;
BYTE stablesoccupied; // [0x0CFE] Number of occupied stables
BYTE chocobomask; // [0x0CFF] Mask of occupied stables
_UNKNOWN z_12[196];
FF7CHOCOBO chocobos[6]; // [0x0DC4] Chocobo slots
_UNKNOWN z_13[128];
BYTE disc; // [0x0EA4] Current CD
_UNKNOWN z_14[31];
char chocobonames[6][6];// [0x0EC4] Chocobo names
USHORT chocostaminas[6];// [0x0EE8] Chocobo staminas
_UNKNOWN z_15[24];
char location[24]; // [0x0F14] Name of location
_UNKNOWN z_16[436];
// [0x0F63] Number of times used (Curse Ring)
// [0x0F29][0x08] Map instructions shown

    BYTE battlespeed; // [0x10D8] Battle speed, 0=fastest FF=slowest
    BYTE battmsg; // [0x10D9] Battle message speed
    USHORT flags; // [0x10DA] Flag bits
    _UNKNOWN z_17[16];
    BYTE msgspeed; // [0x10EC] Field message speed
    _UNKNOWN z_18[7];
    _UNKNOWN END_REC;
    //_UNKNOWN END_REC[3340];
} FF7_GAME;


As you can see nothing much was changed except the first 512 bytes are ignored in the save state here is the code I'm using for calculating the CRC, it's pretty much identical only I use where the END of the record is to terminate the loop (END_REC).

Code: [Select]

//---------------------------------------------------------------------------
void TJenovaForm::CheckSum(void)
{
char     *Buffer,
            *Termination;
int       temp, Bit;
long     Result = 0xFFFF;//,
            //length = 4336;
long     Mask = 0x8000;

    //temp = sizeof(FF7_GAME);
    Buffer =       (char *)&Game->desc;
    Termination =  (char *)&Game->END_REC;
while( Buffer < Termination)
{
temp = *Buffer;
Result ^= temp << 8;
for(Bit=0; Bit<8; Bit++)
{
if( Result & Mask )
Result = ( Result << 1 ) ^ 0x1021;
else
Result <<= 1;
    Result &= 0xFFFF;
}
      Buffer++;
}
    Result = ~Result;
    Result &= 0x0000FFFF;
Game->checksum = Result;
}

If I make changes however, I've no way to verify the CRC is correct save using Jenova (laugh) of your creation by exporting it to PC then running Jenova on it then exporting (hopefully with proper CRC changes?) I'm wondering if this is a problem for both Jenova and my toy.. hmm.

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
FF7 PSX save format information and region of CRC gen
« Reply #1 on: 2003-02-28 02:32:37 »
Well... I see nothing directly wrong with the code. The checksum region should be from the start of the desc block and 4336 bytes onwards. One thing you should make sure is that the compiler aligns struct members on a byte boundary, since the whole save struct depends on it. You could add a small check in your Checksum routine to see if it's properly set up, like this:
Code: [Select]
(...)
      Buffer =       (char *)&Game->desc;
      Termination =  (char *)&Game->END_REC;
int iLength = Termination - Buffer;
// Make sure iLength == 4336


That's what I can think of right now, let me know the results.

Must...sleep... 4:30 in the morning...

Cyberman

  • *
  • Posts: 1572
    • View Profile
FF7 PSX save format information and region of CRC gen
« Reply #2 on: 2003-02-28 06:11:30 »
It comes out exactly 4336 bytes I made sure the alignment was correct in the compilor settings for the project..

I wonder if the PSX does other checking such as information contain in the chocobo's area.. I'll alter someting else and see if I have the same problem.. hmm.

Well I found the problem.. two lines out of order.. doh.. I was copying the data before I calculated the checksum on it.. so I was returning it without the checksum calculated.
Prior code
Code: [Select]

   // save memory card data
   memcpy(FF7_Pass, FF7SAVE, sizeof(FF7SAVE));
   // calculate checksum
   CheckSum();

So all is well if not my head banging the nearest hard surface.
Correct code
Code: [Select]

   // calculate checksum
   CheckSum();
   // save memory card data
   memcpy(FF7_Pass, FF7SAVE, sizeof(FF7SAVE));


By the way I just ran your Jenova interface, It's better than mine in many ways I suppose that means I should work on mine more :)

Cyb

Alhexx

  • *
  • Posts: 1894
    • View Profile
    • http://www.alhexx.com
FF7 PSX save format information and region of CRC gen
« Reply #3 on: 2003-02-28 20:02:14 »
I haven't read the whole code, but it seems like someone has been workin' hard on this... :)

 - Alhexx