about summary refs log tree commit diff stats
path: root/gba
diff options
context:
space:
mode:
authorslipstream/RoL <l33twax@yahoo.com>2017-02-21 20:50:41 +0000
committerslipstream/RoL <l33twax@yahoo.com>2017-02-21 20:50:41 +0000
commit3600f4249f39ec37e41e57aed70c8af620ff847c (patch)
tree970dfd88984c194c70da64380ef24754442dce3b /gba
parentd448823ffb540cb462548552efe4b5650e66de95 (diff)
downloadgen3uploader-3600f4249f39ec37e41e57aed70c8af620ff847c.tar.gz
gen3uploader-3600f4249f39ec37e41e57aed70c8af620ff847c.tar.bz2
gen3uploader-3600f4249f39ec37e41e57aed70c8af620ff847c.zip
New features and bugfixes
- Fixed FireRed v1.0 (Japan) support
- Now reloads the Pokémon from the loaded savefile after calling the
payload, so the payload can modify those parts of saveBlock1 directly
- Decrypts "secure" save data areas in FireRed, LeafGreen and Emerald
Diffstat (limited to 'gba')
-rw-r--r--gba/source/main.c135
1 files changed, 124 insertions, 11 deletions
diff --git a/gba/source/main.c b/gba/source/main.c index 5e2b708..4e1e31f 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -11,6 +11,92 @@
11 11
12void call_into_middle_of_titlescreen_func(u32 addr,u32 stackspace); 12void call_into_middle_of_titlescreen_func(u32 addr,u32 stackspace);
13 13
14void decrypt_save_structures(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) {
15 if (GAME_RS) {
16 // R/S doesn't have save crypto.
17 return;
18 }
19 u8* sb1raw = (u8*)SaveBlock1;
20 u8* sb2raw = (u8*)SaveBlock2;
21 //u8* sb3raw = (u8*)SaveBlock3; // unused
22
23 u32* xor_key_ptr = (u32*)(&sb2raw[( GAME_EM ? 0xA8 : 0xF20 )]);
24
25 u32 xor_key = *xor_key_ptr;
26 u16 xor_key16 = (u16)xor_key;
27 if (!xor_key) {
28 // xor key is zero, nothing needs to be done.
29 return;
30 }
31
32 u32* ptr_to_xor;
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
14int main(void) { 100int main(void) {
15 // check the ROM code, make sure this game is supported. 101 // check the ROM code, make sure this game is supported.
16 u8* ROM = (u8*) 0x8000000; 102 u8* ROM = (u8*) 0x8000000;
@@ -19,6 +105,7 @@ int main(void) {
19 105
20 void(*loadsave)(char a1); 106 void(*loadsave)(char a1);
21 void(*mainloop)(); 107 void(*mainloop)();
108 void(*load_pokemon)();
22 pSaveBlock1 gSaveBlock1; 109 pSaveBlock1 gSaveBlock1;
23 pSaveBlock2 gSaveBlock2; 110 pSaveBlock2 gSaveBlock2;
24 pSaveBlock3 gSaveBlock3; 111 pSaveBlock3 gSaveBlock3;
@@ -34,6 +121,7 @@ int main(void) {
34 gSaveBlock3 = (pSaveBlock3) 0x20300A0; 121 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
35 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1 122 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
36 mainloop = (void(*)()) 0x80003D9; 123 mainloop = (void(*)()) 0x80003D9;
124 load_pokemon = (void(*)()) 0x8047da9;
37 break; 125 break;
38 case 'FVXA': // Ruby French 126 case 'FVXA': // Ruby French
39 case 'FPXA': // Sapphire French 127 case 'FPXA': // Sapphire French
@@ -42,6 +130,7 @@ int main(void) {
42 gSaveBlock3 = (pSaveBlock3) 0x20300A0; 130 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
43 loadsave = (void(*)(char)) 0x8126351; // same for v1.0 + v1.1 131 loadsave = (void(*)(char)) 0x8126351; // same for v1.0 + v1.1
44 mainloop = (void(*)()) 0x80003D9; 132 mainloop = (void(*)()) 0x80003D9;
133 load_pokemon = (void(*)()) 0x8047e95;
45 break; 134 break;
46 case 'IVXA': // Ruby Italian 135 case 'IVXA': // Ruby Italian
47 case 'IPXA': // Sapphire Italian 136 case 'IPXA': // Sapphire Italian
@@ -50,6 +139,7 @@ int main(void) {
50 gSaveBlock3 = (pSaveBlock3) 0x20300A0; 139 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
51 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1 140 loadsave = (void(*)(char)) 0x8126249; // same for v1.0 + v1.1
52 mainloop = (void(*)()) 0x80003D9; 141 mainloop = (void(*)()) 0x80003D9;
142 load_pokemon = (void(*)()) 0x8047dbd;
53 break; 143 break;
54 case 'SVXA': // Ruby Spanish 144 case 'SVXA': // Ruby Spanish
55 case 'SPXA': // Sapphire Spanish 145 case 'SPXA': // Sapphire Spanish
@@ -58,6 +148,7 @@ int main(void) {
58 gSaveBlock3 = (pSaveBlock3) 0x20300A0; 148 gSaveBlock3 = (pSaveBlock3) 0x20300A0;
59 loadsave = (void(*)(char)) 0x8126349; // same for v1.0 + v1.1 149 loadsave = (void(*)(char)) 0x8126349; // same for v1.0 + v1.1
60 mainloop = (void(*)()) 0x80003D9; 150 mainloop = (void(*)()) 0x80003D9;
151 load_pokemon = (void(*)()) 0x8047ea5;
61 break; 152 break;
62 case 'EVXA': // Ruby English 153 case 'EVXA': // Ruby English
63 case 'EPXA': // Sapphire English 154 case 'EPXA': // Sapphire English
@@ -68,10 +159,12 @@ int main(void) {
68 switch (ROM[0xBC]) { // version number 159 switch (ROM[0xBC]) { // version number
69 case 0: 160 case 0:
70 loadsave = (void(*)(char)) 0x8125EC9; 161 loadsave = (void(*)(char)) 0x8125EC9;
162 load_pokemon = (void(*)()) 0x8047a85;
71 break; 163 break;
72 case 1: 164 case 1:
73 case 2: 165 case 2:
74 loadsave = (void(*)(char)) 0x8125EE9; 166 loadsave = (void(*)(char)) 0x8125EE9;
167 load_pokemon = (void(*)()) 0x8047aa5;
75 break; 168 break;
76 default: 169 default:
77 return 0; // unsupported version 170 return 0; // unsupported version
@@ -84,6 +177,7 @@ int main(void) {
84 gSaveBlock3 = (pSaveBlock3) 0x202FDBC; 177 gSaveBlock3 = (pSaveBlock3) 0x202FDBC;
85 loadsave = (void(*)(char)) 0x8120d05; // same for v1.0 + v1.1 178 loadsave = (void(*)(char)) 0x8120d05; // same for v1.0 + v1.1
86 mainloop = (void(*)()) 0x80002A9; 179 mainloop = (void(*)()) 0x80002A9;
180 load_pokemon = (void(*)()) 0x8044d55;
87 break; 181 break;
88 /// --- FR/LG --- 182 /// --- FR/LG ---
89 // In FR/LG, the function that initialises the save-block pointers to default does not set up saveblock3. 183 // In FR/LG, the function that initialises the save-block pointers to default does not set up saveblock3.
@@ -95,9 +189,10 @@ int main(void) {
95 gSaveBlock2 = (pSaveBlock2) 0x2024588; 189 gSaveBlock2 = (pSaveBlock2) 0x2024588;
96 gSaveBlock3 = (pSaveBlock3) 0x2029314; 190 gSaveBlock3 = (pSaveBlock3) 0x2029314;
97 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3; 191 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
98 loadsave = (void(*)(char)) ( (gamecode << 8) == 'RPB\x00' ? 0x80da721 : 0x80da6f5 ); 192 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
99 mainloop = (void(*)()) 0x8000425; 193 mainloop = (void(*)()) 0x8000425;
100 titlemid = 0x80791df; 194 titlemid = 0x80791df;
195 load_pokemon = (void(*)()) 0x804c251;
101 break; 196 break;
102 case 'FRPB': // FireRed French 197 case 'FRPB': // FireRed French
103 case 'FGPB': // LeafGreen French 198 case 'FGPB': // LeafGreen French
@@ -105,9 +200,10 @@ int main(void) {
105 gSaveBlock2 = (pSaveBlock2) 0x2024588; 200 gSaveBlock2 = (pSaveBlock2) 0x2024588;
106 gSaveBlock3 = (pSaveBlock3) 0x2029314; 201 gSaveBlock3 = (pSaveBlock3) 0x2029314;
107 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3; 202 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
108 loadsave = (void(*)(char)) ( (gamecode << 8) == 'RPB\x00' ? 0x80da7e1 : 0x80da7b5 ); 203 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da7e1 : 0x80da7b5 );
109 mainloop = (void(*)()) 0x8000417; 204 mainloop = (void(*)()) 0x8000417;
110 titlemid = 0x807929f; 205 titlemid = 0x807929f;
206 load_pokemon = (void(*)()) 0x804c311;
111 break; 207 break;
112 case 'IRPB': // FireRed Italian 208 case 'IRPB': // FireRed Italian
113 case 'IGPB': // LeafGreen Italian 209 case 'IGPB': // LeafGreen Italian
@@ -115,9 +211,10 @@ int main(void) {
115 gSaveBlock2 = (pSaveBlock2) 0x2024588; 211 gSaveBlock2 = (pSaveBlock2) 0x2024588;
116 gSaveBlock3 = (pSaveBlock3) 0x2029314; 212 gSaveBlock3 = (pSaveBlock3) 0x2029314;
117 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3; 213 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
118 loadsave = (void(*)(char)) ( (gamecode << 8) == 'RPB\x00' ? 0x80da721 : 0x80da6f5 ); 214 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da721 : 0x80da6f5 );
119 mainloop = (void(*)()) 0x8000425; 215 mainloop = (void(*)()) 0x8000425;
120 titlemid = 0x80791cb; 216 titlemid = 0x80791cb;
217 load_pokemon = (void(*)()) 0x804c23d;
121 break; 218 break;
122 case 'SRPB': // FireRed Spanish 219 case 'SRPB': // FireRed Spanish
123 case 'SGPB': // LeafGreen Spanish 220 case 'SGPB': // LeafGreen Spanish
@@ -125,9 +222,10 @@ int main(void) {
125 gSaveBlock2 = (pSaveBlock2) 0x2024588; 222 gSaveBlock2 = (pSaveBlock2) 0x2024588;
126 gSaveBlock3 = (pSaveBlock3) 0x2029314; 223 gSaveBlock3 = (pSaveBlock3) 0x2029314;
127 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3; 224 *(pSaveBlock3*)(0x3004f60) = gSaveBlock3;
128 loadsave = (void(*)(char)) ( (gamecode << 8) == 'RPB\x00' ? 0x80da809 : 0x80da7dd ); 225 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da809 : 0x80da7dd );
129 mainloop = (void(*)()) 0x8000417; 226 mainloop = (void(*)()) 0x8000417;
130 titlemid = 0x80792b3; 227 titlemid = 0x80792b3;
228 load_pokemon = (void(*)()) 0x804c325;
131 break; 229 break;
132 case 'ERPB': // FireRed English 230 case 'ERPB': // FireRed English
133 case 'EGPB': // LeafGreen English 231 case 'EGPB': // LeafGreen English
@@ -137,14 +235,16 @@ int main(void) {
137 *(pSaveBlock3*)(0x3005010) = gSaveBlock3; 235 *(pSaveBlock3*)(0x3005010) = gSaveBlock3;
138 switch (ROM[0xBC]) { // version number 236 switch (ROM[0xBC]) { // version number
139 case 0: 237 case 0:
140 loadsave = (void(*)(char)) ( (gamecode << 8) == 'RPB\x00' ? 0x80da4fd : 0x80da4d1 ); 238 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da4fd : 0x80da4d1 );
141 mainloop = (void(*)()) 0x800041b; 239 mainloop = (void(*)()) 0x800041b;
142 titlemid = 0x807927b; 240 titlemid = 0x807927b;
241 load_pokemon = (void(*)()) 0x804c231;
143 break; 242 break;
144 case 1: 243 case 1:
145 loadsave = (void(*)(char)) ( (gamecode << 8) == 'RPB\x00' ? 0x80da511 : 0x80da4e5 ); 244 loadsave = (void(*)(char)) ( GAME_FR ? 0x80da511 : 0x80da4e5 );
146 mainloop = (void(*)()) 0x8000429; 245 mainloop = (void(*)()) 0x8000429;
147 titlemid = 0x807928f; 246 titlemid = 0x807928f;
247 load_pokemon = (void(*)()) 0x804c245;
148 break; 248 break;
149 default: 249 default:
150 return 0; // unsupported version 250 return 0; // unsupported version
@@ -158,9 +258,10 @@ int main(void) {
158 *(pSaveBlock3*)(0x3005050) = gSaveBlock3; 258 *(pSaveBlock3*)(0x3005050) = gSaveBlock3;
159 switch (ROM[0xBC]) { // version number 259 switch (ROM[0xBC]) { // version number
160 case 0: 260 case 0:
161 loadsave = (void(*)(char)) ( (gamecode << 8) == 'RPB\x00' ? 0x80db4e5 : 0x80db4b9 ); 261 loadsave = (void(*)(char)) ( GAME_FR ? 0x80db4e5 : 0x80db4b9 );
162 mainloop = (void(*)()) 0x800041b; 262 mainloop = (void(*)()) 0x800041b;
163 titlemid = ( (gamecode << 8) == 'RPB\x00' ? 0x8078a0d : 0x8078a0f ); 263 titlemid = 0x8078a0f;
264 load_pokemon = (void(*)()) 0x804b9e9;
164 break; 265 break;
165 case 1: 266 case 1:
166 if ((gamecode << 8) == 'GPB\x00') { 267 if ((gamecode << 8) == 'GPB\x00') {
@@ -171,7 +272,8 @@ int main(void) {
171 } 272 }
172 loadsave = (void(*)(char)) 0x80db529; // potential LG1.1 address: 0x80db4fd 273 loadsave = (void(*)(char)) 0x80db529; // potential LG1.1 address: 0x80db4fd
173 mainloop = (void(*)()) 0x8000417; 274 mainloop = (void(*)()) 0x8000417;
174 titlemid = 0x8078987; // potential LG1.1 address: 0x8078989 275 titlemid = 0x8078987;
276 load_pokemon = (void(*)()) 0x804b9c5;
175 break; 277 break;
176 default: 278 default:
177 return 0; // unsupported version 279 return 0; // unsupported version
@@ -188,6 +290,7 @@ int main(void) {
188 loadsave = (void(*)(char)) 0x8153075; 290 loadsave = (void(*)(char)) 0x8153075;
189 mainloop = (void(*)()) 0x800042b; 291 mainloop = (void(*)()) 0x800042b;
190 titlemid = 0x816fdb5; 292 titlemid = 0x816fdb5;
293 load_pokemon = (void(*)()) 0x8076dd5;
191 break; 294 break;
192 case 'FEPB': // Emerald French 295 case 'FEPB': // Emerald French
193 gSaveBlock1 = (pSaveBlock1) 0x2025A00; 296 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
@@ -197,6 +300,7 @@ int main(void) {
197 loadsave = (void(*)(char)) 0x815319d; 300 loadsave = (void(*)(char)) 0x815319d;
198 mainloop = (void(*)()) 0x800042b; 301 mainloop = (void(*)()) 0x800042b;
199 titlemid = 0x816fedd; 302 titlemid = 0x816fedd;
303 load_pokemon = (void(*)()) 0x8076dd1;
200 break; 304 break;
201 case 'IEPB': // Emerald Italian 305 case 'IEPB': // Emerald Italian
202 gSaveBlock1 = (pSaveBlock1) 0x2025A00; 306 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
@@ -206,6 +310,7 @@ int main(void) {
206 loadsave = (void(*)(char)) 0x8153065; 310 loadsave = (void(*)(char)) 0x8153065;
207 mainloop = (void(*)()) 0x800042b; 311 mainloop = (void(*)()) 0x800042b;
208 titlemid = 0x816fda5; 312 titlemid = 0x816fda5;
313 load_pokemon = (void(*)()) 0x8076dd5;
209 break; 314 break;
210 case 'SEPB': // Emerald Spanish 315 case 'SEPB': // Emerald Spanish
211 gSaveBlock1 = (pSaveBlock1) 0x2025A00; 316 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
@@ -215,6 +320,7 @@ int main(void) {
215 loadsave = (void(*)(char)) 0x8153175; 320 loadsave = (void(*)(char)) 0x8153175;
216 mainloop = (void(*)()) 0x800042b; 321 mainloop = (void(*)()) 0x800042b;
217 titlemid = 0x816feb5; 322 titlemid = 0x816feb5;
323 load_pokemon = (void(*)()) 0x8076dd1;
218 break; 324 break;
219 case 'EEPB': // Emerald English 325 case 'EEPB': // Emerald English
220 gSaveBlock1 = (pSaveBlock1) 0x2025A00; 326 gSaveBlock1 = (pSaveBlock1) 0x2025A00;
@@ -224,6 +330,7 @@ int main(void) {
224 loadsave = (void(*)(char)) 0x81534d1; 330 loadsave = (void(*)(char)) 0x81534d1;
225 mainloop = (void(*)()) 0x800042b; 331 mainloop = (void(*)()) 0x800042b;
226 titlemid = 0x817014d; 332 titlemid = 0x817014d;
333 load_pokemon = (void(*)()) 0x8076dd5;
227 break; 334 break;
228 case 'JEPB': // Emerald Japanese 335 case 'JEPB': // Emerald Japanese
229 gSaveBlock1 = (pSaveBlock1) 0x20256A4; 336 gSaveBlock1 = (pSaveBlock1) 0x20256A4;
@@ -233,14 +340,20 @@ int main(void) {
233 loadsave = (void(*)(char)) 0x815340d; 340 loadsave = (void(*)(char)) 0x815340d;
234 mainloop = (void(*)()) 0x800042b; 341 mainloop = (void(*)()) 0x800042b;
235 titlemid = 0x816ff45; 342 titlemid = 0x816ff45;
343 load_pokemon = (void(*)()) 0x80767dd;
236 break; 344 break;
237 default: 345 default:
238 return 0; // this game isn't supported 346 return 0; // this game isn't supported
239 } 347 }
240 loadsave(0); 348 loadsave(0);
241 // now the save is loaded, we can do what we want with the loaded blocks. 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);
242 // time to call the payload. 352 // time to call the payload.
243 payload(gSaveBlock1,gSaveBlock2,gSaveBlock3); 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();
244 // In FR/LG/Emerald, just returning to the game is unwise. 357 // In FR/LG/Emerald, just returning to the game is unwise.
245 // The game reloads the savefile. 358 // The game reloads the savefile.
246 // 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) 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)
@@ -249,8 +362,8 @@ int main(void) {
249 // 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. 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.
250 // Here goes... 363 // Here goes...
251 if (titlemid) { 364 if (titlemid) {
252 // Function reserves an extra 4 bytes of stack space in FireRed, and none in Emerald. 365 // Function reserves an extra 4 bytes of stack space in FireRed/LeafGreen, and none in Emerald.
253 call_into_middle_of_titlescreen_func(titlemid,((gamecode << 8) == 'EPB\x00' ? 0 : 4)); 366 call_into_middle_of_titlescreen_func(titlemid,(GAME_EM ? 0 : 4));
254 } 367 }
255 // Now we've done what we want, time to return to the game. 368 // Now we've done what we want, time to return to the game.
256 // Can't just return, the game will reload the save. 369 // Can't just return, the game will reload the save.