diff options
Diffstat (limited to 'gba/source')
-rw-r--r-- | gba/source/libSave.c | 596 | ||||
-rw-r--r-- | gba/source/libSave.h | 27 | ||||
-rw-r--r-- | gba/source/libpayload.c | 312 | ||||
-rw-r--r-- | gba/source/libpayload.h | 160 | ||||
-rw-r--r-- | gba/source/payload.c | 60 | ||||
-rw-r--r-- | gba/source/payload.h | 1 | ||||
-rw-r--r-- | gba/source/saveblocks.h | 338 | ||||
-rw-r--r-- | gba/source/savestructs.h | 793 |
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 | |||
24 | void 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 | |||
33 | void 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 | |||
46 | void 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 | |||
91 | void 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 | //--------------------------------------------------------------------------------- | ||
136 | void 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 | //--------------------------------------------------------------------------------- | ||
149 | void 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 | |||
164 | void 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 | |||
218 | void 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 | //--------------------------------------------------------------------------------- | ||
271 | void 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 | //--------------------------------------------------------------------------------- | ||
285 | void 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 | //--------------------------------------------------------------------------------- | ||
298 | void 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 | //--------------------------------------------------------------------------------- | ||
312 | void 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 | //--------------------------------------------------------------------------------- | ||
325 | void 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 | //--------------------------------------------------------------------------------- | ||
338 | void 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 | //--------------------------------------------------------------------------------- | ||
406 | void 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 | //--------------------------------------------------------------------------------- | ||
446 | void 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 | //--------------------------------------------------------------------------------- | ||
555 | u32 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 | ||
5 | extern "C" { | ||
6 | #endif | ||
7 | //--------------------------------------------------------------------------------- | ||
8 | |||
9 | void GetSave_EEPROM_512B(u8* data); | ||
10 | void PutSave_EEPROM_512B(u8* data); | ||
11 | void GetSave_EEPROM_8KB(u8* data); | ||
12 | void PutSave_EEPROM_8KB(u8* data); | ||
13 | void GetSave_SRAM_32KB(u8* data); | ||
14 | void PutSave_SRAM_32KB(u8* data); | ||
15 | void GetSave_FLASH_64KB(u8* data); | ||
16 | void PutSave_FLASH_64KB(u8* foo); | ||
17 | void GetSave_FLASH_128KB(u8* data); | ||
18 | void PutSave_FLASH_128KB(u8* foo); | ||
19 | |||
20 | u32 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 | ||
14 | static void CryptBoxPokemon(struct BoxPokemon* pkm); | ||
15 | static u16 crc16(const u8* data, u16 len); | ||
16 | static 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 | */ | ||
23 | void 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 | */ | ||
32 | static 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 | */ | ||
44 | void 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 | */ | ||
53 | void 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 | */ | ||
63 | void 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 | */ | ||
75 | union 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 | */ | ||
87 | union 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 | */ | ||
109 | u16 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 | */ | ||
130 | void 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 | */ | ||
140 | struct 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 | */ | ||
151 | struct 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 | */ | ||
161 | struct 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 | */ | ||
172 | struct 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 | */ | ||
182 | struct 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 | */ | ||
193 | struct 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 | */ | ||
203 | struct 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 | */ | ||
214 | struct 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 | */ | ||
223 | u32 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 | */ | ||
245 | u32 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 | */ | ||
260 | u32 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 | */ | ||
270 | u32 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 | */ | ||
281 | static __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 | */ | ||
299 | static 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 | */ | ||
15 | void 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 | */ | ||
23 | void 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 | */ | ||
30 | void 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 | */ | ||
37 | void 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 | */ | ||
46 | union 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 | */ | ||
55 | union 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 | */ | ||
62 | u16 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 | */ | ||
68 | void 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 | */ | ||
76 | struct 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 | */ | ||
84 | struct 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 | */ | ||
92 | struct 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 | */ | ||
100 | struct 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 | */ | ||
108 | struct 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 | */ | ||
116 | struct 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 | */ | ||
124 | struct 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 | */ | ||
132 | struct 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 | */ | ||
139 | u32 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 | */ | ||
146 | u32 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 | */ | ||
153 | u32 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 | */ | ||
160 | u32 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. |
14 | void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) { | 14 | void 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 | ||
13 | typedef u8 SaveBlock1, *pSaveBlock1; | 13 | typedef struct |
14 | typedef u8 SaveBlock2, *pSaveBlock2; | 14 | { |
15 | typedef 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 | |||
96 | typedef 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 | |||
150 | typedef 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 | |||
235 | struct 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 | |||
250 | typedef 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 | |||
274 | typedef 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 | |||
306 | typedef 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 | |||
331 | typedef union { | ||
332 | SaveBlock1_RS rs; | ||
333 | SaveBlock1_FRLG frlg; | ||
334 | SaveBlock1_E e; | ||
335 | } SaveBlock1, *pSaveBlock1; | ||
336 | |||
337 | typedef union { | ||
338 | SaveBlock2_RS rs; | ||
339 | SaveBlock2_FRLG frlg; | ||
340 | SaveBlock2_E e; | ||
341 | } SaveBlock2, *pSaveBlock2; | ||
342 | |||
343 | typedef 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 | |||
16 | struct Coords16 | ||
17 | { | ||
18 | s16 x; | ||
19 | s16 y; | ||
20 | }; | ||
21 | |||
22 | struct UCoords16 | ||
23 | { | ||
24 | u16 x; | ||
25 | u16 y; | ||
26 | }; | ||
27 | |||
28 | struct 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 | |||
49 | typedef void (*TilesetCB)(void); | ||
50 | |||
51 | struct 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 | |||
62 | struct MapData | ||
63 | { | ||
64 | s32 width; | ||
65 | s32 height; | ||
66 | u16 *border; | ||
67 | u16 *map; | ||
68 | struct Tileset *primaryTileset; | ||
69 | struct Tileset *secondaryTileset; | ||
70 | }; | ||
71 | |||
72 | struct 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 | |||
91 | struct WarpEvent | ||
92 | { | ||
93 | s16 x, y; | ||
94 | s8 warpId; | ||
95 | u8 mapGroup; | ||
96 | u8 mapNum; | ||
97 | u8 unk7; | ||
98 | }; | ||
99 | |||
100 | struct 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 | |||
111 | struct BgEvent | ||
112 | { | ||
113 | s16 x, y; | ||
114 | u8 unk4; | ||
115 | u8 kind; | ||
116 | s16 filler_6; | ||
117 | u8 *script; | ||
118 | }; | ||
119 | |||
120 | struct 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 | |||
133 | struct MapConnection | ||
134 | { | ||
135 | u8 direction; | ||
136 | u32 offset; | ||
137 | u8 mapGroup; | ||
138 | u8 mapNum; | ||
139 | }; | ||
140 | |||
141 | struct MapConnections | ||
142 | { | ||
143 | s32 count; | ||
144 | struct MapConnection *connections; | ||
145 | }; | ||
146 | |||
147 | struct 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 | |||
165 | struct 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 | |||
226 | struct 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 | |||
244 | struct 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 | |||
257 | struct BattleEnigmaBerry | ||
258 | { | ||
259 | u8 name[7]; | ||
260 | u8 holdEffect; | ||
261 | u8 itemEffect[18]; | ||
262 | u8 holdEffectParam; | ||
263 | }; | ||
264 | |||
265 | struct 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 | |||
273 | struct __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 | |||
287 | struct PokemonSubstruct0 | ||
288 | { | ||
289 | u16 species; | ||
290 | u16 heldItem; | ||
291 | u32 experience; | ||
292 | u8 ppBonuses; | ||
293 | u8 friendship; | ||
294 | }; | ||
295 | |||
296 | struct PokemonSubstruct1 | ||
297 | { | ||
298 | u16 moves[4]; | ||
299 | u8 pp[4]; | ||
300 | }; | ||
301 | |||
302 | struct 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 | |||
318 | struct 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 | |||
357 | union PokemonSubstruct | ||
358 | { | ||
359 | struct PokemonSubstruct0 type0; | ||
360 | struct PokemonSubstruct1 type1; | ||
361 | struct PokemonSubstruct2 type2; | ||
362 | struct PokemonSubstruct3 type3; | ||
363 | u16 raw[6]; | ||
364 | }; | ||
365 | |||
366 | struct 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 | |||
388 | struct 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 | |||
403 | struct 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 | |||
430 | struct 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 | |||
468 | struct 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 | |||
500 | struct 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 | |||
513 | struct PokemonStorage | ||
514 | { | ||
515 | /* 0x00 */ u8 currentBox; | ||
516 | /* 0x01 */ struct BoxPokemon boxes[14][30]; | ||
517 | u8 boxNames[14][9]; | ||
518 | u8 boxBackground[14]; | ||
519 | }; | ||
520 | |||
521 | struct WarpData | ||
522 | { | ||
523 | s8 mapGroup; | ||
524 | s8 mapNum; | ||
525 | s8 warpId; | ||
526 | s16 x, y; | ||
527 | }; | ||
528 | |||
529 | struct ItemSlot | ||
530 | { | ||
531 | u16 itemId; | ||
532 | u16 quantity; | ||
533 | }; | ||
534 | |||
535 | struct __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 | |||
546 | struct 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 | |||
562 | struct RamScriptData | ||
563 | { | ||
564 | u8 magic; | ||
565 | u8 mapGroup; | ||
566 | u8 mapNum; | ||
567 | u8 objectId; | ||
568 | u8 script[995]; | ||
569 | } __attribute__((aligned(1),packed)); | ||
570 | |||
571 | struct RamScript | ||
572 | { | ||
573 | u32 checksum; | ||
574 | struct RamScriptData data; | ||
575 | } __attribute__((aligned(1),packed)); | ||
576 | |||
577 | struct SB1_2EFC_Struct | ||
578 | { | ||
579 | u8 unknown[0x20]; | ||
580 | }; | ||
581 | |||
582 | struct 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 | |||
591 | struct TVShowCommon { | ||
592 | /*0x00*/ u8 var00; | ||
593 | /*0x01*/ u8 var01; | ||
594 | }; | ||
595 | |||
596 | struct 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 | |||
605 | struct 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 | |||
615 | struct 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 | |||
628 | struct 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 | |||
641 | struct 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 | |||
660 | typedef 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 | |||
669 | struct __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 | |||
678 | struct 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 | |||
691 | struct 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 | |||
702 | typedef union OldMan { | ||
703 | struct UnkMauvilleOldManStruct oldMan1; | ||
704 | struct UnkMauvilleOldManStruct2 oldMan2; | ||
705 | } OldMan; | ||
706 | |||
707 | struct 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 | |||
726 | struct 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 | |||
737 | struct 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 | |||
767 | struct DaycarePokemon { | ||
768 | struct BoxPokemon pokemon; | ||
769 | u8 unk_50[56]; | ||
770 | u32 steps; | ||
771 | }; | ||
772 | |||
773 | |||
774 | struct Time | ||
775 | { | ||
776 | /*0x00*/ s16 days; | ||
777 | /*0x02*/ s8 hours; | ||
778 | /*0x03*/ s8 minutes; | ||
779 | /*0x04*/ s8 seconds; | ||
780 | }; | ||
781 | |||
782 | struct 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 | ||