about summary refs log tree commit diff stats
path: root/gba/source
diff options
context:
space:
mode:
Diffstat (limited to 'gba/source')
-rw-r--r--gba/source/libSave.c596
-rw-r--r--gba/source/libSave.h27
-rw-r--r--gba/source/libpayload.c312
-rw-r--r--gba/source/libpayload.h160
-rw-r--r--gba/source/payload.c60
-rw-r--r--gba/source/payload.h1
-rw-r--r--gba/source/saveblocks.h338
-rw-r--r--gba/source/savestructs.h793
8 files changed, 1656 insertions, 631 deletions
diff --git a/gba/source/libSave.c b/gba/source/libSave.c deleted file mode 100644 index e3bda1d..0000000 --- a/gba/source/libSave.c +++ /dev/null
@@ -1,596 +0,0 @@
1/*
2 libSave
3 Cartridge backup memory save routines. To use, call the required
4 routine with a pointer to an appropriately sized array of data to
5 be read from or written to the cartridge.
6 Data types are from wintermute's gba_types.h libgba library.
7 Original file from SendSave by Chishm
8*/
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <gba_dma.h>
14
15#define EEPROM_ADDRESS (0xDFFFF00)
16#define REG_EEPROM *(vu16 *)(EEPROM_ADDRESS)
17#define REG_DMA3CNT_H *(vu16 *)(REG_BASE + 0x0de)
18#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204)
19
20//-----------------------------------------------------------------------
21// Common EEPROM Routines
22//-----------------------------------------------------------------------
23
24void EEPROM_SendPacket( u16* packet, int size )
25{
26 REG_WAITCNT = (REG_WAITCNT & 0xF8FF) | 0x0300;
27 REG_DMA3SAD = (u32)packet;
28 REG_DMA3DAD = EEPROM_ADDRESS;
29 REG_DMA3CNT = 0x80000000 + size;
30 while((REG_DMA3CNT_H & 0x8000) != 0) ;
31}
32
33void EEPROM_ReceivePacket( u16* packet, int size )
34{
35 REG_WAITCNT = (REG_WAITCNT & 0xF8FF) | 0x0300;
36 REG_DMA3SAD = EEPROM_ADDRESS;
37 REG_DMA3DAD = (u32)packet;
38 REG_DMA3CNT = 0x80000000 + size;
39 while((REG_DMA3CNT_H & 0x8000) != 0) ;
40}
41
42//-----------------------------------------------------------------------
43// Routines for 512B EEPROM
44//-----------------------------------------------------------------------
45
46void EEPROM_Read_512B( volatile u8 offset, u8* dest ) // dest must point to 8 bytes
47{
48 u16 packet[68];
49 u8* out_pos;
50 u16* in_pos;
51 u8 out_byte;
52 int byte, bit;
53
54 memset( packet, 0, 68*2 );
55
56 // Read request
57 packet[0] = 1;
58 packet[1] = 1;
59
60 // 6 bits eeprom address (MSB first)
61 packet[2] = (offset>>5)&1;
62 packet[3] = (offset>>4)&1;
63 packet[4] = (offset>>3)&1;
64 packet[5] = (offset>>2)&1;
65 packet[6] = (offset>>1)&1;
66 packet[7] = (offset)&1;
67
68 // End of request
69 packet[8] = 0;
70
71 // Do transfers
72 EEPROM_SendPacket( packet, 9 );
73 memset( packet, 0, 68*2 );
74 EEPROM_ReceivePacket( packet, 68 );
75
76 // Extract data
77 in_pos = &packet[4];
78 out_pos = dest;
79 for( byte = 7; byte >= 0; --byte )
80 {
81 out_byte = 0;
82 for( bit = 7; bit >= 0; --bit )
83 {
84// out_byte += (*in_pos++)<<bit;
85 out_byte += ((*in_pos++)&1)<<bit;
86 }
87 *out_pos++ = out_byte ;
88 }
89}
90
91void EEPROM_Write_512B( volatile u8 offset, u8* source ) // source must point to 8 bytes
92{
93 u16 packet[73];
94 u8* in_pos;
95 u16* out_pos;
96 u8 in_byte;
97 int byte, bit;
98
99 memset( packet, 0, 73*2 );
100
101 // Write request
102 packet[0] = 1;
103 packet[1] = 0;
104
105 // 6 bits eeprom address (MSB first)
106 packet[2] = (offset>>5)&1;
107 packet[3] = (offset>>4)&1;
108 packet[4] = (offset>>3)&1;
109 packet[5] = (offset>>2)&1;
110 packet[6] = (offset>>1)&1;
111 packet[7] = (offset)&1;
112
113 // Extract data
114 in_pos = source;
115 out_pos = &packet[8];
116 for( byte = 7; byte >= 0; --byte )
117 {
118 in_byte = *in_pos++;
119 for( bit = 7; bit >= 0; --bit )
120 {
121 *out_pos++ = (in_byte>>bit)&1;
122 }
123 }
124
125 // End of request
126 packet[72] = 0;
127
128 // Do transfers
129 EEPROM_SendPacket( packet, 73 );
130
131 // Wait for EEPROM to finish (should timeout after 10 ms)
132 while( (REG_EEPROM & 1) == 0 );
133}
134
135//---------------------------------------------------------------------------------
136void GetSave_EEPROM_512B(u8* data)
137//---------------------------------------------------------------------------------
138{
139 volatile u8 x;
140 u32 sleep;
141
142 for (x=0;x<64;++x){
143 EEPROM_Read_512B(x,&data[x*8]);
144 for(sleep=0;sleep<512000;sleep++);
145 }
146}
147
148//---------------------------------------------------------------------------------
149void PutSave_EEPROM_512B(u8* data)
150//---------------------------------------------------------------------------------
151{
152 volatile u8 x;
153 u32 sleep;
154
155 for (x=0;x<64;x++){
156 EEPROM_Write_512B(x,&data[x*8]);
157 for(sleep=0;sleep<512000;sleep++);
158 }
159}
160//-----------------------------------------------------------------------
161// Routines for 8KB EEPROM
162//-----------------------------------------------------------------------
163
164void EEPROM_Read_8KB( volatile u16 offset, u8* dest ) // dest must point to 8 bytes
165{
166 u16 packet[68];
167 u8* out_pos;
168 u16* in_pos;
169 u8 out_byte;
170 int byte, bit;
171
172 memset( packet, 0, 68*2 );
173
174 // Read request
175 packet[0] = 1;
176 packet[1] = 1;
177
178 // 14 bits eeprom address (MSB first)
179 packet[2] = (offset>>13)&1;
180 packet[3] = (offset>>12)&1;
181 packet[4] = (offset>>11)&1;
182 packet[5] = (offset>>10)&1;
183 packet[6] = (offset>>9)&1;
184 packet[7] = (offset>>8)&1;
185 packet[8] = (offset>>7)&1;
186 packet[9] = (offset>>6)&1;
187 packet[10] = (offset>>5)&1;
188 packet[11] = (offset>>4)&1;
189 packet[12] = (offset>>3)&1;
190 packet[13] = (offset>>2)&1;
191 packet[14] = (offset>>1)&1;
192 packet[15] = (offset)&1;
193
194 // End of request
195 packet[16] = 0;
196
197 // Do transfers
198 EEPROM_SendPacket( packet, 17 );
199 memset( packet, 0, 68*2 );
200 EEPROM_ReceivePacket( packet, 68 );
201
202 // Extract data
203 in_pos = &packet[4];
204 out_pos = dest;
205 for( byte = 7; byte >= 0; --byte )
206 {
207 out_byte = 0;
208 for( bit = 7; bit >= 0; --bit )
209 {
210// out_byte += (*in_pos++)<<bit;
211 out_byte += ((*in_pos++)&1)<<bit;
212 }
213 *out_pos++ = out_byte;
214 }
215
216}
217
218void EEPROM_Write_8KB( volatile u16 offset, u8* source ) // source must point to 8 bytes
219{
220 u16 packet[81];
221 u8* in_pos;
222 u16* out_pos;
223 u8 in_byte;
224 int byte, bit;
225
226 memset( packet, 0, 81*2 );
227
228 // Write request
229 packet[0] = 1;
230 packet[1] = 0;
231
232 // 14 bits eeprom address (MSB first)
233 packet[2] = (offset>>13)&1;
234 packet[3] = (offset>>12)&1;
235 packet[4] = (offset>>11)&1;
236 packet[5] = (offset>>10)&1;
237 packet[6] = (offset>>9)&1;
238 packet[7] = (offset>>8)&1;
239 packet[8] = (offset>>7)&1;
240 packet[9] = (offset>>6)&1;
241 packet[10] = (offset>>5)&1;
242 packet[11] = (offset>>4)&1;
243 packet[12] = (offset>>3)&1;
244 packet[13] = (offset>>2)&1;
245 packet[14] = (offset>>1)&1;
246 packet[15] = (offset)&1;
247
248 // Extract data
249 in_pos = source;
250 out_pos = &packet[16];
251 for( byte = 7; byte >= 0; --byte )
252 {
253 in_byte = *in_pos++;
254 for( bit = 7; bit >= 0; --bit )
255 {
256 *out_pos++ = (in_byte>>bit)&1;
257 }
258 }
259
260 // End of request
261 packet[80] = 0;
262
263 // Do transfers
264 EEPROM_SendPacket( packet, 81 );
265
266 // Wait for EEPROM to finish (should timeout after 10 ms)
267 while( (REG_EEPROM & 1) == 0 );
268}
269
270//---------------------------------------------------------------------------------
271void GetSave_EEPROM_8KB(u8* data)
272//---------------------------------------------------------------------------------
273{
274 volatile u16 x;
275 u32 sleep;
276
277 for (x=0;x<1024;x++){
278 EEPROM_Read_8KB(x,&data[x*8]);
279 for(sleep=0;sleep<512000;sleep++);
280 }
281
282}
283
284//---------------------------------------------------------------------------------
285void PutSave_EEPROM_8KB(u8* data)
286//---------------------------------------------------------------------------------
287{
288 volatile u16 x;
289 u32 sleep;
290
291 for (x=0;x<1024;x++){
292 EEPROM_Write_8KB(x,&data[x*8]);
293 for(sleep=0;sleep<512000;sleep++);
294 }
295}
296
297//---------------------------------------------------------------------------------
298void GetSave_SRAM_32KB(u8* data)
299//---------------------------------------------------------------------------------
300{
301 volatile u8 *sram= (u8*) 0x0E000000;
302 volatile u16 x;
303
304 for (x = 0; x < 0x8000; ++x)
305 {
306 data[x] = sram[x];
307 }
308
309}
310
311//---------------------------------------------------------------------------------
312void PutSave_SRAM_32KB(u8* data)
313//---------------------------------------------------------------------------------
314{
315 volatile u8 *sram= (u8*) 0x0E000000;
316 volatile u16 x;
317
318 for (x = 0; x < 0x8000; ++x)
319 {
320 sram[x] = data[x];
321 }
322}
323
324//---------------------------------------------------------------------------------
325void GetSave_FLASH_64KB(u8* data)
326//---------------------------------------------------------------------------------
327{
328 volatile u8 *sram= (u8*) 0x0E000000;
329 volatile u32 x;
330
331 for (x = 0; x < 0x10000; ++x)
332 {
333 data[x] = sram[x];
334 }
335}
336
337//---------------------------------------------------------------------------------
338void PutSave_FLASH_64KB(u8* foo)
339//---------------------------------------------------------------------------------
340{
341 volatile u8 *fctrl0 = (u8*) 0xE005555;
342 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
343 volatile u8 *fctrl2 = (u8*) 0xE000000;
344
345 //init flash
346 *fctrl0 = 0xAA;
347 *fctrl1 = 0x55;
348 *fctrl0 = 0x90;
349 *fctrl2 = 0xF0;
350
351 //erase chip
352 *fctrl0 = 0xAA;
353 *fctrl1 = 0x55;
354 *fctrl0 = 0x80;
355 *fctrl0 = 0xAA;
356 *fctrl1 = 0x55;
357 *fctrl0 = 0x10;
358
359 //wait for erase done
360 u8 val1;
361 u8 val2;
362 val1 = *fctrl2;
363 val2 = *fctrl2;
364 while (val1 != val2) {
365 val1 = *fctrl2;
366 val2 = *fctrl2;
367 }
368 val1 = *fctrl2;
369 val2 = *fctrl2;
370 while (val1 != val2) {
371 val1 = *fctrl2;
372 val2 = *fctrl2;
373 }
374
375 volatile u8 *data = fctrl2;
376 u32 i;
377 //write data
378 for (i=0; i<65536; i++) {
379 *fctrl0 = 0xAA;
380 *fctrl1 = 0x55;
381 *fctrl0 = 0xA0;
382 data [i] = foo [ i ];
383 val1 = data [ i ];
384 val2 = data [ i ];
385
386 while (val1 != val2) {
387 val1 = data [ i ];
388 val2 = data [ i ];
389 }
390 val1 = data [ i ];
391 val2 = data [ i ];
392 while (val1 != val2) {
393 val1 = data [ i ];
394 val2 = data [ i ];
395 }
396 val1 = data [ i ];
397 val2 = data [ i ];
398 while (val1 != val2) {
399 val1 = data [ i ];
400 val2 = data [ i ];
401 }
402 }
403}
404
405//---------------------------------------------------------------------------------
406void GetSave_FLASH_128KB(u8* data)
407//---------------------------------------------------------------------------------
408{
409 const u32 size = 0x10000;
410
411 volatile u8 *fctrl0 = (u8*) 0xE005555;
412 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
413 volatile u8 *fctrl2 = (u8*) 0xE000000;
414 volatile u32 i;
415 volatile u8 *sram= (u8*) 0x0E000000;
416
417 //init flash
418 *fctrl0 = 0xAA;
419 *fctrl1 = 0x55;
420 *fctrl0 = 0x90;
421 *fctrl2 = 0xF0;
422
423 // read first bank
424 *fctrl0 = 0xAA;
425 *fctrl1 = 0x55;
426 *fctrl0 = 0xB0;
427 *fctrl2 = 0x00;
428
429 for (i=0; i<size; i++){
430 data[i] = sram[i];
431 }
432
433 // read second bank
434 *fctrl0 = 0xAA;
435 *fctrl1 = 0x55;
436 *fctrl0 = 0xB0;
437 *fctrl2 = 0x01;
438
439 for (i=0; i<size; i++){
440 data[i + size] = sram[i];
441 }
442
443}
444
445//---------------------------------------------------------------------------------
446void PutSave_FLASH_128KB(u8* foo)
447//---------------------------------------------------------------------------------
448{
449 volatile u8 *fctrl0 = (u8*) 0xE005555;
450 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
451 volatile u8 *fctrl2 = (u8*) 0xE000000;
452
453 u8 val1;
454 u8 val2;
455
456 //init flash
457 *fctrl0 = 0xAA;
458 *fctrl1 = 0x55;
459 *fctrl0 = 0x90;
460 *fctrl2 = 0xF0;
461
462 //erase chip
463 *fctrl0 = 0xAA;
464 *fctrl1 = 0x55;
465 *fctrl0 = 0x80;
466 *fctrl0 = 0xAA;
467 *fctrl1 = 0x55;
468 *fctrl0 = 0x10;
469
470 //wait for erase done
471 val1 = *fctrl2;
472 val2 = *fctrl2;
473 while (val1 != val2) {
474 val1 = *fctrl2;
475 val2 = *fctrl2;
476 }
477 val1 = *fctrl2;
478 val2 = *fctrl2;
479 while (val1 != val2) {
480 val1 = *fctrl2;
481 val2 = *fctrl2;
482 }
483
484 volatile u8 *data = fctrl2;
485 volatile u32 i;
486 // change to bank 0
487 *fctrl0 = 0xAA;
488 *fctrl1 = 0x55;
489 *fctrl0 = 0xB0;
490 *fctrl2 = 0x00;
491
492 //write data
493 for (i=0; i<65536; i++) {
494 *fctrl0 = 0xAA;
495 *fctrl1 = 0x55;
496 *fctrl0 = 0xA0;
497 data [i] = foo [ i ];
498 val1 = data [ i ];
499 val2 = data [ i ];
500
501 while (val1 != val2) {
502 val1 = data [ i ];
503 val2 = data [ i ];
504 }
505 val1 = data [ i ];
506 val2 = data [ i ];
507 while (val1 != val2) {
508 val1 = data [ i ];
509 val2 = data [ i ];
510 }
511 val1 = data [ i ];
512 val2 = data [ i ];
513 while (val1 != val2) {
514 val1 = data [ i ];
515 val2 = data [ i ];
516 }
517 }
518
519 // Change to bank 1
520 *fctrl0 = 0xAA;
521 *fctrl1 = 0x55;
522 *fctrl0 = 0xB0;
523 *fctrl2 = 0x01;
524
525 //write data
526 for (i=0; i<65536; i++) {
527 *fctrl0 = 0xAA;
528 *fctrl1 = 0x55;
529 *fctrl0 = 0xA0;
530 data [i] = foo [ i + 0x10000];
531 val1 = data [ i ];
532 val2 = data [ i ];
533
534 while (val1 != val2) {
535 val1 = data [ i ];
536 val2 = data [ i ];
537 }
538 val1 = data [ i ];
539 val2 = data [ i ];
540 while (val1 != val2) {
541 val1 = data [ i ];
542 val2 = data [ i ];
543 }
544 val1 = data [ i ];
545 val2 = data [ i ];
546 while (val1 != val2) {
547 val1 = data [ i ];
548 val2 = data [ i ];
549 }
550 }
551
552}
553
554//---------------------------------------------------------------------------------
555u32 SaveSize(u8* data, s32 gamesize)
556//---------------------------------------------------------------------------------
557{
558 if(gamesize < 0)
559 return 0;
560
561 u32 *pak= ((u32*)0x08000000);
562 s32 x;
563 u16 i;
564 s32 size = gamesize/4;
565
566
567 for (x=size-1;x>=0;x--){
568 switch (pak[x]) {
569 case 0x53414C46:
570 if (pak[x+1] == 0x5F4D3148){
571 return 0x20000; // FLASH_128KB
572 } else if ((pak[x+1] & 0x0000FFFF) == 0x00005F48){
573 return 0x10000; // FLASH_64KB
574 } else if (pak[x+1] == 0x32313548){
575 return 0x10000; // FLASH_64KB
576 }
577 break;
578 case 0x52504545:
579 if ((pak[x+1] & 0x00FFFFFF) == 0x005F4D4F){
580 GetSave_EEPROM_8KB(data);
581 for(i = 8; i < 0x800; i += 8) {
582 if(memcmp(data, data+i, 8) != 0)
583 return 0x2000; // EEPROM_8KB
584 }
585 return 0x200; // EEPROM_512B
586 }
587 break;
588 case 0x4D415253:
589 if ((pak[x+1] & 0x000000FF) == 0x0000005F){
590 return 0x8000; // SRAM_32KB
591 }
592 }
593 }
594 return 0;
595}
596
diff --git a/gba/source/libSave.h b/gba/source/libSave.h deleted file mode 100644 index 5ecf822..0000000 --- a/gba/source/libSave.h +++ /dev/null
@@ -1,27 +0,0 @@
1
2
3//---------------------------------------------------------------------------------
4#ifdef __cplusplus
5extern "C" {
6#endif
7//---------------------------------------------------------------------------------
8
9void GetSave_EEPROM_512B(u8* data);
10void PutSave_EEPROM_512B(u8* data);
11void GetSave_EEPROM_8KB(u8* data);
12void PutSave_EEPROM_8KB(u8* data);
13void GetSave_SRAM_32KB(u8* data);
14void PutSave_SRAM_32KB(u8* data);
15void GetSave_FLASH_64KB(u8* data);
16void PutSave_FLASH_64KB(u8* foo);
17void GetSave_FLASH_128KB(u8* data);
18void PutSave_FLASH_128KB(u8* foo);
19
20u32 SaveSize(u8* data, s32 gamesize);
21
22
23//---------------------------------------------------------------------------------
24#ifdef __cplusplus
25} // extern "C"
26#endif
27//---------------------------------------------------------------------------------
diff --git a/gba/source/libpayload.c b/gba/source/libpayload.c new file mode 100644 index 0000000..f13a34f --- /dev/null +++ b/gba/source/libpayload.c
@@ -0,0 +1,312 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * libpayload.c: contains helper functions for the payload
8 */
9
10#include <gba.h>
11#include "payload.h"
12
13// private functions
14static void CryptBoxPokemon(struct BoxPokemon* pkm);
15static u16 crc16(const u8* data, u16 len);
16static u32 CalculateRamScriptDataChecksum(struct RamScriptData* ramScript);
17
18/**
19 * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily.
20 * Remember to call EncryptPokemon() afterwards.
21 * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of.
22*/
23void DecryptPokemon(struct Pokemon* pkm) {
24 struct BoxPokemon* boxMon = &(pkm->box);
25 CryptBoxPokemon(boxMon);
26}
27
28/**
29 * Private function that does the actual work of crypting the substructures of a BoxPokemon.
30 * @param struct BoxPokemon* pkm The BoxPokemon whose substructures will be crypted.
31*/
32static void CryptBoxPokemon(struct BoxPokemon* pkm) {
33 for (u32 i = 0; i < 12; i++) {
34 pkm->secure.raw[i] ^= (pkm->otId ^ pkm->personality);
35 }
36}
37
38/**
39 * Decrypts the substructures of a core Pokémon structure, so they can be viewed or modified easily.
40 * Used by DecryptPokemon().
41 * Remember to call EncryptPokemon() afterwards.
42 * @param struct BoxPokemon* pkm The BoxPokemon to decrypt the substructures of.
43*/
44void DecryptBoxPokemon(struct BoxPokemon* pkm) {
45 CryptBoxPokemon(pkm);
46}
47
48/**
49 * Encrypts the substructures of a Pokémon structure, and fixes the checksum.
50 * Must be used after DecryptPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
51 * @param struct Pokemon* pkm The Pokémon to encrypt the substructures and fix the checksum of.
52*/
53void EncryptPokemon(struct Pokemon* pkm) {
54 struct BoxPokemon* boxMon = &(pkm->box);
55 EncryptBoxPokemon(boxMon);
56}
57
58/**
59 * Encrypts the substructures of a core Pokémon structure, and fixes the checksum.
60 * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
61 * @param struct BoxPokemon* pkm The BoxPokemon to encrypt the substructures and fix the checksum of.
62*/
63void EncryptBoxPokemon(struct BoxPokemon* pkm) {
64 FixBoxPokemonChecksum(pkm);
65 CryptBoxPokemon(pkm);
66}
67
68/**
69 * Gets a substructure of a Pokémon structure.
70 * Call DecryptPokemon() first or the substructure data will be encrypted.
71 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
72 * @param u8 substructId The substructure to get.
73 * @return union PokemonSubstruct* The substructure.
74*/
75union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId) {
76 struct BoxPokemon* boxMon = &(pkm->box);
77 return GetBoxPokemonSubstruct(boxMon,substructId);
78}
79
80/**
81 * Gets a substructure of a core Pokémon structure.
82 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
83 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
84 * @param u8 substructId The substructure to get.
85 * @return union PokemonSubstruct* The substructure.
86*/
87union PokemonSubstruct* GetBoxPokemonSubstruct(struct BoxPokemon* pkm,u8 substructId) {
88 if (substructId > 3) return NULL;
89 u32 personality = pkm->personality;
90 // Staring at the substruct indexes, I noticed the last two columns are the reverse of the first two!
91 // that is, substructId==2 column is the reverse of substructId==1, substructId==3 is the reverse of substructId==0
92 // At least that means there's no need to hardcode all four.
93 u8 substruct_idxes[2][24] = {
94 { 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3 },
95 { 1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2 }
96 };
97 u32 modulo = (personality % 24);
98 if (substructId < 2) {
99 return &( pkm->secure.substructs[ substruct_idxes[substructId][modulo] ] );
100 }
101 return &( pkm->secure.substructs[ substruct_idxes[3 - substructId][23 - modulo] ] );
102}
103
104/**
105 * Gets the checksum of a core Pokémon structure.
106 * @param struct BoxPokemon* pkm The BoxPokemon to calculate the checksum of.
107 * @return u16 The checksum.
108*/
109u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm) {
110 u16 checksum = 0;
111 union PokemonSubstruct* substructs[4] = {
112 GetBoxPokemonSubstruct(pkm,0),
113 GetBoxPokemonSubstruct(pkm,1),
114 GetBoxPokemonSubstruct(pkm,2),
115 GetBoxPokemonSubstruct(pkm,3)
116 };
117
118 for (int substruct = 0; substruct < 4; substruct++) {
119 for (int i = 0; i < 6; i++) {
120 checksum += substructs[substruct]->raw[i];
121 }
122 }
123 return checksum;
124}
125
126/**
127 * Fixes the checksum of a core Pokémon structure.
128 * @param struct BoxPokemon* pkm The BoxPokemon to fix the checksum of.
129*/
130void FixBoxPokemonChecksum(struct BoxPokemon* pkm) {
131 pkm->checksum = CalculateBoxPokemonChecksum(pkm);
132}
133
134/**
135 * Gets the zeroth substructure ("Growth") of a Pokémon structure.
136 * Call DecryptPokemon() first or the substructure data will be encrypted.
137 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
138 * @return struct PokemonSubstruct0* The substructure.
139*/
140struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm) {
141 struct BoxPokemon* boxMon = &(pkm->box);
142 return GetBoxPokemonSubstruct0(boxMon);
143}
144
145/**
146 * Gets the zeroth substructure ("Growth") of a core Pokémon structure.
147 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
148 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
149 * @return struct PokemonSubstruct0* The substructure.
150*/
151struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm) {
152 return &( GetBoxPokemonSubstruct(pkm,0)->type0 );
153}
154
155/**
156 * Gets the first substructure ("Attacks") of a Pokémon structure.
157 * Call DecryptPokemon() first or the substructure data will be encrypted.
158 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
159 * @return struct PokemonSubstruct0* The substructure.
160*/
161struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm) {
162 struct BoxPokemon* boxMon = &(pkm->box);
163 return GetBoxPokemonSubstruct1(boxMon);
164}
165
166/**
167 * Gets the first substructure ("Attacks") of a core Pokémon structure.
168 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
169 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
170 * @return struct PokemonSubstruct1* The substructure.
171*/
172struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm) {
173 return &( GetBoxPokemonSubstruct(pkm,1)->type1 );
174}
175
176/**
177 * Gets the second substructure ("EVs & Condition") of a Pokémon structure.
178 * Call DecryptPokemon() first or the substructure data will be encrypted.
179 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
180 * @return struct PokemonSubstruct0* The substructure.
181*/
182struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm) {
183 struct BoxPokemon* boxMon = &(pkm->box);
184 return GetBoxPokemonSubstruct2(boxMon);
185}
186
187/**
188 * Gets the second substructure ("EVs & Condition") of a core Pokémon structure.
189 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
190 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
191 * @return struct PokemonSubstruct2* The substructure.
192*/
193struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm) {
194 return &( GetBoxPokemonSubstruct(pkm,2)->type2 );
195}
196
197/**
198 * Gets the third substructure ("Miscellaneous") of a Pokémon structure.
199 * Call DecryptPokemon() first or the substructure data will be encrypted.
200 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
201 * @return struct PokemonSubstruct0* The substructure.
202*/
203struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm) {
204 struct BoxPokemon* boxMon = &(pkm->box);
205 return GetBoxPokemonSubstruct3(boxMon);
206}
207
208/**
209 * Gets the third substructure ("Miscellaneous") of a core Pokémon structure.
210 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
211 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
212 * @return struct PokemonSubstruct3* The substructure.
213*/
214struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm) {
215 return &( GetBoxPokemonSubstruct(pkm,3)->type3 );
216}
217
218/**
219 * Calculates the checksum for an R/S-specific Enigma Berry structure in SaveBlock1.
220 * @param struct EnigmaBerry* enigmaBerry The R/S-specific Enigma Berry to calculate the checksum for.
221 * @return u32 The checksum.
222*/
223u32 CalculateEnigmaBerryChecksumRS(struct EnigmaBerry* enigmaBerry) {
224 if (!GAME_RS) return 0; // Enigma Berry structure changed in FR/LG, use CalculateEnigmaBerryChecksumFRLGE() instead.
225 u32 checksum = 0;
226 // Save off and zero out the original Enigma Berry description pointers.
227 const u8* description[2] = { enigmaBerry->berry.description1, enigmaBerry->berry.description2 };
228 enigmaBerry->berry.description1 = enigmaBerry->berry.description2 = NULL;
229 u8* enigmaBerryBytes = (u8*)enigmaBerry;
230 // Calculate the checksum.
231 for (u32 i = 0; i < 1324; i++) {
232 checksum += enigmaBerryBytes[i];
233 }
234 // Restore the saved description.
235 enigmaBerry->berry.description1 = description[0];
236 enigmaBerry->berry.description2 = description[1];
237 return checksum;
238}
239
240/**
241 * Calculates the checksum for an FR/LG/Emerald-specific Enigma Berry structure in SaveBlock1.
242 * @param struct EnigmaBerryFRLGE* enigmaBerry The FR/LG/Emerald-specific Enigma Berry to calculate the checksum for.
243 * @return u32 The checksum.
244*/
245u32 CalculateEnigmaBerryChecksumFRLGE(struct EnigmaBerryFRLGE* enigmaBerry) {
246 if (GAME_RS) return 0; // Enigma Berry structure is different in R/S, use CalculateEnigmaBerryChecksumRS() instead.
247 u32 checksum = 0;
248 u8* enigmaBerryBytes = (u8*)enigmaBerry;
249 for (int i = 0; i < 0x30; i++) {
250 checksum += enigmaBerryBytes[i];
251 }
252 return checksum;
253}
254
255/**
256 * Calculates the checksum for an unspecified Enigma Berry structure in SaveBlock1. (detected by current game)
257 * @param void* enigmaBerry The Enigma Berry structure to calculate the checksum for.
258 * @return u32 The checksum.
259 */
260u32 CalculateEnigmaBerryChecksum(void* enigmaBerry) {
261 if (GAME_RS) return CalculateEnigmaBerryChecksumRS( (struct EnigmaBerry*) enigmaBerry );
262 return CalculateEnigmaBerryChecksumFRLGE( (struct EnigmaBerryFRLGE*) enigmaBerry );
263}
264
265/**
266 * Calculates the checksum for a RAM script structure in SaveBlock1.
267 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
268 * @return u32 The checksum.
269 */
270u32 CalculateRamScriptChecksum(struct RamScript* ramScript) {
271 asm(""); // make sure the call to CalculateRamScriptDataChecksum() is *not* inlined.
272 // For some reason, if it gets inlined, something happens, and the wrong length is used when checksumming...
273 return CalculateRamScriptDataChecksum(&ramScript->data);
274}
275
276/**
277 * Calculates the checksum for a RAM script structure in SaveBlock1.
278 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
279 * @return u32 The checksum.
280 */
281static __attribute__ ((noinline)) u32 CalculateRamScriptDataChecksum(struct RamScriptData* ramScript) {
282 u32 checksum = 0;
283 u32 i = 0;
284 u8* ramScriptBytes = (u8*)(ramScript);
285 if (GAME_RS) {
286 for (i = 0; i < sizeof(struct RamScriptData); i++) checksum += ramScriptBytes[i];
287 return checksum;
288 }
289
290 return (u32)crc16(ramScriptBytes,sizeof(struct RamScriptData) + 1);
291}
292
293/**
294 * Private function to CRC-16, (used by FR/LG/Emerald ramscript checksum). Adapted from http://forums.glitchcity.info/index.php?topic=7114.0
295 * @param u8* Data to checksum
296 * @param u16 Length of data
297 * @return u16 The checksum
298*/
299static u16 crc16(const u8* data, u16 len) {
300 u16 crc = 0x1121;
301 for (u16 i = 0; i < len; ++i) {
302 crc ^= data[i];
303 for (u16 j = 0; j < 8; ++j) {
304 if(crc & 1) {
305 crc = (crc >> 1) ^ 0x8408;
306 } else {
307 crc >>= 1;
308 }
309 }
310 }
311 return ~crc;
312} \ No newline at end of file
diff --git a/gba/source/libpayload.h b/gba/source/libpayload.h new file mode 100644 index 0000000..4be6fb3 --- /dev/null +++ b/gba/source/libpayload.h
@@ -0,0 +1,160 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * libpayload.h: header for payload helper functions
8 */
9
10/**
11 * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily.
12 * Remember to call EncryptPokemon() afterwards.
13 * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of.
14*/
15void DecryptPokemon(struct Pokemon* pkm);
16
17/**
18 * Decrypts the substructures of a core Pokémon structure, so they can be viewed or modified easily.
19 * Used by DecryptPokemon().
20 * Remember to call EncryptPokemon() afterwards.
21 * @param struct BoxPokemon* pkm The BoxPokemon to decrypt the substructures of.
22*/
23void DecryptBoxPokemon(struct BoxPokemon* pkm);
24
25/**
26 * Encrypts the substructures of a Pokémon structure, and fixes the checksum.
27 * Must be used after DecryptPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
28 * @param struct Pokemon* pkm The Pokémon to encrypt the substructures and fix the checksum of.
29*/
30void EncryptPokemon(struct Pokemon* pkm);
31
32/**
33 * Encrypts the substructures of a core Pokémon structure, and fixes the checksum.
34 * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
35 * @param struct BoxPokemon* pkm The BoxPokemon to encrypt the substructures and fix the checksum of.
36*/
37void EncryptBoxPokemon(struct BoxPokemon* pkm);
38
39/**
40 * Gets a substructure of a Pokémon structure.
41 * Call DecryptPokemon() first or the substructure data will be encrypted.
42 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
43 * @param u8 substructId The substructure to get.
44 * @return union PokemonSubstruct* The substructure.
45*/
46union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId);
47
48/**
49 * Gets a substructure of a core Pokémon structure.
50 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
51 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
52 * @param u8 substructId The substructure to get.
53 * @return union PokemonSubstruct* The substructure.
54*/
55union PokemonSubstruct* GetBoxPokemonSubstruct(struct BoxPokemon* pkm,u8 substructId);
56
57/**
58 * Gets the checksum of a core Pokémon structure.
59 * @param struct BoxPokemon* pkm The BoxPokemon to calculate the checksum of.
60 * @return u16 The checksum.
61*/
62u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm);
63
64/**
65 * Fixes the checksum of a core Pokémon structure.
66 * @param struct BoxPokemon* pkm The BoxPokemon to fix the checksum of.
67*/
68void FixBoxPokemonChecksum(struct BoxPokemon* pkm);
69
70/**
71 * Gets the zeroth substructure ("Growth") of a Pokémon structure.
72 * Call DecryptPokemon() first or the substructure data will be encrypted.
73 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
74 * @return struct PokemonSubstruct0* The substructure.
75*/
76struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm);
77
78/**
79 * Gets the zeroth substructure ("Growth") of a core Pokémon structure.
80 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
81 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
82 * @return struct PokemonSubstruct0* The substructure.
83*/
84struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm);
85
86/**
87 * Gets the first substructure ("Attacks") of a Pokémon structure.
88 * Call DecryptPokemon() first or the substructure data will be encrypted.
89 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
90 * @return struct PokemonSubstruct0* The substructure.
91*/
92struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm);
93
94/**
95 * Gets the first substructure ("Attacks") of a core Pokémon structure.
96 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
97 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
98 * @return struct PokemonSubstruct1* The substructure.
99*/
100struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm);
101
102/**
103 * Gets the second substructure ("EVs & Condition") of a Pokémon structure.
104 * Call DecryptPokemon() first or the substructure data will be encrypted.
105 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
106 * @return struct PokemonSubstruct0* The substructure.
107*/
108struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm);
109
110/**
111 * Gets the second substructure ("EVs & Condition") of a core Pokémon structure.
112 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
113 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
114 * @return struct PokemonSubstruct2* The substructure.
115*/
116struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm);
117
118/**
119 * Gets the third substructure ("Miscellaneous") of a Pokémon structure.
120 * Call DecryptPokemon() first or the substructure data will be encrypted.
121 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
122 * @return struct PokemonSubstruct0* The substructure.
123*/
124struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm);
125
126/**
127 * Gets the third substructure ("Miscellaneous") of a core Pokémon structure.
128 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
129 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
130 * @return struct PokemonSubstruct3* The substructure.
131*/
132struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm);
133
134/**
135 * Calculates the checksum for an R/S-specific Enigma Berry structure in SaveBlock1.
136 * @param struct EnigmaBerry* enigmaBerry The R/S-specific Enigma Berry to calculate the checksum for.
137 * @return u32 The checksum.
138*/
139u32 CalculateEnigmaBerryChecksumRS(struct EnigmaBerry* enigmaBerry);
140
141/**
142 * Calculates the checksum for an FR/LG/Emerald-specific Enigma Berry structure in SaveBlock1.
143 * @param struct EnigmaBerryFRLGE* enigmaBerry The FR/LG/Emerald-specific Enigma Berry to calculate the checksum for.
144 * @return u32 The checksum.
145*/
146u32 CalculateEnigmaBerryChecksumFRLGE(struct EnigmaBerryFRLGE* enigmaBerry);
147
148/**
149 * Calculates the checksum for an unspecified Enigma Berry structure in SaveBlock1. (detected by current game)
150 * @param void* enigmaBerry The Enigma Berry structure to calculate the checksum for.
151 * @return u32 The checksum.
152 */
153u32 CalculateEnigmaBerryChecksum(void* enigmaBerry);
154
155/**
156 * Calculates the checksum for a RAM script structure in SaveBlock1.
157 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
158 * @return u32 The checksum.
159 */
160u32 CalculateRamScriptChecksum(struct RamScript* ramScript); \ No newline at end of file
diff --git a/gba/source/payload.c b/gba/source/payload.c index 7015774..665af70 100644 --- a/gba/source/payload.c +++ b/gba/source/payload.c
@@ -12,7 +12,61 @@
12 12
13// Your payload code should obviously go into the body of this, the payload function. 13// Your payload code should obviously go into the body of this, the payload function.
14void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) { 14void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) {
15 // This example payload will modify the first character of the player's name. 15 // HoF-warp example payload!
16 // It will change to 'z'. You can see the character encoding table here: http://bulbapedia.bulbagarden.net/wiki/Character_encoding_in_Generation_III 16
17 SaveBlock2[0] = 0xee; // 'z' 17 // Structure offsets are different between R/S, FR/LG, and Emerald.
18 // The beginning of the structures are the same but do NOT take shortcuts here, it's not good practise.
19 // If you want to support multiple games, make specific checks for games, use the right structure for each game.
20 SaveBlock1_RS* sb1rs = &SaveBlock1->rs;
21 SaveBlock1_FRLG* sb1frlg = &SaveBlock1->frlg;
22 SaveBlock1_E* sb1e = &SaveBlock1->e;
23 if (GAME_FRLG) {
24 sb1frlg->location.mapGroup = 1; // generic indoors?
25 sb1frlg->location.mapNum = 80; // Hall of Fame
26 // set coords to the same place that the champions' room script sets them to
27 sb1frlg->location.x = sb1frlg->pos.x = 5;
28 sb1frlg->location.y = sb1frlg->pos.y = 12;
29 sb1frlg->mapDataId = 0xDA; // from HoF map-header
30 sb1frlg->location.warpId = 0xff;
31 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
32 if (sb1frlg->playerPartyCount == 0) {
33 sb1frlg->playerPartyCount = 1;
34 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
35 // so let's hack together one. i don't care about it becoming a bad egg at all.
36 sb1frlg->playerParty[0].box.personality++;
37 }
38 return;
39 } else if (GAME_RS) {
40 sb1rs->location.mapGroup = 16; // Ever Grande City
41 sb1rs->location.mapNum = 11; // Hall of Fame
42 // set coords to the same place that the champions' room script sets them to
43 sb1rs->location.x = sb1rs->pos.x = 7;
44 sb1rs->location.y = sb1rs->pos.y = 16;
45 sb1rs->mapDataId = 299; // from HoF map-header
46 sb1rs->location.warpId = 0xff;
47 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
48 if (sb1rs->playerPartyCount == 0) {
49 sb1rs->playerPartyCount = 1;
50 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
51 // so let's hack together one. i don't care about it becoming a bad egg at all.
52 sb1rs->playerParty[0].box.personality++;
53 }
54 return;
55 } else if (GAME_EM) {
56 sb1e->location.mapGroup = 16; // Ever Grande City
57 sb1e->location.mapNum = 11; // Hall of Fame
58 // set coords to the same place that the champions' room script sets them to
59 sb1e->location.x = sb1e->pos.x = 7;
60 sb1e->location.y = sb1e->pos.y = 16;
61 sb1e->mapDataId = 298; // from HoF map-header
62 sb1e->location.warpId = 0xff;
63 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
64 if (sb1e->playerPartyCount == 0) {
65 sb1e->playerPartyCount = 1;
66 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
67 // so let's hack together one. i don't care about it becoming a bad egg at all.
68 sb1e->playerParty[0].box.personality++;
69 }
70 return;
71 }
18} \ No newline at end of file 72} \ No newline at end of file
diff --git a/gba/source/payload.h b/gba/source/payload.h index d95476c..ea87200 100644 --- a/gba/source/payload.h +++ b/gba/source/payload.h
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10#include "saveblocks.h" 10#include "saveblocks.h"
11#include "libpayload.h"
11 12
12#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00') 13#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00')
13#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00') 14#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00')
diff --git a/gba/source/saveblocks.h b/gba/source/saveblocks.h index 45c127c..cf0a5c3 100644 --- a/gba/source/saveblocks.h +++ b/gba/source/saveblocks.h
@@ -7,9 +7,337 @@
7 * saveblocks.h: describes saveblock structures for all of Gen 3 (yay!) 7 * saveblocks.h: describes saveblock structures for all of Gen 3 (yay!)
8 */ 8 */
9 9
10// TODO: this entire file. Placeholders for now, fill in later, if I can be bothered. 10// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity
11// I don't really want to make a fork of pokeruby's headers for now... 11#include "savestructs.h"
12 12
13typedef u8 SaveBlock1, *pSaveBlock1; 13typedef struct
14typedef u8 SaveBlock2, *pSaveBlock2; 14{
15typedef u8 SaveBlock3, *pSaveBlock3; \ No newline at end of file 15 /*0x00*/ struct Coords16 pos;
16 /*0x04*/ struct WarpData location;
17 /*0x0C*/ struct WarpData warp[4];
18 /*0x2C*/ u16 battleMusic;
19 /*0x2E*/ u8 weather;
20 /*0x2F*/ u8 filler_2F;
21 /*0x30*/ u8 flashUsed;
22 /*0x32*/ u16 mapDataId;
23 /*0x34*/ u16 mapView[0x100];
24 /*0x234*/ u8 playerPartyCount;
25 /*0x238*/ struct Pokemon playerParty[6];
26 /*0x490*/ u32 money;
27 /*0x494*/ u16 coins;
28 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
29 /*0x498*/ struct ItemSlot pcItems[50];
30 /*0x560*/ struct ItemSlot bagPocket_Items[20];
31 /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[20];
32 /*0x600*/ struct ItemSlot bagPocket_PokeBalls[16];
33 /*0x640*/ struct ItemSlot bagPocket_TMHM[64];
34 /*0x740*/ struct ItemSlot bagPocket_Berries[46];
35 /*0x7F8*/ struct Pokeblock pokeblocks[40];
36 /*0x938*/ u8 unk938[52]; // pokedex related
37 /*0x96C*/ u16 berryBlenderRecords[3];
38 /*0x972*/ u8 filler_972[0x6];
39 /*0x978*/ u16 trainerRematchStepCounter;
40 /*0x97A*/ u8 trainerRematches[100];
41 /*0x9E0*/ struct MapObject mapObjects[16];
42 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
43 /*0x1220*/ u8 flags[0x120];
44 /*0x1340*/ u16 vars[0x100];
45 /*0x1540*/ u32 gameStats[50];
46 /*0x1608*/ struct BerryTree berryTrees[128];
47 /*0x1A08*/ struct SecretBaseRecord secretBases[20];
48 /*0x2688*/ u8 playerRoomDecor[12];
49 /*0x2694*/ u8 playerRoomDecorPos[12];
50 /*0x26A0*/ u8 decorDesk[10];
51 /*0x26AA*/ u8 decorChair[10];
52 /*0x26B4*/ u8 decorPlant[10];
53 /*0x26BE*/ u8 decorOrnament[30];
54 /*0x26DC*/ u8 decorMat[30];
55 /*0x26FA*/ u8 decorPoster[10];
56 /*0x2704*/ u8 decorDoll[40];
57 /*0x272C*/ u8 decorCushion[10];
58 /*0x2736*/ u8 padding_2736[2];
59 /*0x2738*/ TVShow tvShows[24];
60 /*0x2A98*/ u8 filler_2A98[0x64];
61 /*0x2AFC*/ u16 outbreakPokemonSpecies;
62 /*0x2AFE*/ u8 outbreakLocationMapNum;
63 /*0x2AFF*/ u8 outbreakLocationMapGroup;
64 /*0x2B00*/ u8 outbreakPokemonLevel;
65 /*0x2B01*/ u8 outbreakUnk1;
66 /*0x2B02*/ u16 outbreakUnk2;
67 /*0x2B04*/ u16 outbreakPokemonMoves[4];
68 /*0x2B0C*/ u8 outbreakUnk4;
69 /*0x2B0D*/ u8 outbreakPokemonProbability;
70 /*0x2B0E*/ u16 outbreakUnk5;
71 /*0x2B10*/ u8 filler_2B0E[0xC];
72 /*0x2B1C*/ u16 unk2B1C[4];
73 /*0x2B24*/ u8 filler_2B24[0x28];
74 /*0x2B4C*/ struct MailStruct mail[16];
75 /*0x2D8C*/ u8 filler_2D8C[0x8];
76 /*0x2D94*/ OldMan oldMan;
77 /*0x2DC0*/ u8 unk_2DC0[0x14];
78 /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff
79 /*0x2DFC*/ u8 filler_2DFC[0x100];
80 /*0x2EFC*/ struct SB1_2EFC_Struct sb1_2EFC_struct[5];
81 /*0x2F9C*/ u8 filler_2F9C[0xA0];
82 /*0x303C*/ u8 filler_303C[0x38];
83 /*0x3074*/ u8 filler_3074[0x42];
84 /*0x30B6*/ u8 filler_30B6;
85 /*0x30B7*/ u8 filler_30B7[0x59];
86 /*0x3110*/ u8 giftRibbons[7];
87 /*0x3117*/ u8 filler_311B[0x2D];
88 /*0x3144*/ struct Roamer roamer;
89 /*0x3158*/ u8 filler_3158[0x8];
90 /*0x3160*/ struct EnigmaBerry enigmaBerry; // this is actually offset by 0x98 ...
91 /*0x3690*/ struct RamScript ramScript;
92 /*0x3A7C*/ u8 filler_3A7C[0x10];
93 /*0x3A8C*/ u8 unk3A8C[52]; //pokedex related
94} SaveBlock1_RS;
95
96typedef struct // Don't rely on the commented offsets, they'll be wrong due to elements removed in FR/LG...
97{
98 /*0x00*/ struct Coords16 pos;
99 /*0x04*/ struct WarpData location;
100 /*0x0C*/ struct WarpData warp[4];
101 /*0x2C*/ u16 battleMusic;
102 /*0x2E*/ u8 weather;
103 /*0x2F*/ u8 filler_2F;
104 /*0x30*/ u8 flashUsed;
105 /*0x32*/ u16 mapDataId;
106// /*0x34*/ u16 mapView[0x100]; // Not in fr/lg
107 /*0x234*/ u8 playerPartyCount;
108 /*0x238*/ struct Pokemon playerParty[6];
109 /*0x490*/ u32 money;
110 /*0x494*/ u16 coins;
111 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
112 /*0x498*/ struct ItemSlot pcItems[30];
113 /*0x560*/ struct ItemSlot bagPocket_Items[42];
114 /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[30];
115 /*0x600*/ struct ItemSlot bagPocket_PokeBalls[13];
116 /*0x640*/ struct ItemSlot bagPocket_TMHM[58];
117 /*0x740*/ struct ItemSlot bagPocket_Berries[43];
118// /*0x7F8*/ struct Pokeblock pokeblocks[40]; // Not in fr/lg
119 /*0x938*/ u8 unk938[52]; // pokedex related
120 /*0x96C*/ u8 unk_62C[12];
121 /*0x972*/ u8 filler_972[0x6];
122 /*0x97A*/ u8 unk_63E[98];
123 /*0x9E0*/ struct MapObject mapObjects[16];
124 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
125 /*0x1220*/ u8 flags[0x120];
126 /*0x1340*/ u16 vars[0x100];
127 /*0x1540*/ u32 gameStats[64]; // encrypted with saveblock2 xor-key
128 struct QuestStory questlog[4];
129 u8 messages[12][4];
130 struct NPCState npc_states[0x10];
131 u8 unk_2f10[112];
132 struct DaycarePokemon daycare[2];
133 u8 unk_3098[56];
134 struct Roamer roamer;
135 u8 unk_30e4[8];
136 /*0x3160*/ struct EnigmaBerryFRLGE enigmaBerry;
137 u8 unk_3120[0x1C0]; // 4 bytes of CRC16, then 444 bytes of unknown. Mystery Gift related.
138 u8 unk_32E0[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_1"
139 u8 unk_3430[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_2"
140 u8 unk_368C[0x9C]; // padding? doesn't seem to be actually used
141 struct RamScript ramScript;
142 u8 unk_3A07[17];
143 u8 pokemon_flags_2[52];
144 u8 rivalName[8];
145 u8 unk_3a54[128];
146 u8 words[21][10];
147 u8 unk_3ba6[570];
148} __attribute__((aligned(1))) SaveBlock1_FRLG;
149
150typedef struct // Don't rely on the commented offsets, they'll be wrong due to elements changed/added in Emerald...
151{
152 /*0x00*/ struct Coords16 pos;
153 /*0x04*/ struct WarpData location;
154 /*0x0C*/ struct WarpData warp[4];
155 /*0x2C*/ u16 battleMusic;
156 /*0x2E*/ u8 weather;
157 /*0x2F*/ u8 filler_2F;
158 /*0x30*/ u8 flashUsed;
159 /*0x32*/ u16 mapDataId;
160 /*0x34*/ u16 mapView[0x100];
161 /*0x234*/ u8 playerPartyCount;
162 /*0x238*/ struct Pokemon playerParty[6];
163 /*0x490*/ u32 money;
164 /*0x494*/ u16 coins;
165 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
166 /*0x498*/ struct ItemSlot pcItems[50];
167 /*0x560*/ struct ItemSlot bagPocket_Items[30];
168 /*0x5D8*/ struct ItemSlot bagPocket_KeyItems[30];
169 /*0x650*/ struct ItemSlot bagPocket_PokeBalls[16];
170 /*0x690*/ struct ItemSlot bagPocket_TMHM[64];
171 /*0x790*/ struct ItemSlot bagPocket_Berries[46];
172 /*0x7F8*/ struct Pokeblock pokeblocks[40]; // every offset is shifted by 0x50 from here on thanks to changed bag-counts
173 /*0x938*/ u8 unk938[52]; // pokedex related
174 /*0x96C*/ u16 berryBlenderRecords[3];
175 /*0x972*/ u8 filler_972[0x6];
176 /*0x978*/ u16 trainerRematchStepCounter;
177 /*0x97A*/ u8 trainerRematches[100];
178 /*0x9E0*/ struct MapObject mapObjects[16];
179 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
180 /*0x1220*/ u8 flags[0x12C];
181 /*0x1340*/ u16 vars[0x100]; // offsets shifted by 0x5C from here on thanks to added flags
182 /*0x1540*/ u32 gameStats[64]; // encrypted with saveblock2 xor-key
183 /*0x1608*/ struct BerryTree berryTrees[128]; // offsets shifted by 0x94 from here on thanks to added 14 gamestats
184 /*0x1A08*/ struct SecretBaseRecord secretBases[20];
185 /*0x2688*/ u8 playerRoomDecor[12];
186 /*0x2694*/ u8 playerRoomDecorPos[12];
187 /*0x26A0*/ u8 decorDesk[10];
188 /*0x26AA*/ u8 decorChair[10];
189 /*0x26B4*/ u8 decorPlant[10];
190 /*0x26BE*/ u8 decorOrnament[30];
191 /*0x26DC*/ u8 decorMat[30];
192 /*0x26FA*/ u8 decorPoster[10];
193 /*0x2704*/ u8 decorDoll[40];
194 /*0x272C*/ u8 decorCushion[10];
195 // /*0x2736*/ u8 padding_2736[2];
196 /*0x2738*/ TVShow tvShows[24];
197 /*0x2A98*/ u8 filler_2A98[0x64];
198 /*0x2AFC*/ u16 outbreakPokemonSpecies; // offset by 0x94
199 /*0x2AFE*/ u8 outbreakLocationMapNum;
200 /*0x2AFF*/ u8 outbreakLocationMapGroup;
201 /*0x2B00*/ u8 outbreakPokemonLevel;
202 /*0x2B01*/ u8 outbreakUnk1;
203 /*0x2B02*/ u16 outbreakUnk2;
204 /*0x2B04*/ u16 outbreakPokemonMoves[4];
205 /*0x2B0C*/ u8 outbreakUnk4;
206 /*0x2B0D*/ u8 outbreakPokemonProbability;
207 /*0x2B0E*/ u16 outbreakUnk5;
208 /*0x2B10*/ u8 filler_2B0E[0xC];
209 /*0x2B1C*/ u16 unk2B1C[4];
210 /*0x2B24*/ u8 filler_2B24[0x28];
211 /*0x2B4C*/ struct MailStruct mail[16]; // offset by 0x94
212 /*0x2D8C*/ u8 filler_2D8C[0x8];
213 /*0x2D94*/ OldMan oldMan;
214 /*0x2DC0*/ u8 unk_2DC0[0x14];
215 /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff
216 // /*0x2DFC*/ u8 filler_2DFC[0x100];
217 /*0x2EFC*/ struct SB1_2EFC_Struct sb1_2EFC_struct[12];
218 u8 unk_3010[0x198]; // no idea if any of this is actually used.
219 /*0x3110*/ u8 giftRibbons[7];
220 /*0x3117*/ u8 filler_311B[0x2D];
221 /*0x3144*/ struct Roamer roamer;
222 /*0x3158*/ u8 filler_3158[0x8];
223 /*0x3160*/ struct EnigmaBerryFRLGE enigmaBerry;
224 u8 unk_322C[0x1C0]; // 4 bytes of CRC16, then 444 bytes of unknown. Mystery Gift related.
225 u8 unk_33EC[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_1"
226 u8 unk_353C[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_2"
227 u8 unk_368C[0x9C]; // padding? doesn't seem to be actually used
228 /*0x3690*/ struct RamScript ramScript;
229 /*0x3A7C*/ u8 filler_3A7C[0x10];
230 /*0x3A8C*/ u8 unk3A8C[52]; //pokedex related
231} SaveBlock1_E;
232
233// ---
234
235struct SaveBlock2_Sub
236{
237 /*0x0000, 0x00A8*/ u8 filler_000[0x4AE];
238 /*0x04AE, 0x0556*/ u8 var_4AE;
239 /*0x04AF, 0x0557*/ u8 var_4AF;
240 /*0x04B0, 0x0558*/ u16 var_4B0;
241 /*0x04B2, 0x055A*/ u16 var_4B2;
242 /*0x04B4, 0x055C*/ u16 var_4B4;
243 /*0x04B6, 0x055E*/ u16 var_4B6;
244 /*0x04B8, 0x0560*/ u8 filler_4B8[0x10];
245 /*0x04C8, 0x0570*/ u16 var_4C8;
246 /*0x04CA, 0x0572*/ u16 var_4CA;
247 /*0x04CC, 0x0574*/ u8 filler_4CC[0x31C];
248};
249
250typedef struct
251{
252 /*0x00*/ u8 playerName[8];
253 /*0x08*/ u8 playerGender; // MALE, FEMALE
254 /*0x09*/ u8 specialSaveWarp;
255 /*0x0A*/ u8 playerTrainerId[4];
256 /*0x0E*/ u16 playTimeHours;
257 /*0x10*/ u8 playTimeMinutes;
258 /*0x11*/ u8 playTimeSeconds;
259 /*0x12*/ u8 playTimeVBlanks;
260 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
261 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
262 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
263 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
264 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
265 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
266 u16 regionMapZoom:1; // whether the map is zoomed in
267 /*0x18*/ struct Pokedex pokedex;
268 /*0x90*/ u8 filler_90[0x8];
269 /*0x98*/ struct Time localTimeOffset;
270 /*0xA0*/ struct Time lastBerryTreeUpdate;
271 /*0xA8*/ struct SaveBlock2_Sub filler_A8;
272} SaveBlock2_RS;
273
274typedef struct
275{
276 /*0x00*/ u8 playerName[8];
277 /*0x08*/ u8 playerGender; // MALE, FEMALE
278 /*0x09*/ u8 specialSaveWarp;
279 /*0x0A*/ u8 playerTrainerId[4];
280 /*0x0E*/ u16 playTimeHours;
281 /*0x10*/ u8 playTimeMinutes;
282 /*0x11*/ u8 playTimeSeconds;
283 /*0x12*/ u8 playTimeVBlanks;
284 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
285 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
286 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
287 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
288 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
289 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
290 u16 regionMapZoom:1; // whether the map is zoomed in
291 /*0x18*/ struct Pokedex pokedex;
292 /*0x90*/ u8 filler_90[0x8];
293 /*0x98*/ struct Time localTimeOffset;
294 /*0xA0*/ struct Time lastBerryTreeUpdate;
295 /*0xA8*/ struct SaveBlock2_Sub filler_A8;
296 /*0x890*/ u8 unk_890[8];
297 /*0x898*/ u8 mapdata[0x258];
298 /*0xaf0*/ u16 field_af0;
299 /*0xaf2*/ u16 field_af2;
300 /*0xaf4*/ u16 field_af4;
301 /*0xaf6*/ u16 field_af6;
302 /*0xaf8*/ u8 unk_af8[0x428];
303 /*0xf20*/ u32 xor_key;
304} SaveBlock2_FRLG;
305
306typedef struct
307{
308 /*0x00*/ u8 playerName[8];
309 /*0x08*/ u8 playerGender; // MALE, FEMALE
310 /*0x09*/ u8 specialSaveWarp;
311 /*0x0A*/ u8 playerTrainerId[4];
312 /*0x0E*/ u16 playTimeHours;
313 /*0x10*/ u8 playTimeMinutes;
314 /*0x11*/ u8 playTimeSeconds;
315 /*0x12*/ u8 playTimeVBlanks;
316 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
317 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
318 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
319 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
320 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
321 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
322 u16 regionMapZoom:1; // whether the map is zoomed in
323 /*0x18*/ struct Pokedex pokedex;
324 /*0x90*/ u8 filler_90[0x8];
325 /*0x98*/ struct Time localTimeOffset;
326 /*0xA0*/ struct Time lastBerryTreeUpdate;
327 /*0xA8*/ u32 xor_key;
328 /*0xAC*/ struct SaveBlock2_Sub filler_A8;
329} SaveBlock2_E;
330
331typedef union {
332 SaveBlock1_RS rs;
333 SaveBlock1_FRLG frlg;
334 SaveBlock1_E e;
335} SaveBlock1, *pSaveBlock1;
336
337typedef union {
338 SaveBlock2_RS rs;
339 SaveBlock2_FRLG frlg;
340 SaveBlock2_E e;
341} SaveBlock2, *pSaveBlock2;
342
343typedef struct PokemonStorage SaveBlock3, *pSaveBlock3; \ No newline at end of file
diff --git a/gba/source/savestructs.h b/gba/source/savestructs.h new file mode 100644 index 0000000..2bf4d4d --- /dev/null +++ b/gba/source/savestructs.h
@@ -0,0 +1,793 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * saveblocks.h: describes structures used by saveblocks for all of Gen 3
8 */
9
10// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity
11
12#define POKEMON_NAME_LENGTH 10
13#define OT_NAME_LENGTH 7
14#define TILE_SIZE_4BPP 32
15
16struct Coords16
17{
18 s16 x;
19 s16 y;
20};
21
22struct UCoords16
23{
24 u16 x;
25 u16 y;
26};
27
28struct SecretBaseRecord
29{
30 u8 sbr_field_0; // ID?
31 u8 sbr_field_1_0:4;
32 u8 gender:1;
33 u8 sbr_field_1_5:1;
34 u8 sbr_field_2[7]; // 0xFF bytes?
35 u8 trainerId[4]; // byte 0 is used for determining trainer class
36 u16 sbr_field_e;
37 u8 sbr_field_10;
38 u8 sbr_field_11;
39 u8 decorations[16];
40 u8 sbr_field_22[16];
41 u32 partyPersonality[6];
42 u16 partyMoves[6 * 4];
43 u16 partySpecies[6];
44 u16 partyHeldItems[6];
45 u8 partyLevels[6];
46 u8 partyEVs[6];
47};
48
49typedef void (*TilesetCB)(void);
50
51struct Tileset
52{
53 u8 isCompressed;
54 u8 isSecondary;
55 void *tiles;
56 void *palettes;
57 void *metatiles;
58 void *metatileAttributes;
59 TilesetCB callback;
60};
61
62struct MapData
63{
64 s32 width;
65 s32 height;
66 u16 *border;
67 u16 *map;
68 struct Tileset *primaryTileset;
69 struct Tileset *secondaryTileset;
70};
71
72struct MapObjectTemplate
73{
74 /*0x00*/ u8 localId;
75 /*0x01*/ u8 graphicsId;
76 /*0x02*/ u8 unk2;
77 /*0x04*/ s16 x;
78 /*0x06*/ s16 y;
79 /*0x08*/ u8 elevation;
80 /*0x09*/ u8 movementType;
81 /*0x0A*/ u8 unkA_0:4;
82 u8 unkA_4:4;
83 ///*0x0B*/ u8 fillerB[1];
84 /*0x0C*/ u16 unkC;
85 /*0x0E*/ u16 unkE;
86 /*0x10*/ u8 *script;
87 /*0x14*/ u16 flagId;
88 /*0x16*/ u8 filler_16[2];
89}; /*size = 0x18*/
90
91struct WarpEvent
92{
93 s16 x, y;
94 s8 warpId;
95 u8 mapGroup;
96 u8 mapNum;
97 u8 unk7;
98};
99
100struct CoordEvent
101{
102 s16 x, y;
103 u8 unk4;
104 u8 filler_5;
105 u16 trigger;
106 u16 index;
107 u8 filler_A[0x2];
108 u8 *script;
109};
110
111struct BgEvent
112{
113 s16 x, y;
114 u8 unk4;
115 u8 kind;
116 s16 filler_6;
117 u8 *script;
118};
119
120struct MapEvents
121{
122 u8 mapObjectCount;
123 u8 warpCount;
124 u8 coordEventCount;
125 u8 bgEventCount;
126
127 struct MapObjectTemplate *mapObjects;
128 struct WarpEvent *warps;
129 struct CoordEvent *coordEvents;
130 struct BgEvent *bgEvents;
131};
132
133struct MapConnection
134{
135 u8 direction;
136 u32 offset;
137 u8 mapGroup;
138 u8 mapNum;
139};
140
141struct MapConnections
142{
143 s32 count;
144 struct MapConnection *connections;
145};
146
147struct MapHeader
148{
149 struct MapData *mapData;
150 struct MapEvents *events;
151 u8 *mapScripts;
152 struct MapConnections *connections;
153 u16 music;
154 u16 mapDataId;
155 u8 name;
156 u8 cave;
157 u8 weather;
158 /* 0x17 */ u8 mapType;
159 u8 filler_18;
160 u8 escapeRope;
161 u8 flags;
162 u8 battleType;
163};
164
165struct MapObject
166{
167 /*0x00*/ u32 active:1;
168 u32 mapobj_bit_1:1;
169 u32 mapobj_bit_2:1;
170 u32 mapobj_bit_3:1;
171 u32 mapobj_bit_4:1;
172 u32 mapobj_bit_5:1;
173 u32 mapobj_bit_6:1;
174 u32 mapobj_bit_7:1;
175 /*0x01*/ u32 mapobj_bit_8:1;
176 u32 mapobj_bit_9:1;
177 u32 mapobj_bit_10:1;
178 u32 mapobj_bit_11:1;
179 u32 mapobj_bit_12:1;
180 u32 mapobj_bit_13:1;
181 u32 mapobj_bit_14:1;
182 u32 mapobj_bit_15:1;
183 /*0x02*/ u32 mapobj_bit_16:1;
184 u32 mapobj_bit_17:1;
185 u32 mapobj_bit_18:1;
186 u32 mapobj_bit_19:1;
187 u32 mapobj_bit_20:1;
188 u32 mapobj_bit_21:1;
189 u32 mapobj_bit_22:1;
190 u32 mapobj_bit_23:1;
191 /*0x03*/ u32 mapobj_bit_24:1;
192 u32 mapobj_bit_25:1;
193 u32 mapobj_bit_26:1;
194 u32 mapobj_bit_27:1;
195 u32 mapobj_bit_28:1;
196 u32 mapobj_bit_29:1;
197 u32 mapobj_bit_30:1;
198 u32 mapobj_bit_31:1;
199 /*0x04*/ u8 spriteId;
200 /*0x05*/ u8 graphicsId;
201 /*0x06*/ u8 animPattern;
202 /*0x07*/ u8 trainerType;
203 /*0x08*/ u8 localId;
204 /*0x09*/ u8 mapNum;
205 /*0x0A*/ u8 mapGroup;
206 /*0x0B*/ u8 mapobj_unk_0B_0:4;
207 u8 elevation:4;
208 /*0x0C*/ struct Coords16 coords1;
209 /*0x10*/ struct Coords16 coords2;
210 /*0x14*/ struct Coords16 coords3;
211 /*0x18*/ u8 mapobj_unk_18:4; //current direction?
212 /*0x18*/ u8 placeholder18:4;
213 /*0x19*/ u8 mapobj_unk_19;
214 /*0x1A*/ u8 mapobj_unk_1A;
215 /*0x1B*/ u8 mapobj_unk_1B;
216 /*0x1C*/ u8 mapobj_unk_1C;
217 /*0x1D*/ u8 trainerRange_berryTreeId;
218 /*0x1E*/ u8 mapobj_unk_1E;
219 /*0x1F*/ u8 mapobj_unk_1F;
220 /*0x20*/ u8 mapobj_unk_20;
221 /*0x21*/ u8 mapobj_unk_21;
222 /*0x22*/ u8 animId;
223 /*size = 0x24*/
224};
225
226struct Berry
227{
228 const u8 name[7];
229 u8 firmness;
230 u16 size;
231 u8 maxYield;
232 u8 minYield;
233 const u8 *description1;
234 const u8 *description2;
235 u8 stageDuration;
236 u8 spicy;
237 u8 dry;
238 u8 sweet;
239 u8 bitter;
240 u8 sour;
241 u8 smoothness;
242};
243
244struct EnigmaBerry
245{
246 struct Berry berry;
247 u8 pic[(6 * 6) * TILE_SIZE_4BPP];
248 u16 palette[16];
249 u8 description1[45];
250 u8 description2[45];
251 u8 itemEffect[18];
252 u8 holdEffect;
253 u8 holdEffectParam;
254 u32 checksum;
255};
256
257struct BattleEnigmaBerry
258{
259 u8 name[7];
260 u8 holdEffect;
261 u8 itemEffect[18];
262 u8 holdEffectParam;
263};
264
265struct EnigmaBerryFRLGE {
266 struct Berry berry; // 0x00
267 u8 itemEffect[18]; // 0x1C
268 u8 holdEffect; // 0x2E
269 u8 holdEffectParam; // 0x2F
270 u32 checksum; // 0x30
271};
272
273struct __attribute__((aligned(4))) BerryTree
274{
275 u8 berry;
276 u8 stage:7;
277 u8 growthSparkle:1;
278 u16 secondsUntilNextStage;
279 u8 berryYield;
280 u8 regrowthCount:4;
281 u8 watered1:1;
282 u8 watered2:1;
283 u8 watered3:1;
284 u8 watered4:1;
285};
286
287struct PokemonSubstruct0
288{
289 u16 species;
290 u16 heldItem;
291 u32 experience;
292 u8 ppBonuses;
293 u8 friendship;
294};
295
296struct PokemonSubstruct1
297{
298 u16 moves[4];
299 u8 pp[4];
300};
301
302struct PokemonSubstruct2
303{
304 u8 hpEV;
305 u8 attackEV;
306 u8 defenseEV;
307 u8 speedEV;
308 u8 spAttackEV;
309 u8 spDefenseEV;
310 u8 cool;
311 u8 beauty;
312 u8 cute;
313 u8 smart;
314 u8 tough;
315 u8 sheen;
316};
317
318struct PokemonSubstruct3
319{
320 /* 0x00 */ u8 pokerus;
321 /* 0x01 */ u8 metLocation;
322
323 /* 0x02 */ u16 metLevel:7;
324 /* 0x02 */ u16 metGame:4;
325 /* 0x03 */ u16 pokeball:4;
326 /* 0x03 */ u16 otGender:1;
327
328 /* 0x04 */ u32 hpIV:5;
329 /* 0x04 */ u32 attackIV:5;
330 /* 0x05 */ u32 defenseIV:5;
331 /* 0x05 */ u32 speedIV:5;
332 /* 0x05 */ u32 spAttackIV:5;
333 /* 0x06 */ u32 spDefenseIV:5;
334 /* 0x07 */ u32 isEgg:1;
335 /* 0x07 */ u32 altAbility:1;
336
337 /* 0x08 */ u32 coolRibbon:3;
338 /* 0x08 */ u32 beautyRibbon:3;
339 /* 0x08 */ u32 cuteRibbon:3;
340 /* 0x09 */ u32 smartRibbon:3;
341 /* 0x09 */ u32 toughRibbon:3;
342 /* 0x09 */ u32 championRibbon:1;
343 /* 0x0A */ u32 winningRibbon:1;
344 /* 0x0A */ u32 victoryRibbon:1;
345 /* 0x0A */ u32 artistRibbon:1;
346 /* 0x0A */ u32 effortRibbon:1;
347 /* 0x0A */ u32 giftRibbon1:1;
348 /* 0x0A */ u32 giftRibbon2:1;
349 /* 0x0A */ u32 giftRibbon3:1;
350 /* 0x0A */ u32 giftRibbon4:1;
351 /* 0x0B */ u32 giftRibbon5:1;
352 /* 0x0B */ u32 giftRibbon6:1;
353 /* 0x0B */ u32 giftRibbon7:1;
354 /* 0x0B */ u32 fatefulEncounter:5; // unused in Ruby/Sapphire, but the high bit must be set for Mew/Deoxys to obey in FR/LG/Emerald
355};
356
357union PokemonSubstruct
358{
359 struct PokemonSubstruct0 type0;
360 struct PokemonSubstruct1 type1;
361 struct PokemonSubstruct2 type2;
362 struct PokemonSubstruct3 type3;
363 u16 raw[6];
364};
365
366struct BoxPokemon
367{
368 u32 personality;
369 u32 otId;
370 u8 nickname[POKEMON_NAME_LENGTH];
371 u8 language;
372 u8 isBadEgg:1;
373 u8 hasSpecies:1;
374 u8 isEgg:1;
375 u8 unused:5;
376 u8 otName[OT_NAME_LENGTH];
377 u8 markings;
378 u16 checksum;
379 u16 unknown;
380
381 union
382 {
383 u32 raw[12];
384 union PokemonSubstruct substructs[4];
385 } secure;
386};
387
388struct Pokemon
389{
390 struct BoxPokemon box;
391 u32 status;
392 u8 level;
393 u8 pokerus;
394 u16 hp;
395 u16 maxHP;
396 u16 attack;
397 u16 defense;
398 u16 speed;
399 u16 spAttack;
400 u16 spDefense;
401};
402
403struct UnknownPokemonStruct
404{
405 u16 species;
406 u16 heldItem;
407 u16 moves[4];
408 u8 level;
409 u8 ppBonuses;
410 u8 hpEV;
411 u8 attackEV;
412 u8 defenseEV;
413 u8 speedEV;
414 u8 spAttackEV;
415 u8 spDefenseEV;
416 u32 otId;
417 u32 hpIV:5;
418 u32 attackIV:5;
419 u32 defenseIV:5;
420 u32 speedIV:5;
421 u32 spAttackIV:5;
422 u32 spDefenseIV:5;
423 u32 gap:1;
424 u32 altAbility:1;
425 u32 personality;
426 u8 nickname[POKEMON_NAME_LENGTH + 1];
427 u8 friendship;
428};
429
430struct BattlePokemon
431{
432 /* 0x00 */ u16 species;
433 /* 0x02 */ u16 attack;
434 /* 0x04 */ u16 defense;
435 /* 0x06 */ u16 speed;
436 /* 0x08 */ u16 spAttack;
437 /* 0x0A */ u16 spDefense;
438 /* 0x0C */ u16 moves[4];
439 /* 0x14 */ u32 hpIV:5;
440 /* 0x14 */ u32 attackIV:5;
441 /* 0x15 */ u32 defenseIV:5;
442 /* 0x15 */ u32 speedIV:5;
443 /* 0x16 */ u32 spAttackIV:5;
444 /* 0x17 */ u32 spDefenseIV:5;
445 /* 0x17 */ u32 isEgg:1;
446 /* 0x17 */ u32 altAbility:1;
447 /* 0x18 */ s8 statStages[8];
448 /* 0x20 */ u8 ability;
449 /* 0x21 */ u8 type1;
450 /* 0x22 */ u8 type2;
451 /* 0x23 */ u8 unknown;
452 /* 0x24 */ u8 pp[4];
453 /* 0x28 */ u16 hp;
454 /* 0x2A */ u8 level;
455 /* 0x2B */ u8 friendship;
456 /* 0x2C */ u16 maxHP;
457 /* 0x2E */ u16 item;
458 /* 0x30 */ u8 nickname[POKEMON_NAME_LENGTH + 1];
459 /* 0x3B */ u8 ppBonuses;
460 /* 0x3C */ u8 otName[8];
461 /* 0x44 */ u32 experience;
462 /* 0x48 */ u32 personality;
463 /* 0x4C */ u32 status1;
464 /* 0x50 */ u32 status2;
465 /* 0x54 */ u32 otId;
466};
467
468struct BaseStats
469{
470 /* 0x00 */ u8 baseHP;
471 /* 0x01 */ u8 baseAttack;
472 /* 0x02 */ u8 baseDefense;
473 /* 0x03 */ u8 baseSpeed;
474 /* 0x04 */ u8 baseSpAttack;
475 /* 0x05 */ u8 baseSpDefense;
476 /* 0x06 */ u8 type1;
477 /* 0x07 */ u8 type2;
478 /* 0x08 */ u8 catchRate;
479 /* 0x09 */ u8 expYield;
480 /* 0x0A */ u16 evYield_HP:2;
481 /* 0x0A */ u16 evYield_Attack:2;
482 /* 0x0A */ u16 evYield_Defense:2;
483 /* 0x0A */ u16 evYield_Speed:2;
484 /* 0x0B */ u16 evYield_SpAttack:2;
485 /* 0x0B */ u16 evYield_SpDefense:2;
486 /* 0x0C */ u16 item1;
487 /* 0x0E */ u16 item2;
488 /* 0x10 */ u8 genderRatio;
489 /* 0x11 */ u8 eggCycles;
490 /* 0x12 */ u8 friendship;
491 /* 0x13 */ u8 growthRate;
492 /* 0x14 */ u8 eggGroup1;
493 /* 0x15 */ u8 eggGroup2;
494 /* 0x16 */ u8 ability1;
495 /* 0x17 */ u8 ability2;
496 /* 0x18 */ u8 safariZoneFleeRate;
497 /* 0x19 */ u8 bodyColor;
498};
499
500struct BattleMove
501{
502 u8 effect;
503 u8 power;
504 u8 type;
505 u8 accuracy;
506 u8 pp;
507 u8 secondaryEffectChance;
508 u8 target;
509 u8 priority;
510 u32 flags;
511};
512
513struct PokemonStorage
514{
515 /* 0x00 */ u8 currentBox;
516 /* 0x01 */ struct BoxPokemon boxes[14][30];
517 u8 boxNames[14][9];
518 u8 boxBackground[14];
519};
520
521struct WarpData
522{
523 s8 mapGroup;
524 s8 mapNum;
525 s8 warpId;
526 s16 x, y;
527};
528
529struct ItemSlot
530{
531 u16 itemId;
532 u16 quantity;
533};
534
535struct __attribute__((aligned(2))) Pokeblock
536{
537 u8 color;
538 u8 spicy;
539 u8 dry;
540 u8 sweet;
541 u8 bitter;
542 u8 sour;
543 u8 feel;
544};
545
546struct Roamer
547{
548 /*0x00*/ u32 ivs;
549 /*0x04*/ u32 personality;
550 /*0x08*/ u16 species;
551 /*0x0A*/ u16 hp;
552 /*0x0C*/ u8 level;
553 /*0x0D*/ u8 status;
554 /*0x0E*/ u8 cool;
555 /*0x0F*/ u8 beauty;
556 /*0x10*/ u8 cute;
557 /*0x11*/ u8 smart;
558 /*0x12*/ u8 tough;
559 /*0x13*/ u8 active;
560};
561
562struct RamScriptData
563{
564 u8 magic;
565 u8 mapGroup;
566 u8 mapNum;
567 u8 objectId;
568 u8 script[995];
569} __attribute__((aligned(1),packed));
570
571struct RamScript
572{
573 u32 checksum;
574 struct RamScriptData data;
575} __attribute__((aligned(1),packed));
576
577struct SB1_2EFC_Struct
578{
579 u8 unknown[0x20];
580};
581
582struct EasyChatPair
583{
584 u16 unk0_0:7;
585 u16 unk0_7:7;
586 u16 unk1_6:1;
587 u16 unk2;
588 u16 words[2];
589}; /*size = 0x8*/
590
591struct TVShowCommon {
592 /*0x00*/ u8 var00;
593 /*0x01*/ u8 var01;
594};
595
596struct TVShowFanClubLetter {
597 /*0x00*/ u8 var00;
598 /*0x01*/ u8 var01;
599 /*0x02*/ u16 species;
600 u8 pad04[12];
601 /*0x10*/ u8 playerName[8];
602 /*0x18*/ u8 var18;
603};
604
605struct TVShowRecentHappenings {
606 /*0x00*/ u8 var00;
607 /*0x01*/ u8 var01;
608 /*0x02*/ u16 var02;
609 u8 pad04[12];
610 /*0x10*/ u8 var10[8];
611 /*0x18*/ u8 var18;
612 u8 pad19[10];
613};
614
615struct TVShowFanclubOpinions {
616 /*0x00*/ u8 var00;
617 /*0x01*/ u8 var01;
618 /*0x02*/ u16 var02;
619 /*0x04*/ u8 var04A:4;
620 u8 var04B:4;
621 /*0x04*/ u8 var05[8];
622 /*0x0D*/ u8 var0D;
623 /*0x0E*/ u8 var0E;
624 /*0x0F*/ u8 var0F;
625 /*0x10*/ u8 var10[8];
626};
627
628struct TVShowNameRaterShow {
629 /*0x00*/ u8 var00;
630 /*0x01*/ u8 var01;
631 /*0x02*/ u16 species;
632 /*0x04*/ u8 pokemonName[11];
633 /*0x0F*/ u8 trainerName[11];
634 /*0x1A*/ u8 random;
635 /*0x1B*/ u8 random2;
636 /*0x1C*/ u16 var1C;
637 /*0x1E*/ u8 language;
638 /*0x1F*/ u8 var1F;
639};
640
641struct TVShowMassOutbreak {
642 /*0x00*/ u8 var00;
643 /*0x01*/ u8 var01;
644 /*0x02*/ u8 var02;
645 /*0x03*/ u8 var03;
646 /*0x04*/ u16 moves[4];
647 /*0x0C*/ u16 species;
648 /*0x0E*/ u16 var0E;
649 /*0x10*/ u8 locationMapNum;
650 /*0x11*/ u8 locationMapGroup;
651 /*0x12*/ u8 var12;
652 /*0x13*/ u8 probability;
653 /*0x14*/ u8 level;
654 /*0x15*/ u8 var15;
655 /*0x16*/ u16 var16;
656 /*0x18*/ u8 var18;
657 u8 pad19[11];
658};
659
660typedef union TVShow {
661 struct TVShowCommon common;
662 struct TVShowFanClubLetter fanclubLetter;
663 struct TVShowRecentHappenings recentHappenings;
664 struct TVShowFanclubOpinions fanclubOpinions;
665 struct TVShowNameRaterShow nameRaterShow;
666 struct TVShowMassOutbreak massOutbreak;
667} TVShow;
668
669struct __attribute__((aligned(4))) MailStruct
670{
671 /*0x00*/ u16 words[9];
672 /*0x12*/ u8 playerName[8];
673 /*0x1A*/ u8 trainerId[4];
674 /*0x1E*/ u16 species;
675 /*0x20*/ u16 itemId;
676};
677
678struct UnkMauvilleOldManStruct
679{
680 u8 unk_2D94;
681 u8 unk_2D95;
682 /*0x2D96*/ u16 mauvilleOldMan_ecArray[6];
683 /*0x2DA2*/ u16 mauvilleOldMan_ecArray2[6];
684 /*0x2DAE*/ u8 playerName[8];
685 /*0x2DB6*/ u8 filler_2DB6[0x3];
686 /*0x2DB9*/ u8 playerTrainerId[4];
687 u8 unk_2DBD;
688 /* size = 0x2C */
689};
690
691struct UnkMauvilleOldManStruct2
692{
693 u8 filler0;
694 u8 unk1;
695 u8 unk2;
696 u16 mauvilleOldMan_ecArray[10];
697 u16 mauvilleOldMan_ecArray2[6];
698 u8 fillerF[0x2];
699 /* size = 0x2C */
700};
701
702typedef union OldMan {
703 struct UnkMauvilleOldManStruct oldMan1;
704 struct UnkMauvilleOldManStruct2 oldMan2;
705} OldMan;
706
707struct QuestStoryNPC {
708 u16 bitfield;
709 u8 direction;
710 u8 height;
711 u8 type_id;
712 u8 running_behaviour_or_picture_id;
713 u8 is_trainer;
714 u8 local_id;
715 u8 local_mapnumber;
716 u8 local_mapbank;
717 u16 x;
718 u16 y;
719 u8 sight_distance;
720 u8 role_from;
721 u8 unknown_decrement_on_step;
722 u8 unk_11;
723 u16 padding_12;
724};
725
726struct QuestStory {
727 u8 active;
728 u8 bank;
729 u8 map;
730 u8 warpId;
731 u16 x;
732 u16 y;
733 struct QuestStoryNPC npc[0x10];
734 u8 unk_148[0x51f];
735};
736
737struct NPCState {
738 u8 bitfield;
739 u8 obj_anim_and_vis_control;
740 u8 unk_2;
741 u8 unk_3;
742 u8 oamid;
743 u8 type_id;
744 u8 running_behaviour_or_picture_id;
745 u8 is_trainer;
746 u8 local_id;
747 u8 local_mapnumber;
748 u8 local_mapbank;
749 u8 height;
750 struct Coords16 stay_around;
751 struct Coords16 to;
752 struct Coords16 from;
753 u8 direction;
754 u8 movement_area;
755 u8 objid_surfing;
756 u8 objid_1B;
757 u8 idx_movement_behaviour;
758 u8 sight_distance;
759 u8 role_to;
760 u8 role_from;
761 u8 unk_20;
762 u8 unknown_decrement_on_step;
763 u8 unk_22;
764 u8 unk_23;
765};
766
767struct DaycarePokemon {
768 struct BoxPokemon pokemon;
769 u8 unk_50[56];
770 u32 steps;
771};
772
773
774struct Time
775{
776 /*0x00*/ s16 days;
777 /*0x02*/ s8 hours;
778 /*0x03*/ s8 minutes;
779 /*0x04*/ s8 seconds;
780};
781
782struct Pokedex
783{
784 /*0x00*/ u8 order;
785 /*0x01*/ u8 unknown1;
786 /*0x02*/ u8 nationalMagic; // must equal 0xDA in order to have National mode
787 /*0x03*/ u8 unknown2;
788 /*0x04*/ u32 unownPersonality; // set when you first see Unown
789 /*0x08*/ u32 spindaPersonality; // set when you first see Spinda
790 /*0x0C*/ u32 unknown3;
791 /*0x10*/ u8 owned[52];
792 /*0x44*/ u8 seen[52];
793}; \ No newline at end of file