about summary refs log tree commit diff stats
path: root/gba
diff options
context:
space:
mode:
Diffstat (limited to 'gba')
-rw-r--r--gba/Makefile4
-rw-r--r--gba/source/call_into_middle_of_titlescreen_func.s13
-rw-r--r--gba/source/gamedata.c512
-rw-r--r--gba/source/gamedata.h (renamed from gba/source/payload.h)16
-rw-r--r--gba/source/libpayload.c312
-rw-r--r--gba/source/libpayload.h160
-rw-r--r--gba/source/link.c38
-rw-r--r--gba/source/link.h17
-rw-r--r--gba/source/main.c468
-rw-r--r--gba/source/payload.c72
10 files changed, 679 insertions, 933 deletions
diff --git a/gba/Makefile b/gba/Makefile index b28e0e1..49d0777 100644 --- a/gba/Makefile +++ b/gba/Makefile
@@ -9,7 +9,7 @@ endif
9 9
10%_pkjb.elf: 10%_pkjb.elf:
11 @echo linking pkjb 11 @echo linking pkjb
12 @$(LD) -specs=../gba_pkjb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 12 $(LD) -specs=../gba_pkjb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
13 13
14include $(DEVKITARM)/gba_rules 14include $(DEVKITARM)/gba_rules
15 15
@@ -155,7 +155,7 @@ $(OUTPUT).elf : $(OFILES)
155#--------------------------------------------------------------------------------- 155#---------------------------------------------------------------------------------
156 @echo $(notdir $<) 156 @echo $(notdir $<)
157 @$(bin2o) 157 @$(bin2o)
158 158
159#--------------------------------------------------------------------------------- 159#---------------------------------------------------------------------------------
160# This rule creates assembly source files using grit 160# This rule creates assembly source files using grit
161# grit takes an image file and a .grit describing how the file is to be processed 161# grit takes an image file and a .grit describing how the file is to be processed
diff --git a/gba/source/call_into_middle_of_titlescreen_func.s b/gba/source/call_into_middle_of_titlescreen_func.s deleted file mode 100644 index 7908f6b..0000000 --- a/gba/source/call_into_middle_of_titlescreen_func.s +++ /dev/null
@@ -1,13 +0,0 @@
1 .text
2 .code 16
3
4 .global call_into_middle_of_titlescreen_func
5 .thumb_func
6call_into_middle_of_titlescreen_func:
7 push {lr}
8 push {r4-r5}
9 @ use r4 (which already got saved to the stack) as scratch space to reserve a variable amount of stack space
10 mov r4,sp
11 sub r4,r4,r1
12 mov sp,r4
13 bx r0 \ No newline at end of file
diff --git a/gba/source/gamedata.c b/gba/source/gamedata.c new file mode 100644 index 0000000..6868b2b --- /dev/null +++ b/gba/source/gamedata.c
@@ -0,0 +1,512 @@
1/*
2 * Copyright (C) 2017 hatkirby
3 * Copyright (C) 2017 slipstream/RoL
4 *
5 * This software may be modified and distributed under the terms
6 * of the MIT license. See the LICENSE file for details.
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
249 // default does not set up saveblock3. Which will need to be set up before
250 // loading the save if we want boxed Pokémon to not disappear. Oh, and
251 // loadsave() offset is different between FR and LG...
252
253 case 'DRPB': // FireRed German
254 case 'DGPB': // LeafGreen German
255 {
256 gSaveBlock1 = (pSaveBlock1) 0x202552C;
257 gSaveBlock2 = (pSaveBlock2) 0x2024588;
258 gSaveBlock3 = (pSaveBlock3) 0x2029314;
259 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
260 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
261 //mainloop = (void(*)()) 0x8000425;
262 //titlemid = 0x80791df;
263 //load_pokemon = (void(*)()) 0x804c251;
264
265 break;
266 }
267
268 case 'FRPB': // FireRed French
269 case 'FGPB': // LeafGreen French
270 {
271 gSaveBlock1 = (pSaveBlock1) 0x202552C;
272 gSaveBlock2 = (pSaveBlock2) 0x2024588;
273 gSaveBlock3 = (pSaveBlock3) 0x2029314;
274 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
275 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da7e1 : 0x80da7b5 );
276 //mainloop = (void(*)()) 0x8000417;
277 //titlemid = 0x807929f;
278 //load_pokemon = (void(*)()) 0x804c311;
279
280 break;
281 }
282
283 case 'IRPB': // FireRed Italian
284 case 'IGPB': // LeafGreen Italian
285 {
286 gSaveBlock1 = (pSaveBlock1) 0x202552C;
287 gSaveBlock2 = (pSaveBlock2) 0x2024588;
288 gSaveBlock3 = (pSaveBlock3) 0x2029314;
289 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
290 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
291 //mainloop = (void(*)()) 0x8000425;
292 //titlemid = 0x80791cb;
293 //load_pokemon = (void(*)()) 0x804c23d;
294
295 break;
296 }
297
298 case 'SRPB': // FireRed Spanish
299 case 'SGPB': // LeafGreen Spanish
300 {
301 gSaveBlock1 = (pSaveBlock1) 0x202552C;
302 gSaveBlock2 = (pSaveBlock2) 0x2024588;
303 gSaveBlock3 = (pSaveBlock3) 0x2029314;
304 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
305 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da809 : 0x80da7dd );
306 //mainloop = (void(*)()) 0x8000417;
307 //titlemid = 0x80792b3;
308 //load_pokemon = (void(*)()) 0x804c325;
309
310 break;
311 }
312
313 case 'ERPB': // FireRed English
314 case 'EGPB': // LeafGreen English
315 {
316 gSaveBlock1 = (pSaveBlock1) 0x202552C;
317 gSaveBlock2 = (pSaveBlock2) 0x2024588;
318 gSaveBlock3 = (pSaveBlock3) 0x2029314;
319 *(pSaveBlock3*)(0x3005010) = gSaveBlock3;
320
321 // version number
322 switch (ROM[0xBC])
323 {
324 case 0:
325 {
326 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da4fd : 0x80da4d1 );
327 //mainloop = (void(*)()) 0x800041b;
328 //titlemid = 0x807927b;
329 //load_pokemon = (void(*)()) 0x804c231;
330
331 break;
332 }
333
334 case 1:
335 {
336 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da511 : 0x80da4e5 );
337 //mainloop = (void(*)()) 0x8000429;
338 //titlemid = 0x807928f;
339 //load_pokemon = (void(*)()) 0x804c245;
340
341 break;
342 }
343
344 default:
345 {
346 return false; // unsupported version
347 }
348 }
349
350 break;
351 }
352
353 case 'JRPB': // FireRed Japanese
354 case 'JGPB': // LeafGreen Japanese
355 {
356 gSaveBlock1 = (pSaveBlock1) 0x202548C;
357 gSaveBlock2 = (pSaveBlock2) 0x20244E8;
358 gSaveBlock3 = (pSaveBlock3) 0x202924C;
359 *(pSaveBlock3*)(0x3005050) = gSaveBlock3;
360
361 // version number
362 switch (ROM[0xBC])
363 {
364 case 0:
365 {
366 loadsave = (void(*)(char)) ( GAME_FR ? 0x80db4e5 : 0x80db4b9 );
367 //mainloop = (void(*)()) 0x800041b;
368 //titlemid = 0x8078a0f;
369 //load_pokemon = (void(*)()) 0x804b9e9;
370
371 break;
372 }
373
374 case 1:
375 {
376 if ((gamecode << 8) == 'GPB\x00')
377 {
378 // LeafGreen v1.1 Japanese is undumped.
379 // Therefore, it is unsupported.
380 // I will make guesses at the offsets in the comments, but I will
381 // not actually implement them until LeafGreen v1.1 is dumped.
382
383 return false;
384 }
385
386 loadsave = (void(*)(char)) 0x80db529;
387 // potential LG1.1 address: 0x80db4fd
388 //mainloop = (void(*)()) 0x8000417;
389 //titlemid = 0x8078987;
390 //load_pokemon = (void(*)()) 0x804b9c5;
391
392 break;
393 }
394
395 default:
396 {
397 return false; // unsupported version
398 }
399 }
400
401 break;
402 }
403
404 /// --- Emerald ---
405 // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in
406 // FR/LG it was saveblock3). The initial save loading code after the
407 // copyright screen is also updated, now it sets up ASLR/crypto here before
408 // loading the save.
409
410 case 'DEPB': // Emerald German
411 {
412 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
413 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
414 gSaveBlock3 = (pSaveBlock3) 0x2029808;
415 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
416 loadsave = (void(*)(char)) 0x8153075;
417 //mainloop = (void(*)()) 0x800042b;
418 //titlemid = 0x816fdb5;
419 //load_pokemon = (void(*)()) 0x8076dd5;
420
421 break;
422 }
423
424 case 'FEPB': // Emerald French
425 {
426 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
427 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
428 gSaveBlock3 = (pSaveBlock3) 0x2029808;
429 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
430 loadsave = (void(*)(char)) 0x815319d;
431 //mainloop = (void(*)()) 0x800042b;
432 //titlemid = 0x816fedd;
433 //load_pokemon = (void(*)()) 0x8076dd1;
434
435 break;
436 }
437
438 case 'IEPB': // Emerald Italian
439 {
440 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
441 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
442 gSaveBlock3 = (pSaveBlock3) 0x2029808;
443 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
444 loadsave = (void(*)(char)) 0x8153065;
445 //mainloop = (void(*)()) 0x800042b;
446 //titlemid = 0x816fda5;
447 //load_pokemon = (void(*)()) 0x8076dd5;
448
449 break;
450 }
451
452 case 'SEPB': // Emerald Spanish
453 {
454 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
455 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
456 gSaveBlock3 = (pSaveBlock3) 0x2029808;
457 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
458 loadsave = (void(*)(char)) 0x8153175;
459 //mainloop = (void(*)()) 0x800042b;
460 //titlemid = 0x816feb5;
461 //load_pokemon = (void(*)()) 0x8076dd1;
462
463 break;
464 }
465
466 case 'EEPB': // Emerald English
467 {
468 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
469 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
470 gSaveBlock3 = (pSaveBlock3) 0x2029808;
471 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
472 loadsave = (void(*)(char)) 0x81534d1;
473 //mainloop = (void(*)()) 0x800042b;
474 //titlemid = 0x817014d;
475 //load_pokemon = (void(*)()) 0x8076dd5;
476
477 break;
478 }
479
480 case 'JEPB': // Emerald Japanese
481 {
482 gSaveBlock1 = (pSaveBlock1) 0x20256A4;
483 gSaveBlock2 = (pSaveBlock2) 0x20246F8;
484 gSaveBlock3 = (pSaveBlock3) 0x20294AC;
485 *(pSaveBlock1*)(0x3005aec) = gSaveBlock1;
486 loadsave = (void(*)(char)) 0x815340d;
487 //mainloop = (void(*)()) 0x800042b;
488 //titlemid = 0x816ff45;
489 //load_pokemon = (void(*)()) 0x80767dd;
490
491 break;
492 }
493
494 default:
495 {
496 return false; // this game isn't supported
497 }
498 }
499
500 loadsave(0);
501
502 // now the save is loaded, we can do what we want with the loaded blocks.
503 // first, we're going to want to decrypt the parts that are crypted, if
504 // applicable.
505 decryptSaveStructures(gSaveBlock1,gSaveBlock2,gSaveBlock3);
506
507 *SaveBlock1 = gSaveBlock1;
508 *SaveBlock2 = gSaveBlock2;
509 *SaveBlock3 = gSaveBlock3;
510
511 return true;
512}
diff --git a/gba/source/payload.h b/gba/source/gamedata.h index ea87200..4d0a2a9 100644 --- a/gba/source/payload.h +++ b/gba/source/gamedata.h
@@ -1,14 +1,15 @@
1/* 1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017. 2 * Copyright (C) 2017 hatkirby
3 * Copyright (C) 2017 slipstream/RoL
3 * 4 *
4 * This software may be modified and distributed under the terms 5 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details. 6 * of the MIT license. See the LICENSE file for details.
6 *
7 * payload.h: header file describing payload function
8 */ 7 */
8#ifndef _GAMEDATA_H_
9#define _GAMEDATA_H_
9 10
11#include <gba.h>
10#include "saveblocks.h" 12#include "saveblocks.h"
11#include "libpayload.h"
12 13
13#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00') 14#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00')
14#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00') 15#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00')
@@ -20,4 +21,9 @@
20 21
21#define LANG_JAPAN ((*(u8*)(0x80000AF)) == 'J') 22#define LANG_JAPAN ((*(u8*)(0x80000AF)) == 'J')
22 23
23void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3); \ No newline at end of file 24bool initSaveData(
25 pSaveBlock1* SaveBlock1,
26 pSaveBlock2* SaveBlock2,
27 pSaveBlock3* SaveBlock3);
28
29#endif
diff --git a/gba/source/libpayload.c b/gba/source/libpayload.c deleted file mode 100644 index f13a34f..0000000 --- a/gba/source/libpayload.c +++ /dev/null
@@ -1,312 +0,0 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * libpayload.c: contains helper functions for the payload
8 */
9
10#include <gba.h>
11#include "payload.h"
12
13// private functions
14static void CryptBoxPokemon(struct BoxPokemon* pkm);
15static u16 crc16(const u8* data, u16 len);
16static u32 CalculateRamScriptDataChecksum(struct RamScriptData* ramScript);
17
18/**
19 * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily.
20 * Remember to call EncryptPokemon() afterwards.
21 * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of.
22*/
23void DecryptPokemon(struct Pokemon* pkm) {
24 struct BoxPokemon* boxMon = &(pkm->box);
25 CryptBoxPokemon(boxMon);
26}
27
28/**
29 * Private function that does the actual work of crypting the substructures of a BoxPokemon.
30 * @param struct BoxPokemon* pkm The BoxPokemon whose substructures will be crypted.
31*/
32static void CryptBoxPokemon(struct BoxPokemon* pkm) {
33 for (u32 i = 0; i < 12; i++) {
34 pkm->secure.raw[i] ^= (pkm->otId ^ pkm->personality);
35 }
36}
37
38/**
39 * Decrypts the substructures of a core Pokémon structure, so they can be viewed or modified easily.
40 * Used by DecryptPokemon().
41 * Remember to call EncryptPokemon() afterwards.
42 * @param struct BoxPokemon* pkm The BoxPokemon to decrypt the substructures of.
43*/
44void DecryptBoxPokemon(struct BoxPokemon* pkm) {
45 CryptBoxPokemon(pkm);
46}
47
48/**
49 * Encrypts the substructures of a Pokémon structure, and fixes the checksum.
50 * Must be used after DecryptPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
51 * @param struct Pokemon* pkm The Pokémon to encrypt the substructures and fix the checksum of.
52*/
53void EncryptPokemon(struct Pokemon* pkm) {
54 struct BoxPokemon* boxMon = &(pkm->box);
55 EncryptBoxPokemon(boxMon);
56}
57
58/**
59 * Encrypts the substructures of a core Pokémon structure, and fixes the checksum.
60 * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
61 * @param struct BoxPokemon* pkm The BoxPokemon to encrypt the substructures and fix the checksum of.
62*/
63void EncryptBoxPokemon(struct BoxPokemon* pkm) {
64 FixBoxPokemonChecksum(pkm);
65 CryptBoxPokemon(pkm);
66}
67
68/**
69 * Gets a substructure of a Pokémon structure.
70 * Call DecryptPokemon() first or the substructure data will be encrypted.
71 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
72 * @param u8 substructId The substructure to get.
73 * @return union PokemonSubstruct* The substructure.
74*/
75union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId) {
76 struct BoxPokemon* boxMon = &(pkm->box);
77 return GetBoxPokemonSubstruct(boxMon,substructId);
78}
79
80/**
81 * Gets a substructure of a core Pokémon structure.
82 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
83 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
84 * @param u8 substructId The substructure to get.
85 * @return union PokemonSubstruct* The substructure.
86*/
87union PokemonSubstruct* GetBoxPokemonSubstruct(struct BoxPokemon* pkm,u8 substructId) {
88 if (substructId > 3) return NULL;
89 u32 personality = pkm->personality;
90 // Staring at the substruct indexes, I noticed the last two columns are the reverse of the first two!
91 // that is, substructId==2 column is the reverse of substructId==1, substructId==3 is the reverse of substructId==0
92 // At least that means there's no need to hardcode all four.
93 u8 substruct_idxes[2][24] = {
94 { 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3 },
95 { 1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2 }
96 };
97 u32 modulo = (personality % 24);
98 if (substructId < 2) {
99 return &( pkm->secure.substructs[ substruct_idxes[substructId][modulo] ] );
100 }
101 return &( pkm->secure.substructs[ substruct_idxes[3 - substructId][23 - modulo] ] );
102}
103
104/**
105 * Gets the checksum of a core Pokémon structure.
106 * @param struct BoxPokemon* pkm The BoxPokemon to calculate the checksum of.
107 * @return u16 The checksum.
108*/
109u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm) {
110 u16 checksum = 0;
111 union PokemonSubstruct* substructs[4] = {
112 GetBoxPokemonSubstruct(pkm,0),
113 GetBoxPokemonSubstruct(pkm,1),
114 GetBoxPokemonSubstruct(pkm,2),
115 GetBoxPokemonSubstruct(pkm,3)
116 };
117
118 for (int substruct = 0; substruct < 4; substruct++) {
119 for (int i = 0; i < 6; i++) {
120 checksum += substructs[substruct]->raw[i];
121 }
122 }
123 return checksum;
124}
125
126/**
127 * Fixes the checksum of a core Pokémon structure.
128 * @param struct BoxPokemon* pkm The BoxPokemon to fix the checksum of.
129*/
130void FixBoxPokemonChecksum(struct BoxPokemon* pkm) {
131 pkm->checksum = CalculateBoxPokemonChecksum(pkm);
132}
133
134/**
135 * Gets the zeroth substructure ("Growth") of a Pokémon structure.
136 * Call DecryptPokemon() first or the substructure data will be encrypted.
137 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
138 * @return struct PokemonSubstruct0* The substructure.
139*/
140struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm) {
141 struct BoxPokemon* boxMon = &(pkm->box);
142 return GetBoxPokemonSubstruct0(boxMon);
143}
144
145/**
146 * Gets the zeroth substructure ("Growth") of a core Pokémon structure.
147 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
148 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
149 * @return struct PokemonSubstruct0* The substructure.
150*/
151struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm) {
152 return &( GetBoxPokemonSubstruct(pkm,0)->type0 );
153}
154
155/**
156 * Gets the first substructure ("Attacks") of a Pokémon structure.
157 * Call DecryptPokemon() first or the substructure data will be encrypted.
158 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
159 * @return struct PokemonSubstruct0* The substructure.
160*/
161struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm) {
162 struct BoxPokemon* boxMon = &(pkm->box);
163 return GetBoxPokemonSubstruct1(boxMon);
164}
165
166/**
167 * Gets the first substructure ("Attacks") of a core Pokémon structure.
168 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
169 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
170 * @return struct PokemonSubstruct1* The substructure.
171*/
172struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm) {
173 return &( GetBoxPokemonSubstruct(pkm,1)->type1 );
174}
175
176/**
177 * Gets the second substructure ("EVs & Condition") of a Pokémon structure.
178 * Call DecryptPokemon() first or the substructure data will be encrypted.
179 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
180 * @return struct PokemonSubstruct0* The substructure.
181*/
182struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm) {
183 struct BoxPokemon* boxMon = &(pkm->box);
184 return GetBoxPokemonSubstruct2(boxMon);
185}
186
187/**
188 * Gets the second substructure ("EVs & Condition") of a core Pokémon structure.
189 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
190 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
191 * @return struct PokemonSubstruct2* The substructure.
192*/
193struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm) {
194 return &( GetBoxPokemonSubstruct(pkm,2)->type2 );
195}
196
197/**
198 * Gets the third substructure ("Miscellaneous") of a Pokémon structure.
199 * Call DecryptPokemon() first or the substructure data will be encrypted.
200 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
201 * @return struct PokemonSubstruct0* The substructure.
202*/
203struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm) {
204 struct BoxPokemon* boxMon = &(pkm->box);
205 return GetBoxPokemonSubstruct3(boxMon);
206}
207
208/**
209 * Gets the third substructure ("Miscellaneous") of a core Pokémon structure.
210 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
211 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
212 * @return struct PokemonSubstruct3* The substructure.
213*/
214struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm) {
215 return &( GetBoxPokemonSubstruct(pkm,3)->type3 );
216}
217
218/**
219 * Calculates the checksum for an R/S-specific Enigma Berry structure in SaveBlock1.
220 * @param struct EnigmaBerry* enigmaBerry The R/S-specific Enigma Berry to calculate the checksum for.
221 * @return u32 The checksum.
222*/
223u32 CalculateEnigmaBerryChecksumRS(struct EnigmaBerry* enigmaBerry) {
224 if (!GAME_RS) return 0; // Enigma Berry structure changed in FR/LG, use CalculateEnigmaBerryChecksumFRLGE() instead.
225 u32 checksum = 0;
226 // Save off and zero out the original Enigma Berry description pointers.
227 const u8* description[2] = { enigmaBerry->berry.description1, enigmaBerry->berry.description2 };
228 enigmaBerry->berry.description1 = enigmaBerry->berry.description2 = NULL;
229 u8* enigmaBerryBytes = (u8*)enigmaBerry;
230 // Calculate the checksum.
231 for (u32 i = 0; i < 1324; i++) {
232 checksum += enigmaBerryBytes[i];
233 }
234 // Restore the saved description.
235 enigmaBerry->berry.description1 = description[0];
236 enigmaBerry->berry.description2 = description[1];
237 return checksum;
238}
239
240/**
241 * Calculates the checksum for an FR/LG/Emerald-specific Enigma Berry structure in SaveBlock1.
242 * @param struct EnigmaBerryFRLGE* enigmaBerry The FR/LG/Emerald-specific Enigma Berry to calculate the checksum for.
243 * @return u32 The checksum.
244*/
245u32 CalculateEnigmaBerryChecksumFRLGE(struct EnigmaBerryFRLGE* enigmaBerry) {
246 if (GAME_RS) return 0; // Enigma Berry structure is different in R/S, use CalculateEnigmaBerryChecksumRS() instead.
247 u32 checksum = 0;
248 u8* enigmaBerryBytes = (u8*)enigmaBerry;
249 for (int i = 0; i < 0x30; i++) {
250 checksum += enigmaBerryBytes[i];
251 }
252 return checksum;
253}
254
255/**
256 * Calculates the checksum for an unspecified Enigma Berry structure in SaveBlock1. (detected by current game)
257 * @param void* enigmaBerry The Enigma Berry structure to calculate the checksum for.
258 * @return u32 The checksum.
259 */
260u32 CalculateEnigmaBerryChecksum(void* enigmaBerry) {
261 if (GAME_RS) return CalculateEnigmaBerryChecksumRS( (struct EnigmaBerry*) enigmaBerry );
262 return CalculateEnigmaBerryChecksumFRLGE( (struct EnigmaBerryFRLGE*) enigmaBerry );
263}
264
265/**
266 * Calculates the checksum for a RAM script structure in SaveBlock1.
267 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
268 * @return u32 The checksum.
269 */
270u32 CalculateRamScriptChecksum(struct RamScript* ramScript) {
271 asm(""); // make sure the call to CalculateRamScriptDataChecksum() is *not* inlined.
272 // For some reason, if it gets inlined, something happens, and the wrong length is used when checksumming...
273 return CalculateRamScriptDataChecksum(&ramScript->data);
274}
275
276/**
277 * Calculates the checksum for a RAM script structure in SaveBlock1.
278 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
279 * @return u32 The checksum.
280 */
281static __attribute__ ((noinline)) u32 CalculateRamScriptDataChecksum(struct RamScriptData* ramScript) {
282 u32 checksum = 0;
283 u32 i = 0;
284 u8* ramScriptBytes = (u8*)(ramScript);
285 if (GAME_RS) {
286 for (i = 0; i < sizeof(struct RamScriptData); i++) checksum += ramScriptBytes[i];
287 return checksum;
288 }
289
290 return (u32)crc16(ramScriptBytes,sizeof(struct RamScriptData) + 1);
291}
292
293/**
294 * Private function to CRC-16, (used by FR/LG/Emerald ramscript checksum). Adapted from http://forums.glitchcity.info/index.php?topic=7114.0
295 * @param u8* Data to checksum
296 * @param u16 Length of data
297 * @return u16 The checksum
298*/
299static u16 crc16(const u8* data, u16 len) {
300 u16 crc = 0x1121;
301 for (u16 i = 0; i < len; ++i) {
302 crc ^= data[i];
303 for (u16 j = 0; j < 8; ++j) {
304 if(crc & 1) {
305 crc = (crc >> 1) ^ 0x8408;
306 } else {
307 crc >>= 1;
308 }
309 }
310 }
311 return ~crc;
312} \ No newline at end of file
diff --git a/gba/source/libpayload.h b/gba/source/libpayload.h deleted file mode 100644 index 4be6fb3..0000000 --- a/gba/source/libpayload.h +++ /dev/null
@@ -1,160 +0,0 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * libpayload.h: header for payload helper functions
8 */
9
10/**
11 * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily.
12 * Remember to call EncryptPokemon() afterwards.
13 * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of.
14*/
15void DecryptPokemon(struct Pokemon* pkm);
16
17/**
18 * Decrypts the substructures of a core Pokémon structure, so they can be viewed or modified easily.
19 * Used by DecryptPokemon().
20 * Remember to call EncryptPokemon() afterwards.
21 * @param struct BoxPokemon* pkm The BoxPokemon to decrypt the substructures of.
22*/
23void DecryptBoxPokemon(struct BoxPokemon* pkm);
24
25/**
26 * Encrypts the substructures of a Pokémon structure, and fixes the checksum.
27 * Must be used after DecryptPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
28 * @param struct Pokemon* pkm The Pokémon to encrypt the substructures and fix the checksum of.
29*/
30void EncryptPokemon(struct Pokemon* pkm);
31
32/**
33 * Encrypts the substructures of a core Pokémon structure, and fixes the checksum.
34 * Must be used after DecryptBoxPokemon() has been called, otherwise the Pokémon you decrypted and forgot to re-encrypt will become a Bad Egg.
35 * @param struct BoxPokemon* pkm The BoxPokemon to encrypt the substructures and fix the checksum of.
36*/
37void EncryptBoxPokemon(struct BoxPokemon* pkm);
38
39/**
40 * Gets a substructure of a Pokémon structure.
41 * Call DecryptPokemon() first or the substructure data will be encrypted.
42 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
43 * @param u8 substructId The substructure to get.
44 * @return union PokemonSubstruct* The substructure.
45*/
46union PokemonSubstruct* GetPokemonSubstruct(struct Pokemon* pkm,u8 substructId);
47
48/**
49 * Gets a substructure of a core Pokémon structure.
50 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
51 * @param struct Pokemon* pkm The Pokemon to get a substructure of.
52 * @param u8 substructId The substructure to get.
53 * @return union PokemonSubstruct* The substructure.
54*/
55union PokemonSubstruct* GetBoxPokemonSubstruct(struct BoxPokemon* pkm,u8 substructId);
56
57/**
58 * Gets the checksum of a core Pokémon structure.
59 * @param struct BoxPokemon* pkm The BoxPokemon to calculate the checksum of.
60 * @return u16 The checksum.
61*/
62u16 CalculateBoxPokemonChecksum(struct BoxPokemon* pkm);
63
64/**
65 * Fixes the checksum of a core Pokémon structure.
66 * @param struct BoxPokemon* pkm The BoxPokemon to fix the checksum of.
67*/
68void FixBoxPokemonChecksum(struct BoxPokemon* pkm);
69
70/**
71 * Gets the zeroth substructure ("Growth") of a Pokémon structure.
72 * Call DecryptPokemon() first or the substructure data will be encrypted.
73 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
74 * @return struct PokemonSubstruct0* The substructure.
75*/
76struct PokemonSubstruct0* GetPokemonSubstruct0(struct Pokemon* pkm);
77
78/**
79 * Gets the zeroth substructure ("Growth") of a core Pokémon structure.
80 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
81 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
82 * @return struct PokemonSubstruct0* The substructure.
83*/
84struct PokemonSubstruct0* GetBoxPokemonSubstruct0(struct BoxPokemon* pkm);
85
86/**
87 * Gets the first substructure ("Attacks") of a Pokémon structure.
88 * Call DecryptPokemon() first or the substructure data will be encrypted.
89 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
90 * @return struct PokemonSubstruct0* The substructure.
91*/
92struct PokemonSubstruct1* GetPokemonSubstruct1(struct Pokemon* pkm);
93
94/**
95 * Gets the first substructure ("Attacks") of a core Pokémon structure.
96 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
97 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
98 * @return struct PokemonSubstruct1* The substructure.
99*/
100struct PokemonSubstruct1* GetBoxPokemonSubstruct1(struct BoxPokemon* pkm);
101
102/**
103 * Gets the second substructure ("EVs & Condition") of a Pokémon structure.
104 * Call DecryptPokemon() first or the substructure data will be encrypted.
105 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
106 * @return struct PokemonSubstruct0* The substructure.
107*/
108struct PokemonSubstruct2* GetPokemonSubstruct2(struct Pokemon* pkm);
109
110/**
111 * Gets the second substructure ("EVs & Condition") of a core Pokémon structure.
112 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
113 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
114 * @return struct PokemonSubstruct2* The substructure.
115*/
116struct PokemonSubstruct2* GetBoxPokemonSubstruct2(struct BoxPokemon* pkm);
117
118/**
119 * Gets the third substructure ("Miscellaneous") of a Pokémon structure.
120 * Call DecryptPokemon() first or the substructure data will be encrypted.
121 * @param struct Pokemon* pkm The Pokémon to get a substructure of.
122 * @return struct PokemonSubstruct0* The substructure.
123*/
124struct PokemonSubstruct3* GetPokemonSubstruct3(struct Pokemon* pkm);
125
126/**
127 * Gets the third substructure ("Miscellaneous") of a core Pokémon structure.
128 * Call DecryptBoxPokemon() first or the substructure data will be encrypted.
129 * @param struct BoxPokemon* pkm The BoxPokemon to get the substructure of.
130 * @return struct PokemonSubstruct3* The substructure.
131*/
132struct PokemonSubstruct3* GetBoxPokemonSubstruct3(struct BoxPokemon* pkm);
133
134/**
135 * Calculates the checksum for an R/S-specific Enigma Berry structure in SaveBlock1.
136 * @param struct EnigmaBerry* enigmaBerry The R/S-specific Enigma Berry to calculate the checksum for.
137 * @return u32 The checksum.
138*/
139u32 CalculateEnigmaBerryChecksumRS(struct EnigmaBerry* enigmaBerry);
140
141/**
142 * Calculates the checksum for an FR/LG/Emerald-specific Enigma Berry structure in SaveBlock1.
143 * @param struct EnigmaBerryFRLGE* enigmaBerry The FR/LG/Emerald-specific Enigma Berry to calculate the checksum for.
144 * @return u32 The checksum.
145*/
146u32 CalculateEnigmaBerryChecksumFRLGE(struct EnigmaBerryFRLGE* enigmaBerry);
147
148/**
149 * Calculates the checksum for an unspecified Enigma Berry structure in SaveBlock1. (detected by current game)
150 * @param void* enigmaBerry The Enigma Berry structure to calculate the checksum for.
151 * @return u32 The checksum.
152 */
153u32 CalculateEnigmaBerryChecksum(void* enigmaBerry);
154
155/**
156 * Calculates the checksum for a RAM script structure in SaveBlock1.
157 * @param struct RamScript* ramScript The RAM script structure to calculate the checksum for.
158 * @return u32 The checksum.
159 */
160u32 CalculateRamScriptChecksum(struct RamScript* ramScript); \ No newline at end of file
diff --git a/gba/source/link.c b/gba/source/link.c new file mode 100644 index 0000000..c84e44d --- /dev/null +++ b/gba/source/link.c
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2017 hatkirby
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#include "link.h"
8
9#define JOY_WRITE 2
10#define JOY_READ 4
11#define JOY_RW 6
12
13void initializeLink()
14{
15 REG_HS_CTRL |= JOY_RW;
16 REG_JOYTR = 0;
17 while ((REG_HS_CTRL & JOY_WRITE) == 0);
18 REG_HS_CTRL |= JOY_RW;
19}
20
21void waitForAck()
22{
23 while ((REG_HS_CTRL & JOY_WRITE) == 0);
24 REG_HS_CTRL |= JOY_RW;
25 REG_JOYTR = 0;
26 while ((REG_HS_CTRL & JOY_WRITE) == 0);
27 REG_HS_CTRL |= JOY_RW;
28}
29
30void sendS32(s32 val)
31{
32 REG_JOYTR = val;
33}
34
35void sendU32(u32 val)
36{
37 REG_JOYTR = val;
38}
diff --git a/gba/source/link.h b/gba/source/link.h new file mode 100644 index 0000000..08fd998 --- /dev/null +++ b/gba/source/link.h
@@ -0,0 +1,17 @@
1/*
2 * Copyright (C) 2017 hatkirby
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#ifndef _LINK_H_
8#define _LINK_H_
9
10#include <gba.h>
11
12void initializeLink();
13void waitForAck();
14void sendS32(s32 val);
15void sendU32(u32 val);
16
17#endif
diff --git a/gba/source/main.c b/gba/source/main.c index 4e1e31f..9f97324 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -1,380 +1,110 @@
1/* 1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017. 2 * Copyright (C) 2017 hatkirby
3 * 3 *
4 * This software may be modified and distributed under the terms 4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details. 5 * of the MIT license. See the LICENSE file for details.
6 *
7 * main.c: setup, call payload, return gracefully back to game
8 */ 6 */
9#include <gba.h> 7#include <gba.h>
10#include "payload.h" 8#include "gamedata.h"
9#include "link.h"
11 10
12void call_into_middle_of_titlescreen_func(u32 addr,u32 stackspace); 11int main(void)
12{
13 initializeLink();
13 14
14void decrypt_save_structures(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) { 15 // Identify the host game.
15 if (GAME_RS) { 16 if (GAME_RUBY)
16 // R/S doesn't have save crypto. 17 {
17 return; 18 sendS32(1);
18 } 19 } else if (GAME_SAPP)
19 u8* sb1raw = (u8*)SaveBlock1; 20 {
20 u8* sb2raw = (u8*)SaveBlock2; 21 sendS32(2);
21 //u8* sb3raw = (u8*)SaveBlock3; // unused 22 } else if (GAME_FR)
22 23 {
23 u32* xor_key_ptr = (u32*)(&sb2raw[( GAME_EM ? 0xA8 : 0xF20 )]); 24 sendS32(3);
24 25 } else if (GAME_LG)
25 u32 xor_key = *xor_key_ptr; 26 {
26 u16 xor_key16 = (u16)xor_key; 27 sendS32(4);
27 if (!xor_key) { 28 } else if (GAME_EM)
28 // xor key is zero, nothing needs to be done. 29 {
29 return; 30 sendS32(5);
30 } 31 } else {
31 32 sendS32(-1);
32 u32* ptr_to_xor; 33 waitForAck();
33 u32 save_offset;
34 int i;
35 u32* bag_pocket_offsets;
36 u32* bag_pocket_counts;
37 if (GAME_FRLG) {
38 // loop over and decrypt various things
39 save_offset = 0x3D38 + 4;
40 for (i = 3; i >= 0; i--) {
41 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
42 *ptr_to_xor ^= xor_key;
43 save_offset += 12;
44 }
45 for (i = 0; i <= 0x3f; i++) {
46 save_offset = 0x1200 + (i*sizeof(u32));
47 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
48 *ptr_to_xor ^= xor_key;
49 }
50 // loop over each of the bag pockets and decrypt decrypt decrypt
51 bag_pocket_offsets = (u32[5]) { 0x310, 0x388, 0x430, 0x464, 0x54C };
52 bag_pocket_counts = (u32[5]) { 42, 30, 13, 58, 43 };
53 for (i = 0; i < 5; i++) {
54 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++) {
55 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
56 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
57 }
58 }
59 // decrypt some more stuff
60 save_offset = 0xaf8;
61 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
62 *ptr_to_xor ^= xor_key;
63 save_offset = 0x290;
64 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
65 *ptr_to_xor ^= xor_key;
66 save_offset = 0x294;
67 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
68 } else { // Emerald
69 // loop over and decrypt various things
70 for (i = 0; i <= 0x3f; i++) {
71 save_offset = 0x159c + (i*sizeof(u32));
72 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
73 *ptr_to_xor ^= xor_key;
74 }
75 // loop over each of the bag pockets and decrypt decrypt decrypt
76 bag_pocket_offsets = (u32[5]) { 0x560, 0x5D8, 0x650, 0x690, 0x790 };
77 bag_pocket_counts = (u32[5]) { 30, 30, 16, 64, 46 };
78 for (i = 0; i < 5; i++) {
79 for (int bag_i = 0; bag_i < bag_pocket_counts[i]; bag_i++) {
80 save_offset = bag_pocket_offsets[i] + (sizeof(u32) * bag_i) + 2;
81 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
82 }
83 }
84 // decrypt some more stuff
85 save_offset = 0x1F4;
86 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
87 *ptr_to_xor ^= xor_key;
88 save_offset = 0x490;
89 ptr_to_xor = (u32*)(&sb1raw[save_offset]);
90 *ptr_to_xor ^= xor_key;
91 save_offset = 0x494;
92 *(u16*)(&sb1raw[save_offset]) ^= xor_key16;
93 }
94
95 *xor_key_ptr = 0;
96 return;
97
98}
99 34
100int main(void) { 35 return 0;
101 // check the ROM code, make sure this game is supported. 36 }
102 u8* ROM = (u8*) 0x8000000; 37
103 38 waitForAck();
104 u32 gamecode = (*(u32*)(&ROM[0xAC])); 39
105 40 // Get access to save data.
106 void(*loadsave)(char a1); 41 pSaveBlock1 SaveBlock1;
107 void(*mainloop)(); 42 pSaveBlock2 SaveBlock2;
108 void(*load_pokemon)(); 43 pSaveBlock3 SaveBlock3;
109 pSaveBlock1 gSaveBlock1; 44
110 pSaveBlock2 gSaveBlock2; 45 if (!initSaveData(&SaveBlock1, &SaveBlock2, &SaveBlock3))
111 pSaveBlock3 gSaveBlock3; 46 {
112 u32 titlemid = 0; 47 // Unsupported game version.
113 // get the address of the save loading function. 48 sendS32(-1);
114 switch (gamecode) { 49 waitForAck();
115 // --- R/S --- 50
116 case 'DVXA': // Ruby German 51 return 0;
117 case 'DPXA': // Sapphire German 52 }
118 // TODO: detect debug ROM? 53
119 gSaveBlock1 = (pSaveBlock1) 0x2025734; 54 sendS32(1);
120 gSaveBlock2 = (pSaveBlock2) 0x2024EA4; 55 waitForAck();
121 gSaveBlock3 = (pSaveBlock3) 0x20300A0; 56
122 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1 57 // Send trainer name.
123 mainloop = (void(*)()) 0x80003D9; 58 u8* trainerName = 0;
124 load_pokemon = (void(*)()) 0x8047da9;
125 break;
126 case 'FVXA': // Ruby French
127 case 'FPXA': // Sapphire French
128 gSaveBlock1 = (pSaveBlock1) 0x2025734;
129 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
130 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
131 loadsave = (void(*)(char)) 0x8126351; // same for v1.0 + v1.1
132 mainloop = (void(*)()) 0x80003D9;
133 load_pokemon = (void(*)()) 0x8047e95;
134 break;
135 case 'IVXA': // Ruby Italian
136 case 'IPXA': // Sapphire Italian
137 gSaveBlock1 = (pSaveBlock1) 0x2025734;
138 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
139 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
140 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
141 mainloop = (void(*)()) 0x80003D9;
142 load_pokemon = (void(*)()) 0x8047dbd;
143 break;
144 case 'SVXA': // Ruby Spanish
145 case 'SPXA': // Sapphire Spanish
146 gSaveBlock1 = (pSaveBlock1) 0x2025734;
147 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
148 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
149 loadsave = (void(*)(char)) 0x8126349; // same for v1.0 + v1.1
150 mainloop = (void(*)()) 0x80003D9;
151 load_pokemon = (void(*)()) 0x8047ea5;
152 break;
153 case 'EVXA': // Ruby English
154 case 'EPXA': // Sapphire English
155 gSaveBlock1 = (pSaveBlock1) 0x2025734;
156 gSaveBlock2 = (pSaveBlock2) 0x2024EA4;
157 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
158 mainloop = (void(*)()) 0x80002A5;
159 switch (ROM[0xBC]) { // version number
160 case 0:
161 loadsave = (void(*)(char)) 0x8125EC9;
162 load_pokemon = (void(*)()) 0x8047a85;
163 break;
164 case 1:
165 case 2:
166 loadsave = (void(*)(char)) 0x8125EE9;
167 load_pokemon = (void(*)()) 0x8047aa5;
168 break;
169 default:
170 return 0; // unsupported version
171 }
172 break;
173 case 'JVXA': // Ruby Japanese
174 case 'JPXA': // Sapphire Japanese
175 gSaveBlock1 = (pSaveBlock1) 0x2025494;
176 gSaveBlock2 = (pSaveBlock2) 0x2024C04;
177 gSaveBlock3 = (pSaveBlock3) 0x202FDBC;
178 loadsave = (void(*)(char)) 0x8120d05; // same for v1.0 + v1.1
179 mainloop = (void(*)()) 0x80002A9;
180 load_pokemon = (void(*)()) 0x8044d55;
181 break;
182 /// --- FR/LG ---
183 // In FR/LG, the function that initialises the save-block pointers to default does not set up saveblock3.
184 // Which will need to be set up before loading the save if we want boxed Pokémon to not disappear.
185 // Oh, and loadsave() offset is different between FR and LG...
186 case 'DRPB': // FireRed German
187 case 'DGPB': // LeafGreen German
188 gSaveBlock1 = (pSaveBlock1) 0x202552C;
189 gSaveBlock2 = (pSaveBlock2) 0x2024588;
190 gSaveBlock3 = (pSaveBlock3) 0x2029314;
191 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
192 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
193 mainloop = (void(*)()) 0x8000425;
194 titlemid = 0x80791df;
195 load_pokemon = (void(*)()) 0x804c251;
196 break;
197 case 'FRPB': // FireRed French
198 case 'FGPB': // LeafGreen French
199 gSaveBlock1 = (pSaveBlock1) 0x202552C;
200 gSaveBlock2 = (pSaveBlock2) 0x2024588;
201 gSaveBlock3 = (pSaveBlock3) 0x2029314;
202 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
203 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da7e1 : 0x80da7b5 );
204 mainloop = (void(*)()) 0x8000417;
205 titlemid = 0x807929f;
206 load_pokemon = (void(*)()) 0x804c311;
207 break;
208 case 'IRPB': // FireRed Italian
209 case 'IGPB': // LeafGreen Italian
210 gSaveBlock1 = (pSaveBlock1) 0x202552C;
211 gSaveBlock2 = (pSaveBlock2) 0x2024588;
212 gSaveBlock3 = (pSaveBlock3) 0x2029314;
213 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
214 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
215 mainloop = (void(*)()) 0x8000425;
216 titlemid = 0x80791cb;
217 load_pokemon = (void(*)()) 0x804c23d;
218 break;
219 case 'SRPB': // FireRed Spanish
220 case 'SGPB': // LeafGreen Spanish
221 gSaveBlock1 = (pSaveBlock1) 0x202552C;
222 gSaveBlock2 = (pSaveBlock2) 0x2024588;
223 gSaveBlock3 = (pSaveBlock3) 0x2029314;
224 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
225 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da809 : 0x80da7dd );
226 mainloop = (void(*)()) 0x8000417;
227 titlemid = 0x80792b3;
228 load_pokemon = (void(*)()) 0x804c325;
229 break;
230 case 'ERPB': // FireRed English
231 case 'EGPB': // LeafGreen English
232 gSaveBlock1 = (pSaveBlock1) 0x202552C;
233 gSaveBlock2 = (pSaveBlock2) 0x2024588;
234 gSaveBlock3 = (pSaveBlock3) 0x2029314;
235 *(pSaveBlock3*)(0x3005010) = gSaveBlock3;
236 switch (ROM[0xBC]) { // version number
237 case 0:
238 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da4fd : 0x80da4d1 );
239 mainloop = (void(*)()) 0x800041b;
240 titlemid = 0x807927b;
241 load_pokemon = (void(*)()) 0x804c231;
242 break;
243 case 1:
244 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da511 : 0x80da4e5 );
245 mainloop = (void(*)()) 0x8000429;
246 titlemid = 0x807928f;
247 load_pokemon = (void(*)()) 0x804c245;
248 break;
249 default:
250 return 0; // unsupported version
251 }
252 break;
253 case 'JRPB': // FireRed Japanese
254 case 'JGPB': // LeafGreen Japanese
255 gSaveBlock1 = (pSaveBlock1) 0x202548C;
256 gSaveBlock2 = (pSaveBlock2) 0x20244E8;
257 gSaveBlock3 = (pSaveBlock3) 0x202924C;
258 *(pSaveBlock3*)(0x3005050) = gSaveBlock3;
259 switch (ROM[0xBC]) { // version number
260 case 0:
261 loadsave = (void(*)(char)) ( GAME_FR ? 0x80db4e5 : 0x80db4b9 );
262 mainloop = (void(*)()) 0x800041b;
263 titlemid = 0x8078a0f;
264 load_pokemon = (void(*)()) 0x804b9e9;
265 break;
266 case 1:
267 if ((gamecode << 8) == 'GPB\x00') {
268 // LeafGreen v1.1 Japanese is undumped.
269 // Therefore, it is unsupported.
270 // I will make guesses at the offsets in the comments, but I will not actually implement them until LeafGreen v1.1 is dumped.
271 return 0;
272 }
273 loadsave = (void(*)(char)) 0x80db529; // potential LG1.1 address: 0x80db4fd
274 mainloop = (void(*)()) 0x8000417;
275 titlemid = 0x8078987;
276 load_pokemon = (void(*)()) 0x804b9c5;
277 break;
278 default:
279 return 0; // unsupported version
280 }
281 break;
282 /// --- Emerald ---
283 // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in FR/LG it was saveblock3).
284 // The initial save loading code after the copyright screen is also updated, now it sets up ASLR/crypto here before loading the save.
285 case 'DEPB': // Emerald German
286 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
287 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
288 gSaveBlock3 = (pSaveBlock3) 0x2029808;
289 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
290 loadsave = (void(*)(char)) 0x8153075;
291 mainloop = (void(*)()) 0x800042b;
292 titlemid = 0x816fdb5;
293 load_pokemon = (void(*)()) 0x8076dd5;
294 break;
295 case 'FEPB': // Emerald French
296 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
297 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
298 gSaveBlock3 = (pSaveBlock3) 0x2029808;
299 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
300 loadsave = (void(*)(char)) 0x815319d;
301 mainloop = (void(*)()) 0x800042b;
302 titlemid = 0x816fedd;
303 load_pokemon = (void(*)()) 0x8076dd1;
304 break;
305 case 'IEPB': // Emerald Italian
306 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
307 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
308 gSaveBlock3 = (pSaveBlock3) 0x2029808;
309 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
310 loadsave = (void(*)(char)) 0x8153065;
311 mainloop = (void(*)()) 0x800042b;
312 titlemid = 0x816fda5;
313 load_pokemon = (void(*)()) 0x8076dd5;
314 break;
315 case 'SEPB': // Emerald Spanish
316 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
317 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
318 gSaveBlock3 = (pSaveBlock3) 0x2029808;
319 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
320 loadsave = (void(*)(char)) 0x8153175;
321 mainloop = (void(*)()) 0x800042b;
322 titlemid = 0x816feb5;
323 load_pokemon = (void(*)()) 0x8076dd1;
324 break;
325 case 'EEPB': // Emerald English
326 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
327 gSaveBlock2 = (pSaveBlock2) 0x2024A54;
328 gSaveBlock3 = (pSaveBlock3) 0x2029808;
329 *(pSaveBlock1*)(0x3005d8c) = gSaveBlock1;
330 loadsave = (void(*)(char)) 0x81534d1;
331 mainloop = (void(*)()) 0x800042b;
332 titlemid = 0x817014d;
333 load_pokemon = (void(*)()) 0x8076dd5;
334 break;
335 case 'JEPB': // Emerald Japanese
336 gSaveBlock1 = (pSaveBlock1) 0x20256A4;
337 gSaveBlock2 = (pSaveBlock2) 0x20246F8;
338 gSaveBlock3 = (pSaveBlock3) 0x20294AC;
339 *(pSaveBlock1*)(0x3005aec) = gSaveBlock1;
340 loadsave = (void(*)(char)) 0x815340d;
341 mainloop = (void(*)()) 0x800042b;
342 titlemid = 0x816ff45;
343 load_pokemon = (void(*)()) 0x80767dd;
344 break;
345 default:
346 return 0; // this game isn't supported
347 }
348 loadsave(0);
349 // now the save is loaded, we can do what we want with the loaded blocks.
350 // first, we're going to want to decrypt the parts that are crypted, if applicable.
351 decrypt_save_structures(gSaveBlock1,gSaveBlock2,gSaveBlock3);
352 // time to call the payload.
353 payload(gSaveBlock1,gSaveBlock2,gSaveBlock3);
354 // Now, we better call the function that sets the pokemon-related stuff from the structure elements of the loaded save again.
355 // Just in case the payload did something with that.
356 load_pokemon();
357 // In FR/LG/Emerald, just returning to the game is unwise.
358 // The game reloads the savefile.
359 // 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)
360 // So, better bypass the title screen and get the game to return directly to the Continue/New Game screen.
361 // 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.
362 // 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.
363 // Here goes...
364 if (titlemid) {
365 // Function reserves an extra 4 bytes of stack space in FireRed/LeafGreen, and none in Emerald.
366 call_into_middle_of_titlescreen_func(titlemid,(GAME_EM ? 0 : 4));
367 }
368 // Now we've done what we want, time to return to the game.
369 // Can't just return, the game will reload the save.
370 // So let's just call the main-loop directly ;)
371 // turn the sound back on before we head back to the game
372 *(vu16 *)(REG_BASE + 0x84) = 0x8f;
373 // re-enable interrupts
374 REG_IME = 1;
375 mainloop();
376 // Anything past here will not be executed.
377 return 0;
378}
379 59
60 if (GAME_RS)
61 {
62 trainerName = SaveBlock2->rs.playerName;
63 } else if (GAME_FRLG)
64 {
65 trainerName = SaveBlock2->frlg.playerName;
66 } else if (GAME_EM)
67 {
68 trainerName = SaveBlock2->e.playerName;
69 }
380 70
71 u32 tn1 =
72 (trainerName[0] << 24)
73 | (trainerName[1] << 16)
74 | (trainerName[2] << 8)
75 | (trainerName[3]);
76
77 u32 tn2 =
78 (trainerName[4] << 24)
79 | (trainerName[5] << 16)
80 | (trainerName[6] << 8)
81 | (trainerName[7]);
82
83 sendU32(tn1);
84 waitForAck();
85
86 sendU32(tn2);
87 waitForAck();
88
89 // Send trainer ID.
90 u8* trainerId = 0;
91 if (GAME_RS)
92 {
93 trainerId = SaveBlock2->rs.playerTrainerId;
94 } else if (GAME_FRLG)
95 {
96 trainerId = SaveBlock2->frlg.playerTrainerId;
97 } else if (GAME_EM)
98 {
99 trainerId = SaveBlock2->e.playerTrainerId;
100 }
101
102 u32 tti =
103 (trainerId[1] << 8)
104 | (trainerId[0]);
105
106 sendU32(tti);
107 waitForAck();
108
109 // Halt();
110}
diff --git a/gba/source/payload.c b/gba/source/payload.c deleted file mode 100644 index 665af70..0000000 --- a/gba/source/payload.c +++ /dev/null
@@ -1,72 +0,0 @@
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 * payload.c: place where user payload should go :)
8 */
9
10#include <gba.h>
11#include "payload.h"
12
13// Your payload code should obviously go into the body of this, the payload function.
14void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) {
15 // HoF-warp example payload!
16
17 // Structure offsets are different between R/S, FR/LG, and Emerald.
18 // The beginning of the structures are the same but do NOT take shortcuts here, it's not good practise.
19 // If you want to support multiple games, make specific checks for games, use the right structure for each game.
20 SaveBlock1_RS* sb1rs = &SaveBlock1->rs;
21 SaveBlock1_FRLG* sb1frlg = &SaveBlock1->frlg;
22 SaveBlock1_E* sb1e = &SaveBlock1->e;
23 if (GAME_FRLG) {
24 sb1frlg->location.mapGroup = 1; // generic indoors?
25 sb1frlg->location.mapNum = 80; // Hall of Fame
26 // set coords to the same place that the champions' room script sets them to
27 sb1frlg->location.x = sb1frlg->pos.x = 5;
28 sb1frlg->location.y = sb1frlg->pos.y = 12;
29 sb1frlg->mapDataId = 0xDA; // from HoF map-header
30 sb1frlg->location.warpId = 0xff;
31 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
32 if (sb1frlg->playerPartyCount == 0) {
33 sb1frlg->playerPartyCount = 1;
34 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
35 // so let's hack together one. i don't care about it becoming a bad egg at all.
36 sb1frlg->playerParty[0].box.personality++;
37 }
38 return;
39 } else if (GAME_RS) {
40 sb1rs->location.mapGroup = 16; // Ever Grande City
41 sb1rs->location.mapNum = 11; // Hall of Fame
42 // set coords to the same place that the champions' room script sets them to
43 sb1rs->location.x = sb1rs->pos.x = 7;
44 sb1rs->location.y = sb1rs->pos.y = 16;
45 sb1rs->mapDataId = 299; // from HoF map-header
46 sb1rs->location.warpId = 0xff;
47 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
48 if (sb1rs->playerPartyCount == 0) {
49 sb1rs->playerPartyCount = 1;
50 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
51 // so let's hack together one. i don't care about it becoming a bad egg at all.
52 sb1rs->playerParty[0].box.personality++;
53 }
54 return;
55 } else if (GAME_EM) {
56 sb1e->location.mapGroup = 16; // Ever Grande City
57 sb1e->location.mapNum = 11; // Hall of Fame
58 // set coords to the same place that the champions' room script sets them to
59 sb1e->location.x = sb1e->pos.x = 7;
60 sb1e->location.y = sb1e->pos.y = 16;
61 sb1e->mapDataId = 298; // from HoF map-header
62 sb1e->location.warpId = 0xff;
63 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
64 if (sb1e->playerPartyCount == 0) {
65 sb1e->playerPartyCount = 1;
66 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
67 // so let's hack together one. i don't care about it becoming a bad egg at all.
68 sb1e->playerParty[0].box.personality++;
69 }
70 return;
71 }
72} \ No newline at end of file