diff --git a/.gitignore b/.gitignore index bee34d2..026531c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ build/ *.zip .vscode/ source/payload_builder.exe -source/test_payload.txt +source/test_payload.txt \ No newline at end of file diff --git a/include/debug_mode.h b/include/debug_mode.h index f11d487..1ad5dbd 100644 --- a/include/debug_mode.h +++ b/include/debug_mode.h @@ -11,7 +11,7 @@ #define SHOW_INVALID_PKMN false #define DEBUG_GAME LEAFGREEN_ID -#define DEBUG_VERS VERS_1_1 +#define DEBUG_VERS VERS_1_0 #define DEBUG_LANG LANG_ENG #define ENABLE_MATCH_PID true diff --git a/include/gba_rom_values/base_gba_rom_struct.h b/include/gba_rom_values/base_gba_rom_struct.h index f178fdd..55ac5a4 100644 --- a/include/gba_rom_values/base_gba_rom_struct.h +++ b/include/gba_rom_values/base_gba_rom_struct.h @@ -36,25 +36,36 @@ struct ROM_DATA int loc_copyMonToPC; int loc_gSpecialVar_0x8000; int loc_gSaveBlock1; // Only used in R/S - int loc_gSaveBlock1PTR; // Only used in FR/LG/E int loc_getSetPokedexFlag; int loc_gSaveDataBuffer; // The location of the saveDataBuffer int loc_readFlashSector; int loc_loadSaveSection30; // The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + int loc_m4aMPlayStop; + int loc_gMPlayInfo_BGM; + int loc_gMPlayInfo_SE2; + int loc_MPlayStart; + int loc_CreateFanfareTask; + int loc_sFanfareCounter; + int loc_gPlttBufferFaded; + int loc_gSprites; + int loc_voicegroup; + int loc_sPicTable_NPC; // sPicTable_OldWoman in FRLG int offset_ramscript; // Ramscript offset as found within the SaveBlock1 struct in global.h int offset_flags; // Flag offset as found within the SaveBlock1 struct in global.h int offset_wondercard; int offset_script; int text_region; + int special_DrawWholeMapView; // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt - int e4_flag; // The flag that is set when you become champion. Often listed as "GAME_CLEAR" - int mg_flag; // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS - int unused_flag_start; // The start of the unused flags and must have 31 open flags in a row + int e4_flag; // The flag that is set when you become champion. Often listed as "GAME_CLEAR" + int mg_flag; // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS + int unused_flag_start; // The start of the unused flags and must have 31 open flags in a row u8 map_bank; u8 map_id; u8 npc_id; + u8 npc_palette; u8 def_map_bank; u8 def_map_id; diff --git a/include/gba_rom_values/eng_gba_rom_values.h b/include/gba_rom_values/eng_gba_rom_values.h index 5ea87d1..cfb4c0e 100644 --- a/include/gba_rom_values/eng_gba_rom_values.h +++ b/include/gba_rom_values/eng_gba_rom_values.h @@ -24,15 +24,17 @@ const struct ROM_DATA ENG_RUBY_v0 = { .offset_flags = 0x1220, // Flag offset as found within the SaveBlock1 struct in global.h .offset_script = 0x0810, .text_region = TEXT_HOENN, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x800 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x800 + 0x4C, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x21, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 20, - .map_id = 2, + .map_bank = 14, + .map_id = 11, .npc_id = 1, + .npc_palette = 5, .def_map_bank = 8, .def_map_id = 1, @@ -55,21 +57,32 @@ const struct ROM_DATA ENG_SAPPHIRE_v0 = { .loc_getSetPokedexFlag = 0x08090D90, .loc_gSaveDataBuffer = 0x02000000, // Known as "gSharedMem" in RS .loc_readFlashSector = 0x08125BF8, // Known as "DoReadFlashWholeSection" in RS - + .loc_m4aMPlayStop = 0x081DE6D0, + .loc_gMPlayInfo_BGM = 0x03007380, + .loc_gMPlayInfo_SE2 = 0x03007400, + .loc_MPlayStart = 0x081DE5EC, + .loc_CreateFanfareTask = 0x08074F4C, + .loc_sFanfareCounter = 0x030006DA, + .loc_gPlttBufferFaded = 0x0202EEC8, + .loc_gSprites = 0x02020004, + .loc_voicegroup = 0x08451FEC, + .loc_sPicTable_NPC = 0x0836E718, // The following should be consistant across languages and revisions. .offset_ramscript = 0x3690, // Ramscript offset as found within the SaveBlock1 struct in global.h .offset_flags = 0x1220, // Flag offset as found within the SaveBlock1 struct in global.h .offset_script = 0x0810, .text_region = TEXT_HOENN, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x800 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x800 + 0x4C, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x21, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 20, - .map_id = 2, + .map_bank = 14, + .map_id = 11, .npc_id = 1, + .npc_palette = 5, .def_map_bank = 8, .def_map_id = 1, @@ -98,15 +111,17 @@ const struct ROM_DATA ENG_RUBY_v1 = { .offset_flags = 0x1220, // Flag offset as found within the SaveBlock1 struct in global.h .offset_script = 0x0810, .text_region = TEXT_HOENN, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x800 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x800 + 0x4C, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x21, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 20, - .map_id = 2, + .map_bank = 14, + .map_id = 11, .npc_id = 1, + .npc_palette = 5, .def_map_bank = 8, .def_map_id = 1, @@ -135,15 +150,17 @@ const struct ROM_DATA ENG_SAPPHIRE_v1 = { .offset_flags = 0x1220, // Flag offset as found within the SaveBlock1 struct in global.h .offset_script = 0x0810, .text_region = TEXT_HOENN, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x800 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x800 + 0x4C, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x21, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 20, - .map_id = 2, + .map_bank = 14, + .map_id = 11, .npc_id = 1, + .npc_palette = 5, .def_map_bank = 8, .def_map_id = 1, @@ -172,15 +189,17 @@ const struct ROM_DATA ENG_RUBY_v2 = { .offset_flags = 0x1220, // Flag offset as found within the SaveBlock1 struct in global.h .offset_script = 0x0810, .text_region = TEXT_HOENN, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x800 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x800 + 0x4C, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x21, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 20, - .map_id = 2, + .map_bank = 14, + .map_id = 11, .npc_id = 1, + .npc_palette = 5, .def_map_bank = 8, .def_map_id = 1, @@ -209,15 +228,17 @@ const struct ROM_DATA ENG_SAPPHIRE_v2 = { .offset_flags = 0x1220, // Flag offset as found within the SaveBlock1 struct in global.h .offset_script = 0x0810, .text_region = TEXT_HOENN, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x800 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x800 + 0x4C, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x21, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 20, - .map_id = 2, + .map_bank = 14, + .map_id = 11, .npc_id = 1, + .npc_palette = 5, .def_map_bank = 8, .def_map_id = 1, @@ -236,11 +257,20 @@ const struct ROM_DATA ENG_FIRERED_v0 = { .loc_copyMonToPC = 0x08040B90, // Known as "SendMonToPC" .loc_gSpecialVar_0x8000 = 0x020370B8, - .loc_gSaveBlock1PTR = 0x03005008, - .loc_getSetPokedexFlag = 0x08088E8C, + .loc_getSetPokedexFlag = 0x08088E74, .loc_gSaveDataBuffer = 0x02039A38, // The location of the saveDataBuffer .loc_readFlashSector = 0x080DA190, - .loc_loadSaveSection30 = 0x0815D7BC,// The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_loadSaveSection30 = 0x0815D7BC, // The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_m4aMPlayStop = 0x081DD93C, + .loc_gMPlayInfo_BGM = 0x03007300, + .loc_gMPlayInfo_SE2 = 0x03007380, + .loc_MPlayStart = 0x081DD858, + .loc_CreateFanfareTask = 0x08071CEC, + .loc_sFanfareCounter = 0x03000FC6, + .loc_gPlttBufferFaded = 0x020375F8, + .loc_gSprites = 0x0202063C, + .loc_voicegroup = 0x084957A0, + .loc_sPicTable_NPC = 0x083A0AB8, // The following should be consistant across languages and revisions. .offset_ramscript = 0x361C, // Ramscript offset as found within the SaveBlock1 struct in global.h @@ -248,15 +278,17 @@ const struct ROM_DATA ENG_FIRERED_v0 = { .offset_wondercard = 0x0460, .offset_script = 0x079C, .text_region = TEXT_KANTO, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x860 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x860 + 0x7B, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x20, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 30, + .map_bank = 31, .map_id = 0, .npc_id = 1, + .npc_palette = 3, .def_map_bank = 0xFF, .def_map_id = 0xFF, @@ -275,11 +307,20 @@ const struct ROM_DATA ENG_LEAFGREEN_v0 = { .loc_copyMonToPC = 0x08040B90, .loc_gSpecialVar_0x8000 = 0x020370B8, - .loc_gSaveBlock1PTR = 0x03005008, .loc_getSetPokedexFlag = 0x08088E48, .loc_gSaveDataBuffer = 0x02039A38, // The location of the saveDataBuffer .loc_readFlashSector = 0x080DA164, - .loc_loadSaveSection30 = 0x0815D798,// The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_loadSaveSection30 = 0x0815D798, // The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_m4aMPlayStop = 0x081DD918, + .loc_gMPlayInfo_BGM = 0x03007300, + .loc_gMPlayInfo_SE2 = 0x03007380, + .loc_MPlayStart = 0x081DD834, + .loc_CreateFanfareTask = 0x08071CEC, + .loc_sFanfareCounter = 0x03000FC6, + .loc_gPlttBufferFaded = 0x020375F8, + .loc_gSprites = 0x0202063C, + .loc_voicegroup = 0x0849507C, + .loc_sPicTable_NPC = 0x083A0A98, // The following should be consistant across languages and revisions. .offset_ramscript = 0x361C, // Ramscript offset as found within the SaveBlock1 struct in global.h @@ -287,15 +328,17 @@ const struct ROM_DATA ENG_LEAFGREEN_v0 = { .offset_wondercard = 0x0460, .offset_script = 0x079C, .text_region = TEXT_KANTO, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x860 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x860 + 0x7B, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x20, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 30, + .map_bank = 31, .map_id = 0, .npc_id = 1, + .npc_palette = 3, .def_map_bank = 0xFF, .def_map_id = 0xFF, @@ -314,11 +357,20 @@ const struct ROM_DATA ENG_FIRERED_v1 = { .loc_copyMonToPC = 0x08040BA4, .loc_gSpecialVar_0x8000 = 0x020370B8, - .loc_gSaveBlock1PTR = 0x03005008, .loc_getSetPokedexFlag = 0x08088E88, .loc_gSaveDataBuffer = 0x02039A38, // The location of the saveDataBuffer .loc_readFlashSector = 0x080DA1A4, - .loc_loadSaveSection30 = 0x0815D834,// The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_loadSaveSection30 = 0x0815D834, // The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_m4aMPlayStop = 0x081DD9AC, + .loc_gMPlayInfo_BGM = 0x03007300, + .loc_gMPlayInfo_SE2 = 0x03007380, + .loc_MPlayStart = 0x081DD8C8, + .loc_CreateFanfareTask = 0x08071D00, + .loc_sFanfareCounter = 0x03000FC6, + .loc_gPlttBufferFaded = 0x020375F8, + .loc_gSprites = 0x0202063C, + .loc_voicegroup = 0x08495800, + .loc_sPicTable_NPC = 0x083A0B28, // The following should be consistant across languages and revisions. .offset_ramscript = 0x361C, // Ramscript offset as found within the SaveBlock1 struct in global.h @@ -326,15 +378,17 @@ const struct ROM_DATA ENG_FIRERED_v1 = { .offset_wondercard = 0x0460, .offset_script = 0x079C, .text_region = TEXT_KANTO, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x860 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x860 + 0x7B, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x20, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 30, + .map_bank = 31, .map_id = 0, .npc_id = 1, + .npc_palette = 3, .def_map_bank = 0xFF, .def_map_id = 0xFF, @@ -353,18 +407,28 @@ const struct ROM_DATA ENG_LEAFGREEN_v1 = { .loc_copyMonToPC = 0x08040BA4, .loc_gSpecialVar_0x8000 = 0x020370B8, - .loc_gSaveBlock1PTR = 0x03005008, .loc_getSetPokedexFlag = 0x08088E5C, .loc_gSaveDataBuffer = 0x02039A38, // The location of the saveDataBuffer .loc_readFlashSector = 0x080DA178, - .loc_loadSaveSection30 = 0x0815D810,// The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald - + .loc_loadSaveSection30 = 0x0815D810, // The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_m4aMPlayStop = 0x081DD988, + .loc_gMPlayInfo_BGM = 0x03007300, + .loc_gMPlayInfo_SE2 = 0x03007380, + .loc_MPlayStart = 0x081DD8A4, + .loc_CreateFanfareTask = 0x08071D00, + .loc_sFanfareCounter = 0x03000FC6, + .loc_gPlttBufferFaded = 0x020375F8, + .loc_gSprites = 0x0202063C, + .loc_voicegroup = 0x084950EC, + .loc_sPicTable_NPC = 0x083A0B08, + // The following should be consistant across languages and revisions. .offset_ramscript = 0x361C, // Ramscript offset as found within the SaveBlock1 struct in global.h .offset_flags = 0x0EE0, // Flag offset as found within the SaveBlock1 struct in global.h .offset_wondercard = 0x0460, .offset_script = 0x079C, .text_region = TEXT_KANTO, + .special_DrawWholeMapView = 0x8E, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x860 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" @@ -374,6 +438,7 @@ const struct ROM_DATA ENG_LEAFGREEN_v1 = { .map_bank = 31, .map_id = 0, .npc_id = 1, + .npc_palette = 3, .def_map_bank = 0xFF, .def_map_id = 0xFF, @@ -392,11 +457,20 @@ const struct ROM_DATA ENG_EMERALD_v0 = { .loc_copyMonToPC = 0x0806B490, .loc_gSpecialVar_0x8000 = 0x020375D8, - .loc_gSaveBlock1PTR = 0x03005D8C, .loc_getSetPokedexFlag = 0x080C0664, .loc_gSaveDataBuffer = 0x0203ABBC, // The location of the saveDataBuffer .loc_readFlashSector = 0x0815314C, - .loc_loadSaveSection30 = 0x081D3AD8,// The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_loadSaveSection30 = 0x081D3AD8, // The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + .loc_m4aMPlayStop = 0x082E0978, + .loc_gMPlayInfo_BGM = 0x03007420, + .loc_gMPlayInfo_SE2 = 0x03007630, + .loc_MPlayStart = 0x082E0894, + .loc_CreateFanfareTask = 0x080A3170, + .loc_sFanfareCounter = 0x03000F4E, + .loc_gPlttBufferFaded = 0x02037B14, + .loc_gSprites = 0x02020630, + .loc_voicegroup = 0x086A6DE4, + .loc_sPicTable_NPC = 0x08506404, // The following should be consistant across languages and revisions. .offset_ramscript = 0x3728, // Ramscript offset as found within the SaveBlock1 struct in global.h @@ -404,15 +478,17 @@ const struct ROM_DATA ENG_EMERALD_v0 = { .offset_wondercard = 0x056C, .offset_script = 0x08A8, .text_region = TEXT_HOENN, + .special_DrawWholeMapView = 0x91, // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt .e4_flag = 0x860 + 0x04, // The flag that is set when you become champion. Often listed as "GAME_CLEAR" .mg_flag = 0x860 + 0x7B, // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS .unused_flag_start = 0x20, // The start of the unused flags and must have 31 open flags in a row - .map_bank = 20, - .map_id = 2, + .map_bank = 15, + .map_id = 13, .npc_id = 1, + .npc_palette = 5, .def_map_bank = 0xFF, .def_map_id = 0xFF, diff --git a/include/mystery_gift_builder.h b/include/mystery_gift_builder.h index bead1e2..9d564b5 100644 --- a/include/mystery_gift_builder.h +++ b/include/mystery_gift_builder.h @@ -277,9 +277,7 @@ private: void add_asm(u16 command); void init_npc_location(u8 bank, u8 map, u8 npc); void add_word(u32 word); - void four_align(); - void add_padding(); - + // Scripting commands void setvirtualaddress(u32 location); void lock(); @@ -319,7 +317,6 @@ private: void msgboxMacro(u32 location); void changeSpriteMacro(u8 npcId, u32 spriteTablePtr); - void copyPaletteMacro(u8 palNum, const unsigned short palette_array[]); void changePaletteMacro(u8 npcId, u8 palNum); // ASM commands diff --git a/include/rom_data.h b/include/rom_data.h index 61fccbb..e09262d 100644 --- a/include/rom_data.h +++ b/include/rom_data.h @@ -40,33 +40,44 @@ public: int loc_sendMonToPC; int loc_gSpecialVar_0x8000; int loc_gSaveBlock1; // Only used in R/S - int loc_gSaveBlock1PTR; // Only used in FR/LG/E int loc_setPokedexFlag; int loc_gSaveDataBuffer; // The location of the saveDataBuffer int loc_readFlashSector; - int loc_loadSaveSection30;// The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + int loc_loadSaveSection30; // The location of the function that loads save section 30: CEReaderTool_LoadTrainerTower_r in FRLG, TryReadTrainerHill_Internal in Emerald + int loc_m4aMPlayStop; + int loc_gMPlayInfo_BGM; + int loc_gMPlayInfo_SE2; + int loc_MPlayStart; + int loc_CreateFanfareTask; + int loc_sFanfareCounter; + int loc_gPlttBufferFaded; + int loc_gSprites; + int loc_voicegroup; + int loc_sPicTable_NPC; int offset_ramscript; // Ramscript offset as found within the SaveBlock1 struct in global.h int offset_flags; // Flag offset as found within the SaveBlock1 struct in global.h int offset_wondercard; int offset_script; int text_region; + int special_DrawWholeMapView; // PKHeX's list of flags is useful for making sure the detection is accurate: https://github.com/kwsch/PKHeX/blob/78a557c3cdaa6f48b42cc96df8ccb4d20b897937/PKHeX.Core/Resources/text/other/flags_rs.txt int e4_flag; // The flag that is set when you become champion. Often listed as "GAME_CLEAR" int mg_flag; // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS - int unused_flag_start; // The start of the unused flags and must have 31 open flags in a row - int all_collected_flag; // The flag for if everything has been collected + int unused_flag_start; // The start of the unused flags and must have 31 open flags in a row + int all_collected_flag; // The flag for if everything has been collected int pkmn_collected_flag_start; // The beginning of the flags for each of the Pokemon u8 map_bank; u8 map_id; u8 npc_id; + u8 npc_palette; u8 def_map_bank; u8 def_map_id; u8 def_npc_id; - - private: + +private: void fill_values(const ROM_DATA *rom_values); }; diff --git a/include/script_var.h b/include/script_var.h index 19b31fd..5633914 100644 --- a/include/script_var.h +++ b/include/script_var.h @@ -22,9 +22,12 @@ class asm_var : public script_var public: using script_var::script_var; void set_start(); // Add a pointer to where the start is - u8 add_reference(); // Add a location for the variable to be refrenced in the script + void set_start(bool nIsDirect); // Add a pointer to where the start is + u8 add_reference(); // Add a location for the variable to be refrenced in the script + u8 add_reference(int nCommand_offset); // Add a location for the variable to be refrenced in the script void fill_refrences(u8 mg_array_ptr[]); // goes through all the script locations and updates them to point to the start u32 get_loc_in_sec30(); + bool isDirect; }; class xse_var : public script_var @@ -70,9 +73,8 @@ public: using xse_var::xse_var; void insert_sprite_data(u8 mg_array[], const unsigned int sprite_array[], unsigned int size, const unsigned short palette_array[]); void set_start(); - }; +}; - class music_var : public xse_var { public: @@ -83,4 +85,4 @@ public: int numTracks; std::vector trackPointers; std::vector> trackArrays; - }; \ No newline at end of file +}; \ No newline at end of file diff --git a/source/mystery_gift_builder.cpp b/source/mystery_gift_builder.cpp index 7184662..945c758 100644 --- a/source/mystery_gift_builder.cpp +++ b/source/mystery_gift_builder.cpp @@ -5,7 +5,11 @@ #include "pokemon_data.h" #include "rom_data.h" +#define MG_SCRIPT false +#define S30_SCRIPT true + extern rom_data curr_rom; +bool asm_payload_location; // These are static variables int var_call_check_flag = (VAR_ID_START + 0x04); @@ -49,21 +53,23 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) asm_var currPkmnIndex_ptr(ptr_index, sec30_variable_list, &curr_section30_index); asm_var pkmnStruct(curr_rom.loc_gSaveDataBuffer, sec30_variable_list, &curr_section30_index); asm_var dexStruct(curr_rom.loc_gSaveDataBuffer + (MAX_PKMN_IN_BOX * POKEMON_SIZE), sec30_variable_list, &curr_section30_index); - asm_var flashBuffer_ptr(curr_rom.loc_gSaveDataBuffer, sec30_variable_list, &curr_section30_index); - asm_var readFlashSector_ptr(curr_rom.loc_readFlashSector + READ_AS_THUMB, sec30_variable_list, &curr_section30_index); - asm_var m4aMPlayStop_ptr(0x081dd988 + READ_AS_THUMB, sec30_variable_list, &curr_section30_index); - asm_var gMPlayInfo_BGM_ptr(0x03007300, sec30_variable_list, &curr_section30_index); - asm_var gMPlayInfo_SE2_ptr(0x03007380, sec30_variable_list, &curr_section30_index); - asm_var MPlayStart_ptr(0x081dd8a4 + READ_AS_THUMB, sec30_variable_list, &curr_section30_index); - asm_var CreateFanfareTask_ptr(0x08071d00 + READ_AS_THUMB, sec30_variable_list, &curr_section30_index); - asm_var sFanfareCounter_ptr(0x03000fc6, sec30_variable_list, &curr_section30_index); - asm_var gPlttBufferFaded(0x020375f8 + (32 * 0x1A), sec30_variable_list, &curr_section30_index); //0x1A is the pallet number - asm_var copySizeControl(CPU_SET_32BIT | ((32)/(32/8) & 0x1FFFFF), sec30_variable_list, &curr_section30_index); // CPU_SET_32BIT | ((size)/(32/8) & 0x1FFFFF) + asm_var m4aMPlayStop_ptr(curr_rom.loc_m4aMPlayStop + READ_AS_THUMB, sec30_variable_list, &curr_section30_index); + asm_var gMPlayInfo_BGM_ptr(curr_rom.loc_gMPlayInfo_BGM, sec30_variable_list, &curr_section30_index); + asm_var gMPlayInfo_SE2_ptr(curr_rom.loc_gMPlayInfo_SE2, sec30_variable_list, &curr_section30_index); + asm_var MPlayStart_ptr(curr_rom.loc_MPlayStart + READ_AS_THUMB, sec30_variable_list, &curr_section30_index); + asm_var CreateFanfareTask_ptr(curr_rom.loc_CreateFanfareTask + READ_AS_THUMB, sec30_variable_list, &curr_section30_index); + asm_var sFanfareCounter_ptr(curr_rom.loc_sFanfareCounter, sec30_variable_list, &curr_section30_index); + asm_var gPlttBufferFaded_ptr(curr_rom.loc_gPlttBufferFaded + (32 * 0x1A), sec30_variable_list, &curr_section30_index); // 0x1A is the pallet number + asm_var copySizeControl(CPU_SET_32BIT | ((32) / (32 / 8) & 0x1FFFFF), sec30_variable_list, &curr_section30_index); // CPU_SET_32BIT | ((size)/(32/8) & 0x1FFFFF) + + asm_var flashBuffer_ptr(curr_rom.loc_gSaveDataBuffer, mg_variable_list, &curr_mg_index); + asm_var readFlashSector_ptr(curr_rom.loc_readFlashSector + READ_AS_THUMB, mg_variable_list, &curr_mg_index); asm_var mainAsmStart(sec30_variable_list, &curr_section30_index); asm_var dexAsmStart(sec30_variable_list, &curr_section30_index); asm_var customSoundASM(sec30_variable_list, &curr_section30_index); asm_var loadPalette(sec30_variable_list, &curr_section30_index); + asm_var loadSec30(mg_variable_list, &curr_mg_index); xse_var jumpLoop(mg_variable_list, &curr_mg_index); xse_var jumpBoxFull(mg_variable_list, &curr_mg_index); @@ -74,10 +80,10 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) xse_var jumpNotToSideFull(mg_variable_list, &curr_mg_index); textbox_var textGreet(mg_variable_list, &curr_mg_index); - textbox_var textReceived(mg_variable_list, &curr_mg_index); textbox_var textYouMustBe(mg_variable_list, &curr_mg_index); textbox_var textIAm(mg_variable_list, &curr_mg_index); + textbox_var textReceived(sec30_variable_list, &curr_section30_index); textbox_var textPCFull(sec30_variable_list, &curr_section30_index); textbox_var textThank(sec30_variable_list, &curr_section30_index); textbox_var textTest(sec30_variable_list, &curr_section30_index); @@ -95,6 +101,8 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) movement_var movementLookDown(sec30_variable_list, &curr_section30_index); movement_var movementOutOfWay(sec30_variable_list, &curr_section30_index); movement_var movementInWay(sec30_variable_list, &curr_section30_index); + movement_var movementGoUp(sec30_variable_list, &curr_section30_index); + movement_var movementGoDown(sec30_variable_list, &curr_section30_index); sprite_var spriteLooker(sec30_variable_list, &curr_section30_index); @@ -121,16 +129,37 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) // À = Player name // Ň = New line // ƞ = string terminator - textGreet.set_text(u"I may not look like much now,Ňbut when I was younger…"); - textReceived.set_text(u"ȆÀÁƲÀ’S POKÉMON were sent to theŇPC!"); + switch (curr_rom.gamecode) + { + case RUBY_ID: + textGreet.set_text(u"When I was young, I traveled the worldŇas a POKéMON TRAINER."); + textMoveBox.set_text(u"ȆÀËOh, of course, I have to unlockŇthe door. Silly me!"); + textWeHere.set_text(u"ȆÀËLOOKER: I am here in Hoenn to findŇthe leader Maxie.ȼHowever, in the meantime, I amŇhelping my friend Professor Jazmine.ȼThis is why you are here, no?ȼI shall contact her and tell herŇyou are ready.ŞCome! Allons y!"); + break; + case SAPPHIRE_ID: + textGreet.set_text(u"When I was young, I traveled the worldŇas a POKéMON TRAINER."); + textMoveBox.set_text(u"ȆÀËOh, of course, I have to unlockŇthe door. Silly me!"); + textWeHere.set_text(u"ȆÀËLOOKER: I am here in Hoenn to findŇthe leader Archie.ȼHowever, in the meantime, I amŇhelping my friend Professor Jazmine.ȼThis is why you are here, no?ȼI shall contact her and tell herŇyou are ready.ŞCome! Allons y!"); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + textGreet.set_text(u"I may not look like much now,Ňbut when I was younger…"); + textMoveBox.set_text(u"ȆÀËOh, of course, I have to moveŇthe boxes. Silly me!"); + textWeHere.set_text(u"ȆÀËLOOKER: I am here in the Sevii IslandsŇto find the leader Giovanni.ȼHowever, in the meantime, I amŇhelping my friend Professor Jazmine.ȼThis is why you are here, no?ȼI shall contact her and tell herŇyou are ready.ŞCome! Allons y!"); + break; + case EMERALD_ID: + textGreet.set_text(u"When I was young, I traveled the worldŇas a POKéMON TRAINER."); + textMoveBox.set_text(u"ȆÀËOh, of course, I have to moveŇthe plants. Silly me!"); + textWeHere.set_text(u"ȆÀËLOOKER: I am here in Hoenn to findŇthe leaders Maxie and Archie.ȼHowever, in the meantime, I amŇhelping my friend Professor Jazmine.ȼThis is why you are here, no?ȼI shall contact her and tell herŇyou are ready.ŞCome! Allons y!"); + break; + } + textReceived.set_text(u"ȆÀÁƲÀ’S POKéMON were sent to theŇPC!"); textYouMustBe.set_text(first_time ? u"Ah! You must be ƲÀ!ŇI was told you’d be coming.ȼOh! I still wear my disguise! Pardon!ŇOr, rather, let me introduce myself." : u"Ah, ƲÀ! Welcome back!ŇGood to see you again!ȼOh! I still wear my disguise! Pardon!"); textIAm.set_text(first_time ? u"ȆÀËI am a globe-trotting elite of theŇInternational Police.ȼMy name…ŞAh, no, I shall inform you of myŇcode name only.ȼMy code name, it is LOOKER.ŇIt is how I am called!" : u"ȆÀËIt is I, globe-trotting elite of theŇInternational Police.ȼMy code name, it is LOOKER.ŇIt is how I am called!"); - textWeHere.set_text(u"ȆÀËLOOKER: I am here in Kanto to findŇthe leader Giovanni.ȼHowever, in the meantime, I amŇhelping my friend Professor Jazmine.ȼThis is why you are here, no?ȼI shall contact her and tell herŇyou are ready.ŞCome! Allons y!"); - textMoveBox.set_text(u"ȆÀËOh, of course, I have to moveŇthe boxes. Silly me!"); - textPCConvo.set_text(u"ȆÀÉJAZ: Ah, LOOKER! Good to hear fromŇyou! I take it ƲÀ has arrived?ȼȆÀËLOOKER: Indeed! They’re here andŇready to receive their POKÉMON!ȼȆÀÉJAZ: Excellent! I’ll be sending themŇover momentarily… stand by!"); // ȼDon’t worry ƲÀ,Ňyou won’t have to do a thing!"); + textPCConvo.set_text(u"ȆÀÉJAZ: Ah, LOOKER! Good to hear fromŇyou! I take it ƲÀ has arrived?ȼȆÀËLOOKER: Indeed! They’re here andŇready to receive their POKéMON!ȼȆÀÉJAZ: Excellent! I’ll be sending themŇover momentarily… stand by!"); // ȼDon’t worry ƲÀ,Ňyou won’t have to do a thing!"); textPCThanks.set_text(u"ȆÀÉJAZ: It looks like everything wasŇsent to your PC successfully!ȼThanks again for your help ƲÀ!ŇSee you around, LOOKER!"); textThank.set_text(u"ȆÀËThanks for stopping by, ƲÀ!ȼIf you’ll excuse me, I need toŇreturn to my disguise.ŞUntil our paths cross again!"); - textPCFull.set_text(u"ȆÀÉJAZ: Hm, it seems like the PC is full!ȼGo make some room, and I can sendŇover the rest of your POKÉMON."); + textPCFull.set_text(u"ȆÀÉJAZ: Hm, it seems like the PC is full!ȼGo make some room, and I can sendŇover the rest of your POKéMON."); textLookerFull.set_text(u"ȆÀËLOOKER: Speak to me again afterŇyou’ve made room, ƲÀ!ȼIn the meantime, I will return toŇmy disguise."); const int movementSlowSpinArray[16] = { @@ -190,11 +219,32 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) const int movementExclaimArray[1] = {MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK}; movementExclaim.set_movement(movementExclaimArray, 1); - const int movementToBoxesArray[3] = {MOVEMENT_ACTION_WALK_FAST_UP, MOVEMENT_ACTION_WALK_FAST_UP, MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK}; - movementToBoxes.set_movement(movementToBoxesArray, 3); + const int movementToBoxesArrayRS[4] = {MOVEMENT_ACTION_WALK_FAST_UP, MOVEMENT_ACTION_WALK_FAST_LEFT, MOVEMENT_ACTION_WALK_FAST_UP, MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK}; + const int movementToBoxesArrayFRLG[3] = {MOVEMENT_ACTION_WALK_FAST_UP, MOVEMENT_ACTION_WALK_FAST_UP, MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK}; + const int movementToBoxesArrayE[6] = {MOVEMENT_ACTION_WALK_FAST_UP, MOVEMENT_ACTION_WALK_FAST_LEFT, MOVEMENT_ACTION_WALK_FAST_LEFT, MOVEMENT_ACTION_WALK_FAST_LEFT, MOVEMENT_ACTION_FACE_UP, MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK}; + + const int movementWalkBackArrayRS[3] = {MOVEMENT_ACTION_WALK_FAST_DOWN, MOVEMENT_ACTION_WALK_FAST_RIGHT, MOVEMENT_ACTION_WALK_FAST_DOWN}; + const int movementWalkBackArrayFRLG[2] = {MOVEMENT_ACTION_WALK_FAST_DOWN, MOVEMENT_ACTION_WALK_FAST_DOWN}; + const int movementWalkBackArrayE[4] = {MOVEMENT_ACTION_WALK_FAST_RIGHT, MOVEMENT_ACTION_WALK_FAST_RIGHT, MOVEMENT_ACTION_WALK_FAST_RIGHT, MOVEMENT_ACTION_WALK_FAST_DOWN}; + + switch (curr_rom.gamecode) + { + case RUBY_ID: + case SAPPHIRE_ID: + movementToBoxes.set_movement(movementToBoxesArrayRS, 4); + movementWalkBack.set_movement(movementWalkBackArrayRS, 3); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + movementToBoxes.set_movement(movementToBoxesArrayFRLG, 3); + movementWalkBack.set_movement(movementWalkBackArrayFRLG, 2); + break; + case EMERALD_ID: + movementToBoxes.set_movement(movementToBoxesArrayE, 6); + movementWalkBack.set_movement(movementWalkBackArrayE, 4); + break; + } - const int movementWalkBackArray[2] = {MOVEMENT_ACTION_WALK_FAST_DOWN, MOVEMENT_ACTION_WALK_FAST_DOWN}; - movementWalkBack.set_movement(movementWalkBackArray, 2); const int movementLookDownArray[1] = {MOVEMENT_ACTION_FACE_DOWN}; movementLookDown.set_movement(movementLookDownArray, 1); @@ -204,6 +254,12 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) const int movementInWayArray[2] = {MOVEMENT_ACTION_WALK_FAST_LEFT, MOVEMENT_ACTION_FACE_DOWN}; movementInWay.set_movement(movementInWayArray, 2); + const int movementGoUpArray[1] = {MOVEMENT_ACTION_WALK_FAST_UP}; + movementGoUp.set_movement(movementGoUpArray, 1); + + const int movementGoDownArray[2] = {MOVEMENT_ACTION_WALK_FAST_DOWN, MOVEMENT_ACTION_FACE_UP}; + movementGoDown.set_movement(movementGoDownArray, 2); + // v Instrument songLooker.add_track({0xBC, 0x00, 0xBB, 0x38, 0xBD, 0x38, 0xBE, 0x64, 0xBF, 0x30, 0xD4, 0x37, 0x64, 0x86, 0x3C, 0x86, 0x40, 0x86, 0x43, 0x86, 0x48, 0x86, 0x4C, 0x86, 0xE0, 0x4F, 0x92, 0x4C, 0x92, 0xD4, 0x38, 0x86, 0x3C, 0x86, 0x3F, 0x86, 0x44, 0x86, 0x48, 0x86, 0x4B, 0x86, 0xE0, 0x50, 0x92, 0x4B, 0x92, 0xD4, 0x3A, 0x86, 0x3E, 0x86, 0x41, 0x86, 0x46, 0x86, 0x4A, 0x86, 0x4D, 0x86, 0xE0, 0x52, 0x8C, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0xF2, 0x54, 0xA8, 0xAF, 0x83, 0xB1}); // songLooker.add_track({0xBC, 0x00, 0xBD, 0x3C, 0xBE, 0x5A, 0xBF, 0x50, 0x92, 0xD4, 0x24, 0x64, 0x86, 0x28, 0x86, 0x2B, 0x86, 0xE0, 0x28, 0x92, 0x24, 0x9C, 0xD4, 0x86, 0x27, 0x86, 0x2C, 0x86, 0xE0, 0x27, 0x92, 0x24, 0x9C, 0xD4, 0x26, 0x86, 0x29, 0x86, 0x2E, 0x86, 0xE0, 0x35, 0x8C, 0x86, 0xD4, 0x32, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0xF0, 0x30, 0xA8, 0xAF, 0x83, 0xB1}); @@ -245,6 +301,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) textPCThanks.insert_text(save_section_30); textLookerFull.insert_text(save_section_30); textMoveBox.insert_text(save_section_30); + textReceived.insert_text(save_section_30); movementSlowSpin.insert_movement(save_section_30); movementFastSpin.insert_movement(save_section_30); @@ -254,13 +311,15 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) movementLookDown.insert_movement(save_section_30); movementOutOfWay.insert_movement(save_section_30); movementInWay.insert_movement(save_section_30); + movementGoUp.insert_movement(save_section_30); + movementGoDown.insert_movement(save_section_30); while (curr_section30_index % 4 != 0) { curr_section30_index++; // Align the code so that it is byte aligned } - songLooker.insert_music_data(save_section_30, 0, 0, 0, 0x084950ec); + songLooker.insert_music_data(save_section_30, 0, 0, 0, curr_rom.loc_voicegroup); asm_var customSong(songLooker.get_loc_in_sec30(), sec30_variable_list, &curr_section30_index); asm_var customSongDuration(388, sec30_variable_list, &curr_section30_index); @@ -274,7 +333,9 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) spriteLooker.insert_sprite_data(save_section_30, marioTiles, 256, marioPal); asm_var paletteData(curr_rom.loc_gSaveDataBuffer + (curr_section30_index - 32), sec30_variable_list, &curr_section30_index); - mainAsmStart.set_start(); // Set the memory pointer location for ASM start + asm_payload_location = S30_SCRIPT; + + mainAsmStart.set_start(false); // Set the memory pointer location for ASM start push(rlist_lr); // save the load register to the stack ldr3(r3, curr_pkmn_index_ptr.add_reference()); // set r3 to the pointer to the pokemon index variable ldr1(r3, r3, 0); // set r3 to the value in memory r3 points to @@ -300,7 +361,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) add_word(sendMonToPC_ptr.place_word()); // the location of "SendMonToPC", plus one (so it is interpreted as thumb code) add_word(returned_box_success_ptr.place_word()); // the location of variable "0x8006" (the return value) - dexAsmStart.set_start(); // Note the location where the Dex ASM starts + dexAsmStart.set_start(false); // Note the location where the Dex ASM starts push(rlist_lr); // save the load register to the stack ldr3(r0, currPkmnIndex_ptr.add_reference()); // load the pointer to the index variable into r0 ldr1(r0, r0, 0); // load the value at r0's pointer @@ -330,7 +391,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) add_word(dexSeenCaught_ptr.place_word()); // the location of the DEX_SEEN_CAUGHT variable add_word(setPokedexFlag_ptr.place_word()); // the location of GetSetPokedexFlag, plus one (so it is interpreted as thumb code) - customSoundASM.set_start(); // Note the location where the custom sound ASM starts + customSoundASM.set_start(false); // Note the location where the custom sound ASM starts push(rlist_lr); // save the load register to the stack ldr3(r0, gMPlayInfo_BGM_ptr.add_reference()); // load the gMPlayInfo_BGM function location into r0 ldr3(r2, m4aMPlayStop_ptr.add_reference()); // load the m4aMPlayStop location into r2 @@ -368,33 +429,42 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) add_word(customSong.place_word()); add_word(customSongDuration.place_word()); - loadPalette.set_start(); // Note the location where the custom sound ASM starts - push(rlist_lr); // save the load register to the stack - ldr3(r0, paletteData.add_reference()); // load the paletteData location into r0 - ldr3(r1, gPlttBufferFaded.add_reference()); // load the gPlttBufferFaded location into r1 - ldr3(r2, copySizeControl.add_reference()); // load the copySizeControl location into r2 - mov3(r3, r15); // move r15 (the program counter) to r3 - add2(r3, 5); // add 5 to r3 to compensate for the four following bytes, as well as to tell it to read as THUMB code - mov3(r14, r3); // move r3 into r14 (the load register) - swi(0x0B); // Call the CpuSet SWI for copying data (CpuCopy16) - pop(rlist_r0); // remove r0 from the stack and put it into r0 - bx(r0); // jump to r0 (return to where the function was called) + loadPalette.set_start(false); // Note the location where the custom sound ASM starts + push(rlist_lr); // save the load register to the stack + ldr3(r0, paletteData.add_reference()); // load the paletteData location into r0 + ldr3(r1, gPlttBufferFaded_ptr.add_reference()); // load the gPlttBufferFaded location into r1 + ldr3(r2, copySizeControl.add_reference()); // load the copySizeControl location into r2 + mov3(r3, r15); // move r15 (the program counter) to r3 + add2(r3, 5); // add 5 to r3 to compensate for the four following bytes, as well as to tell it to read as THUMB code + mov3(r14, r3); // move r3 into r14 (the load register) + swi(0x0B); // Call the CpuSet SWI for copying data (CpuCopy16) + pop(rlist_r0); // remove r0 from the stack and put it into r0 + bx(r0); // jump to r0 (return to where the function was called) while (curr_section30_index % 4 != 0) { curr_section30_index++; // Align the code so that it is byte aligned } add_word(paletteData.place_word()); - add_word(gPlttBufferFaded.place_word()); + add_word(gPlttBufferFaded_ptr.place_word()); add_word(copySizeControl.place_word()); + // The start of the Mystery Gift Script + asm_payload_location = MG_SCRIPT; // Located at 0x?8A8 in the .sav init_npc_location(curr_rom.map_bank, curr_rom.map_id, curr_rom.npc_id); // Set the location of the NPC setvirtualaddress(VIRTUAL_ADDRESS); // Set virtual address - callASM(curr_rom.loc_loadSaveSection30 + READ_AS_THUMB); // Load save section 30 into saveDataBuffer - lock(); // Lock the player - faceplayer(); // Have the NPC face the player - virtualmsgbox(textGreet.add_reference(1)); // Start the dialouge + if (curr_rom.gamecode == RUBY_ID || curr_rom.gamecode == SAPPHIRE_ID) + { + callASM(loadSec30.add_reference(1)); + } + else + { + callASM(curr_rom.loc_loadSaveSection30 + READ_AS_THUMB); // Load save section 30 into saveDataBuffer + } + lock(); // Lock the player + faceplayer(); // Have the NPC face the player + virtualmsgbox(textGreet.add_reference(1)); // Start the dialouge waitmsg(); waitkeypress(); applymovement(curr_rom.npc_id, movementExclaim.get_loc_in_sec30()); @@ -409,7 +479,6 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) applymovement(curr_rom.npc_id, movementFastSpin.get_loc_in_sec30()); waitmovement(curr_rom.npc_id); changeSpriteMacro(1, spriteLooker.get_loc_in_sec30()); - // copyPaletteMacro(0xA, marioPal); callASM(loadPalette.get_loc_in_sec30()); changePaletteMacro(curr_rom.npc_id, 0xA); applymovement(curr_rom.npc_id, movementLookDown.get_loc_in_sec30()); @@ -418,8 +487,8 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) virtualmsgbox(textIAm.add_reference(1)); waitmsg(); waitkeypress(); - changeSpriteMacro(1, 0x083a0b08); - changePaletteMacro(curr_rom.npc_id, 0x3); + changeSpriteMacro(1, curr_rom.loc_sPicTable_NPC); + changePaletteMacro(curr_rom.npc_id, curr_rom.npc_palette); applymovement(curr_rom.npc_id, movementFastSpin.get_loc_in_sec30()); waitmovement(curr_rom.npc_id); applymovement(curr_rom.npc_id, movementSlowSpin.get_loc_in_sec30()); @@ -437,17 +506,57 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) waitse(); msgboxMacro(textMoveBox.get_loc_in_sec30()); fadeScreen(1); - // Place the PC - setMetaTile(4, 1, 98, 0); - // Place the boxes - setMetaTile(2, 1, 385, 1); - setMetaTile(2, 2, 386, 0); - special(0x8E); - playse(0xC); + switch (curr_rom.gamecode) + { + case RUBY_ID: + case SAPPHIRE_ID: + setMetaTile(3, 1, 4, 1); + setMetaTile(3, 0, 515, 0); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + setMetaTile(4, 1, 98, 0); + setMetaTile(2, 1, 385, 1); + setMetaTile(2, 2, 386, 0); + break; + case EMERALD_ID: + setMetaTile(3, 1, 4, 1); + setMetaTile(3, 2, 566, 1); + setMetaTile(1, 1, 531, 1); + setMetaTile(1, 2, 539, 0); + applymovement(curr_rom.npc_id, movementGoUp.get_loc_in_sec30()); + break; + } + special(curr_rom.special_DrawWholeMapView); + switch (curr_rom.gamecode) + { + case RUBY_ID: + case SAPPHIRE_ID: + playse(0x2C); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + case EMERALD_ID: + playse(0xC); + break; + } waitse(); fadeScreen(0); - setMetaTile(4, 1, 99, 0); - special(0x8E); + switch (curr_rom.gamecode) + { + case RUBY_ID: + case SAPPHIRE_ID: + setMetaTile(3, 1, 5, 1); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + setMetaTile(4, 1, 99, 0); + break; + case EMERALD_ID: + setMetaTile(3, 1, 5, 1); + break; + } + special(curr_rom.special_DrawWholeMapView); playse(0x2); waitse(); msgboxMacro(textPCConvo.get_loc_in_sec30()); @@ -475,31 +584,70 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) virtualgotoif(COND_LESSTHAN, jumpLoop.add_reference(2)); // if index is less than six, jump to the start of the loop setflag(curr_rom.all_collected_flag); // Set the "all collected" flag fanfare(257); // Play the received fanfare - virtualmsgbox(textReceived.add_reference(1)); // Display the recieved text - waitmsg(); - waitkeypress(); - waitfanfare(); // Wait for the fanfare + msgboxMacro(textReceived.get_loc_in_sec30()); // Display the recieved text + waitfanfare(); // Wait for the fanfare // -- POKEMON INJECTION END -- jumpAllCollected.set_start(); // Set the destination for if all the Pokemon have already been collected msgboxMacro(textPCThanks.get_loc_in_sec30()); // Display the thank text - setMetaTile(4, 1, 98, 0); - special(0x8E); + switch (curr_rom.gamecode) + { + case RUBY_ID: + case SAPPHIRE_ID: + setMetaTile(3, 1, 4, 1); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + setMetaTile(4, 1, 98, 0); + break; + case EMERALD_ID: + setMetaTile(3, 1, 4, 0); + break; + } + special(curr_rom.special_DrawWholeMapView); playse(0x3); waitse(); fadeScreen(1); - // Place the PC - setMetaTile(4, 1, 385, 1); - // Place the boxes - setMetaTile(2, 1, 272, 1); - setMetaTile(2, 2, 273, 0); - special(0x8E); - playse(0xC); + // Place the PC and boxes + switch (curr_rom.gamecode) + { + case RUBY_ID: + case SAPPHIRE_ID: + setMetaTile(3, 1, 661, 1); + setMetaTile(3, 0, 653, 0); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + setMetaTile(4, 1, 385, 1); + setMetaTile(2, 1, 272, 1); + setMetaTile(2, 2, 273, 0); + break; + case EMERALD_ID: + setMetaTile(3, 1, 577, 1); + setMetaTile(3, 2, 539, 1); + setMetaTile(1, 1, 525, 1); + setMetaTile(1, 2, 566, 0); + applymovement(curr_rom.npc_id, movementGoDown.get_loc_in_sec30()); + break; + } + special(curr_rom.special_DrawWholeMapView); + switch (curr_rom.gamecode) + { + case RUBY_ID: + case SAPPHIRE_ID: + playse(0x2C); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + case EMERALD_ID: + playse(0xC); + break; + } waitse(); fadeScreen(0); applymovement(curr_rom.npc_id, movementWalkBack.get_loc_in_sec30()); waitmovement(curr_rom.npc_id); - compare(0x800C, 2); // 0x800C == SpecialVar_Facing + compare(0x800C, 1); // 0x800C == SpecialVar_Facing virtualgotoif(COND_NOTEQUAL, jumpNotToSide.add_reference(2)); applymovement(0xFF, movementInWay.get_loc_in_sec30()); waitmovement(0xFF); @@ -513,7 +661,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) jumpBoxFull.set_start(); // Set the destination for if the box is full msgboxMacro(textPCFull.get_loc_in_sec30()); // Display the thank text setMetaTile(4, 1, 98, 0); - special(0x8E); + special(curr_rom.special_DrawWholeMapView); playse(0x3); waitse(); fadeScreen(1); @@ -522,12 +670,24 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) // Place the boxes setMetaTile(2, 1, 272, 1); setMetaTile(2, 2, 273, 0); - special(0x8E); - playse(0xC); + special(curr_rom.special_DrawWholeMapView); + switch (curr_rom.gamecode) + { + case RUBY_ID: + case SAPPHIRE_ID: + playse(0x2C); + break; + case FIRERED_ID: + case LEAFGREEN_ID: + case EMERALD_ID: + playse(0xC); + break; + } waitse(); fadeScreen(0); applymovement(curr_rom.npc_id, movementWalkBack.get_loc_in_sec30()); waitmovement(curr_rom.npc_id); + compare(0x800C, 1); // 0x800C == SpecialVar_Facing virtualgotoif(COND_NOTEQUAL, jumpNotToSideFull.add_reference(2)); applymovement(0xFF, movementInWay.get_loc_in_sec30()); waitmovement(0xFF); @@ -537,9 +697,26 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data) release(); // Release the player end(); // End the script + while (curr_mg_index % 4 != 0) + { + curr_mg_index++; // Align the code so that it is byte aligned + } + loadSec30.set_start(true); + push(rlist_lr); // save the load register to the stack + mov1(r0, 30); // set r0 to 30 (the sector ID for eReader data) + ldr3(r1, flashBuffer_ptr.add_reference()); // set r1 to the location of "flashBuffer" plus one, since it is thumb code + ldr3(r2, readFlashSector_ptr.add_reference()); // set r2 to the location of "readFlashSector" plus one, since it is thumb code + mov3(r3, r15); // move r15 (the program counter) to r3 + add2(r3, 5); // add 5 to r3 to compensate for the four following bytes, plus to tell the system to read as thumb code + mov3(r14, r3); // move r3 into r14 (the load register) + bx(r2); // jump to the pointer stored in r2 (readFlashSector) + pop(rlist_r0); // remove r0 from the stack and put it into r0 + bx(r0); // go to r0 + add_word(flashBuffer_ptr.place_word()); + add_word(readFlashSector_ptr.place_word()); + textGreet.insert_virtual_text(mg_script); textYouMustBe.insert_virtual_text(mg_script); - textReceived.insert_virtual_text(mg_script); textIAm.insert_virtual_text(mg_script); for (unsigned int i = 0; i < mg_variable_list.size(); i++) // Fill all the refrences for script variables in the mg @@ -635,9 +812,18 @@ u16 mystery_gift_script::calc_crc16() // Implementation taken from PokeEmerald D void mystery_gift_script::add_asm(u16 command) { - save_section_30[curr_section30_index] = command >> 0; - save_section_30[curr_section30_index + 1] = command >> 8; - curr_section30_index += 2; + if (asm_payload_location == S30_SCRIPT) + { + save_section_30[curr_section30_index] = command >> 0; + save_section_30[curr_section30_index + 1] = command >> 8; + curr_section30_index += 2; + } + else + { + mg_script[curr_mg_index] = command >> 0; + mg_script[curr_mg_index + 1] = command >> 8; + curr_mg_index += 2; + } } // Scripting commands: @@ -961,23 +1147,15 @@ void mystery_gift_script::msgboxMacro(u32 location) void mystery_gift_script::changeSpriteMacro(u8 npcId, u32 spriteTablePtr) { - writebytetooffset(spriteTablePtr >> 0, 0x0202063c + (0x44 * npcId) + 0xC + 0); - writebytetooffset(spriteTablePtr >> 8, 0x0202063c + (0x44 * npcId) + 0xC + 1); - writebytetooffset(spriteTablePtr >> 16, 0x0202063c + (0x44 * npcId) + 0xC + 2); - writebytetooffset(spriteTablePtr >> 24, 0x0202063c + (0x44 * npcId) + 0xC + 3); -} - -void mystery_gift_script::copyPaletteMacro(u8 palNum, const unsigned short palette_array[]) -{ - for (int i = 0; i < 32; i++) - { - writebytetooffset(palette_array[i / 2] >> (8 * (i % 2)), 0x020375f8 + 0x200 + (32 * palNum) + i); - } + writebytetooffset(spriteTablePtr >> 0, curr_rom.loc_gSprites + (0x44 * npcId) + 0xC + 0); + writebytetooffset(spriteTablePtr >> 8, curr_rom.loc_gSprites + (0x44 * npcId) + 0xC + 1); + writebytetooffset(spriteTablePtr >> 16, curr_rom.loc_gSprites + (0x44 * npcId) + 0xC + 2); + writebytetooffset(spriteTablePtr >> 24, curr_rom.loc_gSprites + (0x44 * npcId) + 0xC + 3); } void mystery_gift_script::changePaletteMacro(u8 npcId, u8 palNum) { - writebytetooffset((palNum << 4) | 0x08, 0x0202063c + (0x44 * npcId) + 0x5); + writebytetooffset((palNum << 4) | 0x08, curr_rom.loc_gSprites + (0x44 * npcId) + 0x5); } // ASM Commands @@ -1150,22 +1328,3 @@ void mystery_gift_script::add_word(u32 word) add_asm(word >> 0); add_asm(word >> 16); } - -void mystery_gift_script::four_align() -{ - // while(curr_index % 4 != 0) - for (int i = 0; i < curr_mg_index % 4; i++) - { - mg_script[curr_mg_index] = 0xAA; - curr_mg_index++; - four_align_value++; - } -} - -void mystery_gift_script::add_padding() -{ - if (curr_mg_index % 4 != 0) - { - add_asm(0x0000); - } -} diff --git a/source/payload_builder.cpp b/source/payload_builder.cpp index e04ef7a..7a48d82 100644 --- a/source/payload_builder.cpp +++ b/source/payload_builder.cpp @@ -1088,11 +1088,11 @@ void write_call(int generation, byte array_data[], int &offset, word call_locati } }; -int test_main() // Rename to "main" to send the payload to test_payload.txt +int main() // Rename to "main" to send the payload to test_payload.txt { freopen("test_payload.txt", "w", stdout); std::cout << std::endl; - byte *payload = generate_payload(ENG_GOLD, true); + byte *payload = generate_payload(ENG_YELLOW, true); for (int i = 0; i < PAYLOAD_SIZE; i++) { std::cout << "0x" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned int)payload[i] << ", "; diff --git a/source/rom_data.cpp b/source/rom_data.cpp index 4d37c9b..1ba8356 100644 --- a/source/rom_data.cpp +++ b/source/rom_data.cpp @@ -57,16 +57,27 @@ void rom_data::fill_values(const ROM_DATA *rom_values) loc_sendMonToPC = rom_values->loc_copyMonToPC; loc_gSpecialVar_0x8000 = rom_values->loc_gSpecialVar_0x8000; loc_gSaveBlock1 = rom_values->loc_gSaveBlock1; - loc_gSaveBlock1PTR = rom_values->loc_gSaveBlock1PTR; loc_setPokedexFlag = rom_values->loc_getSetPokedexFlag; loc_gSaveDataBuffer = rom_values->loc_gSaveDataBuffer; loc_readFlashSector = rom_values->loc_readFlashSector; loc_loadSaveSection30 = rom_values->loc_loadSaveSection30; + loc_m4aMPlayStop = rom_values->loc_m4aMPlayStop; + loc_gMPlayInfo_BGM = rom_values->loc_gMPlayInfo_BGM; + loc_gMPlayInfo_SE2 = rom_values->loc_gMPlayInfo_SE2; + loc_MPlayStart = rom_values->loc_MPlayStart; + loc_CreateFanfareTask = rom_values->loc_CreateFanfareTask; + loc_sFanfareCounter = rom_values->loc_sFanfareCounter; + loc_gPlttBufferFaded = rom_values->loc_gPlttBufferFaded; + loc_gSprites = rom_values->loc_gSprites; + loc_voicegroup = rom_values->loc_voicegroup; + loc_sPicTable_NPC = rom_values->loc_sPicTable_NPC; + offset_ramscript = rom_values->offset_ramscript; offset_flags = rom_values->offset_flags; offset_wondercard = rom_values->offset_wondercard; offset_script = rom_values->offset_script; text_region = rom_values->text_region; + special_DrawWholeMapView = rom_values->special_DrawWholeMapView; e4_flag = rom_values->e4_flag; // The flag that is set when you become champion. Often listed as "GAME_CLEAR" mg_flag = rom_values->mg_flag; // The flag that is set when you enable Mystery Gift. Known as "EXDATA_ENABLE" in RS @@ -77,6 +88,7 @@ void rom_data::fill_values(const ROM_DATA *rom_values) map_bank = (DEBUG_MODE ? rom_values->test_map_bank : rom_values->map_bank); map_id = (DEBUG_MODE ? rom_values->test_map_id : rom_values->map_id); npc_id = (DEBUG_MODE ? rom_values->test_npc_id : rom_values->npc_id); + npc_palette = rom_values->npc_palette; def_map_bank = rom_values->def_map_bank; def_map_id = rom_values->def_map_id; diff --git a/source/script_var.cpp b/source/script_var.cpp index cc13a8e..edf7cd6 100644 --- a/source/script_var.cpp +++ b/source/script_var.cpp @@ -47,11 +47,23 @@ void script_var::fill_refrences(u8 mg_array[]) void asm_var::set_start() { start_location_in_script = *curr_loc_ptr - 2; + isDirect = false; +} + +void asm_var::set_start(bool nIsDirect) +{ + start_location_in_script = *curr_loc_ptr - 2; + isDirect = nIsDirect; } u8 asm_var::add_reference() { - location_list.push_back(*curr_loc_ptr); + return add_reference(0); +} + +u8 asm_var::add_reference(int nCommand_offset) +{ + location_list.push_back(*curr_loc_ptr + nCommand_offset); return 0x00; } @@ -59,7 +71,17 @@ void asm_var::fill_refrences(u8 mg_array[]) { for (unsigned int i = 0; i < location_list.size(); i++) { - mg_array[location_list[i]] += ((start_location_in_script - location_list[i]) / 4) & 0xFF; + if (isDirect) + { + for (int j = 0; j < 4; j++) + { + mg_array[location_list[i] + j] += (start_location_in_script + curr_rom.loc_gSaveBlock1 + curr_rom.offset_ramscript + 7) >> (j * 8); + } + } + else + { + mg_array[location_list[i]] += ((start_location_in_script - location_list[i]) / 4) & 0xFF; + } } } @@ -133,8 +155,16 @@ void textbox_var::insert_text(u8 mg_array[]) set_start(); for (unsigned int parser = 0; parser < text.length(); parser++) { - mg_array[*curr_loc_ptr] = get_gen_3_char((char16_t)(text.at(parser)), false); - (*curr_loc_ptr)++; + byte character = get_gen_3_char((char16_t)(text.at(parser)), false); + if (curr_rom.is_hoenn() && (character == 0xFC) && (get_gen_3_char((char16_t)(text.at(parser + 1)), false) == 0x01)) // Removes colored text + { + parser += 2; + } + else + { + mg_array[*curr_loc_ptr] = character; + (*curr_loc_ptr)++; + } } mg_array[*curr_loc_ptr] = 0xFF; // End string (*curr_loc_ptr)++; @@ -145,8 +175,16 @@ void textbox_var::insert_virtual_text(u8 mg_array[]) set_virtual_start(); for (unsigned int parser = 0; parser < text.length(); parser++) { - mg_array[*curr_loc_ptr] = get_gen_3_char((char16_t)(text.at(parser)), false); - (*curr_loc_ptr)++; + byte character = get_gen_3_char((char16_t)(text.at(parser)), false); + if (curr_rom.is_hoenn() && (character == 0xFC) && (get_gen_3_char((char16_t)(text.at(parser + 1)), false) == 0x01)) // Removes colored text + { + parser += 2; + } + else + { + mg_array[*curr_loc_ptr] = character; + (*curr_loc_ptr)++; + } } mg_array[*curr_loc_ptr] = 0xFF; // End string (*curr_loc_ptr)++; diff --git a/source/test_payload.txt b/source/test_payload.txt index fc680de..8e21ef1 100644 --- a/source/test_payload.txt +++ b/source/test_payload.txt @@ -1,85 +1,85 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, # 0x10 -0xFD, 0xFD, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0xFD, 0xFD, 0x85, 0x84, 0x8D, 0x8D, 0x84, 0x8B, 0x50, 0x50, 0x50, 0x50, 0x50, 0x06, 0x15, 0x15, # 0x20 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x30 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x40 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x50 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x60 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x70 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x80 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x90 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0xA0 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0xB0 -0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0xC0 -0x80, 0x80, 0x80, 0xD6, 0xC5, 0x50, 0x3E, 0x05, 0xD7, 0xCD, 0xF6, 0x4D, 0xC3, 0xB0, 0x05, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0xD0 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0xE0 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0xF0 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x100 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x110 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x120 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x130 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0xC8, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x140 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x150 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x160 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, # 0x170 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0xE3, 0xFF, # 0x180 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0xC2, 0x00, 0xCD, 0xCB, 0x1F, 0x3E, 0x1C, 0xCD, 0x7E, 0x3E, 0xCD, 0xFC, 0x79, 0x00, 0x00, # 0x190 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xCD, 0x24, 0x7A, 0xC3, 0xD6, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xAA, # 0x1A0 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xFF, 0x36, 0x02, 0x00, 0x00, 0x00, 0x00, 0x21, 0x61, 0x01, 0x11, 0xD0, 0xC5, 0x18, 0xD1, 0x00, # 0x1B0 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFF, 0xFF, 0x3E, 0x01, 0xCD, 0x7E, 0x3E, # 0x1C0 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xCD, 0xDD, 0x16, 0x21, 0x2E, 0xC4, 0x06, 0x03, 0x0E, 0x0E, 0xCD, 0x67, 0x5B, 0x21, 0x43, 0xC4, # 0x1D0 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFF, 0xFF, 0xCD, 0xE2, +0x11, 0x7A, 0xC6, 0xCD, 0x23, 0x17, 0x21, 0xAA, 0xFF, 0x36, 0x02, 0x21, 0x7E, 0xDA, 0x36, 0xFD, # 0x1E0 -0x0E, 0x21, 0x2E, 0xC4, 0x06, 0x03, 0x0E, 0x0E, 0x3E, 0x0A, 0xD7, 0xCD, 0x88, 0x4D, 0x21, 0x43, +0x11, 0x7D, 0xDA, 0x01, 0x64, 0x04, 0x00, 0x00, 0x00, 0x21, 0xAA, 0xFF, 0x36, 0x02, 0x21, 0x61, # 0x1F0 -0xC4, 0x11, 0x7A, 0xC6, 0xCD, 0x74, 0x0F, 0x21, 0xCD, 0xFF, 0x36, 0x02, 0x3E, 0x01, 0xCD, 0xE1, +0x01, 0x11, 0x51, 0xC6, 0x01, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x21, 0x94, 0xCF, 0x36, 0x01, 0xFA, # 0x200 -0x30, 0x21, 0x6B, 0xAD, 0x36, 0xFD, 0x11, 0x6A, 0xAD, 0x01, 0x50, 0x04, 0xCD, 0x10, 0x07, 0x21, +0x50, 0xC6, 0x5F, 0x16, 0x00, 0x21, 0x51, 0xC6, 0x19, 0x1E, 0xFF, 0x3C, 0xEA, 0x50, 0xC6, 0xFA, # 0x210 -0xCD, 0xFF, 0x36, 0x02, 0x21, 0x54, 0x06, 0x11, 0x51, 0xC6, 0x01, 0x1E, 0x00, 0x00, 0x00, 0x00, +0x7F, 0xDA, 0x47, 0x2A, 0xBB, 0x28, 0x0C, 0xB8, 0x30, 0xE5, 0x21, 0x91, 0xCF, 0x77, 0xCD, 0x0F, # 0x220 -0x21, 0x08, 0xD0, 0x36, 0x01, 0xFA, 0x50, 0xC6, 0x5F, 0x16, 0x00, 0x21, 0x51, 0xC6, 0x19, 0x3C, +0x7A, 0x18, 0xDC, 0x3E, 0x1C, 0xCD, 0x7E, 0x3E, 0xCD, 0x32, 0x7B, 0xCD, 0x56, 0x7B, 0xC3, 0x05, # 0x230 -0xEA, 0x50, 0xC6, 0xFA, 0x6C, 0xAD, 0x47, 0x2A, 0xFE, 0xFF, 0x28, 0x0F, 0xB8, 0x30, 0xE6, 0x21, +0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, # 0x240 -0x05, 0xD0, 0x77, 0x3E, 0x03, 0xD7, 0xCD, 0x3F, 0x60, 0x18, 0xDA, 0xC3, 0xB4, 0xC7, 0x00, 0x00, +0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, # 0x250 -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, +0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x93, # 0x260 -0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, +0x91, 0x80, 0x8D, 0x92, 0x85, 0x84, 0x91, 0x91, 0x88, 0x8D, 0x86, 0xF2, 0xF2, 0x4E, 0x7F, 0x8F, # 0x270 -0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0x8B, 0x84, 0x80, 0x92, 0x84, 0x7F, 0x96, 0x80, 0x88, 0x93, 0xE7, 0x7F, 0x50, 0x00, 0x00, 0x00, # 0x280 -0xFF, 0xFF, 0x93, 0x91, 0x80, 0x8D, 0x92, 0x85, 0x84, 0x91, 0x91, 0x88, 0x8D, 0x86, 0xF2, 0xF2, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 0x290 -0x4E, 0x7F, 0x8F, 0x8B, 0x84, 0x80, 0x92, 0x84, 0x7F, 0x96, 0x80, 0x88, 0x93, 0xE7, 0x7F, 0x50, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 0x2A0