about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorslipstream/RoL <l33twax@yahoo.com>2017-02-26 14:27:20 +0000
committerslipstream/RoL <l33twax@yahoo.com>2017-02-26 14:27:20 +0000
commite37cc7de9583b00166e96a6632ba25edefff43ca (patch)
tree592e49249f8e171a29cf3c140081ef054975eb59
parentfac6ea00fd51e5be1d99db44746ed046378a6c65 (diff)
downloadgen3uploader-e37cc7de9583b00166e96a6632ba25edefff43ca.tar.gz
gen3uploader-e37cc7de9583b00166e96a6632ba25edefff43ca.tar.bz2
gen3uploader-e37cc7de9583b00166e96a6632ba25edefff43ca.zip
Major changes
- Added saveblock structures.
- Changed example payload, now it warps to Hall of Fame.
- Added helper library for Pokémon manipulation, checksum calculation,
etc.
- Removed libSave, it's not needed.
-rw-r--r--README.md2
-rw-r--r--gba/source/libSave.c596
-rw-r--r--gba/source/libSave.h27
-rw-r--r--gba/source/libpayload.c312
-rw-r--r--gba/source/libpayload.h160
-rw-r--r--gba/source/payload.c60
-rw-r--r--gba/source/payload.h1
-rw-r--r--gba/source/saveblocks.h338
-rw-r--r--gba/source/savestructs.h793
9 files changed, 1657 insertions, 632 deletions
diff --git a/README.md b/README.md index 4483a83..b833c50 100644 --- a/README.md +++ b/README.md
@@ -3,7 +3,7 @@ A GC and Wii homebrew app that sends a binary to the GBA using the different mul
3 3
4# Usage 4# Usage
5Have a GC Controller in Port 1 and a GBA with Gen3 game in Port 2. 5Have a GC Controller in Port 1 and a GBA with Gen3 game in Port 2.
6Put your payload code to do some interesting stuff with the Pokémon game you have in `gba` dir. Example code that changes first character of player name to 'z' on Pokémon Ruby English (v1.0-1.2) provided. 6Put your payload code to do some interesting stuff with the Pokémon game you have in `gba` dir. Example code that warps the character to the Hall of Fame, adding a Bad Egg if the save has no Pokémon provided.
7Recompile, send to Wii or GC, turn on your GBA, hope that your code runs after the initial copyright screen of the game. 7Recompile, send to Wii or GC, turn on your GBA, hope that your code runs after the initial copyright screen of the game.
8(Code execution rate is for some reason not 100% reliable, PR to fix would be greatly appreciated. Sometimes KeyC derivation fails, sometimes GBA ignores the sent multiboot image, could be due to failure of a few different sends) 8(Code execution rate is for some reason not 100% reliable, PR to fix would be greatly appreciated. Sometimes KeyC derivation fails, sometimes GBA ignores the sent multiboot image, could be due to failure of a few different sends)
9 9
diff --git a/gba/source/libSave.c b/gba/source/libSave.c deleted file mode 100644 index e3bda1d..0000000 --- a/gba/source/libSave.c +++ /dev/null
@@ -1,596 +0,0 @@
1/*
2 libSave
3 Cartridge backup memory save routines. To use, call the required
4 routine with a pointer to an appropriately sized array of data to
5 be read from or written to the cartridge.
6 Data types are from wintermute's gba_types.h libgba library.
7 Original file from SendSave by Chishm
8*/
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <gba_dma.h>
14
15#define EEPROM_ADDRESS (0xDFFFF00)
16#define REG_EEPROM *(vu16 *)(EEPROM_ADDRESS)
17#define REG_DMA3CNT_H *(vu16 *)(REG_BASE + 0x0de)
18#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204)
19
20//-----------------------------------------------------------------------
21// Common EEPROM Routines
22//-----------------------------------------------------------------------
23
24void EEPROM_SendPacket( u16* packet, int size )
25{
26 REG_WAITCNT = (REG_WAITCNT & 0xF8FF) | 0x0300;
27 REG_DMA3SAD = (u32)packet;
28 REG_DMA3DAD = EEPROM_ADDRESS;
29 REG_DMA3CNT = 0x80000000 + size;
30 while((REG_DMA3CNT_H & 0x8000) != 0) ;
31}
32
33void EEPROM_ReceivePacket( u16* packet, int size )
34{
35 REG_WAITCNT = (REG_WAITCNT & 0xF8FF) | 0x0300;
36 REG_DMA3SAD = EEPROM_ADDRESS;
37 REG_DMA3DAD = (u32)packet;
38 REG_DMA3CNT = 0x80000000 + size;
39 while((REG_DMA3CNT_H & 0x8000) != 0) ;
40}
41
42//-----------------------------------------------------------------------
43// Routines for 512B EEPROM
44//-----------------------------------------------------------------------
45
46void EEPROM_Read_512B( volatile u8 offset, u8* dest ) // dest must point to 8 bytes
47{
48 u16 packet[68];
49 u8* out_pos;
50 u16* in_pos;
51 u8 out_byte;
52 int byte, bit;
53
54 memset( packet, 0, 68*2 );
55
56 // Read request
57 packet[0] = 1;
58 packet[1] = 1;
59
60 // 6 bits eeprom address (MSB first)
61 packet[2] = (offset>>5)&1;
62 packet[3] = (offset>>4)&1;
63 packet[4] = (offset>>3)&1;
64 packet[5] = (offset>>2)&1;
65 packet[6] = (offset>>1)&1;
66 packet[7] = (offset)&1;
67
68 // End of request
69 packet[8] = 0;
70
71 // Do transfers
72 EEPROM_SendPacket( packet, 9 );
73 memset( packet, 0, 68*2 );
74 EEPROM_ReceivePacket( packet, 68 );
75
76 // Extract data
77 in_pos = &packet[4];
78 out_pos = dest;
79 for( byte = 7; byte >= 0; --byte )
80 {
81 out_byte = 0;
82 for( bit = 7; bit >= 0; --bit )
83 {
84// out_byte += (*in_pos++)<<bit;
85 out_byte += ((*in_pos++)&1)<<bit;
86 }
87 *out_pos++ = out_byte ;
88 }
89}
90
91void EEPROM_Write_512B( volatile u8 offset, u8* source ) // source must point to 8 bytes
92{
93 u16 packet[73];
94 u8* in_pos;
95 u16* out_pos;
96 u8 in_byte;
97 int byte, bit;
98
99 memset( packet, 0, 73*2 );
100
101 // Write request
102 packet[0] = 1;
103 packet[1] = 0;
104
105 // 6 bits eeprom address (MSB first)
106 packet[2] = (offset>>5)&1;
107 packet[3] = (offset>>4)&1;
108 packet[4] = (offset>>3)&1;
109 packet[5] = (offset>>2)&1;
110 packet[6] = (offset>>1)&1;
111 packet[7] = (offset)&1;
112
113 // Extract data
114 in_pos = source;
115 out_pos = &packet[8];
116 for( byte = 7; byte >= 0; --byte )
117 {
118 in_byte = *in_pos++;
119 for( bit = 7; bit >= 0; --bit )
120 {
121 *out_pos++ = (in_byte>>bit)&1;
122 }
123 }
124
125 // End of request
126 packet[72] = 0;
127
128 // Do transfers
129 EEPROM_SendPacket( packet, 73 );
130
131 // Wait for EEPROM to finish (should timeout after 10 ms)
132 while( (REG_EEPROM & 1) == 0 );
133}
134
135//---------------------------------------------------------------------------------
136void GetSave_EEPROM_512B(u8* data)
137//---------------------------------------------------------------------------------
138{
139 volatile u8 x;
140 u32 sleep;
141
142 for (x=0;x<64;++x){
143 EEPROM_Read_512B(x,&data[x*8]);
144 for(sleep=0;sleep<512000;sleep++);
145 }
146}
147
148//---------------------------------------------------------------------------------
149void PutSave_EEPROM_512B(u8* data)
150//---------------------------------------------------------------------------------
151{
152 volatile u8 x;
153 u32 sleep;
154
155 for (x=0;x<64;x++){
156 EEPROM_Write_512B(x,&data[x*8]);
157 for(sleep=0;sleep<512000;sleep++);
158 }
159}
160//-----------------------------------------------------------------------
161// Routines for 8KB EEPROM
162//-----------------------------------------------------------------------
163
164void EEPROM_Read_8KB( volatile u16 offset, u8* dest ) // dest must point to 8 bytes
165{
166 u16 packet[68];
167 u8* out_pos;
168 u16* in_pos;
169 u8 out_byte;
170 int byte, bit;
171
172 memset( packet, 0, 68*2 );
173
174 // Read request
175 packet[0] = 1;
176 packet[1] = 1;
177
178 // 14 bits eeprom address (MSB first)
179 packet[2] = (offset>>13)&1;
180 packet[3] = (offset>>12)&1;
181 packet[4] = (offset>>11)&1;
182 packet[5] = (offset>>10)&1;
183 packet[6] = (offset>>9)&1;
184 packet[7] = (offset>>8)&1;
185 packet[8] = (offset>>7)&1;
186 packet[9] = (offset>>6)&1;
187 packet[10] = (offset>>5)&1;
188 packet[11] = (offset>>4)&1;
189 packet[12] = (offset>>3)&1;
190 packet[13] = (offset>>2)&1;
191 packet[14] = (offset>>1)&1;
192 packet[15] = (offset)&1;
193
194 // End of request
195 packet[16] = 0;
196
197 // Do transfers
198 EEPROM_SendPacket( packet, 17 );
199 memset( packet, 0, 68*2 );
200 EEPROM_ReceivePacket( packet, 68 );
201
202 // Extract data
203 in_pos = &packet[4];
204 out_pos = dest;
205 for( byte = 7; byte >= 0; --byte )
206 {
207 out_byte = 0;
208 for( bit = 7; bit >= 0; --bit )
209 {
210// out_byte += (*in_pos++)<<bit;
211 out_byte += ((*in_pos++)&1)<<bit;
212 }
213 *out_pos++ = out_byte;
214 }
215
216}
217
218void EEPROM_Write_8KB( volatile u16 offset, u8* source ) // source must point to 8 bytes
219{
220 u16 packet[81];
221 u8* in_pos;
222 u16* out_pos;
223 u8 in_byte;
224 int byte, bit;
225
226 memset( packet, 0, 81*2 );
227
228 // Write request
229 packet[0] = 1;
230 packet[1] = 0;
231
232 // 14 bits eeprom address (MSB first)
233 packet[2] = (offset>>13)&1;
234 packet[3] = (offset>>12)&1;
235 packet[4] = (offset>>11)&1;
236 packet[5] = (offset>>10)&1;
237 packet[6] = (offset>>9)&1;
238 packet[7] = (offset>>8)&1;
239 packet[8] = (offset>>7)&1;
240 packet[9] = (offset>>6)&1;
241 packet[10] = (offset>>5)&1;
242 packet[11] = (offset>>4)&1;
243 packet[12] = (offset>>3)&1;
244 packet[13] = (offset>>2)&1;
245 packet[14] = (offset>>1)&1;
246 packet[15] = (offset)&1;
247
248 // Extract data
249 in_pos = source;
250 out_pos = &packet[16];
251 for( byte = 7; byte >= 0; --byte )
252 {
253 in_byte = *in_pos++;
254 for( bit = 7; bit >= 0; --bit )
255 {
256 *out_pos++ = (in_byte>>bit)&1;
257 }
258 }
259
260 // End of request
261 packet[80] = 0;
262
263 // Do transfers
264 EEPROM_SendPacket( packet, 81 );
265
266 // Wait for EEPROM to finish (should timeout after 10 ms)
267 while( (REG_EEPROM & 1) == 0 );
268}
269
270//---------------------------------------------------------------------------------
271void GetSave_EEPROM_8KB(u8* data)
272//---------------------------------------------------------------------------------
273{
274 volatile u16 x;
275 u32 sleep;
276
277 for (x=0;x<1024;x++){
278 EEPROM_Read_8KB(x,&data[x*8]);
279 for(sleep=0;sleep<512000;sleep++);
280 }
281
282}
283
284//---------------------------------------------------------------------------------
285void PutSave_EEPROM_8KB(u8* data)
286//---------------------------------------------------------------------------------
287{
288 volatile u16 x;
289 u32 sleep;
290
291 for (x=0;x<1024;x++){
292 EEPROM_Write_8KB(x,&data[x*8]);
293 for(sleep=0;sleep<512000;sleep++);
294 }
295}
296
297//---------------------------------------------------------------------------------
298void GetSave_SRAM_32KB(u8* data)
299//---------------------------------------------------------------------------------
300{
301 volatile u8 *sram= (u8*) 0x0E000000;
302 volatile u16 x;
303
304 for (x = 0; x < 0x8000; ++x)
305 {
306 data[x] = sram[x];
307 }
308
309}
310
311//---------------------------------------------------------------------------------
312void PutSave_SRAM_32KB(u8* data)
313//---------------------------------------------------------------------------------
314{
315 volatile u8 *sram= (u8*) 0x0E000000;
316 volatile u16 x;
317
318 for (x = 0; x < 0x8000; ++x)
319 {
320 sram[x] = data[x];
321 }
322}
323
324//---------------------------------------------------------------------------------
325void GetSave_FLASH_64KB(u8* data)
326//---------------------------------------------------------------------------------
327{
328 volatile u8 *sram= (u8*) 0x0E000000;
329 volatile u32 x;
330
331 for (x = 0; x < 0x10000; ++x)
332 {
333 data[x] = sram[x];
334 }
335}
336
337//---------------------------------------------------------------------------------
338void PutSave_FLASH_64KB(u8* foo)
339//---------------------------------------------------------------------------------
340{
341 volatile u8 *fctrl0 = (u8*) 0xE005555;
342 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
343 volatile u8 *fctrl2 = (u8*) 0xE000000;
344
345 //init flash
346 *fctrl0 = 0xAA;
347 *fctrl1 = 0x55;
348 *fctrl0 = 0x90;
349 *fctrl2 = 0xF0;
350
351 //erase chip
352 *fctrl0 = 0xAA;
353 *fctrl1 = 0x55;
354 *fctrl0 = 0x80;
355 *fctrl0 = 0xAA;
356 *fctrl1 = 0x55;
357 *fctrl0 = 0x10;
358
359 //wait for erase done
360 u8 val1;
361 u8 val2;
362 val1 = *fctrl2;
363 val2 = *fctrl2;
364 while (val1 != val2) {
365 val1 = *fctrl2;
366 val2 = *fctrl2;
367 }
368 val1 = *fctrl2;
369 val2 = *fctrl2;
370 while (val1 != val2) {
371 val1 = *fctrl2;
372 val2 = *fctrl2;
373 }
374
375 volatile u8 *data = fctrl2;
376 u32 i;
377 //write data
378 for (i=0; i<65536; i++) {
379 *fctrl0 = 0xAA;
380 *fctrl1 = 0x55;
381 *fctrl0 = 0xA0;
382 data [i] = foo [ i ];
383 val1 = data [ i ];
384 val2 = data [ i ];
385
386 while (val1 != val2) {
387 val1 = data [ i ];
388 val2 = data [ i ];
389 }
390 val1 = data [ i ];
391 val2 = data [ i ];
392 while (val1 != val2) {
393 val1 = data [ i ];
394 val2 = data [ i ];
395 }
396 val1 = data [ i ];
397 val2 = data [ i ];
398 while (val1 != val2) {
399 val1 = data [ i ];
400 val2 = data [ i ];
401 }
402 }
403}
404
405//---------------------------------------------------------------------------------
406void GetSave_FLASH_128KB(u8* data)
407//---------------------------------------------------------------------------------
408{
409 const u32 size = 0x10000;
410
411 volatile u8 *fctrl0 = (u8*) 0xE005555;
412 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
413 volatile u8 *fctrl2 = (u8*) 0xE000000;
414 volatile u32 i;
415 volatile u8 *sram= (u8*) 0x0E000000;
416
417 //init flash
418 *fctrl0 = 0xAA;
419 *fctrl1 = 0x55;
420 *fctrl0 = 0x90;
421 *fctrl2 = 0xF0;
422
423 // read first bank
424 *fctrl0 = 0xAA;
425 *fctrl1 = 0x55;
426 *fctrl0 = 0xB0;
427 *fctrl2 = 0x00;
428
429 for (i=0; i<size; i++){
430 data[i] = sram[i];
431 }
432
433 // read second bank
434 *fctrl0 = 0xAA;
435 *fctrl1 = 0x55;
436 *fctrl0 = 0xB0;
437 *fctrl2 = 0x01;
438
439 for (i=0; i<size; i++){
440 data[i + size] = sram[i];
441 }
442
443}
444
445//---------------------------------------------------------------------------------
446void PutSave_FLASH_128KB(u8* foo)
447//---------------------------------------------------------------------------------
448{
449 volatile u8 *fctrl0 = (u8*) 0xE005555;
450 volatile u8 *fctrl1 = (u8*) 0xE002AAA;
451 volatile u8 *fctrl2 = (u8*) 0xE000000;
452
453 u8 val1;
454 u8 val2;
455
456 //init flash
457 *fctrl0 = 0xAA;
458 *fctrl1 = 0x55;
459 *fctrl0 = 0x90;
460 *fctrl2 = 0xF0;
461
462 //erase chip
463 *fctrl0 = 0xAA;
464 *fctrl1 = 0x55;
465 *fctrl0 = 0x80;
466 *fctrl0 = 0xAA;
467 *fctrl1 = 0x55;
468 *fctrl0 = 0x10;
469
470 //wait for erase done
471 val1 = *fctrl2;
472 val2 = *fctrl2;
473 while (val1 != val2) {
474 val1 = *fctrl2;
475 val2 = *fctrl2;
476 }
477 val1 = *fctrl2;
478 val2 = *fctrl2;
479 while (val1 != val2) {
480 val1 = *fctrl2;
481 val2 = *fctrl2;
482 }
483
484 volatile u8 *data = fctrl2;
485 volatile u32 i;
486 // change to bank 0
487 *fctrl0 = 0xAA;
488 *fctrl1 = 0x55;
489 *fctrl0 = 0xB0;
490 *fctrl2 = 0x00;
491
492 //write data
493 for (i=0; i<65536; i++) {
494 *fctrl0 = 0xAA;
495 *fctrl1 = 0x55;
496 *fctrl0 = 0xA0;
497 data [i] = foo [ i ];
498 val1 = data [ i ];
499 val2 = data [ i ];
500
501 while (val1 != val2) {
502 val1 = data [ i ];
503 val2 = data [ i ];
504 }
505 val1 = data [ i ];
506 val2 = data [ i ];
507 while (val1 != val2) {
508 val1 = data [ i ];
509 val2 = data [ i ];
510 }
511 val1 = data [ i ];
512 val2 = data [ i ];
513 while (val1 != val2) {
514 val1 = data [ i ];
515 val2 = data [ i ];
516 }
517 }
518
519 // Change to bank 1
520 *fctrl0 = 0xAA;
521 *fctrl1 = 0x55;
522 *fctrl0 = 0xB0;
523 *fctrl2 = 0x01;
524
525 //write data
526 for (i=0; i<65536; i++) {
527 *fctrl0 = 0xAA;
528 *fctrl1 = 0x55;
529 *fctrl0 = 0xA0;
530 data [i] = foo [ i + 0x10000];
531 val1 = data [ i ];
532 val2 = data [ i ];
533
534 while (val1 != val2) {
535 val1 = data [ i ];
536 val2 = data [ i ];
537 }
538 val1 = data [ i ];
539 val2 = data [ i ];
540 while (val1 != val2) {
541 val1 = data [ i ];
542 val2 = data [ i ];
543 }
544 val1 = data [ i ];
545 val2 = data [ i ];
546 while (val1 != val2) {
547 val1 = data [ i ];
548 val2 = data [ i ];
549 }
550 }
551
552}
553
554//---------------------------------------------------------------------------------
555u32 SaveSize(u8* data, s32 gamesize)
556//---------------------------------------------------------------------------------
557{
558 if(gamesize < 0)
559 return 0;
560
561 u32 *pak= ((u32*)0x08000000);
562 s32 x;
563 u16 i;
564 s32 size = gamesize/4;
565
566
567 for (x=size-1;x>=0;x--){
568 switch (pak[x]) {
569 case 0x53414C46:
570 if (pak[x+1] == 0x5F4D3148){
571 return 0x20000; // FLASH_128KB
572 } else if ((pak[x+1] & 0x0000FFFF) == 0x00005F48){
573 return 0x10000; // FLASH_64KB
574 } else if (pak[x+1] == 0x32313548){
575 return 0x10000; // FLASH_64KB
576 }
577 break;
578 case 0x52504545:
579 if ((pak[x+1] & 0x00FFFFFF) == 0x005F4D4F){
580 GetSave_EEPROM_8KB(data);
581 for(i = 8; i < 0x800; i += 8) {
582 if(memcmp(data, data+i, 8) != 0)
583 return 0x2000; // EEPROM_8KB
584 }
585 return 0x200; // EEPROM_512B
586 }
587 break;
588 case 0x4D415253:
589 if ((pak[x+1] & 0x000000FF) == 0x0000005F){
590 return 0x8000; // SRAM_32KB
591 }
592 }
593 }
594 return 0;
595}
596
diff --git a/gba/source/libSave.h b/gba/source/libSave.h deleted file mode 100644 index 5ecf822..0000000 --- a/gba/source/libSave.h +++ /dev/null
@@ -1,27 +0,0 @@
1
2
3//---------------------------------------------------------------------------------
4#ifdef __cplusplus
5extern "C" {
6#endif
7//---------------------------------------------------------------------------------
8
9void GetSave_EEPROM_512B(u8* data);
10void PutSave_EEPROM_512B(u8* data);
11void GetSave_EEPROM_8KB(u8* data);
12void PutSave_EEPROM_8KB(u8* data);
13void GetSave_SRAM_32KB(u8* data);
14void PutSave_SRAM_32KB(u8* data);
15void GetSave_FLASH_64KB(u8* data);
16void PutSave_FLASH_64KB(u8* foo);
17void GetSave_FLASH_128KB(u8* data);
18void PutSave_FLASH_128KB(u8* foo);
19
20u32 SaveSize(u8* data, s32 gamesize);
21
22
23//---------------------------------------------------------------------------------
24#ifdef __cplusplus
25} // extern "C"
26#endif
27//---------------------------------------------------------------------------------
diff --git a/gba/source/libpayload.c b/gba/source/libpayload.c new file mode 100644 index 0000000..f13a34f --- /dev/null +++ b/gba/source/libpayload.c
@@ -0,0 +1,312 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * libpayload.c: contains helper functions for the payload
8 */
9
10#include <gba.h>
11#include "payload.h"
12
13// private functions
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 new file mode 100644 index 0000000..4be6fb3 --- /dev/null +++ b/gba/source/libpayload.h
@@ -0,0 +1,160 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * libpayload.h: header for payload helper functions
8 */
9
10/**
11 * Decrypts the substructures of a Pokémon structure, so they can be viewed or modified easily.
12 * Remember to call EncryptPokemon() afterwards.
13 * @param struct Pokemon* pkm The Pokémon to decrypt the substructures of.
14*/
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/payload.c b/gba/source/payload.c index 7015774..665af70 100644 --- a/gba/source/payload.c +++ b/gba/source/payload.c
@@ -12,7 +12,61 @@
12 12
13// Your payload code should obviously go into the body of this, the payload function. 13// Your payload code should obviously go into the body of this, the payload function.
14void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) { 14void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) {
15 // This example payload will modify the first character of the player's name. 15 // HoF-warp example payload!
16 // It will change to 'z'. You can see the character encoding table here: http://bulbapedia.bulbagarden.net/wiki/Character_encoding_in_Generation_III 16
17 SaveBlock2[0] = 0xee; // 'z' 17 // Structure offsets are different between R/S, FR/LG, and Emerald.
18 // The beginning of the structures are the same but do NOT take shortcuts here, it's not good practise.
19 // If you want to support multiple games, make specific checks for games, use the right structure for each game.
20 SaveBlock1_RS* sb1rs = &SaveBlock1->rs;
21 SaveBlock1_FRLG* sb1frlg = &SaveBlock1->frlg;
22 SaveBlock1_E* sb1e = &SaveBlock1->e;
23 if (GAME_FRLG) {
24 sb1frlg->location.mapGroup = 1; // generic indoors?
25 sb1frlg->location.mapNum = 80; // Hall of Fame
26 // set coords to the same place that the champions' room script sets them to
27 sb1frlg->location.x = sb1frlg->pos.x = 5;
28 sb1frlg->location.y = sb1frlg->pos.y = 12;
29 sb1frlg->mapDataId = 0xDA; // from HoF map-header
30 sb1frlg->location.warpId = 0xff;
31 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
32 if (sb1frlg->playerPartyCount == 0) {
33 sb1frlg->playerPartyCount = 1;
34 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
35 // so let's hack together one. i don't care about it becoming a bad egg at all.
36 sb1frlg->playerParty[0].box.personality++;
37 }
38 return;
39 } else if (GAME_RS) {
40 sb1rs->location.mapGroup = 16; // Ever Grande City
41 sb1rs->location.mapNum = 11; // Hall of Fame
42 // set coords to the same place that the champions' room script sets them to
43 sb1rs->location.x = sb1rs->pos.x = 7;
44 sb1rs->location.y = sb1rs->pos.y = 16;
45 sb1rs->mapDataId = 299; // from HoF map-header
46 sb1rs->location.warpId = 0xff;
47 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
48 if (sb1rs->playerPartyCount == 0) {
49 sb1rs->playerPartyCount = 1;
50 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
51 // so let's hack together one. i don't care about it becoming a bad egg at all.
52 sb1rs->playerParty[0].box.personality++;
53 }
54 return;
55 } else if (GAME_EM) {
56 sb1e->location.mapGroup = 16; // Ever Grande City
57 sb1e->location.mapNum = 11; // Hall of Fame
58 // set coords to the same place that the champions' room script sets them to
59 sb1e->location.x = sb1e->pos.x = 7;
60 sb1e->location.y = sb1e->pos.y = 16;
61 sb1e->mapDataId = 298; // from HoF map-header
62 sb1e->location.warpId = 0xff;
63 // make sure the HoF script doesn't crash, which it will do if 0 pokémon
64 if (sb1e->playerPartyCount == 0) {
65 sb1e->playerPartyCount = 1;
66 // this isn't enough, the heal animation recalculates the party count ignoring empty spots
67 // so let's hack together one. i don't care about it becoming a bad egg at all.
68 sb1e->playerParty[0].box.personality++;
69 }
70 return;
71 }
18} \ No newline at end of file 72} \ No newline at end of file
diff --git a/gba/source/payload.h b/gba/source/payload.h index d95476c..ea87200 100644 --- a/gba/source/payload.h +++ b/gba/source/payload.h
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10#include "saveblocks.h" 10#include "saveblocks.h"
11#include "libpayload.h"
11 12
12#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00') 13#define GAME_RUBY (((*(u32*)(0x80000AC)) << 8) == 'VXA\x00')
13#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00') 14#define GAME_SAPP (((*(u32*)(0x80000AC)) << 8) == 'PXA\x00')
diff --git a/gba/source/saveblocks.h b/gba/source/saveblocks.h index 45c127c..cf0a5c3 100644 --- a/gba/source/saveblocks.h +++ b/gba/source/saveblocks.h
@@ -7,9 +7,337 @@
7 * saveblocks.h: describes saveblock structures for all of Gen 3 (yay!) 7 * saveblocks.h: describes saveblock structures for all of Gen 3 (yay!)
8 */ 8 */
9 9
10// TODO: this entire file. Placeholders for now, fill in later, if I can be bothered. 10// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity
11// I don't really want to make a fork of pokeruby's headers for now... 11#include "savestructs.h"
12 12
13typedef u8 SaveBlock1, *pSaveBlock1; 13typedef struct
14typedef u8 SaveBlock2, *pSaveBlock2; 14{
15typedef u8 SaveBlock3, *pSaveBlock3; \ No newline at end of file 15 /*0x00*/ struct Coords16 pos;
16 /*0x04*/ struct WarpData location;
17 /*0x0C*/ struct WarpData warp[4];
18 /*0x2C*/ u16 battleMusic;
19 /*0x2E*/ u8 weather;
20 /*0x2F*/ u8 filler_2F;
21 /*0x30*/ u8 flashUsed;
22 /*0x32*/ u16 mapDataId;
23 /*0x34*/ u16 mapView[0x100];
24 /*0x234*/ u8 playerPartyCount;
25 /*0x238*/ struct Pokemon playerParty[6];
26 /*0x490*/ u32 money;
27 /*0x494*/ u16 coins;
28 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
29 /*0x498*/ struct ItemSlot pcItems[50];
30 /*0x560*/ struct ItemSlot bagPocket_Items[20];
31 /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[20];
32 /*0x600*/ struct ItemSlot bagPocket_PokeBalls[16];
33 /*0x640*/ struct ItemSlot bagPocket_TMHM[64];
34 /*0x740*/ struct ItemSlot bagPocket_Berries[46];
35 /*0x7F8*/ struct Pokeblock pokeblocks[40];
36 /*0x938*/ u8 unk938[52]; // pokedex related
37 /*0x96C*/ u16 berryBlenderRecords[3];
38 /*0x972*/ u8 filler_972[0x6];
39 /*0x978*/ u16 trainerRematchStepCounter;
40 /*0x97A*/ u8 trainerRematches[100];
41 /*0x9E0*/ struct MapObject mapObjects[16];
42 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
43 /*0x1220*/ u8 flags[0x120];
44 /*0x1340*/ u16 vars[0x100];
45 /*0x1540*/ u32 gameStats[50];
46 /*0x1608*/ struct BerryTree berryTrees[128];
47 /*0x1A08*/ struct SecretBaseRecord secretBases[20];
48 /*0x2688*/ u8 playerRoomDecor[12];
49 /*0x2694*/ u8 playerRoomDecorPos[12];
50 /*0x26A0*/ u8 decorDesk[10];
51 /*0x26AA*/ u8 decorChair[10];
52 /*0x26B4*/ u8 decorPlant[10];
53 /*0x26BE*/ u8 decorOrnament[30];
54 /*0x26DC*/ u8 decorMat[30];
55 /*0x26FA*/ u8 decorPoster[10];
56 /*0x2704*/ u8 decorDoll[40];
57 /*0x272C*/ u8 decorCushion[10];
58 /*0x2736*/ u8 padding_2736[2];
59 /*0x2738*/ TVShow tvShows[24];
60 /*0x2A98*/ u8 filler_2A98[0x64];
61 /*0x2AFC*/ u16 outbreakPokemonSpecies;
62 /*0x2AFE*/ u8 outbreakLocationMapNum;
63 /*0x2AFF*/ u8 outbreakLocationMapGroup;
64 /*0x2B00*/ u8 outbreakPokemonLevel;
65 /*0x2B01*/ u8 outbreakUnk1;
66 /*0x2B02*/ u16 outbreakUnk2;
67 /*0x2B04*/ u16 outbreakPokemonMoves[4];
68 /*0x2B0C*/ u8 outbreakUnk4;
69 /*0x2B0D*/ u8 outbreakPokemonProbability;
70 /*0x2B0E*/ u16 outbreakUnk5;
71 /*0x2B10*/ u8 filler_2B0E[0xC];
72 /*0x2B1C*/ u16 unk2B1C[4];
73 /*0x2B24*/ u8 filler_2B24[0x28];
74 /*0x2B4C*/ struct MailStruct mail[16];
75 /*0x2D8C*/ u8 filler_2D8C[0x8];
76 /*0x2D94*/ OldMan oldMan;
77 /*0x2DC0*/ u8 unk_2DC0[0x14];
78 /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff
79 /*0x2DFC*/ u8 filler_2DFC[0x100];
80 /*0x2EFC*/ struct SB1_2EFC_Struct sb1_2EFC_struct[5];
81 /*0x2F9C*/ u8 filler_2F9C[0xA0];
82 /*0x303C*/ u8 filler_303C[0x38];
83 /*0x3074*/ u8 filler_3074[0x42];
84 /*0x30B6*/ u8 filler_30B6;
85 /*0x30B7*/ u8 filler_30B7[0x59];
86 /*0x3110*/ u8 giftRibbons[7];
87 /*0x3117*/ u8 filler_311B[0x2D];
88 /*0x3144*/ struct Roamer roamer;
89 /*0x3158*/ u8 filler_3158[0x8];
90 /*0x3160*/ struct EnigmaBerry enigmaBerry; // this is actually offset by 0x98 ...
91 /*0x3690*/ struct RamScript ramScript;
92 /*0x3A7C*/ u8 filler_3A7C[0x10];
93 /*0x3A8C*/ u8 unk3A8C[52]; //pokedex related
94} SaveBlock1_RS;
95
96typedef struct // Don't rely on the commented offsets, they'll be wrong due to elements removed in FR/LG...
97{
98 /*0x00*/ struct Coords16 pos;
99 /*0x04*/ struct WarpData location;
100 /*0x0C*/ struct WarpData warp[4];
101 /*0x2C*/ u16 battleMusic;
102 /*0x2E*/ u8 weather;
103 /*0x2F*/ u8 filler_2F;
104 /*0x30*/ u8 flashUsed;
105 /*0x32*/ u16 mapDataId;
106// /*0x34*/ u16 mapView[0x100]; // Not in fr/lg
107 /*0x234*/ u8 playerPartyCount;
108 /*0x238*/ struct Pokemon playerParty[6];
109 /*0x490*/ u32 money;
110 /*0x494*/ u16 coins;
111 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
112 /*0x498*/ struct ItemSlot pcItems[30];
113 /*0x560*/ struct ItemSlot bagPocket_Items[42];
114 /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[30];
115 /*0x600*/ struct ItemSlot bagPocket_PokeBalls[13];
116 /*0x640*/ struct ItemSlot bagPocket_TMHM[58];
117 /*0x740*/ struct ItemSlot bagPocket_Berries[43];
118// /*0x7F8*/ struct Pokeblock pokeblocks[40]; // Not in fr/lg
119 /*0x938*/ u8 unk938[52]; // pokedex related
120 /*0x96C*/ u8 unk_62C[12];
121 /*0x972*/ u8 filler_972[0x6];
122 /*0x97A*/ u8 unk_63E[98];
123 /*0x9E0*/ struct MapObject mapObjects[16];
124 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
125 /*0x1220*/ u8 flags[0x120];
126 /*0x1340*/ u16 vars[0x100];
127 /*0x1540*/ u32 gameStats[64]; // encrypted with saveblock2 xor-key
128 struct QuestStory questlog[4];
129 u8 messages[12][4];
130 struct NPCState npc_states[0x10];
131 u8 unk_2f10[112];
132 struct DaycarePokemon daycare[2];
133 u8 unk_3098[56];
134 struct Roamer roamer;
135 u8 unk_30e4[8];
136 /*0x3160*/ struct EnigmaBerryFRLGE enigmaBerry;
137 u8 unk_3120[0x1C0]; // 4 bytes of CRC16, then 444 bytes of unknown. Mystery Gift related.
138 u8 unk_32E0[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_1"
139 u8 unk_3430[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_2"
140 u8 unk_368C[0x9C]; // padding? doesn't seem to be actually used
141 struct RamScript ramScript;
142 u8 unk_3A07[17];
143 u8 pokemon_flags_2[52];
144 u8 rivalName[8];
145 u8 unk_3a54[128];
146 u8 words[21][10];
147 u8 unk_3ba6[570];
148} __attribute__((aligned(1))) SaveBlock1_FRLG;
149
150typedef struct // Don't rely on the commented offsets, they'll be wrong due to elements changed/added in Emerald...
151{
152 /*0x00*/ struct Coords16 pos;
153 /*0x04*/ struct WarpData location;
154 /*0x0C*/ struct WarpData warp[4];
155 /*0x2C*/ u16 battleMusic;
156 /*0x2E*/ u8 weather;
157 /*0x2F*/ u8 filler_2F;
158 /*0x30*/ u8 flashUsed;
159 /*0x32*/ u16 mapDataId;
160 /*0x34*/ u16 mapView[0x100];
161 /*0x234*/ u8 playerPartyCount;
162 /*0x238*/ struct Pokemon playerParty[6];
163 /*0x490*/ u32 money;
164 /*0x494*/ u16 coins;
165 /*0x496*/ u16 registeredItem; // registered for use with SELECT button
166 /*0x498*/ struct ItemSlot pcItems[50];
167 /*0x560*/ struct ItemSlot bagPocket_Items[30];
168 /*0x5D8*/ struct ItemSlot bagPocket_KeyItems[30];
169 /*0x650*/ struct ItemSlot bagPocket_PokeBalls[16];
170 /*0x690*/ struct ItemSlot bagPocket_TMHM[64];
171 /*0x790*/ struct ItemSlot bagPocket_Berries[46];
172 /*0x7F8*/ struct Pokeblock pokeblocks[40]; // every offset is shifted by 0x50 from here on thanks to changed bag-counts
173 /*0x938*/ u8 unk938[52]; // pokedex related
174 /*0x96C*/ u16 berryBlenderRecords[3];
175 /*0x972*/ u8 filler_972[0x6];
176 /*0x978*/ u16 trainerRematchStepCounter;
177 /*0x97A*/ u8 trainerRematches[100];
178 /*0x9E0*/ struct MapObject mapObjects[16];
179 /*0xC20*/ struct MapObjectTemplate mapObjectTemplates[64];
180 /*0x1220*/ u8 flags[0x12C];
181 /*0x1340*/ u16 vars[0x100]; // offsets shifted by 0x5C from here on thanks to added flags
182 /*0x1540*/ u32 gameStats[64]; // encrypted with saveblock2 xor-key
183 /*0x1608*/ struct BerryTree berryTrees[128]; // offsets shifted by 0x94 from here on thanks to added 14 gamestats
184 /*0x1A08*/ struct SecretBaseRecord secretBases[20];
185 /*0x2688*/ u8 playerRoomDecor[12];
186 /*0x2694*/ u8 playerRoomDecorPos[12];
187 /*0x26A0*/ u8 decorDesk[10];
188 /*0x26AA*/ u8 decorChair[10];
189 /*0x26B4*/ u8 decorPlant[10];
190 /*0x26BE*/ u8 decorOrnament[30];
191 /*0x26DC*/ u8 decorMat[30];
192 /*0x26FA*/ u8 decorPoster[10];
193 /*0x2704*/ u8 decorDoll[40];
194 /*0x272C*/ u8 decorCushion[10];
195 // /*0x2736*/ u8 padding_2736[2];
196 /*0x2738*/ TVShow tvShows[24];
197 /*0x2A98*/ u8 filler_2A98[0x64];
198 /*0x2AFC*/ u16 outbreakPokemonSpecies; // offset by 0x94
199 /*0x2AFE*/ u8 outbreakLocationMapNum;
200 /*0x2AFF*/ u8 outbreakLocationMapGroup;
201 /*0x2B00*/ u8 outbreakPokemonLevel;
202 /*0x2B01*/ u8 outbreakUnk1;
203 /*0x2B02*/ u16 outbreakUnk2;
204 /*0x2B04*/ u16 outbreakPokemonMoves[4];
205 /*0x2B0C*/ u8 outbreakUnk4;
206 /*0x2B0D*/ u8 outbreakPokemonProbability;
207 /*0x2B0E*/ u16 outbreakUnk5;
208 /*0x2B10*/ u8 filler_2B0E[0xC];
209 /*0x2B1C*/ u16 unk2B1C[4];
210 /*0x2B24*/ u8 filler_2B24[0x28];
211 /*0x2B4C*/ struct MailStruct mail[16]; // offset by 0x94
212 /*0x2D8C*/ u8 filler_2D8C[0x8];
213 /*0x2D94*/ OldMan oldMan;
214 /*0x2DC0*/ u8 unk_2DC0[0x14];
215 /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff
216 // /*0x2DFC*/ u8 filler_2DFC[0x100];
217 /*0x2EFC*/ struct SB1_2EFC_Struct sb1_2EFC_struct[12];
218 u8 unk_3010[0x198]; // no idea if any of this is actually used.
219 /*0x3110*/ u8 giftRibbons[7];
220 /*0x3117*/ u8 filler_311B[0x2D];
221 /*0x3144*/ struct Roamer roamer;
222 /*0x3158*/ u8 filler_3158[0x8];
223 /*0x3160*/ struct EnigmaBerryFRLGE enigmaBerry;
224 u8 unk_322C[0x1C0]; // 4 bytes of CRC16, then 444 bytes of unknown. Mystery Gift related.
225 u8 unk_33EC[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_1"
226 u8 unk_353C[0x150]; // 4 bytes of CRC16, then 332 bytes of unknown. Mystery Gift related. "mevent_buffer_2"
227 u8 unk_368C[0x9C]; // padding? doesn't seem to be actually used
228 /*0x3690*/ struct RamScript ramScript;
229 /*0x3A7C*/ u8 filler_3A7C[0x10];
230 /*0x3A8C*/ u8 unk3A8C[52]; //pokedex related
231} SaveBlock1_E;
232
233// ---
234
235struct SaveBlock2_Sub
236{
237 /*0x0000, 0x00A8*/ u8 filler_000[0x4AE];
238 /*0x04AE, 0x0556*/ u8 var_4AE;
239 /*0x04AF, 0x0557*/ u8 var_4AF;
240 /*0x04B0, 0x0558*/ u16 var_4B0;
241 /*0x04B2, 0x055A*/ u16 var_4B2;
242 /*0x04B4, 0x055C*/ u16 var_4B4;
243 /*0x04B6, 0x055E*/ u16 var_4B6;
244 /*0x04B8, 0x0560*/ u8 filler_4B8[0x10];
245 /*0x04C8, 0x0570*/ u16 var_4C8;
246 /*0x04CA, 0x0572*/ u16 var_4CA;
247 /*0x04CC, 0x0574*/ u8 filler_4CC[0x31C];
248};
249
250typedef struct
251{
252 /*0x00*/ u8 playerName[8];
253 /*0x08*/ u8 playerGender; // MALE, FEMALE
254 /*0x09*/ u8 specialSaveWarp;
255 /*0x0A*/ u8 playerTrainerId[4];
256 /*0x0E*/ u16 playTimeHours;
257 /*0x10*/ u8 playTimeMinutes;
258 /*0x11*/ u8 playTimeSeconds;
259 /*0x12*/ u8 playTimeVBlanks;
260 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
261 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
262 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
263 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
264 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
265 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
266 u16 regionMapZoom:1; // whether the map is zoomed in
267 /*0x18*/ struct Pokedex pokedex;
268 /*0x90*/ u8 filler_90[0x8];
269 /*0x98*/ struct Time localTimeOffset;
270 /*0xA0*/ struct Time lastBerryTreeUpdate;
271 /*0xA8*/ struct SaveBlock2_Sub filler_A8;
272} SaveBlock2_RS;
273
274typedef struct
275{
276 /*0x00*/ u8 playerName[8];
277 /*0x08*/ u8 playerGender; // MALE, FEMALE
278 /*0x09*/ u8 specialSaveWarp;
279 /*0x0A*/ u8 playerTrainerId[4];
280 /*0x0E*/ u16 playTimeHours;
281 /*0x10*/ u8 playTimeMinutes;
282 /*0x11*/ u8 playTimeSeconds;
283 /*0x12*/ u8 playTimeVBlanks;
284 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
285 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
286 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
287 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
288 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
289 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
290 u16 regionMapZoom:1; // whether the map is zoomed in
291 /*0x18*/ struct Pokedex pokedex;
292 /*0x90*/ u8 filler_90[0x8];
293 /*0x98*/ struct Time localTimeOffset;
294 /*0xA0*/ struct Time lastBerryTreeUpdate;
295 /*0xA8*/ struct SaveBlock2_Sub filler_A8;
296 /*0x890*/ u8 unk_890[8];
297 /*0x898*/ u8 mapdata[0x258];
298 /*0xaf0*/ u16 field_af0;
299 /*0xaf2*/ u16 field_af2;
300 /*0xaf4*/ u16 field_af4;
301 /*0xaf6*/ u16 field_af6;
302 /*0xaf8*/ u8 unk_af8[0x428];
303 /*0xf20*/ u32 xor_key;
304} SaveBlock2_FRLG;
305
306typedef struct
307{
308 /*0x00*/ u8 playerName[8];
309 /*0x08*/ u8 playerGender; // MALE, FEMALE
310 /*0x09*/ u8 specialSaveWarp;
311 /*0x0A*/ u8 playerTrainerId[4];
312 /*0x0E*/ u16 playTimeHours;
313 /*0x10*/ u8 playTimeMinutes;
314 /*0x11*/ u8 playTimeSeconds;
315 /*0x12*/ u8 playTimeVBlanks;
316 /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
317 /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
318 u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
319 u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
320 u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
321 u16 optionsBattleSceneOff:1; // whether battle animations are disabled
322 u16 regionMapZoom:1; // whether the map is zoomed in
323 /*0x18*/ struct Pokedex pokedex;
324 /*0x90*/ u8 filler_90[0x8];
325 /*0x98*/ struct Time localTimeOffset;
326 /*0xA0*/ struct Time lastBerryTreeUpdate;
327 /*0xA8*/ u32 xor_key;
328 /*0xAC*/ struct SaveBlock2_Sub filler_A8;
329} SaveBlock2_E;
330
331typedef union {
332 SaveBlock1_RS rs;
333 SaveBlock1_FRLG frlg;
334 SaveBlock1_E e;
335} SaveBlock1, *pSaveBlock1;
336
337typedef union {
338 SaveBlock2_RS rs;
339 SaveBlock2_FRLG frlg;
340 SaveBlock2_E e;
341} SaveBlock2, *pSaveBlock2;
342
343typedef struct PokemonStorage SaveBlock3, *pSaveBlock3; \ No newline at end of file
diff --git a/gba/source/savestructs.h b/gba/source/savestructs.h new file mode 100644 index 0000000..2bf4d4d --- /dev/null +++ b/gba/source/savestructs.h
@@ -0,0 +1,793 @@
1/*
2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 *
7 * saveblocks.h: describes structures used by saveblocks for all of Gen 3
8 */
9
10// Most of the structures come from pokeruby, FR/LG changes come from my own research / the firered IDB on pokecommunity
11
12#define POKEMON_NAME_LENGTH 10
13#define OT_NAME_LENGTH 7
14#define TILE_SIZE_4BPP 32
15
16struct Coords16
17{
18 s16 x;
19 s16 y;
20};
21
22struct UCoords16
23{
24 u16 x;
25 u16 y;
26};
27
28struct SecretBaseRecord
29{
30 u8 sbr_field_0; // ID?
31 u8 sbr_field_1_0:4;
32 u8 gender:1;
33 u8 sbr_field_1_5:1;
34 u8 sbr_field_2[7]; // 0xFF bytes?
35 u8 trainerId[4]; // byte 0 is used for determining trainer class
36 u16 sbr_field_e;
37 u8 sbr_field_10;
38 u8 sbr_field_11;
39 u8 decorations[16];
40 u8 sbr_field_22[16];
41 u32 partyPersonality[6];
42 u16 partyMoves[6 * 4];
43 u16 partySpecies[6];
44 u16 partyHeldItems[6];
45 u8 partyLevels[6];
46 u8 partyEVs[6];
47};
48
49typedef void (*TilesetCB)(void);
50
51struct Tileset
52{
53 u8 isCompressed;
54 u8 isSecondary;
55 void *tiles;
56 void *palettes;
57 void *metatiles;
58 void *metatileAttributes;
59 TilesetCB callback;
60};
61
62struct MapData
63{
64 s32 width;
65 s32 height;
66 u16 *border;
67 u16 *map;
68 struct Tileset *primaryTileset;
69 struct Tileset *secondaryTileset;
70};
71
72struct MapObjectTemplate
73{
74 /*0x00*/ u8 localId;
75 /*0x01*/ u8 graphicsId;
76 /*0x02*/ u8 unk2;
77 /*0x04*/ s16 x;
78 /*0x06*/ s16 y;
79 /*0x08*/ u8 elevation;
80 /*0x09*/ u8 movementType;
81 /*0x0A*/ u8 unkA_0:4;
82 u8 unkA_4:4;
83 ///*0x0B*/ u8 fillerB[1];
84 /*0x0C*/ u16 unkC;
85 /*0x0E*/ u16 unkE;
86 /*0x10*/ u8 *script;
87 /*0x14*/ u16 flagId;
88 /*0x16*/ u8 filler_16[2];
89}; /*size = 0x18*/
90
91struct WarpEvent
92{
93 s16 x, y;
94 s8 warpId;
95 u8 mapGroup;
96 u8 mapNum;
97 u8 unk7;
98};
99
100struct CoordEvent
101{
102 s16 x, y;
103 u8 unk4;
104 u8 filler_5;
105 u16 trigger;
106 u16 index;
107 u8 filler_A[0x2];
108 u8 *script;
109};
110
111struct BgEvent
112{
113 s16 x, y;
114 u8 unk4;
115 u8 kind;
116 s16 filler_6;
117 u8 *script;
118};
119
120struct MapEvents
121{
122 u8 mapObjectCount;
123 u8 warpCount;
124 u8 coordEventCount;
125 u8 bgEventCount;
126
127 struct MapObjectTemplate *mapObjects;
128 struct WarpEvent *warps;
129 struct CoordEvent *coordEvents;
130 struct BgEvent *bgEvents;
131};
132
133struct MapConnection
134{
135 u8 direction;
136 u32 offset;
137 u8 mapGroup;
138 u8 mapNum;
139};
140
141struct MapConnections
142{
143 s32 count;
144 struct MapConnection *connections;
145};
146
147struct MapHeader
148{
149 struct MapData *mapData;
150 struct MapEvents *events;
151 u8 *mapScripts;
152 struct MapConnections *connections;
153 u16 music;
154 u16 mapDataId;
155 u8 name;
156 u8 cave;
157 u8 weather;
158 /* 0x17 */ u8 mapType;
159 u8 filler_18;
160 u8 escapeRope;
161 u8 flags;
162 u8 battleType;
163};
164
165struct MapObject
166{
167 /*0x00*/ u32 active:1;
168 u32 mapobj_bit_1:1;
169 u32 mapobj_bit_2:1;
170 u32 mapobj_bit_3:1;
171 u32 mapobj_bit_4:1;
172 u32 mapobj_bit_5:1;
173 u32 mapobj_bit_6:1;
174 u32 mapobj_bit_7:1;
175 /*0x01*/ u32 mapobj_bit_8:1;
176 u32 mapobj_bit_9:1;
177 u32 mapobj_bit_10:1;
178 u32 mapobj_bit_11:1;
179 u32 mapobj_bit_12:1;
180 u32 mapobj_bit_13:1;
181 u32 mapobj_bit_14:1;
182 u32 mapobj_bit_15:1;
183 /*0x02*/ u32 mapobj_bit_16:1;
184 u32 mapobj_bit_17:1;
185 u32 mapobj_bit_18:1;
186 u32 mapobj_bit_19:1;
187 u32 mapobj_bit_20:1;
188 u32 mapobj_bit_21:1;
189 u32 mapobj_bit_22:1;
190 u32 mapobj_bit_23:1;
191 /*0x03*/ u32 mapobj_bit_24:1;
192 u32 mapobj_bit_25:1;
193 u32 mapobj_bit_26:1;
194 u32 mapobj_bit_27:1;
195 u32 mapobj_bit_28:1;
196 u32 mapobj_bit_29:1;
197 u32 mapobj_bit_30:1;
198 u32 mapobj_bit_31:1;
199 /*0x04*/ u8 spriteId;
200 /*0x05*/ u8 graphicsId;
201 /*0x06*/ u8 animPattern;
202 /*0x07*/ u8 trainerType;
203 /*0x08*/ u8 localId;
204 /*0x09*/ u8 mapNum;
205 /*0x0A*/ u8 mapGroup;
206 /*0x0B*/ u8 mapobj_unk_0B_0:4;
207 u8 elevation:4;
208 /*0x0C*/ struct Coords16 coords1;
209 /*0x10*/ struct Coords16 coords2;
210 /*0x14*/ struct Coords16 coords3;
211 /*0x18*/ u8 mapobj_unk_18:4; //current direction?
212 /*0x18*/ u8 placeholder18:4;
213 /*0x19*/ u8 mapobj_unk_19;
214 /*0x1A*/ u8 mapobj_unk_1A;
215 /*0x1B*/ u8 mapobj_unk_1B;
216 /*0x1C*/ u8 mapobj_unk_1C;
217 /*0x1D*/ u8 trainerRange_berryTreeId;
218 /*0x1E*/ u8 mapobj_unk_1E;
219 /*0x1F*/ u8 mapobj_unk_1F;
220 /*0x20*/ u8 mapobj_unk_20;
221 /*0x21*/ u8 mapobj_unk_21;
222 /*0x22*/ u8 animId;
223 /*size = 0x24*/
224};
225
226struct Berry
227{
228 const u8 name[7];
229 u8 firmness;
230 u16 size;
231 u8 maxYield;
232 u8 minYield;
233 const u8 *description1;
234 const u8 *description2;
235 u8 stageDuration;
236 u8 spicy;
237 u8 dry;
238 u8 sweet;
239 u8 bitter;
240 u8 sour;
241 u8 smoothness;
242};
243
244struct EnigmaBerry
245{
246 struct Berry berry;
247 u8 pic[(6 * 6) * TILE_SIZE_4BPP];
248 u16 palette[16];
249 u8 description1[45];
250 u8 description2[45];
251 u8 itemEffect[18];
252 u8 holdEffect;
253 u8 holdEffectParam;
254 u32 checksum;
255};
256
257struct BattleEnigmaBerry
258{
259 u8 name[7];
260 u8 holdEffect;
261 u8 itemEffect[18];
262 u8 holdEffectParam;
263};
264
265struct EnigmaBerryFRLGE {
266 struct Berry berry; // 0x00
267 u8 itemEffect[18]; // 0x1C
268 u8 holdEffect; // 0x2E
269 u8 holdEffectParam; // 0x2F
270 u32 checksum; // 0x30
271};
272
273struct __attribute__((aligned(4))) BerryTree
274{
275 u8 berry;
276 u8 stage:7;
277 u8 growthSparkle:1;
278 u16 secondsUntilNextStage;
279 u8 berryYield;
280 u8 regrowthCount:4;
281 u8 watered1:1;
282 u8 watered2:1;
283 u8 watered3:1;
284 u8 watered4:1;
285};
286
287struct PokemonSubstruct0
288{
289 u16 species;
290 u16 heldItem;
291 u32 experience;
292 u8 ppBonuses;
293 u8 friendship;
294};
295
296struct PokemonSubstruct1
297{
298 u16 moves[4];
299 u8 pp[4];
300};
301
302struct PokemonSubstruct2
303{
304 u8 hpEV;
305 u8 attackEV;
306 u8 defenseEV;
307 u8 speedEV;
308 u8 spAttackEV;
309 u8 spDefenseEV;
310 u8 cool;
311 u8 beauty;
312 u8 cute;
313 u8 smart;
314 u8 tough;
315 u8 sheen;
316};
317
318struct PokemonSubstruct3
319{
320 /* 0x00 */ u8 pokerus;
321 /* 0x01 */ u8 metLocation;
322
323 /* 0x02 */ u16 metLevel:7;
324 /* 0x02 */ u16 metGame:4;
325 /* 0x03 */ u16 pokeball:4;
326 /* 0x03 */ u16 otGender:1;
327
328 /* 0x04 */ u32 hpIV:5;
329 /* 0x04 */ u32 attackIV:5;
330 /* 0x05 */ u32 defenseIV:5;
331 /* 0x05 */ u32 speedIV:5;
332 /* 0x05 */ u32 spAttackIV:5;
333 /* 0x06 */ u32 spDefenseIV:5;
334 /* 0x07 */ u32 isEgg:1;
335 /* 0x07 */ u32 altAbility:1;
336
337 /* 0x08 */ u32 coolRibbon:3;
338 /* 0x08 */ u32 beautyRibbon:3;
339 /* 0x08 */ u32 cuteRibbon:3;
340 /* 0x09 */ u32 smartRibbon:3;
341 /* 0x09 */ u32 toughRibbon:3;
342 /* 0x09 */ u32 championRibbon:1;
343 /* 0x0A */ u32 winningRibbon:1;
344 /* 0x0A */ u32 victoryRibbon:1;
345 /* 0x0A */ u32 artistRibbon:1;
346 /* 0x0A */ u32 effortRibbon:1;
347 /* 0x0A */ u32 giftRibbon1:1;
348 /* 0x0A */ u32 giftRibbon2:1;
349 /* 0x0A */ u32 giftRibbon3:1;
350 /* 0x0A */ u32 giftRibbon4:1;
351 /* 0x0B */ u32 giftRibbon5:1;
352 /* 0x0B */ u32 giftRibbon6:1;
353 /* 0x0B */ u32 giftRibbon7:1;
354 /* 0x0B */ u32 fatefulEncounter:5; // unused in Ruby/Sapphire, but the high bit must be set for Mew/Deoxys to obey in FR/LG/Emerald
355};
356
357union PokemonSubstruct
358{
359 struct PokemonSubstruct0 type0;
360 struct PokemonSubstruct1 type1;
361 struct PokemonSubstruct2 type2;
362 struct PokemonSubstruct3 type3;
363 u16 raw[6];
364};
365
366struct BoxPokemon
367{
368 u32 personality;
369 u32 otId;
370 u8 nickname[POKEMON_NAME_LENGTH];
371 u8 language;
372 u8 isBadEgg:1;
373 u8 hasSpecies:1;
374 u8 isEgg:1;
375 u8 unused:5;
376 u8 otName[OT_NAME_LENGTH];
377 u8 markings;
378 u16 checksum;
379 u16 unknown;
380
381 union
382 {
383 u32 raw[12];
384 union PokemonSubstruct substructs[4];
385 } secure;
386};
387
388struct Pokemon
389{
390 struct BoxPokemon box;
391 u32 status;
392 u8 level;
393 u8 pokerus;
394 u16 hp;
395 u16 maxHP;
396 u16 attack;
397 u16 defense;
398 u16 speed;
399 u16 spAttack;
400 u16 spDefense;
401};
402
403struct UnknownPokemonStruct
404{
405 u16 species;
406 u16 heldItem;
407 u16 moves[4];
408 u8 level;
409 u8 ppBonuses;
410 u8 hpEV;
411 u8 attackEV;
412 u8 defenseEV;
413 u8 speedEV;
414 u8 spAttackEV;
415 u8 spDefenseEV;
416 u32 otId;
417 u32 hpIV:5;
418 u32 attackIV:5;
419 u32 defenseIV:5;
420 u32 speedIV:5;
421 u32 spAttackIV:5;
422 u32 spDefenseIV:5;
423 u32 gap:1;
424 u32 altAbility:1;
425 u32 personality;
426 u8 nickname[POKEMON_NAME_LENGTH + 1];
427 u8 friendship;
428};
429
430struct BattlePokemon
431{
432 /* 0x00 */ u16 species;
433 /* 0x02 */ u16 attack;
434 /* 0x04 */ u16 defense;
435 /* 0x06 */ u16 speed;
436 /* 0x08 */ u16 spAttack;
437 /* 0x0A */ u16 spDefense;
438 /* 0x0C */ u16 moves[4];
439 /* 0x14 */ u32 hpIV:5;
440 /* 0x14 */ u32 attackIV:5;
441 /* 0x15 */ u32 defenseIV:5;
442 /* 0x15 */ u32 speedIV:5;
443 /* 0x16 */ u32 spAttackIV:5;
444 /* 0x17 */ u32 spDefenseIV:5;
445 /* 0x17 */ u32 isEgg:1;
446 /* 0x17 */ u32 altAbility:1;
447 /* 0x18 */ s8 statStages[8];
448 /* 0x20 */ u8 ability;
449 /* 0x21 */ u8 type1;
450 /* 0x22 */ u8 type2;
451 /* 0x23 */ u8 unknown;
452 /* 0x24 */ u8 pp[4];
453 /* 0x28 */ u16 hp;
454 /* 0x2A */ u8 level;
455 /* 0x2B */ u8 friendship;
456 /* 0x2C */ u16 maxHP;
457 /* 0x2E */ u16 item;
458 /* 0x30 */ u8 nickname[POKEMON_NAME_LENGTH + 1];
459 /* 0x3B */ u8 ppBonuses;
460 /* 0x3C */ u8 otName[8];
461 /* 0x44 */ u32 experience;
462 /* 0x48 */ u32 personality;
463 /* 0x4C */ u32 status1;
464 /* 0x50 */ u32 status2;
465 /* 0x54 */ u32 otId;
466};
467
468struct BaseStats
469{
470 /* 0x00 */ u8 baseHP;
471 /* 0x01 */ u8 baseAttack;
472 /* 0x02 */ u8 baseDefense;
473 /* 0x03 */ u8 baseSpeed;
474 /* 0x04 */ u8 baseSpAttack;
475 /* 0x05 */ u8 baseSpDefense;
476 /* 0x06 */ u8 type1;
477 /* 0x07 */ u8 type2;
478 /* 0x08 */ u8 catchRate;
479 /* 0x09 */ u8 expYield;
480 /* 0x0A */ u16 evYield_HP:2;
481 /* 0x0A */ u16 evYield_Attack:2;
482 /* 0x0A */ u16 evYield_Defense:2;
483 /* 0x0A */ u16 evYield_Speed:2;
484 /* 0x0B */ u16 evYield_SpAttack:2;
485 /* 0x0B */ u16 evYield_SpDefense:2;
486 /* 0x0C */ u16 item1;
487 /* 0x0E */ u16 item2;
488 /* 0x10 */ u8 genderRatio;
489 /* 0x11 */ u8 eggCycles;
490 /* 0x12 */ u8 friendship;
491 /* 0x13 */ u8 growthRate;
492 /* 0x14 */ u8 eggGroup1;
493 /* 0x15 */ u8 eggGroup2;
494 /* 0x16 */ u8 ability1;
495 /* 0x17 */ u8 ability2;
496 /* 0x18 */ u8 safariZoneFleeRate;
497 /* 0x19 */ u8 bodyColor;
498};
499
500struct BattleMove
501{
502 u8 effect;
503 u8 power;
504 u8 type;
505 u8 accuracy;
506 u8 pp;
507 u8 secondaryEffectChance;
508 u8 target;
509 u8 priority;
510 u32 flags;
511};
512
513struct PokemonStorage
514{
515 /* 0x00 */ u8 currentBox;
516 /* 0x01 */ struct BoxPokemon boxes[14][30];
517 u8 boxNames[14][9];
518 u8 boxBackground[14];
519};
520
521struct WarpData
522{
523 s8 mapGroup;
524 s8 mapNum;
525 s8 warpId;
526 s16 x, y;
527};
528
529struct ItemSlot
530{
531 u16 itemId;
532 u16 quantity;
533};
534
535struct __attribute__((aligned(2))) Pokeblock
536{
537 u8 color;
538 u8 spicy;
539 u8 dry;
540 u8 sweet;
541 u8 bitter;
542 u8 sour;
543 u8 feel;
544};
545
546struct Roamer
547{
548 /*0x00*/ u32 ivs;
549 /*0x04*/ u32 personality;
550 /*0x08*/ u16 species;
551 /*0x0A*/ u16 hp;
552 /*0x0C*/ u8 level;
553 /*0x0D*/ u8 status;
554 /*0x0E*/ u8 cool;
555 /*0x0F*/ u8 beauty;
556 /*0x10*/ u8 cute;
557 /*0x11*/ u8 smart;
558 /*0x12*/ u8 tough;
559 /*0x13*/ u8 active;
560};
561
562struct RamScriptData
563{
564 u8 magic;
565 u8 mapGroup;
566 u8 mapNum;
567 u8 objectId;
568 u8 script[995];
569} __attribute__((aligned(1),packed));
570
571struct RamScript
572{
573 u32 checksum;
574 struct RamScriptData data;
575} __attribute__((aligned(1),packed));
576
577struct SB1_2EFC_Struct
578{
579 u8 unknown[0x20];
580};
581
582struct EasyChatPair
583{
584 u16 unk0_0:7;
585 u16 unk0_7:7;
586 u16 unk1_6:1;
587 u16 unk2;
588 u16 words[2];
589}; /*size = 0x8*/
590
591struct TVShowCommon {
592 /*0x00*/ u8 var00;
593 /*0x01*/ u8 var01;
594};
595
596struct TVShowFanClubLetter {
597 /*0x00*/ u8 var00;
598 /*0x01*/ u8 var01;
599 /*0x02*/ u16 species;
600 u8 pad04[12];
601 /*0x10*/ u8 playerName[8];
602 /*0x18*/ u8 var18;
603};
604
605struct TVShowRecentHappenings {
606 /*0x00*/ u8 var00;
607 /*0x01*/ u8 var01;
608 /*0x02*/ u16 var02;
609 u8 pad04[12];
610 /*0x10*/ u8 var10[8];
611 /*0x18*/ u8 var18;
612 u8 pad19[10];
613};
614
615struct TVShowFanclubOpinions {
616 /*0x00*/ u8 var00;
617 /*0x01*/ u8 var01;
618 /*0x02*/ u16 var02;
619 /*0x04*/ u8 var04A:4;
620 u8 var04B:4;
621 /*0x04*/ u8 var05[8];
622 /*0x0D*/ u8 var0D;
623 /*0x0E*/ u8 var0E;
624 /*0x0F*/ u8 var0F;
625 /*0x10*/ u8 var10[8];
626};
627
628struct TVShowNameRaterShow {
629 /*0x00*/ u8 var00;
630 /*0x01*/ u8 var01;
631 /*0x02*/ u16 species;
632 /*0x04*/ u8 pokemonName[11];
633 /*0x0F*/ u8 trainerName[11];
634 /*0x1A*/ u8 random;
635 /*0x1B*/ u8 random2;
636 /*0x1C*/ u16 var1C;
637 /*0x1E*/ u8 language;
638 /*0x1F*/ u8 var1F;
639};
640
641struct TVShowMassOutbreak {
642 /*0x00*/ u8 var00;
643 /*0x01*/ u8 var01;
644 /*0x02*/ u8 var02;
645 /*0x03*/ u8 var03;
646 /*0x04*/ u16 moves[4];
647 /*0x0C*/ u16 species;
648 /*0x0E*/ u16 var0E;
649 /*0x10*/ u8 locationMapNum;
650 /*0x11*/ u8 locationMapGroup;
651 /*0x12*/ u8 var12;
652 /*0x13*/ u8 probability;
653 /*0x14*/ u8 level;
654 /*0x15*/ u8 var15;
655 /*0x16*/ u16 var16;
656 /*0x18*/ u8 var18;
657 u8 pad19[11];
658};
659
660typedef union TVShow {
661 struct TVShowCommon common;
662 struct TVShowFanClubLetter fanclubLetter;
663 struct TVShowRecentHappenings recentHappenings;
664 struct TVShowFanclubOpinions fanclubOpinions;
665 struct TVShowNameRaterShow nameRaterShow;
666 struct TVShowMassOutbreak massOutbreak;
667} TVShow;
668
669struct __attribute__((aligned(4))) MailStruct
670{
671 /*0x00*/ u16 words[9];
672 /*0x12*/ u8 playerName[8];
673 /*0x1A*/ u8 trainerId[4];
674 /*0x1E*/ u16 species;
675 /*0x20*/ u16 itemId;
676};
677
678struct UnkMauvilleOldManStruct
679{
680 u8 unk_2D94;
681 u8 unk_2D95;
682 /*0x2D96*/ u16 mauvilleOldMan_ecArray[6];
683 /*0x2DA2*/ u16 mauvilleOldMan_ecArray2[6];
684 /*0x2DAE*/ u8 playerName[8];
685 /*0x2DB6*/ u8 filler_2DB6[0x3];
686 /*0x2DB9*/ u8 playerTrainerId[4];
687 u8 unk_2DBD;
688 /* size = 0x2C */
689};
690
691struct UnkMauvilleOldManStruct2
692{
693 u8 filler0;
694 u8 unk1;
695 u8 unk2;
696 u16 mauvilleOldMan_ecArray[10];
697 u16 mauvilleOldMan_ecArray2[6];
698 u8 fillerF[0x2];
699 /* size = 0x2C */
700};
701
702typedef union OldMan {
703 struct UnkMauvilleOldManStruct oldMan1;
704 struct UnkMauvilleOldManStruct2 oldMan2;
705} OldMan;
706
707struct QuestStoryNPC {
708 u16 bitfield;
709 u8 direction;
710 u8 height;
711 u8 type_id;
712 u8 running_behaviour_or_picture_id;
713 u8 is_trainer;
714 u8 local_id;
715 u8 local_mapnumber;
716 u8 local_mapbank;
717 u16 x;
718 u16 y;
719 u8 sight_distance;
720 u8 role_from;
721 u8 unknown_decrement_on_step;
722 u8 unk_11;
723 u16 padding_12;
724};
725
726struct QuestStory {
727 u8 active;
728 u8 bank;
729 u8 map;
730 u8 warpId;
731 u16 x;
732 u16 y;
733 struct QuestStoryNPC npc[0x10];
734 u8 unk_148[0x51f];
735};
736
737struct NPCState {
738 u8 bitfield;
739 u8 obj_anim_and_vis_control;
740 u8 unk_2;
741 u8 unk_3;
742 u8 oamid;
743 u8 type_id;
744 u8 running_behaviour_or_picture_id;
745 u8 is_trainer;
746 u8 local_id;
747 u8 local_mapnumber;
748 u8 local_mapbank;
749 u8 height;
750 struct Coords16 stay_around;
751 struct Coords16 to;
752 struct Coords16 from;
753 u8 direction;
754 u8 movement_area;
755 u8 objid_surfing;
756 u8 objid_1B;
757 u8 idx_movement_behaviour;
758 u8 sight_distance;
759 u8 role_to;
760 u8 role_from;
761 u8 unk_20;
762 u8 unknown_decrement_on_step;
763 u8 unk_22;
764 u8 unk_23;
765};
766
767struct DaycarePokemon {
768 struct BoxPokemon pokemon;
769 u8 unk_50[56];
770 u32 steps;
771};
772
773
774struct Time
775{
776 /*0x00*/ s16 days;
777 /*0x02*/ s8 hours;
778 /*0x03*/ s8 minutes;
779 /*0x04*/ s8 seconds;
780};
781
782struct Pokedex
783{
784 /*0x00*/ u8 order;
785 /*0x01*/ u8 unknown1;
786 /*0x02*/ u8 nationalMagic; // must equal 0xDA in order to have National mode
787 /*0x03*/ u8 unknown2;
788 /*0x04*/ u32 unownPersonality; // set when you first see Unown
789 /*0x08*/ u32 spindaPersonality; // set when you first see Spinda
790 /*0x0C*/ u32 unknown3;
791 /*0x10*/ u8 owned[52];
792 /*0x44*/ u8 seen[52];
793}; \ No newline at end of file