diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2017-07-11 16:37:21 -0400 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2017-07-11 16:37:21 -0400 |
commit | 57afb4058710a978bd7b07a368125d04378c62f1 (patch) | |
tree | 7a06f1679f0612c58d5a209a013261ff5ad6cb82 /gba/source | |
parent | 004575f7cec14946c1936aceca6efee38b7f8a74 (diff) | |
download | gen3uploader-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.c | 534 | ||||
-rw-r--r-- | gba/source/gamedata.h | 22 | ||||
-rw-r--r-- | gba/source/link.c | 41 | ||||
-rw-r--r-- | gba/source/link.h | 12 | ||||
-rw-r--r-- | gba/source/main.c | 592 | ||||
-rw-r--r-- | gba/source/saveblocks.h | 343 | ||||
-rw-r--r-- | gba/source/savestructs.h | 793 |
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 | |||
10 | void 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 | |||
122 | bool 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 | |||
17 | bool 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 | |||
7 | void 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 | |||
14 | void 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 | |||
23 | void sendS32(s32 val) | ||
24 | { | ||
25 | REG_JOYTR = val; | ||
26 | //waitForWriteAccess(); | ||
27 | } | ||
28 | |||
29 | void sendU32(u32 val) | ||
30 | { | ||
31 | REG_JOYTR = val; | ||
32 | //waitForWriteAccess(); | ||
33 | } | ||
34 | |||
35 | u32 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 | |||
6 | void waitForWriteAccess(); | ||
7 | void waitForAck(); | ||
8 | void sendS32(s32 val); | ||
9 | void sendU32(u32 val); | ||
10 | u32 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 | ||
19 | s32 getGameSize(void) | 21 | s32 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 | ||
60 | typedef u16 COLOR; | ||
61 | #define MEM_VRAM 0x06000000 | ||
62 | #define SCREEN_WIDTH 240 | ||
63 | #define vid_mem ((u16*)MEM_VRAM) | ||
64 | static inline void m3_plot(int x, int y, COLOR clr) | ||
65 | { vid_mem[y*SCREEN_WIDTH+x]= clr; } | ||
66 | static inline COLOR RGB15(u32 red, u32 green, u32 blue) | ||
67 | { return red | (green<<5) | (blue<<10); } | ||
68 | void 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 | } | ||
79 | void 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 | //--------------------------------------------------------------------------------- |
45 | int main(void) { | 92 | int 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 | |||
13 | typedef 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 | |||
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 | ||