about summary refs log tree commit diff stats
path: root/gba/source
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-07-11 16:37:21 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-07-11 16:37:21 -0400
commit57afb4058710a978bd7b07a368125d04378c62f1 (patch)
tree7a06f1679f0612c58d5a209a013261ff5ad6cb82 /gba/source
parent004575f7cec14946c1936aceca6efee38b7f8a74 (diff)
downloadgen3uploader-57afb4058710a978bd7b07a368125d04378c62f1.tar.gz
gen3uploader-57afb4058710a978bd7b07a368125d04378c62f1.tar.bz2
gen3uploader-57afb4058710a978bd7b07a368125d04378c62f1.zip
started tweaking with stuff
Diffstat (limited to 'gba/source')
-rw-r--r--gba/source/gamedata.c534
-rw-r--r--gba/source/gamedata.h22
-rw-r--r--gba/source/link.c41
-rw-r--r--gba/source/link.h12
-rw-r--r--gba/source/main.c592
-rw-r--r--gba/source/saveblocks.h343
-rw-r--r--gba/source/savestructs.h793
7 files changed, 2129 insertions, 208 deletions
diff --git a/gba/source/gamedata.c b/gba/source/gamedata.c new file mode 100644 index 0000000..19d5100 --- /dev/null +++ b/gba/source/gamedata.c
@@ -0,0 +1,534 @@
1/*
2 * Pokemon Gen III Data Extractor by hatkirby 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 */
8#include "gamedata.h"
9
10void decryptSaveStructures(
11 pSaveBlock1 SaveBlock1,
12 pSaveBlock2 SaveBlock2,
13 pSaveBlock3 SaveBlock3)
14{
15 if (GAME_RS)
16 {
17 // R/S doesn't have save crypto.
18 return;
19 }
20
21 u8* sb1raw = (u8*)SaveBlock1;
22 u8* sb2raw = (u8*)SaveBlock2;
23 //u8* sb3raw = (u8*)SaveBlock3; // unused
24
25 u32* xor_key_ptr = (u32*)(&sb2raw[( GAME_EM ? 0xA8 : 0xF20 )]);
26
27 u32 xor_key = *xor_key_ptr;
28 u16 xor_key16 = (u16)xor_key;
29 if (!xor_key)
30 {
31 // xor key is zero, nothing needs to be done.
32 return;
33 }
34
35 u32* ptr_to_xor;
36 u32 save_offset;
37 int i;
38 u32* bag_pocket_offsets;
39 u32* bag_pocket_counts;
40 if (GAME_FRLG)
41 {
42 // loop over and decrypt various things
43 save_offset = 0x3D38 + 4;
44 for (i = 3; i >= 0; i--)
45 {
46 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
47 *ptr_to_xor ^= xor_key;
48 save_offset += 12;
49 }
50
51 for (i = 0; i <= 0x3f; i++)
52 {
53 save_offset = 0x1200 + (i*sizeof(u32));
54 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
55 *ptr_to_xor ^= xor_key;
56 }
57
58 // loop over each of the bag pockets and decrypt decrypt decrypt
59 bag_pocket_offsets = (u32[5]) { 0x310, 0x388, 0x430, 0x464, 0x54C };
60 bag_pocket_counts = (u32[5]) { 42, 30, 13, 58, 43 };
61
62 for (i = 0; i < 5; i++)
63 {
64 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++)
65 {
66 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
67 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
68 }
69 }
70
71 // decrypt some more stuff
72 save_offset = 0xaf8;
73 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
74 *ptr_to_xor ^= xor_key;
75
76 save_offset = 0x290;
77 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
78 *ptr_to_xor ^= xor_key;
79
80 save_offset = 0x294;
81 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
82 } else {
83 // Emerald
84
85 // loop over and decrypt various things
86 for (i = 0; i <= 0x3f; i++)
87 {
88 save_offset = 0x159c + (i*sizeof(u32));
89 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
90 *ptr_to_xor ^= xor_key;
91 }
92
93 // loop over each of the bag pockets and decrypt decrypt decrypt
94 bag_pocket_offsets = (u32[5]) { 0x560, 0x5D8, 0x650, 0x690, 0x790 };
95 bag_pocket_counts = (u32[5]) { 30, 30, 16, 64, 46 };
96
97 for (i = 0; i < 5; i++)
98 {
99 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++)
100 {
101 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
102 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
103 }
104 }
105
106 // decrypt some more stuff
107 save_offset = 0x1F4;
108 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
109 *ptr_to_xor ^= xor_key;
110
111 save_offset = 0x490;
112 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
113 *ptr_to_xor ^= xor_key;
114
115 save_offset = 0x494;
116 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
117 }
118
119 *xor_key_ptr = 0;
120}
121
122bool initSaveData(
123 pSaveBlock1* SaveBlock1,
124 pSaveBlock2* SaveBlock2,
125 pSaveBlock3* SaveBlock3)
126{
127 // check the ROM code, make sure this game is supported.
128 u8* ROM = (u8*) 0x8000000;
129
130 u32 gamecode = (*(u32*)(&ROM[0xAC]));
131
132 void(*loadsave)(char a1);
133 //void(*mainloop)();
134 //void(*load_pokemon)();
135 pSaveBlock1 gSaveBlock1;
136 pSaveBlock2 gSaveBlock2;
137 pSaveBlock3 gSaveBlock3;
138 //u32 titlemid = 0;
139
140 // get the address of the save loading function.
141 switch (gamecode)
142 {
143 // --- R/S ---
144 case 'DVXA': // Ruby German
145 case 'DPXA': // Sapphire German
146 {
147 // TODO: detect debug ROM?
148 gSaveBlock1 = (pSaveBlock1) 0x2025734;
149 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
150 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
151 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
152 //mainloop = (void(*)()) 0x80003D9;
153 //load_pokemon = (void(*)()) 0x8047da9;
154
155 break;
156 }
157
158 case 'FVXA': // Ruby French
159 case 'FPXA': // Sapphire French
160 {
161 gSaveBlock1 = (pSaveBlock1) 0x2025734;
162 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
163 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
164 loadsave = (void(*)(char)) 0x8126351; // same for v1.0 + v1.1
165 //mainloop = (void(*)()) 0x80003D9;
166 //load_pokemon = (void(*)()) 0x8047e95;
167
168 break;
169 }
170
171 case 'IVXA': // Ruby Italian
172 case 'IPXA': // Sapphire Italian
173 {
174 gSaveBlock1 = (pSaveBlock1) 0x2025734;
175 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
176 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
177 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
178 //mainloop = (void(*)()) 0x80003D9;
179 //load_pokemon = (void(*)()) 0x8047dbd;
180
181 break;
182 }
183
184 case 'SVXA': // Ruby Spanish
185 case 'SPXA': // Sapphire Spanish
186 {
187 gSaveBlock1 = (pSaveBlock1) 0x2025734;
188 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
189 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
190 loadsave = (void(*)(char)) 0x8126349; // same for v1.0 + v1.1
191 //mainloop = (void(*)()) 0x80003D9;
192 //load_pokemon = (void(*)()) 0x8047ea5;
193
194 break;
195 }
196
197 case 'EVXA': // Ruby English
198 case 'EPXA': // Sapphire English
199 {
200 gSaveBlock1 = (pSaveBlock1) 0x2025734;
201 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
202 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
203 //mainloop = (void(*)()) 0x80002A5;
204
205 // version number
206 switch (ROM[0xBC])
207 {
208 case 0:
209 {
210 loadsave = (void(*)(char)) 0x8125EC9;
211 //load_pokemon = (void(*)()) 0x8047a85;
212
213 break;
214 }
215
216 case 1:
217 case 2:
218 {
219 loadsave = (void(*)(char)) 0x8125EE9;
220 //load_pokemon = (void(*)()) 0x8047aa5;
221
222 break;
223 }
224
225 default:
226 {
227 return false; // unsupported version
228 }
229 }
230
231 break;
232 }
233
234 case 'JVXA': // Ruby Japanese
235 case 'JPXA': // Sapphire Japanese
236 {
237 gSaveBlock1 = (pSaveBlock1) 0x2025494;
238 gSaveBlock2 = (pSaveBlock2) 0x2024C04;
239 gSaveBlock3 = (pSaveBlock3) 0x202FDBC;
240 loadsave = (void(*)(char)) 0x8120d05; // same for v1.0 + v1.1
241 //mainloop = (void(*)()) 0x80002A9;
242 //load_pokemon = (void(*)()) 0x8044d55;
243
244 break;
245 }
246
247 /// --- FR/LG ---
248 // In FR/LG, the function that initialises the save-block pointers to default does not set up saveblock3.
249 // Which will need to be set up before loading the save if we want boxed Pokémon to not disappear.
250 // Oh, and loadsave() offset is different between FR and LG...
251
252 case 'DRPB': // FireRed German
253 case 'DGPB': // LeafGreen German
254 {
255 gSaveBlock1 = (pSaveBlock1) 0x202552C;
256 gSaveBlock2 = (pSaveBlock2) 0x2024588;
257 gSaveBlock3 = (pSaveBlock3) 0x2029314;
258 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
259 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
260 //mainloop = (void(*)()) 0x8000425;
261 //titlemid = 0x80791df;
262 //load_pokemon = (void(*)()) 0x804c251;
263
264 break;
265 }
266
267 case 'FRPB': // FireRed French
268 case 'FGPB': // LeafGreen French
269 {
270 gSaveBlock1 = (pSaveBlock1) 0x202552C;
271 gSaveBlock2 = (pSaveBlock2) 0x2024588;
272 gSaveBlock3 = (pSaveBlock3) 0x2029314;
273 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
274 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da7e1 : 0x80da7b5 );
275 //mainloop = (void(*)()) 0x8000417;
276 //titlemid = 0x807929f;
277 //load_pokemon = (void(*)()) 0x804c311;
278
279 break;
280 }
281
282 case 'IRPB': // FireRed Italian
283 case 'IGPB': // LeafGreen Italian
284 {
285 gSaveBlock1 = (pSaveBlock1) 0x202552C;
286 gSaveBlock2 = (pSaveBlock2) 0x2024588;
287 gSaveBlock3 = (pSaveBlock3) 0x2029314;
288 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
289 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
290 //mainloop = (void(*)()) 0x8000425;
291 //titlemid = 0x80791cb;
292 //load_pokemon = (void(*)()) 0x804c23d;
293
294 break;
295 }
296
297 case 'SRPB': // FireRed Spanish
298 case 'SGPB': // LeafGreen Spanish
299 {
300 gSaveBlock1 = (pSaveBlock1) 0x202552C;
301 gSaveBlock2 = (pSaveBlock2) 0x2024588;
302 gSaveBlock3 = (pSaveBlock3) 0x2029314;
303 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
304 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da809 : 0x80da7dd );
305 //mainloop = (void(*)()) 0x8000417;
306 //titlemid = 0x80792b3;
307 //load_pokemon = (void(*)()) 0x804c325;
308
309 break;
310 }
311
312 case 'ERPB': // FireRed English
313 case 'EGPB': // LeafGreen English
314 {
315 gSaveBlock1 = (pSaveBlock1) 0x202552C;
316 gSaveBlock2 = (pSaveBlock2) 0x2024588;
317 gSaveBlock3 = (pSaveBlock3) 0x2029314;
318 *(pSaveBlock3*)(0x3005010) = gSaveBlock3;
319
320 // version number
321 switch (ROM[0xBC])
322 {
323 case 0:
324 {
325 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da4fd : 0x80da4d1 );
326 //mainloop = (void(*)()) 0x800041b;
327 //titlemid = 0x807927b;
328 //load_pokemon = (void(*)()) 0x804c231;
329
330 break;
331 }
332
333 case 1:
334 {
335 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da511 : 0x80da4e5 );
336 //mainloop = (void(*)()) 0x8000429;
337 //titlemid = 0x807928f;
338 //load_pokemon = (void(*)()) 0x804c245;
339
340 break;
341 }
342
343 default:
344 {
345 return false; // unsupported version
346 }
347 }
348
349 break;
350 }
351
352 case 'JRPB': // FireRed Japanese
353 case 'JGPB': // LeafGreen Japanese
354 {
355 gSaveBlock1 = (pSaveBlock1) 0x202548C;
356 gSaveBlock2 = (pSaveBlock2) 0x20244E8;
357 gSaveBlock3 = (pSaveBlock3) 0x202924C;
358 *(pSaveBlock3*)(0x3005050) = gSaveBlock3;
359
360 // version number
361 switch (ROM[0xBC])
362 {
363 case 0:
364 {
365 loadsave = (void(*)(char)) ( GAME_FR ? 0x80db4e5 : 0x80db4b9 );
366 //mainloop = (void(*)()) 0x800041b;
367 //titlemid = 0x8078a0f;
368 //load_pokemon = (void(*)()) 0x804b9e9;
369
370 break;
371 }
372
373 case 1:
374 {
375 if ((gamecode << 8) == 'GPB\x00')
376 {
377 // LeafGreen v1.1 Japanese is undumped.
378 // Therefore, it is unsupported.
379 // I will make guesses at the offsets in the comments, but I will not actually implement them until LeafGreen v1.1 is dumped.
380
381 return false;
382 }
383
384 loadsave = (void(*)(char)) 0x80db529; // potential LG1.1 address: 0x80db4fd
385 //mainloop = (void(*)()) 0x8000417;
386 //titlemid = 0x8078987;
387 //load_pokemon = (void(*)()) 0x804b9c5;
388
389 break;
390 }
391
392 default:
393 {
394 return false; // unsupported version
395 }
396 }
397
398 break;
399 }
400
401 /// --- Emerald ---
402 // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in FR/LG it was saveblock3).
403 // The initial save loading code after the copyright screen is also updated, now it sets up ASLR/crypto here before loading the save.
404
405 case 'DEPB': // Emerald German
406 {
407 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
408 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
409 gSaveBlock3 = (pSaveBlock3) 0x2029808;
410 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
411 loadsave = (void(*)(char)) 0x8153075;
412 //mainloop = (void(*)()) 0x800042b;
413 //titlemid = 0x816fdb5;
414 //load_pokemon = (void(*)()) 0x8076dd5;
415
416 break;
417 }
418
419 case 'FEPB': // Emerald French
420 {
421 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
422 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
423 gSaveBlock3 = (pSaveBlock3) 0x2029808;
424 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
425 loadsave = (void(*)(char)) 0x815319d;
426 //mainloop = (void(*)()) 0x800042b;
427 //titlemid = 0x816fedd;
428 //load_pokemon = (void(*)()) 0x8076dd1;
429
430 break;
431 }
432
433 case 'IEPB': // Emerald Italian
434 {
435 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
436 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
437 gSaveBlock3 = (pSaveBlock3) 0x2029808;
438 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
439 loadsave = (void(*)(char)) 0x8153065;
440 //mainloop = (void(*)()) 0x800042b;
441 //titlemid = 0x816fda5;
442 //load_pokemon = (void(*)()) 0x8076dd5;
443
444 break;
445 }
446
447 case 'SEPB': // Emerald Spanish
448 {
449 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
450 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
451 gSaveBlock3 = (pSaveBlock3) 0x2029808;
452 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
453 loadsave = (void(*)(char)) 0x8153175;
454 //mainloop = (void(*)()) 0x800042b;
455 //titlemid = 0x816feb5;
456 //load_pokemon = (void(*)()) 0x8076dd1;
457
458 break;
459 }
460
461 case 'EEPB': // Emerald English
462 {
463 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
464 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
465 gSaveBlock3 = (pSaveBlock3) 0x2029808;
466 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
467 loadsave = (void(*)(char)) 0x81534d1;
468 //mainloop = (void(*)()) 0x800042b;
469 //titlemid = 0x817014d;
470 //load_pokemon = (void(*)()) 0x8076dd5;
471
472 break;
473 }
474
475 case 'JEPB': // Emerald Japanese
476 {
477 gSaveBlock1 = (pSaveBlock1) 0x20256A4;
478 gSaveBlock2 = (pSaveBlock2) 0x20246F8;
479 gSaveBlock3 = (pSaveBlock3) 0x20294AC;
480 *(pSaveBlock1*)(0x3005aec) = gSaveBlock1;
481 loadsave = (void(*)(char)) 0x815340d;
482 //mainloop = (void(*)()) 0x800042b;
483 //titlemid = 0x816ff45;
484 //load_pokemon = (void(*)()) 0x80767dd;
485
486 break;
487 }
488
489 default:
490 {
491 return false; // this game isn't supported
492 }
493 }
494
495 loadsave(0);
496
497 // now the save is loaded, we can do what we want with the loaded blocks.
498 // first, we're going to want to decrypt the parts that are crypted, if applicable.
499 decryptSaveStructures(gSaveBlock1,gSaveBlock2,gSaveBlock3);
500
501 *SaveBlock1 = gSaveBlock1;
502 *SaveBlock2 = gSaveBlock2;
503 *SaveBlock3 = gSaveBlock3;
504
505 /*
506 // time to call the payload.
507 payload(gSaveBlock1,gSaveBlock2,gSaveBlock3);
508 // Now, we better call the function that sets the pokemon-related stuff from the structure elements of the loaded save again.
509 // Just in case the payload did something with that.
510 load_pokemon();
511 // In FR/LG/Emerald, just returning to the game is unwise.
512 // The game reloads the savefile.
513 // In FR/LG, this is done at the title screen after setting ASLR/saveblock-crypto up. (probably because at initial save-load, SaveBlock3 ptr isn't set up lol)
514 // So, better bypass the title screen and get the game to return directly to the Continue/New Game screen.
515 // In Emerald, the save reload happens after the Continue option was chosen, so we have no choice but to bypass everything and get the game to go straight to the overworld.
516 // Easiest way to do this is to call into the middle of the function we want, using an ASM wrapper to set up the stack.
517 // Here goes...
518 if (titlemid) {
519 // Function reserves an extra 4 bytes of stack space in FireRed/LeafGreen, and none in Emerald.
520 call_into_middle_of_titlescreen_func(titlemid,(GAME_EM ? 0 : 4));
521 }
522 // Now we've done what we want, time to return to the game.
523 // Can't just return, the game will reload the save.
524 // So let's just call the main-loop directly ;)
525 // turn the sound back on before we head back to the game
526 *(vu16 *)(REG_BASE + 0x84) = 0x8f;
527 // re-enable interrupts
528 REG_IME = 1;
529 mainloop();
530 // Anything past here will not be executed.
531 return 0;
532 */
533 return true;
534}
diff --git a/gba/source/gamedata.h b/gba/source/gamedata.h new file mode 100644 index 0000000..99dfa8e --- /dev/null +++ b/gba/source/gamedata.h
@@ -0,0 +1,22 @@
1#ifndef _GAMEDATA_H_
2#define _GAMEDATA_H_
3
4#include <gba.h>
5#include "saveblocks.h"
6
7#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00')
8#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00')
9#define GAME_RS ((GAME_RUBY) || (GAME_SAPP))
10#define GAME_FR (((*(u32*)(0x80000AC)) << 8) == 'RPB\x00')
11#define GAME_LG (((*(u32*)(0x80000AC)) << 8) == 'GPB\x00')
12#define GAME_FRLG ((GAME_FR) || (GAME_LG))
13#define GAME_EM (((*(u32*)(0x80000AC)) << 8) == 'EPB\x00')
14
15#define LANG_JAPAN ((*(u8*)(0x80000AF)) == 'J')
16
17bool initSaveData(
18 pSaveBlock1* SaveBlock1,
19 pSaveBlock2* SaveBlock2,
20 pSaveBlock3* SaveBlock3);
21
22#endif
diff --git a/gba/source/link.c b/gba/source/link.c new file mode 100644 index 0000000..e695622 --- /dev/null +++ b/gba/source/link.c
@@ -0,0 +1,41 @@
1#include "link.h"
2
3#define JOY_WRITE 2
4#define JOY_READ 4
5#define JOY_RW 6
6
7void waitForWriteAccess()
8{
9 //while ((REG_HS_CTRL & JOY_READ) == 0);
10 while ((REG_HS_CTRL & JOY_WRITE) == 0);
11 REG_HS_CTRL |= JOY_RW;
12}
13
14void waitForAck()
15{
16 while ((REG_HS_CTRL & JOY_WRITE) == 0);
17 REG_HS_CTRL |= JOY_RW;
18 REG_JOYTR = 0;
19 while ((REG_HS_CTRL & JOY_WRITE) == 0);
20 REG_HS_CTRL |= JOY_RW;
21}
22
23void sendS32(s32 val)
24{
25 REG_JOYTR = val;
26 //waitForWriteAccess();
27}
28
29void sendU32(u32 val)
30{
31 REG_JOYTR = val;
32 //waitForWriteAccess();
33}
34
35u32 recieveU32()
36{
37 while ((REG_HS_CTRL & JOY_WRITE) == 0);
38 REG_HS_CTRL |= JOY_RW;
39 return REG_JOYRE;
40}
41
diff --git a/gba/source/link.h b/gba/source/link.h new file mode 100644 index 0000000..f18b38a --- /dev/null +++ b/gba/source/link.h
@@ -0,0 +1,12 @@
1#ifndef _LINK_H_
2#define _LINK_H_
3
4#include <gba.h>
5
6void waitForWriteAccess();
7void waitForAck();
8void sendS32(s32 val);
9void sendU32(u32 val);
10u32 recieveU32();
11
12#endif
diff --git a/gba/source/main.c b/gba/source/main.c index ee94c35..104866a 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -8,6 +8,8 @@
8#include <stdio.h> 8#include <stdio.h>
9#include <stdlib.h> 9#include <stdlib.h>
10#include "libSave.h" 10#include "libSave.h"
11#include "gamedata.h"
12#include "link.h"
11 13
12#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204) 14#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204)
13#define JOY_WRITE 2 15#define JOY_WRITE 2
@@ -18,224 +20,398 @@ u8 save_data[0x20000] __attribute__ ((section (".sbss")));
18 20
19s32 getGameSize(void) 21s32 getGameSize(void)
20{ 22{
21 if(*(vu32*)(0x08000004) != 0x51AEFF24) 23 if(*(vu32*)(0x08000004) != 0x51AEFF24)
22 return -1; 24 return -1;
23 s32 i; 25 s32 i;
24 for(i = (1<<20); i < (1<<25); i<<=1) 26 for(i = (1<<20); i < (1<<25); i<<=1)
27 {
28 vu16 *rompos = (vu16*)(0x08000000+i);
29 int j;
30 bool romend = true;
31 for(j = 0; j < 0x1000; j++)
32 {
33 if(rompos[j] != j)
34 {
35 romend = false;
36 break;
37 }
38 }
39 if(romend) break;
40 }
41 return i;
42}
43
44
45// === (from tonc_memdef.h) ===========================================
46
47// --- REG_DISPCNT defines ---
48#define DCNT_MODE0 0x0000
49#define DCNT_MODE1 0x0001
50#define DCNT_MODE2 0x0002
51#define DCNT_MODE3 0x0003
52#define DCNT_MODE4 0x0004
53#define DCNT_MODE5 0x0005
54// layers
55#define DCNT_BG0 0x0100
56#define DCNT_BG1 0x0200
57#define DCNT_BG2 0x0400
58#define DCNT_BG3 0x0800
59#define DCNT_OBJ 0x1000
60typedef u16 COLOR;
61#define MEM_VRAM 0x06000000
62#define SCREEN_WIDTH 240
63#define vid_mem ((u16*)MEM_VRAM)
64static inline void m3_plot(int x, int y, COLOR clr)
65{ vid_mem[y*SCREEN_WIDTH+x]= clr; }
66static inline COLOR RGB15(u32 red, u32 green, u32 blue)
67{ return red | (green<<5) | (blue<<10); }
68void plot_sqr(int x, int y, COLOR clr)
69{
70 /*for (int j=0;j<8; j++)
25 { 71 {
26 vu16 *rompos = (vu16*)(0x08000000+i); 72 for (int i=0;i<8; i++)
27 int j;
28 bool romend = true;
29 for(j = 0; j < 0x1000; j++)
30 { 73 {
31 if(rompos[j] != j) 74 vid_mem[(y*8+j+32)*SCREEN_WIDTH+x*8+i+32] = clr;
32 {
33 romend = false;
34 break;
35 }
36 } 75 }
37 if(romend) break;
38 } 76 }
39 return i; 77 vid_mem[(y*8+1+32)*SCREEN_WIDTH+x*8+1+32] = RGB15(31,31,31);*/
78}
79void m3_fill(COLOR clr)
80{
81 /*int ii;
82 u32 *dst= (u32*)vid_mem;
83 u32 wd= (clr<<16) | clr;
84
85 for(ii=0; ii<SCREEN_WIDTH/4; ii++)
86 *dst++= wd;*/
40} 87}
41 88
42//--------------------------------------------------------------------------------- 89//---------------------------------------------------------------------------------
43// Program entry point 90// Program entry point
44//--------------------------------------------------------------------------------- 91//---------------------------------------------------------------------------------
45int main(void) { 92int main(void)
46//--------------------------------------------------------------------------------- 93{
94 //REG_IME = 0;
95 //REG_DISPCNT= DCNT_MODE3 | DCNT_BG2;
96 m3_fill(RGB15(31,31,31));
97 plot_sqr( 4, 4, RGB15(31, 0, 0) ); // or CLR_RED
47 98
48 // the vblank interrupt must be enabled for VBlankIntrWait() to work 99
49 // since the default dispatcher handles the bios flags no vblank handler 100
50 // is required 101 //*(vu16 *)(REG_BASE + 0x84) = 0x8f;
51 irqInit(); 102 //REG_IME = 1;
52 irqEnable(IRQ_VBLANK); 103 // the vblank interrupt must be enabled for VBlankIntrWait() to work
53 104 // since the default dispatcher handles the bios flags no vblank handler
54 consoleDemoInit(); 105 // is required
55 REG_JOYTR = 0; 106 //irqInit();
56 // ansi escape sequence to set print co-ordinates 107 //irqEnable(IRQ_VBLANK);
57 // /x1b[line;columnH 108
58 u32 i; 109 //consoleDemoInit();
59 iprintf("\x1b[9;2HGBA Link Cable Dumper v1.6\n"); 110 //REG_JOYTR = 0;
60 iprintf("\x1b[10;4HPlease look at the TV\n"); 111
61 // disable this, needs power 112 // ansi escape sequence to set print co-ordinates
62 SNDSTAT = 0; 113 // /x1b[line;columnH
63 SNDBIAS = 0; 114 //u32 i;
64 // Set up waitstates for EEPROM access etc. 115 //iprintf("\x1b[9;2HPokemon Gen III Data Extractor\n");
65 REG_WAITCNT = 0x0317; 116 //iprintf("\x1b[10;4HPlease look at the TV\n");
66 //clear out previous messages 117
67 REG_HS_CTRL |= JOY_RW; 118 // disable this, needs power
68 while (1) { 119 //SNDSTAT = 0;
69 if(REG_HS_CTRL&JOY_READ) 120 //SNDBIAS = 0;
70 { 121
71 REG_HS_CTRL |= JOY_RW; 122 // Set up waitstates for EEPROM access etc.
72 s32 gamesize = getGameSize(); 123 //REG_WAITCNT = 0x0317;
73 u32 savesize = SaveSize(save_data,gamesize); 124
74 REG_JOYTR = gamesize; 125 //clear out previous messages
75 //wait for a cmd receive for safety 126 REG_HS_CTRL |= JOY_RW;
76 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 127 sendU32(0);
77 REG_HS_CTRL |= JOY_RW; 128 plot_sqr( 4, 5, RGB15( 0,31, 0) ); // or CLR_LIME
78 REG_JOYTR = savesize; 129 while (1)
79 //wait for a cmd receive for safety 130 {
80 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 131 waitForWriteAccess();
81 REG_HS_CTRL |= JOY_RW; 132 //while (recieveU32() != 0);
82 if(gamesize == -1) 133 //waitForAck();
83 { 134 plot_sqr( 4, 6, RGB15( 0, 0,31) ); // or CLR_BLUE
84 REG_JOYTR = 0; 135 // Send game size to acknowledge that an actual cart is inserted.
85 continue; //nothing to read 136 //s32 gamesize = getGameSize();
86 } 137 //sendS32(gamesize);
87 //game in, send header 138 //waitForAck();
88 for(i = 0; i < 0xC0; i+=4) 139
89 { 140 // If the game size is illegal, start over.
90 REG_JOYTR = *(vu32*)(0x08000000+i); 141 //if (gamesize == -1)
91 while((REG_HS_CTRL&JOY_READ) == 0) ; 142 //{
92 REG_HS_CTRL |= JOY_RW; 143 // sendS32(0);
93 } 144 //
94 REG_JOYTR = 0; 145 // continue;
95 //wait for other side to choose 146 //}
96 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 147
97 REG_HS_CTRL |= JOY_RW; 148 // Identify the inserted game.
98 u32 choseval = REG_JOYRE; 149 if (GAME_RUBY)
99 if(choseval == 0) 150 {
100 { 151 sendS32(1);
101 REG_JOYTR = 0; 152 } else if (GAME_SAPP)
102 continue; //nothing to read 153 {
103 } 154 sendS32(2);
104 else if(choseval == 1) 155 } else if (GAME_FR)
105 { 156 {
106 //disable interrupts 157 sendS32(3);
107 u32 prevIrqMask = REG_IME; 158 } else if (GAME_LG)
108 REG_IME = 0; 159 {
109 //dump the game 160 sendS32(4);
110 for(i = 0; i < gamesize; i+=4) 161 } else if (GAME_EM)
111 { 162 {
112 REG_JOYTR = *(vu32*)(0x08000000+i); 163 sendS32(5);
113 while((REG_HS_CTRL&JOY_READ) == 0) ; 164 } else {
114 REG_HS_CTRL |= JOY_RW; 165 sendS32(-1);
115 } 166 waitForAck();
116 //restore interrupts 167
117 REG_IME = prevIrqMask; 168 sendS32(0);
118 } 169
119 else if(choseval == 2) 170 continue;
120 { 171 }
121 //disable interrupts 172 plot_sqr( 5, 4, RGB15( 31, 0,31) );
122 u32 prevIrqMask = REG_IME; 173 waitForAck();
123 REG_IME = 0; 174 plot_sqr( 5, 5, RGB15( 16, 16,16) );
124 //backup save 175 // Get access to save data.
125 switch (savesize){ 176 pSaveBlock1 SaveBlock1;
126 case 0x200: 177 pSaveBlock2 SaveBlock2;
127 GetSave_EEPROM_512B(save_data); 178 pSaveBlock3 SaveBlock3;
128 break; 179 if (!initSaveData(&SaveBlock1, &SaveBlock2, &SaveBlock3))
129 case 0x2000: 180 {
130 GetSave_EEPROM_8KB(save_data); 181 // Unsupported game version.
131 break; 182 //iprintf("Unsupported game version\n");
132 case 0x8000: 183 sendS32(-1);
133 GetSave_SRAM_32KB(save_data); 184 waitForAck();
134 break; 185
135 case 0x10000: 186 sendS32(0);
136 GetSave_FLASH_64KB(save_data); 187
137 break; 188 continue;
138 case 0x20000: 189 }
139 GetSave_FLASH_128KB(save_data); 190 plot_sqr( 5, 6, RGB15( 0, 31,16) );
140 break; 191 sendS32(1);
141 default: 192 waitForAck();
142 break; 193 /*
143 } 194 // Send trainer name.
144 //restore interrupts 195 u8* trainerName;
145 REG_IME = prevIrqMask; 196
146 //say gc side we read it 197 if (GAME_RS)
147 REG_JOYTR = savesize; 198 {
148 //wait for a cmd receive for safety 199 trainerName = SaveBlock2->rs.playerName;
149 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 200 } else if (GAME_FRLG)
150 REG_HS_CTRL |= JOY_RW; 201 {
151 //send the save 202 trainerName = SaveBlock2->frlg.playerName;
152 for(i = 0; i < savesize; i+=4) 203 } else if (GAME_EM)
153 { 204 {
154 REG_JOYTR = *(vu32*)(save_data+i); 205 trainerName = SaveBlock2->e.playerName;
155 while((REG_HS_CTRL&JOY_READ) == 0) ; 206 }
156 REG_HS_CTRL |= JOY_RW; 207 iprintf("%d\n", trainerName[0]);
157 } 208 iprintf("%d\n", trainerName[1]);
158 } 209 iprintf("%d\n", trainerName[2]);
159 else if(choseval == 3 || choseval == 4) 210 iprintf("%d\n", trainerName[3]);
160 { 211 iprintf("%d\n", trainerName[4]);
161 REG_JOYTR = savesize; 212 iprintf("%d\n", trainerName[5]);
162 if(choseval == 3) 213 iprintf("%d\n", trainerName[6]);
163 { 214 iprintf("%d\n", trainerName[7]);
164 //receive the save 215
165 for(i = 0; i < savesize; i+=4) 216 u32 tn1 =
166 { 217 (trainerName[0] << 24)
167 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 218 | (trainerName[1] << 16)
168 REG_HS_CTRL |= JOY_RW; 219 | (trainerName[2] << 8)
169 *(vu32*)(save_data+i) = REG_JOYRE; 220 | (trainerName[3]);
170 } 221
171 } 222 u32 tn2 =
172 else 223 (trainerName[4] << 24)
173 { 224 | (trainerName[5] << 16)
174 //clear the save 225 | (trainerName[6] << 8)
175 for(i = 0; i < savesize; i+=4) 226 | (trainerName[7]);
176 *(vu32*)(save_data+i) = 0; 227
177 } 228 sendU32(tn1);
178 //disable interrupts 229 waitForAck();
179 u32 prevIrqMask = REG_IME; 230
180 REG_IME = 0; 231 sendU32(tn2);
181 //write it 232 waitForAck();
182 switch (savesize){ 233*/
183 case 0x200: 234 // Send trainer ID.
184 PutSave_EEPROM_512B(save_data); 235 u8* trainerId = 0;
185 break; 236
186 case 0x2000: 237 if (GAME_RS)
187 PutSave_EEPROM_8KB(save_data); 238 {
188 break; 239 trainerId = SaveBlock2->rs.playerTrainerId;
189 case 0x8000: 240 } else if (GAME_FRLG)
190 PutSave_SRAM_32KB(save_data); 241 {
191 break; 242 trainerId = SaveBlock2->frlg.playerTrainerId;
192 case 0x10000: 243 } else if (GAME_EM)
193 PutSave_FLASH_64KB(save_data); 244 {
194 break; 245 trainerId = SaveBlock2->e.playerTrainerId;
195 case 0x20000: 246 }
196 PutSave_FLASH_128KB(save_data); 247
197 break; 248 u32 tti =
198 default: 249 (trainerId[2] << 8)
199 break; 250 | (trainerId[3]);
200 } 251
201 //restore interrupts 252 sendU32(tti);
202 REG_IME = prevIrqMask; 253 waitForAck();
203 //say gc side we're done 254
204 REG_JOYTR = 0; 255 // Restart, because we're just testing.
205 //wait for a cmd receive for safety 256 sendS32(0);
206 while((REG_HS_CTRL&JOY_WRITE) == 0) ; 257 //continue;
207 REG_HS_CTRL |= JOY_RW; 258 break;
208 } 259
209 REG_JOYTR = 0; 260/*
210 } 261
211 else if(REG_HS_CTRL&JOY_WRITE) 262
212 { 263 //game in, send header
213 REG_HS_CTRL |= JOY_RW; 264 for(i = 0; i < 0xC0; i+=4)
214 u32 choseval = REG_JOYRE; 265 {
215 if(choseval == 5) 266 REG_JOYTR = *(vu32*)(0x08000000+i);
216 { 267 while((REG_HS_CTRL&JOY_READ) == 0) ;
217 //disable interrupts 268 REG_HS_CTRL |= JOY_RW;
218 u32 prevIrqMask = REG_IME; 269 }
219 REG_IME = 0; 270 REG_JOYTR = 0;
220 //dump BIOS 271 //wait for other side to choose
221 for (i = 0; i < 0x4000; i+=4) 272 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
222 { 273 REG_HS_CTRL |= JOY_RW;
223 // the lower bits are inaccurate, so just get it four times :) 274 u32 choseval = REG_JOYRE;
224 u32 a = MidiKey2Freq((WaveData *)(i-4), 180-12, 0) * 2; 275 if(choseval == 0)
225 u32 b = MidiKey2Freq((WaveData *)(i-3), 180-12, 0) * 2; 276 {
226 u32 c = MidiKey2Freq((WaveData *)(i-2), 180-12, 0) * 2; 277 REG_JOYTR = 0;
227 u32 d = MidiKey2Freq((WaveData *)(i-1), 180-12, 0) * 2; 278 continue; //nothing to read
228 REG_JOYTR = ((a>>24<<24) | (d>>24<<16) | (c>>24<<8) | (b>>24)); 279 }
229 while((REG_HS_CTRL&JOY_READ) == 0) ; 280 else if(choseval == 1)
230 REG_HS_CTRL |= JOY_RW; 281 {
231 } 282 //disable interrupts
232 //restore interrupts 283 u32 prevIrqMask = REG_IME;
233 REG_IME = prevIrqMask; 284 REG_IME = 0;
234 } 285 //dump the game
235 REG_JOYTR = 0; 286 for(i = 0; i < gamesize; i+=4)
236 } 287 {
237 Halt(); 288 REG_JOYTR = *(vu32*)(0x08000000+i);
238 } 289 while((REG_HS_CTRL&JOY_READ) == 0) ;
290 REG_HS_CTRL |= JOY_RW;
291 }
292 //restore interrupts
293 REG_IME = prevIrqMask;
294 }
295 else if(choseval == 2)
296 {
297 //disable interrupts
298 u32 prevIrqMask = REG_IME;
299 REG_IME = 0;
300 //backup save
301 switch (savesize){
302 case 0x200:
303 GetSave_EEPROM_512B(save_data);
304 break;
305 case 0x2000:
306 GetSave_EEPROM_8KB(save_data);
307 break;
308 case 0x8000:
309 GetSave_SRAM_32KB(save_data);
310 break;
311 case 0x10000:
312 GetSave_FLASH_64KB(save_data);
313 break;
314 case 0x20000:
315 GetSave_FLASH_128KB(save_data);
316 break;
317 default:
318 break;
319 }
320 //restore interrupts
321 REG_IME = prevIrqMask;
322 //say gc side we read it
323 REG_JOYTR = savesize;
324 //wait for a cmd receive for safety
325 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
326 REG_HS_CTRL |= JOY_RW;
327 //send the save
328 for(i = 0; i < savesize; i+=4)
329 {
330 REG_JOYTR = *(vu32*)(save_data+i);
331 while((REG_HS_CTRL&JOY_READ) == 0) ;
332 REG_HS_CTRL |= JOY_RW;
333 }
334 }
335 else if(choseval == 3 || choseval == 4)
336 {
337 REG_JOYTR = savesize;
338 if(choseval == 3)
339 {
340 //receive the save
341 for(i = 0; i < savesize; i+=4)
342 {
343 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
344 REG_HS_CTRL |= JOY_RW;
345 *(vu32*)(save_data+i) = REG_JOYRE;
346 }
347 }
348 else
349 {
350 //clear the save
351 for(i = 0; i < savesize; i+=4)
352 *(vu32*)(save_data+i) = 0;
353 }
354 //disable interrupts
355 u32 prevIrqMask = REG_IME;
356 REG_IME = 0;
357 //write it
358 switch (savesize){
359 case 0x200:
360 PutSave_EEPROM_512B(save_data);
361 break;
362 case 0x2000:
363 PutSave_EEPROM_8KB(save_data);
364 break;
365 case 0x8000:
366 PutSave_SRAM_32KB(save_data);
367 break;
368 case 0x10000:
369 PutSave_FLASH_64KB(save_data);
370 break;
371 case 0x20000:
372 PutSave_FLASH_128KB(save_data);
373 break;
374 default:
375 break;
376 }
377 //restore interrupts
378 REG_IME = prevIrqMask;
379 //say gc side we're done
380 REG_JOYTR = 0;
381 //wait for a cmd receive for safety
382 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
383 REG_HS_CTRL |= JOY_RW;
384 }
385 REG_JOYTR = 0;
386 }
387 } else if(REG_HS_CTRL&JOY_WRITE)
388 {
389 REG_HS_CTRL |= JOY_RW;
390 u32 choseval = REG_JOYRE;
391 if(choseval == 5)
392 {
393 //disable interrupts
394 u32 prevIrqMask = REG_IME;
395 REG_IME = 0;
396 //dump BIOS
397 for (i = 0; i < 0x4000; i+=4)
398 {
399 // the lower bits are inaccurate, so just get it four times :)
400 u32 a = MidiKey2Freq((WaveData *)(i-4), 180-12, 0) * 2;
401 u32 b = MidiKey2Freq((WaveData *)(i-3), 180-12, 0) * 2;
402 u32 c = MidiKey2Freq((WaveData *)(i-2), 180-12, 0) * 2;
403 u32 d = MidiKey2Freq((WaveData *)(i-1), 180-12, 0) * 2;
404 REG_JOYTR = ((a>>24<<24) | (d>>24<<16) | (c>>24<<8) | (b>>24));
405 while((REG_HS_CTRL&JOY_READ) == 0) ;
406 REG_HS_CTRL |= JOY_RW;
407 }
408 //restore interrupts
409 REG_IME = prevIrqMask;
410 }
411 REG_JOYTR = 0;
412 }*/
413 Halt();
414 }
239} 415}
240 416
241 417
diff --git a/gba/source/saveblocks.h b/gba/source/saveblocks.h new file mode 100644 index 0000000..cf0a5c3 --- /dev/null +++ b/gba/source/saveblocks.h
@@ -0,0 +1,343 @@
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 saveblock structures for all of Gen 3 (yay!)
8 */
9
10// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity
11#include "savestructs.h"
12
13typedef struct
14{
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