Tux Posted June 4, 2011 Share Posted June 4, 2011 Hi, I'm currently developing a software which reads Pokémon save file data. Also, I have a few questions : How does work the small/big blocks mechanics in a 256-kilobytes file ? How does work the save file data in Generation III ? Is the block footer structure the same beetween D/P/Pl/HG/SS/B/W ? Where are located the ID, sID, 'Number of Party Pokémon', the Party Pokémon data, the PC Pokémon data in B/W? Same question for Generation III save file data. Is something new about these save file informations beetween B/W and HG/SS ? Is it the same blocks mechanics between B/W and HG/SS ? What are the blocks limits offsets in B/W ? Tux. Link to comment Share on other sites More sharing options...
codemonkey85 Posted June 6, 2011 Share Posted June 6, 2011 For a 256 KB save file, I imagine there would be no backup blocks. But the game was not meant to save files of this size, so I never bothered with them personally. The Gen III save structure is sort of complicated... I am looking for the documentation I used to figure it out so I don't have to try to explain it (since I'm sure I'd only befuddle you if I tried).EDIT: Ah, look what a quick Google search yields: http://furlocks-forest.net/wiki/?page=Pokemon_GBA_Save_Format The block footers are very similar between all Gen IV games... I think there are minor differences in HGSS, but nothing too complicated IIRC. Your best bet for locating the PKM data in B/W is to just use a save file containing a few PKM you know the PID of, and opening the save file in HxD or some other hex program and doing a search for those PIDs. Um, yes? I don't think B/W switch the blocks around like Gen IV did, making it much more straightforward to find the "current" information. I dunno anything specific about the B/W save data though. Also, don't forget that the Gen III PKM data looks different: http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_in_Generation_III http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_substructures_in_Generation_III Link to comment Share on other sites More sharing options...
Tux Posted June 10, 2011 Author Share Posted June 10, 2011 (edited) Thanks a lot ^^ ! Also, I'm unable to recalculate the save file checksums --' . I have readen your PKMDS vb.net library (by the way, this is a excellent and useful library) source code, and have transcripted the checksums algorithm in C++, but I get wrong checksums ... For example, with 0 for begining block offset, and (0xC0EC + 20) for ending offset (inclusive) and 20 for the footer size, I get 0x5663 (or 0x6356) instead of 0x2306 (EDIT: 0x7A0A or 0x0A7A, offset 0xC0FE to 0xC0FF, sorry) Here is a part my source code : int Savefile::getSeeds(int * seeds) //Output is the 'seeds' parameter array { int v0 = 0; //Signed 32-bit Integer int v1; int v2; int result; do { v1 = v0 << 8; v2 = 0; do { if ((unsigned char)(v1 >> 8 & 0x80) != 0) //unsigned char : unsigned 8-bit integer = Byte v1 = (2 * v1) ^ 0x1021; else v1 *= 2; v2 += 1; } while(v2 < 8); result = (unsigned short) v1; //Unsigned 16-bit integer seeds[v0] = result; v0 ++; } while(v0 <= 0xFF); return result; } unsigned short calculateChecksum(FILE * savefile, unsigned int begin, unsigned int end, unsigned int footerSize) { int seeds[0xFF]; getSeeds(seeds); unsigned char * data = new unsigned char[end-begin-footerSize]; fseek(savefile, begin, SEEK_SET); //Set the cursor at the beginning of the savefile + begin fread(data, 1, (end-begin) - footerSize, savefile); //Read end-begin-footerSize bytes of data into the array 'data' int checksum = 0xFFFF; long long unsigned int i; //64-bit unsigned integer int v4 = end - footerSize; unsigned char v6; i = 0; while (v4 > 0) { v4 -= 1; v6 = (unsigned char)(data[i] ^ (unsigned char)(checksum >> 8)); checksum = (checksum << 8) ^ seeds[v6]; i++; } unsigned short retour = (unsigned short) checksum; delete[] data; // retour ^= 0; return retour; } poke..sav Edited June 11, 2011 by Tux Link to comment Share on other sites More sharing options...
codemonkey85 Posted June 11, 2011 Share Posted June 11, 2011 Just out of curiosity, which game's save file are you trying to calculate a checksum for? Also, I'm no help when it comes to C++. Link to comment Share on other sites More sharing options...
Tux Posted June 11, 2011 Author Share Posted June 11, 2011 I use my Pokémon Pearl's savefile. I don't understand what I got wrong ... Is The temporary variable(initializated at 0xFFFF), which is used to calculate the checksum , a signed 32-bit integer ? Which pairs of offsets (inclusive) should I use to calculate the checksum ? Link to comment Share on other sites More sharing options...
codemonkey85 Posted June 13, 2011 Share Posted June 13, 2011 Hmm. It's been quite some time since I've looked at this part of my library. I have a tight schedule this week but I'll try to look it over when I can. Link to comment Share on other sites More sharing options...
Tux Posted June 18, 2011 Author Share Posted June 18, 2011 Issue fixed ! (my program's generated checksum and Pokegen's are the same) The equivalent of the changes made in C++ are the following in VB .Net : seeds = New Integer(&H100) {} 'instead of : seeds = New Integer(&H100 - 1) {}, line 13304 in PKMDSLIB.vb of your library If (CType((v1 >> 8) And &H80, [byte]) And &H80) <> 0 Then ' Instead of : If (CType(v1 >> 8, [byte]) And &H80) <> 0 Then, l. 13315, supposing CType() returns the 8 firts bits starting from right Also, thanks a lot for your help and for your library :smile: . PS : How is the checksum calculated in Gen III save files ? Link to comment Share on other sites More sharing options...
Kaphotics Posted June 18, 2011 Share Posted June 18, 2011 There are save file editors for gen 3, namely Pokemon Enciclopedia (spanish, translated on forums) and PokeStock (japanese). PSavFix (by loadingNOW iirc) corrects the Chksum, here's the code: ####MAKEFILE#### #Change Dir to your GCC-bin dir DIR := C:/MinGW/bin/ CC := $(DIR)gcc # --- proj PSavFix : Main.o $(CC) -o PSavFix Main.o PSavFIX.o : Main.c $(CC) -c -O3 Main Main.c ##END MAKEFILE## --------------------------------------------------------------- ####MAIN.C#### /*CODE C++*/ #include <stdio.h> #include <stdlib.h> #include <string.h> int Chksum(int length, int *Data) { int Chk,i,tmp; length = length>>2; Chk=0; for(i=0; i<length; i++) Chk += Data[i]; tmp = Chk>>16; tmp +=Chk; Chk = (tmp&0xFFFF); return Chk; } int main(int argc, char** argv) { char *Map,*p,*header; int *Imap,*Data; int Found,id,fix,CHK,OK,i; FILE *fpm, *fp; short *MapPtr; short FLMAP[] = { 0xF24,0xF80,0xF80,0xF80,0xEC0,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0x7D0,0x01C,0x100}; short RSMAP[] = { 0x890,0xF80,0xF80,0xF80,0xC40,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0x7D0,0xF80,0xF80}; short MAX[] = { 0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80,0xF80}; OK = 1; fix = 0; if(argc!=4) { printf("Usage: %s [-fix|-nofix] [-RS|-FL|-MAX] [infile]\n", argv[0]); return 0; } if(!strcmp(argv[2], "-RS")) { printf("Running in RS Mode\r\n"); MapPtr = &RSMAP[0]; } else if(!strcmp(argv[2], "-FL")) { printf("Running in FL Mode\r\n"); MapPtr = &FLMAP[0]; } else if(!strcmp(argv[2], "-MAX")) { printf("Running in MAXCompat Mode - note this mode is NOT recommented\r\n"); MapPtr = &MAX[0]; } else { printf("Please select a mode (-RS -FL -MAX). Read readme for more Information. \r\n"); return 0; } // allocate main ram and load sav header = (char *)malloc(0x1000); Data = (int*)header; printf("Loading: %s...\r\n", argv[3]); fp = fopen(argv[3], "rb+"); if (!fp) { printf("error loading sav \r\n"); return 0; } //check if fix is ON if(!strcmp(argv[1], "-fix")) { printf("Autofix: ON\r\n"); fix = 1; } else printf("Autofix: OFF\r\n"); for(i = 0; i<0x20; i++) { fread(header, 1, 0x1000, fp); CHK=Chksum(MapPtr[Data[1021]&0xF], Data); Found = (Data[1021]>>16)&0xFFFF; id = (Data[1021])&0xFF; if((CHK==Found && Data[1022]==0x8012025) || (id==0 && CHK==0 && Found==0)) printf("Size: %03X Segment: %02X Calc: %04X Found: %04X Sig: %08X - OK\r\n",MapPtr[Data[1021]&0xF],id, CHK,Found, Data[1022]); else { printf("Size: %03X Segment: %02X Calc: %04X Found: %04X Sig: %08X \r\n",MapPtr[Data[1021]&0xF],id, CHK,Found, Data[1022]); OK = 0; if(fix) { fseek(fp, -0xa,SEEK_CUR); header[0xff6]= (0xFF &CHK); header[0xff7]= (0xFF &(CHK>>8)); Data[1022]=0x8012025; p = &header[0xff6]; fwrite(p,1,6,fp); fseek(fp, 0x4,SEEK_CUR); } } } fclose(fp); if(OK) printf("No Problems found \r\n"); else printf("Problems found! (remember Sig=08012025)\r\n"); return 0; } ##END MAIN.C## Link to comment Share on other sites More sharing options...
Tux Posted June 19, 2011 Author Share Posted June 19, 2011 That's great, thanks! Is it the same algorithm/"Map" for Pokémon Emerald? Link to comment Share on other sites More sharing options...
Kaphotics Posted June 19, 2011 Share Posted June 19, 2011 I'm not sure, probably. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now