diff options
author | Swastik Baranwal <swstkbaranwal@gmail.com> | 2019-06-23 18:47:35 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-23 18:47:35 +0530 |
commit | 99703c6ab831d34e6859d8a8f53ba8e73dc4d3d9 (patch) | |
tree | 3a712d3039d152616af58a45a13d82c40a87e58f /src | |
parent | 6d190f861e3559eec922cd760778c0cba6e08397 (diff) | |
parent | 9ee0c34758a63f8c00724b6fc984b4e96be2f7af (diff) |
Merge pull request #5 from pret/master
Take files
Diffstat (limited to 'src')
76 files changed, 39130 insertions, 2036 deletions
diff --git a/src/bag.c b/src/bag.c new file mode 100644 index 000000000..f2fc40d93 --- /dev/null +++ b/src/bag.c @@ -0,0 +1,321 @@ +#include "global.h" +#include "task.h" +#include "palette.h" +#include "item_menu.h" +#include "text.h" +#include "window.h" +#include "text_window.h" +#include "menu_helpers.h" +#include "menu.h" +#include "money.h" +#include "bag.h" + +extern const u8 gText_DepositItem[]; + +const u16 gUnknown_8453098[] = INCBIN_U16("data/bag/bag_window_pal.gbapal"); +const struct TextColor gUnknown_84530B8[] = { + {0, 1, 2}, + {0, 2, 3}, + {0, 3, 2}, + {0, 8, 9} +}; +const struct WindowTemplate gUnknown_84530C4[] = { + { + .bg = 0, + .tilemapLeft = 0x0b, + .tilemapTop = 0x01, + .width = 0x12, + .height = 0x0c, + .paletteNum = 0x0f, + .baseBlock = 0x008a + }, { + .bg = 0, + .tilemapLeft = 0x05, + .tilemapTop = 0x0e, + .width = 0x19, + .height = 0x06, + .paletteNum = 0x0f, + .baseBlock = 0x0162 + }, { + .bg = 0, + .tilemapLeft = 0x01, + .tilemapTop = 0x01, + .width = 0x09, + .height = 0x02, + .paletteNum = 0x0f, + .baseBlock = 0x01f8 + }, DUMMY_WIN_TEMPLATE +}; +const struct WindowTemplate gUnknown_84530E4[] = { + { + .bg = 0, + .tilemapLeft = 0x0b, + .tilemapTop = 0x01, + .width = 0x12, + .height = 0x0c, + .paletteNum = 0x0f, + .baseBlock = 0x008a + }, { + .bg = 0, + .tilemapLeft = 0x05, + .tilemapTop = 0x0e, + .width = 0x19, + .height = 0x06, + .paletteNum = 0x0f, + .baseBlock = 0x0162 + }, { + .bg = 0, + .tilemapLeft = 0x01, + .tilemapTop = 0x01, + .width = 0x08, + .height = 0x02, + .paletteNum = 0x0C, + .baseBlock = 0x01f8 + }, DUMMY_WIN_TEMPLATE +}; +const struct WindowTemplate gUnknown_8453104[] = { + { + .bg = 0, + .tilemapLeft = 24, + .tilemapTop = 15, + .width = 5, + .height = 4, + .paletteNum = 0xF, + .baseBlock = 0x242 + }, { + .bg = 0, + .tilemapLeft = 17, + .tilemapTop = 9, + .width = 12, + .height = 4, + .paletteNum = 0xF, + .baseBlock = 0x242 + }, { + .bg = 0, + .tilemapLeft = 1, + .tilemapTop = 1, + .width = 8, + .height = 3, + .paletteNum = 0xC, + .baseBlock = 0x272 + } +}; + +const struct WindowTemplate gUnknown_845311C = { + .bg = 0, + .tilemapLeft = 23, + .tilemapTop = 15, + .width = 6, + .height = 4, + .paletteNum = 0xF, + .baseBlock = 0x28a +}; + +const struct WindowTemplate gUnknown_8453124 = { + .bg = 0, + .tilemapLeft = 21, + .tilemapTop = 9, + .width = 6, + .height = 4, + .paletteNum = 0xF, + .baseBlock = 0x28a +}; + +const struct WindowTemplate gUnknown_845312C[] = { + { + .bg = 0x00, + .tilemapLeft = 0x02, + .tilemapTop = 0x0f, + .width = 0x1a, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x02a2 + }, { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x0f, + .width = 0x0e, + .height = 0x04, + .paletteNum = 0x0c, + .baseBlock = 0x02a2 + }, { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x0f, + .width = 0x0f, + .height = 0x04, + .paletteNum = 0x0c, + .baseBlock = 0x02da + }, { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x0f, + .width = 0x10, + .height = 0x04, + .paletteNum = 0x0c, + .baseBlock = 0x0316 + }, { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x0f, + .width = 0x17, + .height = 0x04, + .paletteNum = 0x0c, + .baseBlock = 0x0356 + }, { + .bg = 0x00, + .tilemapLeft = 0x16, + .tilemapTop = 0x11, + .width = 0x07, + .height = 0x02, + .paletteNum = 0x0f, + .baseBlock = 0x020a + }, { + .bg = 0x00, + .tilemapLeft = 0x16, + .tilemapTop = 0x0f, + .width = 0x07, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x020a + }, { + .bg = 0x00, + .tilemapLeft = 0x16, + .tilemapTop = 0x0d, + .width = 0x07, + .height = 0x06, + .paletteNum = 0x0f, + .baseBlock = 0x020a + }, { + .bg = 0x00, + .tilemapLeft = 0x16, + .tilemapTop = 0x0b, + .width = 0x07, + .height = 0x08, + .paletteNum = 0x0f, + .baseBlock = 0x020a + } +}; + +const u8 gUnknown_8453174[] = {16, 8, 4}; + +EWRAM_DATA u8 gUnknown_203AD34[11] = {}; + +void sub_810B858(void) +{ + u8 i; + + if (gUnknown_203ACFC.location != 3) + InitWindows(gUnknown_84530C4); + else + InitWindows(gUnknown_84530E4); + DeactivateAllTextPrinters(); + TextWindow_SetUserSelectedFrame(0, 0x64, 0xE0); + TextWindow_SetBubbleFrame_841F1C8(0, 0x6D, 0xD0); + TextWindow_SetStdFrame0_WithPal(0, 0x81, 0xC0); + LoadPalette(gUnknown_8453098, 0xF0, 0x20); + for (i = 0; i < 3; i++) + { + FillWindowPixelBuffer(i, 0x00); + PutWindowTilemap(i); + } + schedule_bg_copy_tilemap_to_vram(0); + for (i = 0; i < 11; i++) + { + gUnknown_203AD34[i] = 0xFF; + } +} + +void sub_810B8F0(u8 windowId, u8 fontId, const u8 * str, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, s8 speed, u8 colorIdx) +{ + AddTextPrinterParameterized4(windowId, fontId, x, y, letterSpacing, lineSpacing, &gUnknown_84530B8[colorIdx], speed, str); +} + +void sub_810B958(const u8 * str) +{ + u32 x = 0x48 - GetStringWidth(1, str, 0); + AddTextPrinterParameterized3(2, 1, x / 2, 1, &gUnknown_84530B8[0], 0, str); +} + +void sub_810B994(void) +{ + u32 x; + SetWindowBorderStyle(2, FALSE, 0x081, 0x0C); + x = 0x40 - GetStringWidth(0, gText_DepositItem, 0); + AddTextPrinterParameterized(2, 0, gText_DepositItem, x / 2, 1, 0, NULL); +} + +u8 sub_810B9DC(u8 a0, u8 a1) +{ + if (gUnknown_203AD34[a0] == 0xFF) + { + gUnknown_203AD34[a0] = AddWindow(&gUnknown_8453104[a0 + a1]); + if (a0 != 6) + { + SetWindowBorderStyle(gUnknown_203AD34[a0], FALSE, 0x064, 0x0E); + } + else + { + SetWindowBorderStyle(gUnknown_203AD34[a0], FALSE, 0x081, 0x0C); + } + schedule_bg_copy_tilemap_to_vram(0); + } + return gUnknown_203AD34[a0]; +} + +void sub_810BA3C(u8 a0) +{ + ClearMenuWindow(gUnknown_203AD34[a0], FALSE); + ClearWindowTilemap(gUnknown_203AD34[a0]); + RemoveWindow(gUnknown_203AD34[a0]); + schedule_bg_copy_tilemap_to_vram(0); + gUnknown_203AD34[a0] = 0xFF; +} + +u8 sub_810BA70(u8 a0) +{ + if (gUnknown_203AD34[a0] == 0xFF) + { + gUnknown_203AD34[a0] = AddWindow(&gUnknown_8453104[a0]); + } + return gUnknown_203AD34[a0]; +} + +void sub_810BA9C(u8 a0) +{ + if (gUnknown_203AD34[a0] != 0xFF) + { + ClearMenuWindow_BorderThickness2(gUnknown_203AD34[a0], FALSE); + ClearWindowTilemap(gUnknown_203AD34[a0]); + RemoveWindow(gUnknown_203AD34[a0]); + PutWindowTilemap(1); + schedule_bg_copy_tilemap_to_vram(0); + gUnknown_203AD34[a0] = 0xFF; + + } +} + +u8 sub_810BAD8(u8 a0) +{ + return gUnknown_203AD34[a0]; +} + +void sub_810BAE8(u8 taskId, const struct YesNoFuncTable * ptrs) +{ + CreateYesNoMenuWithCallbacks(taskId, &gUnknown_845311C, 2, 0, 2, 0x64, 0x0E, ptrs); +} + +void sub_810BB14(u8 taskId, const struct YesNoFuncTable * ptrs) +{ + CreateYesNoMenuWithCallbacks(taskId, &gUnknown_8453124, 2, 0, 2, 0x064, 0x0E, ptrs); +} + +void sub_810BB40(void) +{ + PrintMoneyAmountInMoneyBoxWithBorder(sub_810B9DC(2, 0), 0x081, 0x0C, GetMoney(&gSaveBlock1Ptr->money)); +} + +void sub_810BB74(u8 windowId) +{ + DrawTextBorderOuter(windowId, 0x064, 0x0E); +} diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 6f5577f70..6343b55cd 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -1623,7 +1623,7 @@ static void BattleAICmd_if_status_not_in_party(void) enum { - WEATHER_TYPE_SUN, + WEATHER_TYPE_SUNNY, WEATHER_TYPE_RAIN, WEATHER_TYPE_SANDSTORM, WEATHER_TYPE_HAIL, @@ -1637,8 +1637,8 @@ static void BattleAICmd_get_weather(void) AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_RAIN; if (gBattleWeather & WEATHER_SANDSTORM_ANY) AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_SANDSTORM; - if (gBattleWeather & WEATHER_SUN_ANY) - AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_SUN; + if (gBattleWeather & WEATHER_SUNNY_ANY) + AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_SUNNY; if (gBattleWeather & WEATHER_HAIL) AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_HAIL; diff --git a/src/battle_anim_mon_movement.c b/src/battle_anim_mon_movement.c new file mode 100644 index 000000000..27e6ef28c --- /dev/null +++ b/src/battle_anim_mon_movement.c @@ -0,0 +1,809 @@ +#include "global.h" +#include "battle.h" +#include "battle_anim.h" +#include "task.h" +#include "trig.h" + +#define abs(x) ((x) < 0 ? -(x) : (x)) + +void sub_8098A6C(u8 taskId); +void sub_8098C08(u8 taskId); +void sub_8098D54(u8 taskId); +void sub_8098EF0(u8 taskId); +void sub_8099004(u8 taskId); +void sub_80990AC(struct Sprite * sprite); +void sub_8099120(struct Sprite * sprite); +void sub_8099144(struct Sprite * sprite); +void sub_8099190(struct Sprite * sprite); +void sub_80991B4(struct Sprite * sprite); +void sub_8099270(struct Sprite * sprite); +void sub_80992E0(struct Sprite * sprite); +void sub_8099394(struct Sprite * sprite); +void sub_809946C(struct Sprite * sprite); +void sub_8099530(u8 taskId); +void sub_8099594(u8 taskId); +void sub_80996B8(u8 taskId); +void sub_8099788(u8 taskId); +void sub_8099908(u8 taskId); +void sub_8099B54(u8 taskId); +void sub_8099CB8(u8 taskId); + +const struct SpriteTemplate gUnknown_83D4E4C[] = { + { + 0, 0, &gDummyOamData, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, sub_80990AC + }, { + 0, 0, &gDummyOamData, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, sub_8099144 + }, { + 0, 0, &gDummyOamData, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, sub_80991B4 + }, { + 0, 0, &gDummyOamData, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, sub_80992E0 + }, { + 0, 0, &gDummyOamData, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, sub_8099394 + } +}; + +void sub_80989F8(u8 taskId) +{ + u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]); + + if (spriteId == 0xFF) + DestroyAnimVisualTask(taskId); + else + { + gSprites[spriteId].pos2.x = gBattleAnimArgs[1]; + gSprites[spriteId].pos2.y = gBattleAnimArgs[2]; + gTasks[taskId].data[0] = spriteId; + gTasks[taskId].data[1] = gBattleAnimArgs[3]; + gTasks[taskId].data[2] = gBattleAnimArgs[4]; + gTasks[taskId].data[3] = gBattleAnimArgs[4]; + gTasks[taskId].data[4] = gBattleAnimArgs[1]; + gTasks[taskId].data[5] = gBattleAnimArgs[2]; + gTasks[taskId].func = sub_8098A6C; + gTasks[taskId].func(taskId); + } +} + +void sub_8098A6C(u8 taskId) +{ + if (gTasks[taskId].data[3] == 0) + { + if (gSprites[gTasks[taskId].data[0]].pos2.x == 0) + gSprites[gTasks[taskId].data[0]].pos2.x = gTasks[taskId].data[4]; + else + gSprites[gTasks[taskId].data[0]].pos2.x = 0; + if (gSprites[gTasks[taskId].data[0]].pos2.y == 0) + gSprites[gTasks[taskId].data[0]].pos2.y = gTasks[taskId].data[5]; + else + gSprites[gTasks[taskId].data[0]].pos2.y = 0; + gTasks[taskId].data[3] = gTasks[taskId].data[2]; + if (--gTasks[taskId].data[1] == 0) + { + gSprites[gTasks[taskId].data[0]].pos2.x = 0; + gSprites[gTasks[taskId].data[0]].pos2.y = 0; + DestroyAnimVisualTask(taskId); + } + } + else + gTasks[taskId].data[3]--; +} + +void sub_8098B1C(u8 taskId) +{ + bool8 abort = FALSE; + u8 spriteId; + u8 battlerId; + + if (gBattleAnimArgs[0] < MAX_BATTLERS_COUNT) + { + spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]); + if (spriteId == 0xFF) + abort = TRUE; + } + else if (gBattleAnimArgs[0] != 8) + { + switch (gBattleAnimArgs[0]) + { + case 4: + battlerId = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + break; + case 5: + battlerId = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + break; + case 6: + battlerId = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + break; + default: + battlerId = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + break; + } + if (!sub_8072DF0(battlerId)) + abort = TRUE; + spriteId = gBattlerSpriteIds[battlerId]; + } + else + spriteId = gBattlerSpriteIds[gBattleAnimAttacker]; + if (abort) + DestroyAnimVisualTask(taskId); + else + { + gSprites[spriteId].pos2.x = gBattleAnimArgs[1]; + gSprites[spriteId].pos2.y = gBattleAnimArgs[2]; + gTasks[taskId].data[0] = spriteId; + gTasks[taskId].data[1] = gBattleAnimArgs[3]; + gTasks[taskId].data[2] = gBattleAnimArgs[4]; + gTasks[taskId].data[3] = gBattleAnimArgs[4]; + gTasks[taskId].data[4] = gBattleAnimArgs[1]; + gTasks[taskId].data[5] = gBattleAnimArgs[2]; + gTasks[taskId].func = sub_8098C08; + gTasks[taskId].func(taskId); + } +} + +void sub_8098C08(u8 taskId) +{ + if (gTasks[taskId].data[3] == 0) + { + if (gSprites[gTasks[taskId].data[0]].pos2.x == gTasks[taskId].data[4]) + gSprites[gTasks[taskId].data[0]].pos2.x = -gTasks[taskId].data[4]; + else + gSprites[gTasks[taskId].data[0]].pos2.x = gTasks[taskId].data[4]; + if (gSprites[gTasks[taskId].data[0]].pos2.y == gTasks[taskId].data[5]) + gSprites[gTasks[taskId].data[0]].pos2.y = -gTasks[taskId].data[5]; + else + gSprites[gTasks[taskId].data[0]].pos2.y = gTasks[taskId].data[5]; + gTasks[taskId].data[3] = gTasks[taskId].data[2]; + if (--gTasks[taskId].data[1] == 0) + { + gSprites[gTasks[taskId].data[0]].pos2.x = 0; + gSprites[gTasks[taskId].data[0]].pos2.y = 0; + DestroyAnimVisualTask(taskId); + } + } + else + gTasks[taskId].data[3]--; +} + +void sub_8098CD0(u8 taskId) +{ + u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]); + + if (spriteId == 0xFF) + DestroyAnimVisualTask(taskId); + else + { + gSprites[spriteId].pos2.x += gBattleAnimArgs[1]; + gSprites[spriteId].pos2.y += gBattleAnimArgs[2]; + gTasks[taskId].data[0] = spriteId; + gTasks[taskId].data[1] = 0; + gTasks[taskId].data[2] = gBattleAnimArgs[3]; + gTasks[taskId].data[3] = 0; + gTasks[taskId].data[4] = gBattleAnimArgs[4]; + gTasks[taskId].data[5] = gBattleAnimArgs[1] * 2; + gTasks[taskId].data[6] = gBattleAnimArgs[2] * 2; + gTasks[taskId].func = sub_8098D54; + gTasks[taskId].func(taskId); + } +} + +void sub_8098D54(u8 taskId) +{ + if (gTasks[taskId].data[3] == 0) + { + if (gTasks[taskId].data[1] & 1) + { + gSprites[gTasks[taskId].data[0]].pos2.x += gTasks[taskId].data[5]; + gSprites[gTasks[taskId].data[0]].pos2.y += gTasks[taskId].data[6]; + } + else + { + gSprites[gTasks[taskId].data[0]].pos2.x -= gTasks[taskId].data[5]; + gSprites[gTasks[taskId].data[0]].pos2.y -= gTasks[taskId].data[6]; + } + gTasks[taskId].data[3] = gTasks[taskId].data[4]; + if (++gTasks[taskId].data[1] >= gTasks[taskId].data[2]) + { + if (gTasks[taskId].data[1] & 1) + { + gSprites[gTasks[taskId].data[0]].pos2.x += gTasks[taskId].data[5] / 2; + gSprites[gTasks[taskId].data[0]].pos2.y += gTasks[taskId].data[6] / 2; + } + else + { + gSprites[gTasks[taskId].data[0]].pos2.x -= gTasks[taskId].data[5] / 2; + gSprites[gTasks[taskId].data[0]].pos2.y -= gTasks[taskId].data[6] / 2; + } + DestroyAnimVisualTask(taskId); + } + } + else + gTasks[taskId].data[3]--; +} + +void sub_8098E90(u8 taskId) +{ + u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]); + + gSprites[spriteId].pos2.x = gBattleAnimArgs[1]; + gTasks[taskId].data[0] = spriteId; + gTasks[taskId].data[1] = gBattleAnimArgs[1]; + gTasks[taskId].data[2] = gBattleAnimArgs[2]; + gTasks[taskId].data[3] = gBattleAnimArgs[3]; + gTasks[taskId].data[4] = gBattleAnimArgs[4]; + gTasks[taskId].func = sub_8098EF0; + gTasks[taskId].func(taskId); +} + +void sub_8098EF0(u8 taskId) +{ + u8 spriteId = gTasks[taskId].data[0]; + s16 data1 = gTasks[taskId].data[1]; + if (gTasks[taskId].data[2] == gTasks[taskId].data[8]++) + { + gTasks[taskId].data[8] = 0; + if (gSprites[spriteId].pos2.x == data1) + data1 = -data1; + gSprites[spriteId].pos2.x += data1; + } + gTasks[taskId].data[1] = data1; + gTasks[taskId].data[9] += gTasks[taskId].data[3]; + gSprites[spriteId].pos2.y = gTasks[taskId].data[9] >> 8; + if (--gTasks[taskId].data[4] == 0) + DestroyAnimVisualTask(taskId); +} + +void sub_8098F84(u8 taskId) +{ + u8 r6 = 1; + u8 i; + u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]); + if (gBattleAnimArgs[4] > 5) + gBattleAnimArgs[4] = 5; + for (i = 0; i < gBattleAnimArgs[4]; i++) + r6 *= 2; + gTasks[taskId].data[0] = spriteId; + gTasks[taskId].data[1] = gBattleAnimArgs[1]; + gTasks[taskId].data[2] = gBattleAnimArgs[2]; + gTasks[taskId].data[3] = gBattleAnimArgs[3]; + gTasks[taskId].data[4] = r6; + gTasks[taskId].func = sub_8099004; + gTasks[taskId].func(taskId); +} + +void sub_8099004(u8 taskId) +{ + u8 spriteId = gTasks[taskId].data[0]; + gSprites[spriteId].pos2.x = Sin(gTasks[taskId].data[5], gTasks[taskId].data[1]); + gSprites[spriteId].pos2.y = -Cos(gTasks[taskId].data[5], gTasks[taskId].data[2]); + gSprites[spriteId].pos2.y += gTasks[taskId].data[2]; + gTasks[taskId].data[5] += gTasks[taskId].data[4]; + gTasks[taskId].data[5] &= 0xFF; + if (gTasks[taskId].data[5] == 0) + gTasks[taskId].data[3]--; + if (gTasks[taskId].data[3] == 0) + { + gSprites[spriteId].pos2.x = 0; + gSprites[spriteId].pos2.y = 0; + DestroyAnimVisualTask(taskId); + } +} + +void sub_809907C(u8 taskId) +{ + if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) + gBattleAnimArgs[1] = -gBattleAnimArgs[1]; + sub_8098F84(taskId); +} + +void sub_80990AC(struct Sprite * sprite) +{ + sprite->invisible = TRUE; + if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) + sprite->data[1] = -gBattleAnimArgs[1]; + else + sprite->data[1] = gBattleAnimArgs[1]; + sprite->data[0] = gBattleAnimArgs[0]; + sprite->data[2] = 0; + sprite->data[3] = gBattlerSpriteIds[gBattleAnimAttacker]; + sprite->data[4] = gBattleAnimArgs[0]; + StoreSpriteCallbackInData6(sprite, sub_8099120); + sprite->callback = sub_8074DC4; +} + +void sub_8099120(struct Sprite * sprite) +{ + sprite->data[0] = sprite->data[4]; + sprite->data[1] = -sprite->data[1]; + sprite->callback = sub_8074DC4; + StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); +} + +void sub_8099144(struct Sprite * sprite) +{ + u8 spriteId; + sprite->invisible = TRUE; + spriteId = GetAnimBankSpriteId(gBattleAnimArgs[2]); + sprite->data[0] = gBattleAnimArgs[0]; + sprite->data[1] = 0; + sprite->data[2] = gBattleAnimArgs[1]; + sprite->data[3] = spriteId; + sprite->data[4] = gBattleAnimArgs[0]; + StoreSpriteCallbackInData6(sprite, sub_8099190); + sprite->callback = sub_8074DC4; +} + +void sub_8099190(struct Sprite * sprite) +{ + sprite->data[0] = sprite->data[4]; + sprite->data[2] = -sprite->data[2]; + sprite->callback = sub_8074DC4; + StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); +} + +void sub_80991B4(struct Sprite * sprite) +{ + u8 spriteId; + if (gBattleAnimArgs[0] == 0) + spriteId = gBattlerSpriteIds[gBattleAnimAttacker]; + else + spriteId = gBattlerSpriteIds[gBattleAnimTarget]; + sprite->data[0] = gBattleAnimArgs[2]; + sprite->data[1] = gSprites[spriteId].pos1.x + gSprites[spriteId].pos2.x; + sprite->data[2] = gSprites[spriteId].pos1.x; + sprite->data[3] = gSprites[spriteId].pos1.y + gSprites[spriteId].pos2.y; + sprite->data[4] = gSprites[spriteId].pos1.y; + sub_80754B8(sprite); + sprite->data[3] = 0; + sprite->data[4] = 0; + sprite->data[5] = gSprites[spriteId].pos2.x; + sprite->data[6] = gSprites[spriteId].pos2.y; + sprite->invisible = TRUE; + if (gBattleAnimArgs[1] == 1) + sprite->data[2] = 0; + else if (gBattleAnimArgs[1] == 2) + sprite->data[1] = 0; + sprite->data[7] = gBattleAnimArgs[1]; + sprite->data[7] |= spriteId << 8; + sprite->callback = sub_8099270; +} + +void sub_8099270(struct Sprite * sprite) +{ + u8 data7 = sprite->data[7]; + struct Sprite *otherSprite = &gSprites[sprite->data[7] >> 8]; + if (sprite->data[0] == 0) + { + if (data7 == 1 || data7 == 0) + otherSprite->pos2.x = 0; + if (data7 == 2 || data7 == 0) + otherSprite->pos2.y = 0; + DestroyAnimSprite(sprite); + } + else + { + sprite->data[0]--; + sprite->data[3] += sprite->data[1]; + sprite->data[4] += sprite->data[2]; + otherSprite->pos2.x = (sprite->data[3] >> 8) + sprite->data[5]; + otherSprite->pos2.y = (sprite->data[4] >> 8) + sprite->data[6]; + } +} + +void sub_80992E0(struct Sprite * sprite) +{ + u8 battlerId; + u8 spriteId; + if (gBattleAnimArgs[0] == 0) + battlerId = gBattleAnimAttacker; + else + battlerId = gBattleAnimTarget; + spriteId = gBattlerSpriteIds[battlerId]; + if (GetBattlerSide(battlerId) != B_SIDE_PLAYER) + { + gBattleAnimArgs[1] = -gBattleAnimArgs[1]; + if (gBattleAnimArgs[3] == 1) + gBattleAnimArgs[2] = -gBattleAnimArgs[2]; + } + sprite->data[0] = gBattleAnimArgs[4]; + sprite->data[1] = gSprites[spriteId].pos1.x; + sprite->data[2] = gSprites[spriteId].pos1.x + gBattleAnimArgs[1]; + sprite->data[3] = gSprites[spriteId].pos1.y; + sprite->data[4] = gSprites[spriteId].pos1.y + gBattleAnimArgs[2]; + sub_80754B8(sprite); + sprite->data[3] = 0; + sprite->data[4] = 0; + sprite->data[5] = spriteId; + sprite->invisible = TRUE; + StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); + sprite->callback = sub_8074E14; +} + +void sub_8099394(struct Sprite * sprite) +{ + u8 battlerId; + u8 spriteId; + sprite->invisible = TRUE; + if (gBattleAnimArgs[0] == 0) + battlerId = gBattleAnimAttacker; + else + battlerId = gBattleAnimTarget; + spriteId = gBattlerSpriteIds[battlerId]; + if (GetBattlerSide(battlerId) != B_SIDE_PLAYER) + { + gBattleAnimArgs[1] = -gBattleAnimArgs[1]; + if (gBattleAnimArgs[3] == 1) + gBattleAnimArgs[2] = -gBattleAnimArgs[2]; + } + sprite->data[0] = gBattleAnimArgs[4]; + sprite->data[1] = gSprites[spriteId].pos1.x + gSprites[spriteId].pos2.x; + sprite->data[2] = sprite->data[1] + gBattleAnimArgs[1]; + sprite->data[3] = gSprites[spriteId].pos1.y + gSprites[spriteId].pos2.y; + sprite->data[4] = sprite->data[3] + gBattleAnimArgs[2]; + sub_80754B8(sprite); + sprite->data[3] = gSprites[spriteId].pos2.x << 8; + sprite->data[4] = gSprites[spriteId].pos2.y << 8; + sprite->data[5] = spriteId; + sprite->data[6] = gBattleAnimArgs[5]; + if (gBattleAnimArgs[5] == 0) + StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); + else + StoreSpriteCallbackInData6(sprite, sub_809946C); + sprite->callback = sub_8074E14; +} + +void sub_809946C(struct Sprite * sprite) +{ + gSprites[sprite->data[5]].pos2.x = 0; + gSprites[sprite->data[5]].pos2.y = 0; + DestroyAnimSprite(sprite); +} + +void sub_809949C(u8 taskId) +{ + u16 r7 = 0x8000 / gBattleAnimArgs[3]; + if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) + { + gBattleAnimArgs[1] = -gBattleAnimArgs[1]; + gBattleAnimArgs[5] = -gBattleAnimArgs[5]; + } + gTasks[taskId].data[0] = GetAnimBankSpriteId(gBattleAnimArgs[0]); + gTasks[taskId].data[1] = gBattleAnimArgs[1] * 256 / gBattleAnimArgs[3]; + gTasks[taskId].data[2] = gBattleAnimArgs[2]; + gTasks[taskId].data[3] = gBattleAnimArgs[3]; + gTasks[taskId].data[4] = gBattleAnimArgs[4]; + gTasks[taskId].data[5] = gBattleAnimArgs[5] * 256 / gBattleAnimArgs[6]; + gTasks[taskId].data[6] = gBattleAnimArgs[6]; + gTasks[taskId].data[7] = r7; + gTasks[taskId].func = sub_8099530; +} + +void sub_8099530(u8 taskId) +{ + u8 spriteId = gTasks[taskId].data[0]; + gTasks[taskId].data[11] += gTasks[taskId].data[1]; + gSprites[spriteId].pos2.x = gTasks[taskId].data[11] >> 8; + gSprites[spriteId].pos2.y = Sin((u8)(gTasks[taskId].data[10] >> 8), gTasks[taskId].data[2]); + gTasks[taskId].data[10] += gTasks[taskId].data[7]; + if (--gTasks[taskId].data[3] == 0) + gTasks[taskId].func = sub_8099594; +} + +void sub_8099594(u8 taskId) +{ + u8 spriteId; + + if (gTasks[taskId].data[4] > 0) + gTasks[taskId].data[4]--; + else + { + spriteId = gTasks[taskId].data[0]; + gTasks[taskId].data[12] += gTasks[taskId].data[5]; + gSprites[spriteId].pos2.x = (gTasks[taskId].data[12] >> 8) + (gTasks[taskId].data[11] >> 8); + if (--gTasks[taskId].data[6] == 0) + DestroyAnimVisualTask(taskId); + } +} + +void sub_80995FC(u8 taskId) +{ + u8 spriteId; + + switch (gBattleAnimArgs[0]) + { + case 0: + case 1: + spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]); + break; + case 2: + if (!sub_8072DF0(gBattleAnimAttacker ^ BIT_FLANK)) + { + DestroyAnimVisualTask(taskId); + return; + } + spriteId = gBattlerSpriteIds[gBattleAnimAttacker ^ BIT_FLANK]; + break; + case 3: + if (!sub_8072DF0(gBattleAnimTarget ^ BIT_FLANK)) + { + DestroyAnimVisualTask(taskId); + return; + } + spriteId = gBattlerSpriteIds[gBattleAnimTarget ^ BIT_FLANK]; + break; + default: + DestroyAnimVisualTask(taskId); + return; + } + gTasks[taskId].data[0] = spriteId; + if (GetBattlerSide(gBattleAnimTarget) != B_SIDE_PLAYER) + gTasks[taskId].data[1] = gBattleAnimArgs[1]; + else + gTasks[taskId].data[1] = -gBattleAnimArgs[1]; + gTasks[taskId].func = sub_80996B8; +} + +void sub_80996B8(u8 taskId) +{ + u8 spriteId = gTasks[taskId].data[0]; + gSprites[spriteId].pos2.x += gTasks[taskId].data[1]; + if (gSprites[spriteId].pos2.x + gSprites[spriteId].pos1.x < -0x20 || gSprites[spriteId].pos2.x + gSprites[spriteId].pos1.x > 0x110) + DestroyAnimVisualTask(taskId); +} + +void sub_8099704(u8 taskId) +{ + u8 spriteId; + if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) + gBattleAnimArgs[1] = -gBattleAnimArgs[1]; + spriteId = GetAnimBankSpriteId(gBattleAnimArgs[4]); + gTasks[taskId].data[0] = gBattleAnimArgs[0]; + gTasks[taskId].data[1] = gBattleAnimArgs[1]; + gTasks[taskId].data[2] = gBattleAnimArgs[2]; + gTasks[taskId].data[3] = gBattleAnimArgs[3]; + gTasks[taskId].data[4] = spriteId; + if (gBattleAnimArgs[4] == 0) + gTasks[taskId].data[5] = gBattleAnimAttacker; + else + gTasks[taskId].data[5] = gBattleAnimTarget; + gTasks[taskId].data[12] = 1; + gTasks[taskId].func = sub_8099788; +} + +void sub_8099788(u8 taskId) +{ + u8 spriteId; + u32 r8; + s16 r5; + u16 tmp; + + spriteId = gTasks[taskId].data[4]; + tmp = gTasks[taskId].data[10] + gTasks[taskId].data[2]; + gTasks[taskId].data[10] = tmp; + r8 = tmp >> 8; + r5 = Sin(r8, gTasks[taskId].data[1]); + if (gTasks[taskId].data[0] == 0) + { + gSprites[spriteId].pos2.x = r5; + } + else if (GetBattlerSide(gTasks[taskId].data[5]) == B_SIDE_PLAYER) + { + gSprites[spriteId].pos2.y = abs(r5); + } + else + gSprites[spriteId].pos2.y = -abs(r5); + if ((r8 > 0x7F && gTasks[taskId].data[11] == 0 && gTasks[taskId].data[12] == 1) || (r8 < 0x7F && gTasks[taskId].data[11] == 1 && gTasks[taskId].data[12] == 0)) + { + gTasks[taskId].data[11] ^= 1; + gTasks[taskId].data[12] ^= 1; + if (--gTasks[taskId].data[3] == 0) + { + gSprites[spriteId].pos2.x = 0; + gSprites[spriteId].pos2.y = 0; + DestroyAnimVisualTask(taskId); + } + } +} + +void sub_80998B0(u8 taskId) +{ + u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[3]); + sub_80758E0(spriteId, gBattleAnimArgs[4]); + gTasks[taskId].data[0] = gBattleAnimArgs[0]; + gTasks[taskId].data[1] = gBattleAnimArgs[1]; + gTasks[taskId].data[2] = gBattleAnimArgs[2]; + gTasks[taskId].data[3] = gBattleAnimArgs[2]; + gTasks[taskId].data[4] = spriteId; + gTasks[taskId].data[10] = 0x100; + gTasks[taskId].data[11] = 0x100; + gTasks[taskId].func = sub_8099908; +} + +void sub_8099908(u8 taskId) +{ + u8 spriteId; + gTasks[taskId].data[10] += gTasks[taskId].data[0]; + gTasks[taskId].data[11] += gTasks[taskId].data[1]; + spriteId = gTasks[taskId].data[4]; + obj_id_set_rotscale(spriteId, gTasks[taskId].data[10], gTasks[taskId].data[11], 0); + if (--gTasks[taskId].data[2] == 0) + { + if (gTasks[taskId].data[3] > 0) + { + gTasks[taskId].data[0] = -gTasks[taskId].data[0]; + gTasks[taskId].data[1] = -gTasks[taskId].data[1]; + gTasks[taskId].data[2] = gTasks[taskId].data[3]; + gTasks[taskId].data[3] = 0; + } + else + { + sub_8075980(spriteId); + DestroyAnimVisualTask(taskId); + } + } +} + +void sub_8099980(u8 taskId) +{ + u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[2]); + sub_80758E0(spriteId, 0); + gTasks[taskId].data[1] = 0; + gTasks[taskId].data[2] = gBattleAnimArgs[0]; + if (gBattleAnimArgs[3] != 1) + gTasks[taskId].data[3] = 0; + else + gTasks[taskId].data[3] = gBattleAnimArgs[0] * gBattleAnimArgs[1]; + gTasks[taskId].data[4] = gBattleAnimArgs[1]; + gTasks[taskId].data[5] = spriteId; + gTasks[taskId].data[6] = gBattleAnimArgs[3]; + if (sub_8073788()) + gTasks[taskId].data[7] = 1; + else + { + if (gBattleAnimArgs[2] == 0) + gTasks[taskId].data[7] = GetBattlerSide(gBattleAnimAttacker) == B_SIDE_PLAYER ? 1 : 0; + else + gTasks[taskId].data[7] = GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER ? 1 : 0; + } + if (gTasks[taskId].data[7] && !sub_8073788()) + { + s16 tmp; + tmp = gTasks[taskId].data[3]; + gTasks[taskId].data[3] = -tmp; + tmp = gTasks[taskId].data[4]; + gTasks[taskId].data[4] = -tmp; + } + gTasks[taskId].func = sub_8099B54; +} + +void sub_8099A78(u8 taskId) +{ + u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[2]); + sub_80758E0(spriteId, 0); + gTasks[taskId].data[1] = 0; + gTasks[taskId].data[2] = gBattleAnimArgs[0]; + if (gBattleAnimArgs[2] == 0) + { + if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) + gBattleAnimArgs[1] = -gBattleAnimArgs[1]; + } + else + { + if (GetBattlerSide(gBattleAnimTarget) != B_SIDE_PLAYER) + gBattleAnimArgs[1] = -gBattleAnimArgs[1]; + } + if (gBattleAnimArgs[3] != 1) + gTasks[taskId].data[3] = 0; + else + gTasks[taskId].data[3] = gBattleAnimArgs[0] * gBattleAnimArgs[1]; + gTasks[taskId].data[4] = gBattleAnimArgs[1]; + gTasks[taskId].data[5] = spriteId; + gTasks[taskId].data[6] = gBattleAnimArgs[3]; + gTasks[taskId].data[7] = 1; + if (gTasks[taskId].data[7] ) + { + s16 tmp; + tmp = gTasks[taskId].data[3]; + gTasks[taskId].data[3] = -tmp; + tmp = gTasks[taskId].data[4]; + gTasks[taskId].data[4] = -tmp; + } + gTasks[taskId].func = sub_8099B54; +} + +void sub_8099B54(u8 taskId) +{ + s16 tmp; + gTasks[taskId].data[3] += gTasks[taskId].data[4]; + obj_id_set_rotscale(gTasks[taskId].data[5], 0x100, 0x100, gTasks[taskId].data[3]); + if (gTasks[taskId].data[7]) + sub_80759DC(gTasks[taskId].data[5]); + if (++gTasks[taskId].data[1] >= gTasks[taskId].data[2]) + { + switch (gTasks[taskId].data[6]) + { + case 1: + sub_8075980(gTasks[taskId].data[5]); + // fallthrough + case 0: + default: + DestroyAnimVisualTask(taskId); + break; + case 2: + gTasks[taskId].data[1] = 0; + tmp = gTasks[taskId].data[4]; + gTasks[taskId].data[4] = -tmp; + gTasks[taskId].data[6] = 1; + break; + } + } +} + +void sub_8099BD4(u8 taskId) +{ + if (gBattleAnimArgs[0] == 0) + { + gTasks[taskId].data[15] = gUnknown_2037EEC / 12; + if (gTasks[taskId].data[15] < 1) + gTasks[taskId].data[15] = 1; + if (gTasks[taskId].data[15] > 16) + gTasks[taskId].data[15] = 16; + } + else + { + gTasks[taskId].data[15] = gUnknown_2037EE8 / 12; + if (gTasks[taskId].data[15] < 1) + gTasks[taskId].data[15] = 1; + if (gTasks[taskId].data[15] > 16) + gTasks[taskId].data[15] = 16; + } + gTasks[taskId].data[14] = gTasks[taskId].data[15] / 2; + gTasks[taskId].data[13] = gTasks[taskId].data[14] + (gTasks[taskId].data[15] & 1); + gTasks[taskId].data[12] = 0; + gTasks[taskId].data[10] = gBattleAnimArgs[3]; + gTasks[taskId].data[11] = gBattleAnimArgs[4]; + gTasks[taskId].data[7] = GetAnimBankSpriteId(1); + gTasks[taskId].data[8] = gSprites[gTasks[taskId].data[7]].pos2.x; + gTasks[taskId].data[9] = gSprites[gTasks[taskId].data[7]].pos2.y; + gTasks[taskId].data[0] = 0; + gTasks[taskId].data[1] = gBattleAnimArgs[1]; + gTasks[taskId].data[2] = gBattleAnimArgs[2]; + gTasks[taskId].func = sub_8099CB8; +} + +void sub_8099CB8(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + if (++task->data[0] > task->data[1]) + { + task->data[0] = 0; + task->data[12] = (task->data[12] + 1) & 1; + if (task->data[10]) + { + if (task->data[12]) + { + gSprites[task->data[7]].pos2.x = task->data[8] + task->data[13]; + } + else + { + gSprites[task->data[7]].pos2.x = task->data[8] - task->data[14]; + } + } + if (task->data[11]) + { + if (task->data[12]) + { + gSprites[task->data[7]].pos2.y = task->data[15]; + } + else + { + gSprites[task->data[7]].pos2.y = 0; + } + } + if (!--task->data[2]) + { + gSprites[task->data[7]].pos2.x = 0; + gSprites[task->data[7]].pos2.y = 0; + DestroyAnimVisualTask(taskId); + return; + } + } +} diff --git a/src/berry.c b/src/berry.c new file mode 100644 index 000000000..91d83f40c --- /dev/null +++ b/src/berry.c @@ -0,0 +1,169 @@ +#include "global.h" +#include "berry.h" +#include "text.h" +#include "constants/items.h" + +extern const struct Berry sBerries[]; + +#define ENIGMA_BERRY_STRUCT ({const struct Berry2 *berries = (const struct Berry2 *)sBerries;berries[ITEM_ENIGMA_BERRY - FIRST_BERRY_INDEX];}) + +void sub_809C718(void) +{ + s32 i; + + gSaveBlock1Ptr->enigmaBerry.berry = ENIGMA_BERRY_STRUCT; + for (i = 0; i < 18; i++) + gSaveBlock1Ptr->enigmaBerry.itemEffect[i] = 0; + gSaveBlock1Ptr->enigmaBerry.holdEffect = 0; + gSaveBlock1Ptr->enigmaBerry.holdEffectParam = 0; + gSaveBlock1Ptr->enigmaBerry.checksum = GetEnigmaBerryChecksum(&gSaveBlock1Ptr->enigmaBerry); +} + +void sub_809C794(void) +{ + CpuFill16(0, &gSaveBlock1Ptr->enigmaBerry, sizeof(gSaveBlock1Ptr->enigmaBerry)); + sub_809C718(); +} + +#ifdef NONMATCHING +void SetEnigmaBerry(u8 * berry) +{ + struct EnigmaBerry * enigmaBerry; + + sub_809C794(); + + { + const struct Berry2 * src = (const struct Berry2 *)berry; + struct Berry2 * dest = &gSaveBlock1Ptr->enigmaBerry.berry; + *dest = *src; + } + + enigmaBerry = &gSaveBlock1Ptr->enigmaBerry; + { + s32 i = 0; + u8 * dest = gSaveBlock1Ptr->enigmaBerry.itemEffect; + const u8 * src = berry + 0x516; + + for (i = 0; i < 18; i++) dest[i] = src[i]; + } + enigmaBerry->holdEffect = berry[0x528]; + enigmaBerry->holdEffectParam = berry[0x529]; + enigmaBerry->checksum = GetEnigmaBerryChecksum(enigmaBerry); +} +#else +NAKED +void SetEnigmaBerry(u8 * berry) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tadds r4, r0, 0\n" + "\tbl sub_809C794\n" + "\tadds r5, r4, 0\n" + "\tldr r0, _0809C824 @ =gSaveBlock1Ptr\n" + "\tldr r2, [r0]\n" + "\tldr r0, _0809C828 @ =0x000030ec\n" + "\tadds r4, r2, r0\n" + "\tadds r1, r4, 0\n" + "\tadds r0, r5, 0\n" + "\tldm r0!, {r3,r6,r7}\n" + "\tstm r1!, {r3,r6,r7}\n" + "\tldm r0!, {r3,r6,r7}\n" + "\tstm r1!, {r3,r6,r7}\n" + "\tldr r0, [r0]\n" + "\tstr r0, [r1]\n" + "\tmovs r3, 0\n" + "\tldr r0, _0809C82C @ =0x00003108\n" + "\tadds r6, r2, r0\n" + "\tldr r1, _0809C830 @ =0x00000516\n" + "\tadds r2, r5, r1\n" + "_0809C7F0:\n" + "\tadds r0, r6, r3\n" + "\tadds r1, r2, r3\n" + "\tldrb r1, [r1]\n" + "\tstrb r1, [r0]\n" + "\tadds r3, 0x1\n" + "\tcmp r3, 0x11\n" + "\tble _0809C7F0\n" + "\tmovs r3, 0xA5\n" + "\tlsls r3, 3\n" + "\tadds r0, r5, r3\n" + "\tldrb r0, [r0]\n" + "\tadds r1, r4, 0\n" + "\tadds r1, 0x2E\n" + "\tstrb r0, [r1]\n" + "\tldr r6, _0809C834 @ =0x00000529\n" + "\tadds r0, r5, r6\n" + "\tldrb r0, [r0]\n" + "\tadds r1, 0x1\n" + "\tstrb r0, [r1]\n" + "\tadds r0, r4, 0\n" + "\tbl GetEnigmaBerryChecksum\n" + "\tstr r0, [r4, 0x30]\n" + "\tpop {r4-r7}\n" + "\tpop {r0}\n" + "\tbx r0\n" + "\t.align 2, 0\n" + "_0809C824: .4byte gSaveBlock1Ptr\n" + "_0809C828: .4byte 0x000030ec\n" + "_0809C82C: .4byte 0x00003108\n" + "_0809C830: .4byte 0x00000516\n" + "_0809C834: .4byte 0x00000529"); +} +#endif + +u32 GetEnigmaBerryChecksum(struct EnigmaBerry * enigmaBerry) +{ + const u8 * src = (const u8 *)enigmaBerry; + u32 result = 0; + u32 i; + + for (i = 0; i < offsetof(struct EnigmaBerry, checksum); i++) + result += src[i]; + + return result; +} + +bool32 IsEnigmaBerryValid(void) +{ + if (gSaveBlock1Ptr->enigmaBerry.berry.stageDuration == 0) + return FALSE; + if (gSaveBlock1Ptr->enigmaBerry.berry.maxYield == 0) + return FALSE; + if (GetEnigmaBerryChecksum(&gSaveBlock1Ptr->enigmaBerry) != gSaveBlock1Ptr->enigmaBerry.checksum) + return FALSE; + + return TRUE; +} + +const struct Berry * sub_809C8A0(u8 berryIdx) +{ + if (berryIdx == ITEM_TO_BERRY(ITEM_ENIGMA_BERRY) && IsEnigmaBerryValid()) + return (struct Berry *)&gSaveBlock1Ptr->enigmaBerry.berry; + + if (berryIdx == 0 || berryIdx > ITEM_TO_BERRY(ITEM_ENIGMA_BERRY)) + berryIdx = 1; + + return &sBerries[berryIdx - 1]; +} + +u8 ItemIdToBerryType(u16 itemId) +{ + if (itemId - FIRST_BERRY_INDEX < 0 || itemId - FIRST_BERRY_INDEX > ITEM_ENIGMA_BERRY - FIRST_BERRY_INDEX) + return 1; + + return ITEM_TO_BERRY(itemId); +} + +u16 BerryTypeToItemId(u16 berryType) +{ + if (berryType - 1 < 0 || berryType - 1 > ITEM_ENIGMA_BERRY - FIRST_BERRY_INDEX) + return FIRST_BERRY_INDEX; + + return berryType + FIRST_BERRY_INDEX - 1; +} + +void GetBerryNameByBerryType(u8 berryType, u8 * dest) +{ + const struct Berry * berry = sub_809C8A0(berryType); + memcpy(dest, berry->name, 6); + dest[6] = EOS; +} diff --git a/src/berry_fix_program.c b/src/berry_fix_program.c new file mode 100644 index 000000000..f224bbc47 --- /dev/null +++ b/src/berry_fix_program.c @@ -0,0 +1,191 @@ +#include "global.h" +#include "gpu_regs.h" +#include "multiboot.h" +#include "malloc.h" +#include "bg.h" +#include "graphics.h" +#include "main.h" +#include "sprite.h" +#include "task.h" +#include "scanline_effect.h" +#include "window.h" +#include "text.h" +#include "help_system.h" +#include "menu.h" +#include "m4a.h" + +// Static type declarations + +typedef struct { + u8 state; + u8 unk1; + u16 unk2; + struct MultiBootParam mb; +} berryfix_t; + +// Static RAM declarations + +const void * gUnknown_3005EF0; +int gUnknown_3005EF4; +size_t gUnknown_3005EF8; +struct MultiBootParam gUnknown_3005F00; + +// Static ROM declarations + +static void mb_berry_fix_maincb(void); +static void mb_berry_fix_task(u8 taskId); + +// .rodata + +static const void *const gUnknown_847A890[][3] = { + { + gBerryFixGameboy_Gfx, + gBerryFixGameboy_Tilemap, + gBerryFixGameboy_Pal + }, { + gBerryFixGameboyLogo_Gfx, + gBerryFixGameboyLogo_Tilemap, + gBerryFixGameboyLogo_Pal + }, { + gBerryFixGbaTransfer_Gfx, + gBerryFixGbaTransfer_Tilemap, + gBerryFixGbaTransfer_Pal + }, { + gBerryFixGbaTransferHighlight_Gfx, + gBerryFixGbaTransferHighlight_Tilemap, + gBerryFixGbaTransferHighlight_Pal + }, { + gBerryFixGbaTransferError_Gfx, + gBerryFixGbaTransferError_Tilemap, + gBerryFixGbaTransferError_Pal + }, { + gBerryFixWindow_Gfx, + gBerryFixWindow_Tilemap, + gBerryFixWindow_Pal + }, +}; + +extern const u8 gMultiBootProgram_BerryGlitchFix_Start[0x3BF4]; +extern const u8 gMultiBootProgram_BerryGlitchFix_End[]; + +// .text + +static void mb_berry_fix_print(int scene) +{ + REG_DISPCNT = 0; + REG_BG0HOFS = 0; + REG_BG0VOFS = 0; + REG_BLDCNT = 0; + LZ77UnCompVram(gUnknown_847A890[scene][0], (void *)BG_CHAR_ADDR(0)); + LZ77UnCompVram(gUnknown_847A890[scene][1], (void *)BG_SCREEN_ADDR(31)); + CpuCopy16(gUnknown_847A890[scene][2], (void *)BG_PLTT, 0x200); + REG_BG0CNT = BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(31) | BGCNT_TXT256x256; + REG_DISPCNT = DISPCNT_BG0_ON; +} + +void mb_berry_fix_serve(void) // noreturn +{ + u8 taskId; + DisableInterrupts(0xFFFF); + EnableInterrupts(INTR_FLAG_VBLANK); + m4aSoundVSyncOff(); + SetVBlankCallback(NULL); + DmaFill32(3, 0, (void *)VRAM, VRAM_SIZE); + DmaFill32(3, 0, (void *)PLTT, PLTT_SIZE); + ResetSpriteData(); + ResetTasks(); + ScanlineEffect_Stop(); + gUnknown_3005ECC = 0; + taskId = CreateTask(mb_berry_fix_task, 0); + gTasks[taskId].data[0] = 0; + SetMainCallback2(mb_berry_fix_maincb); +} + +static void mb_berry_fix_maincb(void) +{ + RunTasks(); +} + +static void mb_berry_fix_task(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + switch (data[0]) + { + case 0: + mb_berry_fix_print(5); + data[0] = 1; + break; + case 1: + if (JOY_NEW(A_BUTTON)) + { + mb_berry_fix_print(0); + data[0] = 2; + } + break; + case 2: + if (JOY_NEW(A_BUTTON)) + { + mb_berry_fix_print(1); + data[0] = 4; + } + break; + case 4: + gUnknown_3005EF0 = gMultiBootProgram_BerryGlitchFix_Start; + gUnknown_3005EF8 = gMultiBootProgram_BerryGlitchFix_End - gMultiBootProgram_BerryGlitchFix_Start; + gUnknown_3005F00.masterp = (void *)gMultiBootProgram_BerryGlitchFix_Start; + gUnknown_3005F00.server_type = MULTIBOOT_SERVER_TYPE_NORMAL; + MultiBootInit(&gUnknown_3005F00); + data[1] = 0; + data[0] = 5; + break; + case 5: + if (gUnknown_3005F00.probe_count == 0 && gUnknown_3005F00.response_bit & 0x2 && gUnknown_3005F00.client_bit & 0x2) + { + data[1]++; + if (data[1] > 180) + { + mb_berry_fix_print(2); + MultiBootStartMaster(&gUnknown_3005F00, gUnknown_3005EF0 + MULTIBOOT_HEADER_SIZE, gUnknown_3005EF8 - MULTIBOOT_HEADER_SIZE, 4, 1); + data[1] = 0; + data[0] = 6; + } + else + gUnknown_3005EF4 = MultiBootMain(&gUnknown_3005F00); + } + else + { + data[1] = 0; + gUnknown_3005EF4 = MultiBootMain(&gUnknown_3005F00); + } + break; + case 6: + gUnknown_3005EF4 = MultiBootMain(&gUnknown_3005F00); + if (MultiBootCheckComplete(&gUnknown_3005F00)) + { + mb_berry_fix_print(3); + data[0] = 7; + } + else if (!(gUnknown_3005F00.client_bit & 2)) + data[0] = 9; + break; + case 7: + data[0] = 8; + break; + case 8: + if (JOY_NEW(A_BUTTON)) + { + DestroyTask(taskId); + DoSoftReset(); + } + break; + case 9: + mb_berry_fix_print(4); + data[0] = 10; + break; + case 10: + if (JOY_NEW(A_BUTTON)) + data[0] = 0; + break; + } +} diff --git a/src/berry_powder.c b/src/berry_powder.c new file mode 100644 index 000000000..b3069d697 --- /dev/null +++ b/src/berry_powder.c @@ -0,0 +1,132 @@ +#include "global.h" +#include "event_data.h" +#include "load_save.h" +#include "menu.h" +#include "quest_log.h" +#include "script_menu.h" +#include "string_util.h" +#include "strings.h" +#include "text.h" +#include "text_window.h" + +EWRAM_DATA u8 gUnknown_203F464 = 0; + +u32 sub_815EE3C(u32 * a0) +{ + return *a0 ^ gSaveBlock2Ptr->encryptionKey; +} + +void sub_815EE54(u32 * a0, u32 a1) +{ + *a0 = gSaveBlock2Ptr->encryptionKey ^ a1; +} + +void sub_815EE6C(u32 a0) +{ + ApplyNewEncryptionKeyToWord(&gSaveBlock2Ptr->berryCrush.berryPowderAmount, a0); +} + +bool8 sub_815EE88(u32 a0) +{ + if (sub_815EE3C(&gSaveBlock2Ptr->berryCrush.berryPowderAmount) < a0) + return FALSE; + else + return TRUE; +} + +bool8 sub_815EEB0(void) +{ + if (sub_815EE3C(&gSaveBlock2Ptr->berryCrush.berryPowderAmount) < gSpecialVar_0x8004) + return FALSE; + else + return TRUE; +} + +bool8 sub_815EEE0(u32 a0) +{ + u32 * ptr = &gSaveBlock2Ptr->berryCrush.berryPowderAmount; + u32 amount = sub_815EE3C(ptr) + a0; + if (amount > 99999) + { + sub_815EE54(ptr, 99999); + return FALSE; + } + else + { + sub_815EE54(ptr, amount); + return TRUE; + } +} + +bool8 sub_815EF20(u32 a0) +{ + u32 * ptr = &gSaveBlock2Ptr->berryCrush.berryPowderAmount; + if (!sub_815EE88(a0)) + return FALSE; + else + { + u32 amount = sub_815EE3C(ptr); + sub_815EE54(ptr, amount - a0); + return TRUE; + } +} + +bool8 sub_815EF5C(void) +{ + u32 * ptr = &gSaveBlock2Ptr->berryCrush.berryPowderAmount; + if (!sub_815EE88(gSpecialVar_0x8004)) + return FALSE; + else + { + u32 amount = sub_815EE3C(ptr); + sub_815EE54(ptr, amount - gSpecialVar_0x8004); + return TRUE; + } +} + +u32 GetBerryPowder(void) +{ + return sub_815EE3C(&gSaveBlock2Ptr->berryCrush.berryPowderAmount); +} + +void sub_815EFBC(u8 windowId, u32 powder, u8 x, u8 y, u8 speed) +{ + ConvertIntToDecimalStringN(gStringVar1, powder, STR_CONV_MODE_RIGHT_ALIGN, 5); + AddTextPrinterParameterized(windowId, 0, gStringVar1, x, y, speed, NULL); +} + +void sub_815F014(u8 windowId, u16 baseBlock, u8 palette, u32 powder) +{ + SetWindowBorderStyle(windowId, FALSE, baseBlock, palette); + AddTextPrinterParameterized(windowId, 0, gOtherText_Powder, 0, 0, -1, NULL); + sub_815EFBC(windowId, powder, 39, 12, 0); +} + +void sub_815F070(void) +{ + sub_815EFBC(gUnknown_203F464, GetBerryPowder(), 39, 12, 0); +} + +void sub_815F094(void) +{ + struct WindowTemplate template; + struct WindowTemplate template2; + + if (sub_81119D4(sub_809D6D4) != TRUE) + { + SetWindowTemplateFields(&template, 0, 1, 1, 8, 3, 15, 32); + template2 = template; + gUnknown_203F464 = AddWindow(&template2); + FillWindowPixelBuffer(gUnknown_203F464, 0); + PutWindowTilemap(gUnknown_203F464); + TextWindow_SetStdFrame0_WithPal(gUnknown_203F464, 0x21D, 0xD0); + sub_815F014(gUnknown_203F464, 0x21D, 0xD, GetBerryPowder()); + } +} + +void sub_815F114(void) +{ + ClearWindowTilemap(gUnknown_203F464); + ClearMenuWindow(gUnknown_203F464, 1); + RemoveWindow(gUnknown_203F464); +} diff --git a/src/blend_palette.c b/src/blend_palette.c new file mode 100644 index 000000000..8cd65ae4b --- /dev/null +++ b/src/blend_palette.c @@ -0,0 +1,46 @@ +#include "global.h" +#include "blend_palette.h" +#include "palette.h" + +void BlendPalette(u16 palOffset, u16 numEntries, u8 coeff, u16 blendColor) +{ + u16 i; + for (i = 0; i < numEntries; i++) + { + u16 index = i + palOffset; + struct PlttData *data1 = (struct PlttData *)&gPlttBufferUnfaded[index]; + s8 r = data1->r; + s8 g = data1->g; + s8 b = data1->b; + struct PlttData *data2 = (struct PlttData *)&blendColor; + gPlttBufferFaded[index] = ((r + (((data2->r - r) * coeff) >> 4)) << 0) + | ((g + (((data2->g - g) * coeff) >> 4)) << 5) + | ((b + (((data2->b - b) * coeff) >> 4)) << 10); + } +} + +void sub_8045314(u16 * palbuff, u16 blend_pal, u32 coefficient, s32 size) +{ + if (coefficient == 16) + { + while (--size != -1) + { + *palbuff++ = blend_pal; + } + } + else + { + u16 r = (blend_pal >> 0) & 0x1F; + u16 g = (blend_pal >> 5) & 0x1F; + u16 b = (blend_pal >> 10) & 0x1F; + while (--size != -1) + { + u16 r2 = (*palbuff >> 0) & 0x1F; + u16 g2 = (*palbuff >> 5) & 0x1F; + u16 b2 = (*palbuff >> 10) & 0x1F; + *palbuff++ = ((r2 + (((r - r2) * coefficient) >> 4)) << 0) + | ((g2 + (((g - g2) * coefficient) >> 4)) << 5) + | ((b2 + (((b - b2) * coefficient) >> 4)) << 10); + } + } +} diff --git a/src/blit.c b/src/blit.c new file mode 100644 index 000000000..969f89900 --- /dev/null +++ b/src/blit.c @@ -0,0 +1,212 @@ +#include "global.h" +#include "blit.h" + +void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height) +{ + BlitBitmapRect4Bit(src, dst, srcX, srcY, dstX, dstY, width, height, 0xFF); +} + +void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierSrcY; + s32 multiplierDstY; + s32 loopSrcY, loopDstY; + s32 loopSrcX, loopDstX; + const u8 *pixelsSrc; + u8 *pixelsDst; + s32 toOrr; + s32 toAnd; + s32 toShift; + + if (dst->width - dstX < width) + xEnd = (dst->width - dstX) + srcX; + else + xEnd = srcX + width; + + if (dst->height - dstY < height) + yEnd = (dst->height - dstY) + srcY; + else + yEnd = height + srcY; + + multiplierSrcY = (src->width + (src->width & 7)) >> 3; + multiplierDstY = (dst->width + (dst->width & 7)) >> 3; + + if (colorKey == 0xFF) + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); + pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); + toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); + toShift = ((loopDstX & 1) << 2); + toOrr <<= toShift; + toAnd = 0xF0 >> (toShift); + *pixelsDst = toOrr | (*pixelsDst & toAnd); + } + } + } + else + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); + pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); + toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); + if (toOrr != colorKey) + { + toShift = ((loopDstX & 1) << 2); + toOrr <<= toShift; + toAnd = 0xF0 >> (toShift); + *pixelsDst = toOrr | (*pixelsDst & toAnd); + } + } + } + } +} + +void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierY; + s32 loopX, loopY; + + xEnd = x + width; + if (xEnd > surface->width) + xEnd = surface->width; + + yEnd = y + height; + if (yEnd > surface->height) + yEnd = surface->height; + + multiplierY = (surface->width + (surface->width & 7)) >> 3; + + for (loopY = y; loopY < yEnd; loopY++) + { + for (loopX = x; loopX < xEnd; loopX++) + { + u8 *pixels = surface->pixels + ((loopX >> 1) & 3) + ((loopX >> 3) << 5) + (((loopY >> 3) * multiplierY) << 5) + ((u32)(loopY << 0x1d) >> 0x1B); + if ((loopX & 1) != 0) + { + *pixels &= 0xF; + *pixels |= fillValue << 4; + } + else + { + *pixels &= 0xF0; + *pixels |= fillValue; + } + } + } +} + +void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset) +{ + s32 palOffsetBits; + s32 xEnd; + s32 yEnd; + s32 multiplierSrcY; + s32 multiplierDstY; + s32 loopSrcY, loopDstY; + s32 loopSrcX, loopDstX; + const u8 *pixelsSrc; + u8 *pixelsDst; + s32 colorKeyBits; + + palOffsetBits = (u32)(paletteOffset << 0x1C) >> 0x18; + colorKeyBits = (u32)(colorKey << 0x1C) >> 0x18; + + if (dst->width - dstX < width) + xEnd = (dst->width - dstX) + srcX; + else + xEnd = width + srcX; + + if (dst->height - dstY < height) + yEnd = (srcY + dst->height) - dstY; + else + yEnd = srcY + height; + + multiplierSrcY = (src->width + (src->width & 7)) >> 3; + multiplierDstY = (dst->width + (dst->width & 7)) >> 3; + + if (colorKey == 0xFF) + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + if (loopSrcX & 1) + { + *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); + } + else + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); + } + } + } + } + else + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + if (loopSrcX & 1) + { + if ((*pixelsSrc & 0xF0) != colorKeyBits) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); + } + } + else + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + if ((*pixelsSrc & 0xF) != colorKey) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); + } + } + } + } + } +} + +void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierY; + s32 loopX, loopY; + + xEnd = x + width; + if (xEnd > surface->width) + xEnd = surface->width; + + yEnd = y + height; + if (yEnd > surface->height) + yEnd = surface->height; + + multiplierY = (surface->width + (surface->width & 7)) >> 3; + + for (loopY = y; loopY < yEnd; loopY++) + { + for (loopX = x; loopX < xEnd; loopX++) + { + u8 *pixels = surface->pixels + (loopX & 7) + ((loopX >> 3) << 6) + (((loopY >> 3) * multiplierY) << 6) + ((u32)(loopY << 0x1d) >> 0x1a); + *pixels = fillValue; + } + } +} diff --git a/src/braille_text.c b/src/braille_text.c new file mode 100644 index 000000000..047fcab08 --- /dev/null +++ b/src/braille_text.c @@ -0,0 +1,222 @@ +#include "global.h" +#include "main.h" +#include "window.h" +#include "text.h" +#include "sound.h" + +extern u8 gGlyphInfo[]; + +ALIGNED(4) +static const u8 gUnknown_846FB08[] = {1, 2, 4}; +static const u16 sFont6BrailleGlyphs[] = INCBIN_U16("data/graphics/fonts/font6.fwjpnfont"); + +static void DecompressGlyphFont6(u16); + +u16 Font6Func(struct TextPrinter *textPrinter) +{ + u16 char_; + struct TextPrinterSubStruct *sub; + + sub = &textPrinter->sub_union.sub; + switch (textPrinter->state) + { + case 0: + if (gMain.heldKeys & (A_BUTTON | B_BUTTON) && sub->font_type_upper) + { + textPrinter->delayCounter = 0; + } + if (textPrinter->delayCounter && textPrinter->text_speed) + { + textPrinter->delayCounter --; + if (gTextFlags.canABSpeedUpPrint && gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + sub->font_type_upper = TRUE; + textPrinter->delayCounter = 0; + } + return 3; + } + if (gTextFlags.autoScroll) + { + textPrinter->delayCounter = 1; + } + else + { + textPrinter->delayCounter = textPrinter->text_speed; + } + char_ = *textPrinter->subPrinter.currentChar++; + switch (char_) + { + case EOS: + return 1; + case CHAR_NEWLINE: + textPrinter->subPrinter.currentX = textPrinter->subPrinter.x; + textPrinter->subPrinter.currentY += gFonts[textPrinter->subPrinter.fontId].maxLetterHeight + textPrinter->subPrinter.lineSpacing; + return 2; + case PLACEHOLDER_BEGIN: + textPrinter->subPrinter.currentChar++; + return 2; + case EXT_CTRL_CODE_BEGIN: + char_ = *textPrinter->subPrinter.currentChar++; + switch (char_) + { + case 1: + textPrinter->subPrinter.fgColor = *textPrinter->subPrinter.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->subPrinter.fgColor, textPrinter->subPrinter.bgColor, textPrinter->subPrinter.shadowColor); + return 2; + case 2: + textPrinter->subPrinter.bgColor = *textPrinter->subPrinter.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->subPrinter.fgColor, textPrinter->subPrinter.bgColor, textPrinter->subPrinter.shadowColor); + return 2; + case 3: + textPrinter->subPrinter.shadowColor = *textPrinter->subPrinter.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->subPrinter.fgColor, textPrinter->subPrinter.bgColor, textPrinter->subPrinter.shadowColor); + return 2; + case 4: + textPrinter->subPrinter.fgColor = *textPrinter->subPrinter.currentChar; + textPrinter->subPrinter.bgColor = *++textPrinter->subPrinter.currentChar; + textPrinter->subPrinter.shadowColor = *++textPrinter->subPrinter.currentChar; + textPrinter->subPrinter.currentChar++; + + GenerateFontHalfRowLookupTable(textPrinter->subPrinter.fgColor, textPrinter->subPrinter.bgColor, textPrinter->subPrinter.shadowColor); + return 2; + case 5: + textPrinter->subPrinter.currentChar++; + return 2; + case 6: + sub->font_type = *textPrinter->subPrinter.currentChar; + textPrinter->subPrinter.currentChar++; + return 2; + case 7: + return 2; + case 8: + textPrinter->delayCounter = *textPrinter->subPrinter.currentChar++; + textPrinter->state = 6; + return 2; + case 9: + textPrinter->state = 1; + if (gTextFlags.autoScroll) + { + sub->frames_visible_counter = 0; + } + return 3; + case 10: + textPrinter->state = 5; + return 3; + case 11: + case 16: + textPrinter->subPrinter.currentChar += 2; + return 2; + case 12: + char_ = *++textPrinter->subPrinter.currentChar; + break; + case 13: + textPrinter->subPrinter.currentX = textPrinter->subPrinter.x + *textPrinter->subPrinter.currentChar++; + return 2; + case 14: + textPrinter->subPrinter.currentY = textPrinter->subPrinter.y + *textPrinter->subPrinter.currentChar++; + return 2; + case 15: + FillWindowPixelBuffer(textPrinter->subPrinter.windowId, PIXEL_FILL(textPrinter->subPrinter.bgColor)); + return 2; + } + break; + case CHAR_PROMPT_CLEAR: + textPrinter->state = 2; + TextPrinterInitDownArrowCounters(textPrinter); + return 3; + case CHAR_PROMPT_SCROLL: + textPrinter->state = 3; + TextPrinterInitDownArrowCounters(textPrinter); + return 3; + case 0xF9: + char_ = *textPrinter->subPrinter.currentChar++| 0x100; + break; + case 0xF8: + textPrinter->subPrinter.currentChar++; + return 0; + } + DecompressGlyphFont6(char_); + CopyGlyphToWindow(textPrinter); + textPrinter->subPrinter.currentX += gGlyphInfo[0x80] + textPrinter->subPrinter.letterSpacing; + return 0; + case 1: + if (TextPrinterWait(textPrinter)) + { + textPrinter->state = 0; + } + return 3; + case 2: + if (TextPrinterWaitWithDownArrow(textPrinter)) + { + FillWindowPixelBuffer(textPrinter->subPrinter.windowId, PIXEL_FILL(textPrinter->subPrinter.bgColor)); + textPrinter->subPrinter.currentX = textPrinter->subPrinter.x; + textPrinter->subPrinter.currentY = textPrinter->subPrinter.y; + textPrinter->state = 0; + } + return 3; + case 3: + if (TextPrinterWaitWithDownArrow(textPrinter)) + { + TextPrinterClearDownArrow(textPrinter); + textPrinter->scrollDistance = gFonts[textPrinter->subPrinter.fontId].maxLetterHeight + textPrinter->subPrinter.lineSpacing; + textPrinter->subPrinter.currentX = textPrinter->subPrinter.x; + textPrinter->state = 4; + } + return 3; + case 4: + if (textPrinter->scrollDistance) + { + if (textPrinter->scrollDistance < gUnknown_846FB08[gSaveBlock2Ptr->optionsTextSpeed]) + { + ScrollWindow(textPrinter->subPrinter.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->subPrinter.bgColor)); + textPrinter->scrollDistance = 0; + } + else + { + ScrollWindow(textPrinter->subPrinter.windowId, 0, gUnknown_846FB08[gSaveBlock2Ptr->optionsTextSpeed], PIXEL_FILL(textPrinter->subPrinter.bgColor)); + textPrinter->scrollDistance -= gUnknown_846FB08[gSaveBlock2Ptr->optionsTextSpeed]; + } + CopyWindowToVram(textPrinter->subPrinter.windowId, 2); + } + else + { + textPrinter->state = 0; + } + return 3; + case 5: + if (!IsSEPlaying()) + { + textPrinter->state = 0; + } + return 3; + case 6: + if (textPrinter->delayCounter) + { + textPrinter->delayCounter --; + } + else + { + textPrinter->state = 0; + } + return 3; + } + return 1; +} + +static void DecompressGlyphFont6(u16 glyph) +{ + const u16 *glyphs; + + glyphs = sFont6BrailleGlyphs + 0x100 * (glyph / 8) + 0x10 * (glyph % 8); + DecompressGlyphTile(glyphs, (u16 *)gGlyphInfo); + DecompressGlyphTile(glyphs + 0x8, (u16 *)(gGlyphInfo + 0x20)); + DecompressGlyphTile(glyphs + 0x80, (u16 *)(gGlyphInfo + 0x40)); + DecompressGlyphTile(glyphs + 0x88, (u16 *)(gGlyphInfo + 0x60)); + gGlyphInfo[0x80] = 0x10; + gGlyphInfo[0x81] = 0x10; +} + +u32 GetGlyphWidthFont6(u16 font_type, bool32 isJapanese) +{ + return 0x10; +} diff --git a/src/cereader_tool.c b/src/cereader_tool.c new file mode 100644 index 000000000..1b25f4828 --- /dev/null +++ b/src/cereader_tool.c @@ -0,0 +1,88 @@ +#include "global.h" +#include "util.h" +#include "save.h" +#include "malloc.h" +#include "cereader_tool.h" + +u8 sub_815D654(void) +{ + return (gSaveBlock1Ptr->unkArray[0].unk9 + 1) % 256; +} + +static bool32 ValidateTrainerTowerTrainer(struct TrainerTowerTrainer * trainer) +{ + if (trainer->unk_001 < 1 || trainer->unk_001 > 8) + return FALSE; + if (trainer->unk_002 > 2) + return FALSE; + if (CalcByteArraySum((const u8 *)trainer, offsetof(typeof(*trainer), checksum)) != trainer->checksum) + return FALSE; + return TRUE; +} + +bool32 ValidateTrainerTowerData(struct TrainerTowerData * ttdata) +{ + u32 count = ttdata->count; + s32 i; + if (count < 1 || count > 8) + return FALSE; + for (i = 0; i < count; i++) + { + if (!ValidateTrainerTowerTrainer(&ttdata->trainers[i])) + return FALSE; + } + if (CalcByteArraySum((const u8 *)ttdata->trainers, count * sizeof(ttdata->trainers[0])) != ttdata->checksum) + return FALSE; + return TRUE; +} + +#define SEC30_SIZE (offsetof(struct TrainerTowerData, trainers[4])) +#define SEC31_SIZE (sizeof(struct TrainerTowerData) - SEC30_SIZE) + +static bool32 CEReaderTool_SaveTrainerTower_r(struct TrainerTowerData * ttdata, u8 * buffer) +{ + AGB_ASSERT_EX(ttdata->dummy == 0, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/cereader_tool.c", 198); + AGB_ASSERT_EX(ttdata->id == 0, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/cereader_tool.c", 199) + + memset(buffer, 0, 0x1000); + memcpy(buffer, ttdata, SEC30_SIZE); + buffer[1] = sub_815D654(); + if (TryWriteSpecialSaveSection(30, buffer) != TRUE) + return FALSE; + memset(buffer, 0, 0x1000); + memcpy(buffer, (u8 *)ttdata + SEC30_SIZE, SEC31_SIZE); + if (TryWriteSpecialSaveSection(31, buffer) != TRUE) + return FALSE; + return TRUE; +} + +bool32 CEReaderTool_SaveTrainerTower(struct TrainerTowerData * ttdata) +{ + u8 * buffer = AllocZeroed(0x1000); + bool32 result = CEReaderTool_SaveTrainerTower_r(ttdata, buffer); + Free(buffer); + return result; +} + +static bool32 CEReaderTool_LoadTrainerTower_r(struct TrainerTowerData * ttdata, void * buffer) +{ + if (TryCopySpecialSaveSection(30, buffer) != 1) + return FALSE; + memcpy(ttdata + 0x000, buffer, SEC30_SIZE); + + if (TryCopySpecialSaveSection(31, buffer) != 1) + return FALSE; + memcpy((u8 *)ttdata + SEC30_SIZE, buffer, SEC31_SIZE); + + if (!ValidateTrainerTowerData(ttdata)) + return FALSE; + return TRUE; +} + +bool32 CEReaderTool_LoadTrainerTower(struct TrainerTowerData * ttdata) +{ + void * buffer = AllocZeroed(0x1000); + bool32 success = CEReaderTool_LoadTrainerTower_r(ttdata, buffer); + Free(buffer); + return success; +} diff --git a/src/coins.c b/src/coins.c index 08646e2f9..3a51f6813 100644 --- a/src/coins.c +++ b/src/coins.c @@ -3,8 +3,8 @@ #include "text.h" #include "menu.h" #include "text_window.h" +#include "strings.h" -extern const u8 gText_Coins[]; extern const u8 gUnknown_8417C2D[]; EWRAM_DATA static u8 sCoinsWindowId = 0; @@ -87,7 +87,7 @@ void ShowCoinsWindow(u32 coinAmount, u8 x, u8 y) sCoinsWindowId = AddWindow(&template2); FillWindowPixelBuffer(sCoinsWindowId, 0); PutWindowTilemap(sCoinsWindowId); - sub_814FF2C(sCoinsWindowId, 0x21D, 0xD0); + TextWindow_SetStdFrame0_WithPal(sCoinsWindowId, 0x21D, 0xD0); SetWindowBorderStyle(sCoinsWindowId, FALSE, 0x21D, 0xD); AddTextPrinterParameterized(sCoinsWindowId, 2, gUnknown_8417C2D, 0, 0, 0xFF, 0); PrintCoinsString(coinAmount); @@ -96,6 +96,6 @@ void ShowCoinsWindow(u32 coinAmount, u8 x, u8 y) void HideCoinsWindow(void) { ClearWindowTilemap(sCoinsWindowId); - sub_810F4D8(sCoinsWindowId, TRUE); + ClearMenuWindow(sCoinsWindowId, TRUE); RemoveWindow(sCoinsWindowId); } diff --git a/src/coord_event_weather.c b/src/coord_event_weather.c new file mode 100644 index 000000000..4dbdd574b --- /dev/null +++ b/src/coord_event_weather.c @@ -0,0 +1,47 @@ +#include "global.h" + +void nullsub_27(void) {} +void nullsub_28(void) {} +void nullsub_29(void) {} +void nullsub_30(void) {} +void nullsub_31(void) {} +void nullsub_32(void) {} +void nullsub_33(void) {} +void nullsub_34(void) {} +void nullsub_35(void) {} +void nullsub_36(void) {} +void nullsub_37(void) {} +void nullsub_38(void) {} +void nullsub_39(void) {} + +struct { + u8 weatherId; + void (*callback)(void); +} const gUnknown_83A72A8[] = { + {0x01, nullsub_27}, + {0x02, nullsub_28}, + {0x03, nullsub_29}, + {0x04, nullsub_30}, + {0x05, nullsub_31}, + {0x06, nullsub_32}, + {0x07, nullsub_33}, + {0x08, nullsub_34}, + {0x09, nullsub_35}, + {0x0a, nullsub_36}, + {0x0b, nullsub_37}, + {0x14, nullsub_38}, + {0x15, nullsub_39} +}; + +void trigger_activate_weather(u8 weatherId) +{ + u8 i; + for (i = 0; i < NELEMS(gUnknown_83A72A8); i++) + { + if (gUnknown_83A72A8[i].weatherId == weatherId) + { + gUnknown_83A72A8[i].callback(); + return; + } + } +} diff --git a/src/data/items.json b/src/data/items.json new file mode 100644 index 000000000..b976e4c3e --- /dev/null +++ b/src/data/items.json @@ -0,0 +1,6062 @@ +{ + "items": [ + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MASTER BALL", + "itemId": "ITEM_MASTER_BALL", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The best BALL with the ultimate\\nperformance. It will catch any wild\\nPOKéMON without fail.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 0, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 0 + }, + { + "english": "ULTRA BALL", + "itemId": "ITEM_ULTRA_BALL", + "price": 1200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A very high-grade BALL that offers\\na higher POKéMON catch rate than\\na GREAT BALL.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 1 + }, + { + "english": "GREAT BALL", + "itemId": "ITEM_GREAT_BALL", + "price": 600, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A good, quality BALL that offers\\na higher POKéMON catch rate than\\na standard POKé BALL.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 2, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 2 + }, + { + "english": "POK\u00e9 BALL", + "itemId": "ITEM_POKE_BALL", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A BALL thrown to catch a wild\\nPOKéMON. It is designed in a\\ncapsule style.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 3, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 3 + }, + { + "english": "SAFARI BALL", + "itemId": "ITEM_SAFARI_BALL", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A special BALL that is used only in\\nthe SAFARI ZONE. It is finished in\\na camouflage pattern.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 4, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 4 + }, + { + "english": "NET BALL", + "itemId": "ITEM_NET_BALL", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A somewhat different BALL that\\nworks especially well on WATER- and\\nBUG-type POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 5, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 5 + }, + { + "english": "DIVE BALL", + "itemId": "ITEM_DIVE_BALL", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A somewhat different BALL that\\nworks especially well on POKéMON\\ndeep in the sea.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 6, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 6 + }, + { + "english": "NEST BALL", + "itemId": "ITEM_NEST_BALL", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A somewhat different BALL that\\nworks especially well on weaker\\nPOKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 7, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 7 + }, + { + "english": "REPEAT BALL", + "itemId": "ITEM_REPEAT_BALL", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A somewhat different BALL that\\nworks especially well on POKéMON\\ncaught before.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 8, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 8 + }, + { + "english": "TIMER BALL", + "itemId": "ITEM_TIMER_BALL", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A somewhat different BALL that\\nbecomes progressively better the\\nmore turns there are in a battle.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 9, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 9 + }, + { + "english": "LUXURY BALL", + "itemId": "ITEM_LUXURY_BALL", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A comfortable BALL that makes a\\ncaptured wild POKéMON quickly grow\\nfriendly.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 10, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 10 + }, + { + "english": "PREMIER BALL", + "itemId": "ITEM_PREMIER_BALL", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A rare BALL that has been\\nspecially made to commemorate an\\nevent of some sort.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_POKE_BALLS", + "type": 11, + "fieldUseFunc": "NULL", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeBallEtc", + "secondaryId": 11 + }, + { + "english": "POTION", + "itemId": "ITEM_POTION", + "price": 300, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 20, + "description_english": "A spray-type wound medicine.\\nIt restores the HP of one POKéMON\\nby 20 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "ANTIDOTE", + "itemId": "ITEM_ANTIDOTE", + "price": 100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A spray-type medicine.\\nIt heals one POKéMON from a\\npoisoning.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "BURN HEAL", + "itemId": "ITEM_BURN_HEAL", + "price": 250, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A spray-type medicine.\\nIt heals one POKéMON of a burn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "ICE HEAL", + "itemId": "ITEM_ICE_HEAL", + "price": 250, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A spray-type medicine.\\nIt defrosts a frozen POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "AWAKENING", + "itemId": "ITEM_AWAKENING", + "price": 250, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A spray-type medicine.\\nIt awakens a sleeping POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "PARLYZ HEAL", + "itemId": "ITEM_PARALYZE_HEAL", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A spray-type medicine.\\nIt heals one POKéMON from\\nparalysis.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "FULL RESTORE", + "itemId": "ITEM_FULL_RESTORE", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 255, + "description_english": "A medicine that fully restores the\\nHP and heals any status problems\\nof one POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "MAX POTION", + "itemId": "ITEM_MAX_POTION", + "price": 2500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 255, + "description_english": "A spray-type wound medicine.\\nIt fully restores the HP of one\\nPOKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "HYPER POTION", + "itemId": "ITEM_HYPER_POTION", + "price": 1200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 200, + "description_english": "A spray-type wound medicine.\\nIt restores the HP of one POKéMON\\nby 200 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "SUPER POTION", + "itemId": "ITEM_SUPER_POTION", + "price": 700, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 50, + "description_english": "A spray-type wound medicine.\\nIt restores the HP of one POKéMON\\nby 50 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "FULL HEAL", + "itemId": "ITEM_FULL_HEAL", + "price": 600, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A spray-type medicine.\\nIt heals all the status problems of\\none POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "REVIVE", + "itemId": "ITEM_REVIVE", + "price": 1500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A medicine that revives a fainted\\nPOKéMON, restoring HP by half the\\nmaximum amount.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "MAX REVIVE", + "itemId": "ITEM_MAX_REVIVE", + "price": 4000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A medicine that revives a fainted\\nPOKéMON, restoring HP fully.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "FRESH WATER", + "itemId": "ITEM_FRESH_WATER", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 50, + "description_english": "Water with a high mineral content.\\nIt restores the HP of one POKéMON\\nby 50 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "SODA POP", + "itemId": "ITEM_SODA_POP", + "price": 300, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 60, + "description_english": "A fizzy soda drink.\\nIt restores the HP of one POKéMON\\nby 60 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "LEMONADE", + "itemId": "ITEM_LEMONADE", + "price": 350, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 80, + "description_english": "A very sweet drink.\\nIt restores the HP of one POKéMON\\nby 80 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "MOOMOO MILK", + "itemId": "ITEM_MOOMOO_MILK", + "price": 500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 100, + "description_english": "Highly nutritious milk.\\nIt restores the HP of one POKéMON\\nby 100 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "ENERGYPOWDER", + "itemId": "ITEM_ENERGY_POWDER", + "price": 500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A very bitter medicine powder.\\nIt restores the HP of one POKéMON\\nby 50 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "ENERGY ROOT", + "itemId": "ITEM_ENERGY_ROOT", + "price": 800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A very bitter root.\\nIt restores the HP of one POKéMON\\nby 200 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "HEAL POWDER", + "itemId": "ITEM_HEAL_POWDER", + "price": 450, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A very bitter medicine powder.\\nIt heals all the status problems of\\none POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "REVIVAL HERB", + "itemId": "ITEM_REVIVAL_HERB", + "price": 2800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A very bitter medicinal herb.\\nIt revives a fainted POKéMON,\\nrestoring HP fully.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "ETHER", + "itemId": "ITEM_ETHER", + "price": 1200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 10, + "description_english": "Restores a selected move's PP by\\n10 points for one POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Ether", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Ether", + "secondaryId": 0 + }, + { + "english": "MAX ETHER", + "itemId": "ITEM_MAX_ETHER", + "price": 2000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 255, + "description_english": "Fully restores a selected move's PP\\nfor one POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Ether", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Ether", + "secondaryId": 0 + }, + { + "english": "ELIXIR", + "itemId": "ITEM_ELIXIR", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 10, + "description_english": "Restores the PP of all moves for\\none POKéMON by 10 points each.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Ether", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Ether", + "secondaryId": 0 + }, + { + "english": "MAX ELIXIR", + "itemId": "ITEM_MAX_ELIXIR", + "price": 4500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 255, + "description_english": "Fully restores the PP of all moves\\nfor one POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Ether", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Ether", + "secondaryId": 0 + }, + { + "english": "LAVA COOKIE", + "itemId": "ITEM_LAVA_COOKIE", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "LAVARIDGE TOWN's local specialty.\\nIt heals all the status problems of\\none POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "BLUE FLUTE", + "itemId": "ITEM_BLUE_FLUTE", + "price": 100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A blue glass flute that awakens\\na sleeping POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "YELLOW FLUTE", + "itemId": "ITEM_YELLOW_FLUTE", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A yellow glass flute that snaps one\\nPOKéMON out of confusion.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "RED FLUTE", + "itemId": "ITEM_RED_FLUTE", + "price": 300, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A red glass flute that snaps one\\nPOKéMON out of infatuation.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "BLACK FLUTE", + "itemId": "ITEM_BLACK_FLUTE", + "price": 400, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 50, + "description_english": "A black glass flute.\\nWhen blown, it makes wild POKéMON\\nless likely to appear.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_BlackFlute", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "WHITE FLUTE", + "itemId": "ITEM_WHITE_FLUTE", + "price": 500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 150, + "description_english": "A white glass flute.\\nWhen blown, it makes wild POKéMON\\nmore likely to appear.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_BlackFlute", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BERRY JUICE", + "itemId": "ITEM_BERRY_JUICE", + "price": 100, + "holdEffect": "HOLD_EFFECT_RESTORE_HP", + "holdEffectParam": 20, + "description_english": "A 100% pure juice.\\nIt restores the HP of one POKéMON\\nby 20 points.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "SACRED ASH", + "itemId": "ITEM_SACRED_ASH", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Revives all fainted POKéMON,\\nrestoring HP fully.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_SacredAsh", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SHOAL SALT", + "itemId": "ITEM_SHOAL_SALT", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Pure salt obtained from deep inside\\nthe SHOAL CAVE. It is extremely\\nsalty.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SHOAL SHELL", + "itemId": "ITEM_SHOAL_SHELL", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A pretty seashell found deep inside\\nthe SHOAL CAVE. It is striped in\\nblue and white.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RED SHARD", + "itemId": "ITEM_RED_SHARD", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A small red shard.\\nIt appears to be from some sort of\\na tool made long ago.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BLUE SHARD", + "itemId": "ITEM_BLUE_SHARD", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A small blue shard.\\nIt appears to be from some sort of\\na tool made long ago.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "YELLOW SHARD", + "itemId": "ITEM_YELLOW_SHARD", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A small yellow shard.\\nIt appears to be from some sort of\\na tool made long ago.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "GREEN SHARD", + "itemId": "ITEM_GREEN_SHARD", + "price": 200, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A small green shard.\\nIt appears to be from some sort of\\na tool made long ago.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "HP UP", + "itemId": "ITEM_HP_UP", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A nutritious drink for POKéMON.\\nIt raises the base HP of one\\nPOKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "PROTEIN", + "itemId": "ITEM_PROTEIN", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A nutritious drink for POKéMON.\\nIt raises the base ATTACK stat of\\none POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "IRON", + "itemId": "ITEM_IRON", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A nutritious drink for POKéMON.\\nIt raises the base DEFENSE stat of\\none POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CARBOS", + "itemId": "ITEM_CARBOS", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A nutritious drink for POKéMON.\\nIt raises the base SPEED stat of\\none POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CALCIUM", + "itemId": "ITEM_CALCIUM", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A nutritious drink for POKéMON.\\nIt raises the base SP. ATK stat\\nof one POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RARE CANDY", + "itemId": "ITEM_RARE_CANDY", + "price": 4800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A candy that is packed with energy.\\nIt raises the level of a POKéMON\\nby one.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_RareCandy", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "PP UP", + "itemId": "ITEM_PP_UP", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Slightly raises the maximum PP of\\na selected move for one POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_PpUp", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "ZINC", + "itemId": "ITEM_ZINC", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A nutritious drink for POKéMON.\\nIt raises the base SP. DEF stat\\nof one POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "PP MAX", + "itemId": "ITEM_PP_MAX", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Raises the PP of a selected move\\nto its maximum level for one\\nPOKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_PpUp", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "GUARD SPEC.", + "itemId": "ITEM_GUARD_SPEC", + "price": 700, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An item that prevents stat reduction\\namong party POKéMON for five turns\\nafter use.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_GuardSpec", + "secondaryId": 0 + }, + { + "english": "DIRE HIT", + "itemId": "ITEM_DIRE_HIT", + "price": 650, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Raises the critical-hit ratio of\\nPOKéMON in battle. Wears off if the\\nPOKéMON is withdrawn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_GuardSpec", + "secondaryId": 0 + }, + { + "english": "X ATTACK", + "itemId": "ITEM_X_ATTACK", + "price": 500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Raises the ATTACK stat of POKéMON\\nin battle. Wears off if the POKéMON\\nis withdrawn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_GuardSpec", + "secondaryId": 0 + }, + { + "english": "X DEFEND", + "itemId": "ITEM_X_DEFEND", + "price": 550, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Raises the DEFENSE stat of POKéMON\\nin battle. Wears off if the POKéMON\\nis withdrawn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_GuardSpec", + "secondaryId": 0 + }, + { + "english": "X SPEED", + "itemId": "ITEM_X_SPEED", + "price": 350, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Raises the SPEED stat of POKéMON\\nin battle. Wears off if the POKéMON\\nis withdrawn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_GuardSpec", + "secondaryId": 0 + }, + { + "english": "X ACCURACY", + "itemId": "ITEM_X_ACCURACY", + "price": 950, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Raises the accuracy stat of\\nPOKéMON in battle. Wears off if the\\nPOKéMON is withdrawn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_GuardSpec", + "secondaryId": 0 + }, + { + "english": "X SPECIAL", + "itemId": "ITEM_X_SPECIAL", + "price": 350, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Raises the SP. ATK stat of\\nPOKéMON in battle. Wears off if the\\nPOKéMON is withdrawn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_GuardSpec", + "secondaryId": 0 + }, + { + "english": "POK\u00e9 DOLL", + "itemId": "ITEM_POKE_DOLL", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An attractive doll.\\nUse it to flee from any battle with\\na wild POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeDoll", + "secondaryId": 0 + }, + { + "english": "FLUFFY TAIL", + "itemId": "ITEM_FLUFFY_TAIL", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An attractive item.\\nUse it to flee from any battle with\\na wild POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeDoll", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SUPER REPEL", + "itemId": "ITEM_SUPER_REPEL", + "price": 500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 200, + "description_english": "Prevents weak wild POKéMON from\\nappearing for 200 steps.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_SuperRepel", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MAX REPEL", + "itemId": "ITEM_MAX_REPEL", + "price": 700, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 250, + "description_english": "Prevents weak wild POKéMON from\\nappearing for 250 steps.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_SuperRepel", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "ESCAPE ROPE", + "itemId": "ITEM_ESCAPE_ROPE", + "price": 550, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A long, durable rope.\\nUse it to escape instantly from a\\ncave or a dungeon.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 2, + "fieldUseFunc": "ItemUseOutOfBattle_EscapeRope", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "REPEL", + "itemId": "ITEM_REPEL", + "price": 350, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 100, + "description_english": "Prevents weak wild POKéMON from\\nappearing for 100 steps.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_SuperRepel", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SUN STONE", + "itemId": "ITEM_SUN_STONE", + "price": 2100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A peculiar stone that makes certain\\nspecies of POKéMON evolve.\\nIt is as red as the sun.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_EvoItem", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MOON STONE", + "itemId": "ITEM_MOON_STONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A peculiar stone that makes certain\\nspecies of POKéMON evolve.\\nIt is as black as the night sky.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_EvoItem", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "FIRE STONE", + "itemId": "ITEM_FIRE_STONE", + "price": 2100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A peculiar stone that makes certain\\nspecies of POKéMON evolve.\\nIt is colored orange.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_EvoItem", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "THUNDERSTONE", + "itemId": "ITEM_THUNDER_STONE", + "price": 2100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A peculiar stone that makes certain\\nspecies of POKéMON evolve.\\nIt has a thunderbolt pattern.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_EvoItem", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "WATER STONE", + "itemId": "ITEM_WATER_STONE", + "price": 2100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A peculiar stone that makes certain\\nspecies of POKéMON evolve.\\nIt is a clear light blue.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_EvoItem", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LEAF STONE", + "itemId": "ITEM_LEAF_STONE", + "price": 2100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A peculiar stone that makes certain\\nspecies of POKéMON evolve.\\nIt has a leaf pattern.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 1, + "fieldUseFunc": "FieldUseFunc_EvoItem", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "TINYMUSHROOM", + "itemId": "ITEM_TINY_MUSHROOM", + "price": 500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A small and rare mushroom.\\nIt is quite popular among certain\\npeople.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BIG MUSHROOM", + "itemId": "ITEM_BIG_MUSHROOM", + "price": 5000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A large and rare mushroom.\\nIt is very popular among certain\\npeople.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "PEARL", + "itemId": "ITEM_PEARL", + "price": 1400, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A relatively small pearl that\\nsparkles in a pretty silver color.\\nIt can be sold cheaply.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BIG PEARL", + "itemId": "ITEM_BIG_PEARL", + "price": 7500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A quite-large pearl that sparkles\\nin a pretty silver color.\\nIt can be sold at a high price.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "STARDUST", + "itemId": "ITEM_STARDUST", + "price": 2000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A pretty red sand with a loose,\\nsilky feel.\\nIt can be sold at a high price.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "STAR PIECE", + "itemId": "ITEM_STAR_PIECE", + "price": 9800, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A shard of a pretty gem that\\nsparkles in a red color.\\nIt can be sold at a high price.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "NUGGET", + "itemId": "ITEM_NUGGET", + "price": 10000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A nugget of pure gold that gives\\noff a lustrous gleam.\\nIt can be sold at a high price.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "HEART SCALE", + "itemId": "ITEM_HEART_SCALE", + "price": 100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A pretty, heart-shaped scale that\\nis extremely rare. It glows faintly\\nin the colors of a rainbow.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "ORANGE MAIL", + "itemId": "ITEM_ORANGE_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a cute\\nZIGZAGOON print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "HARBOR MAIL", + "itemId": "ITEM_HARBOR_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a cute\\nWINGULL print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 1 + }, + { + "english": "GLITTER MAIL", + "itemId": "ITEM_GLITTER_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a cute\\nPIKACHU print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 2 + }, + { + "english": "MECH MAIL", + "itemId": "ITEM_MECH_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a cute\\nMAGNEMITE print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 3 + }, + { + "english": "WOOD MAIL", + "itemId": "ITEM_WOOD_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a cute\\nSLAKOTH print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 4 + }, + { + "english": "WAVE MAIL", + "itemId": "ITEM_WAVE_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a cute\\nWAILMER print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 5 + }, + { + "english": "BEAD MAIL", + "itemId": "ITEM_BEAD_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL to be held by a\\nPOKéMON. It will bear the print of\\nthe POKéMON holding it.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 6 + }, + { + "english": "SHADOW MAIL", + "itemId": "ITEM_SHADOW_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a cute\\nDUSKULL print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 7 + }, + { + "english": "TROPIC MAIL", + "itemId": "ITEM_TROPIC_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a cute\\nBELLOSSOM print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 8 + }, + { + "english": "DREAM MAIL", + "itemId": "ITEM_DREAM_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL to be held by a\\nPOKéMON. It will bear the print of\\nthe POKéMON holding it.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 9 + }, + { + "english": "FAB MAIL", + "itemId": "ITEM_FAB_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a\\ngorgeous, extravagant print.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 10 + }, + { + "english": "RETRO MAIL", + "itemId": "ITEM_RETRO_MAIL", + "price": 50, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of MAIL featuring a print\\nof three cute POKéMON.\\nIt is to be held by a POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 0, + "fieldUseFunc": "FieldUseFunc_OrangeMail", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 11 + }, + { + "english": "CHERI BERRY", + "itemId": "ITEM_CHERI_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CURE_PAR", + "holdEffectParam": 0, + "description_english": "When held by a POKéMON, it will be\\nused in battle to heal paralysis.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "CHESTO BERRY", + "itemId": "ITEM_CHESTO_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CURE_SLP", + "holdEffectParam": 0, + "description_english": "When held by a POKéMON, it will be\\nused in battle to wake up.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "PECHA BERRY", + "itemId": "ITEM_PECHA_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CURE_PSN", + "holdEffectParam": 0, + "description_english": "When held by a POKéMON, it will be\\nused in battle to cure poison.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "RAWST BERRY", + "itemId": "ITEM_RAWST_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CURE_BRN", + "holdEffectParam": 0, + "description_english": "When held by a POKéMON, it will be\\nused in battle to heal a burn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "ASPEAR BERRY", + "itemId": "ITEM_ASPEAR_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CURE_FRZ", + "holdEffectParam": 0, + "description_english": "When held by a POKéMON, it will be\\nused in battle for defrosting.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "LEPPA BERRY", + "itemId": "ITEM_LEPPA_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_RESTORE_PP", + "holdEffectParam": 10, + "description_english": "When held by a POKéMON, it will be\\nused in battle to restore 10 PP.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Ether", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Ether", + "secondaryId": 0 + }, + { + "english": "ORAN BERRY", + "itemId": "ITEM_ORAN_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_RESTORE_HP", + "holdEffectParam": 10, + "description_english": "When held by a POKéMON, it will be\\nused in battle to restore 10 HP.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "PERSIM BERRY", + "itemId": "ITEM_PERSIM_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CURE_CONFUSION", + "holdEffectParam": 0, + "description_english": "When held by a POKéMON, it will be\\nused in battle to lift confusion.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "LUM BERRY", + "itemId": "ITEM_LUM_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CURE_STATUS", + "holdEffectParam": 0, + "description_english": "When held by a POKéMON, it will be\\nused in battle to heal any problem.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "SITRUS BERRY", + "itemId": "ITEM_SITRUS_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_RESTORE_HP", + "holdEffectParam": 30, + "description_english": "When held by a POKéMON, it will be\\nused in battle to restore 30 HP.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 1, + "fieldUseFunc": "FieldUseFunc_Medicine", + "battleUsage": 1, + "battleUseFunc": "BattleUseFunc_Medicine", + "secondaryId": 0 + }, + { + "english": "FIGY BERRY", + "itemId": "ITEM_FIGY_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CONFUSE_SPICY", + "holdEffectParam": 8, + "description_english": "A hold item that restores HP but\\nmay cause confusion when used.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "WIKI BERRY", + "itemId": "ITEM_WIKI_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CONFUSE_DRY", + "holdEffectParam": 8, + "description_english": "A hold item that restores HP but\\nmay cause confusion when used.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MAGO BERRY", + "itemId": "ITEM_MAGO_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CONFUSE_SWEET", + "holdEffectParam": 8, + "description_english": "A hold item that restores HP but\\nmay cause confusion when used.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "AGUAV BERRY", + "itemId": "ITEM_AGUAV_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CONFUSE_BITTER", + "holdEffectParam": 8, + "description_english": "A hold item that restores HP but\\nmay cause confusion when used.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "IAPAPA BERRY", + "itemId": "ITEM_IAPAPA_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CONFUSE_SOUR", + "holdEffectParam": 8, + "description_english": "A hold item that restores HP but\\nmay cause confusion when used.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RAZZ BERRY", + "itemId": "ITEM_RAZZ_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BLUK BERRY", + "itemId": "ITEM_BLUK_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "NANAB BERRY", + "itemId": "ITEM_NANAB_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "WEPEAR BERRY", + "itemId": "ITEM_WEPEAR_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "PINAP BERRY", + "itemId": "ITEM_PINAP_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "POMEG BERRY", + "itemId": "ITEM_POMEG_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "KELPSY BERRY", + "itemId": "ITEM_KELPSY_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "QUALOT BERRY", + "itemId": "ITEM_QUALOT_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "HONDEW BERRY", + "itemId": "ITEM_HONDEW_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "GREPA BERRY", + "itemId": "ITEM_GREPA_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "TAMATO BERRY", + "itemId": "ITEM_TAMATO_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CORNN BERRY", + "itemId": "ITEM_CORNN_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MAGOST BERRY", + "itemId": "ITEM_MAGOST_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RABUTA BERRY", + "itemId": "ITEM_RABUTA_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "NOMEL BERRY", + "itemId": "ITEM_NOMEL_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SPELON BERRY", + "itemId": "ITEM_SPELON_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "PAMTRE BERRY", + "itemId": "ITEM_PAMTRE_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "WATMEL BERRY", + "itemId": "ITEM_WATMEL_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "DURIN BERRY", + "itemId": "ITEM_DURIN_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BELUE BERRY", + "itemId": "ITEM_BELUE_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LIECHI BERRY", + "itemId": "ITEM_LIECHI_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_ATTACK_UP", + "holdEffectParam": 4, + "description_english": "When held by a POKéMON, it raises\\nthe ATTACK stat in a pinch.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "GANLON BERRY", + "itemId": "ITEM_GANLON_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_DEFENSE_UP", + "holdEffectParam": 4, + "description_english": "When held by a POKéMON, it raises\\nthe DEFENSE stat in a pinch.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SALAC BERRY", + "itemId": "ITEM_SALAC_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_SPEED_UP", + "holdEffectParam": 4, + "description_english": "When held by a POKéMON, it raises\\nthe SPEED stat in a pinch.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "PETAYA BERRY", + "itemId": "ITEM_PETAYA_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_SP_ATTACK_UP", + "holdEffectParam": 4, + "description_english": "When held by a POKéMON, it raises\\nthe SP. ATK stat in a pinch.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "APICOT BERRY", + "itemId": "ITEM_APICOT_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_SP_DEFENSE_UP", + "holdEffectParam": 4, + "description_english": "When held by a POKéMON, it raises\\nthe SP. DEF stat in a pinch.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LANSAT BERRY", + "itemId": "ITEM_LANSAT_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_CRITICAL_UP", + "holdEffectParam": 4, + "description_english": "When held by a POKéMON, it raises\\nthe critical-hit ratio in a pinch.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "STARF BERRY", + "itemId": "ITEM_STARF_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_RANDOM_STAT_UP", + "holdEffectParam": 4, + "description_english": "When held by a POKéMON, it sharply\\nraises one stat in a pinch.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "ENIGMA BERRY", + "itemId": "ITEM_ENIGMA_BERRY", + "price": 20, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Can be ground up into a powder as\\nan ingredient for medicine.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_BERRY_POUCH", + "type": 4, + "fieldUseFunc": "ItemUseOutOfBattle_EnigmaBerry", + "battleUsage": 1, + "battleUseFunc": "ItemUseInBattle_EnigmaBerry", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BRIGHTPOWDER", + "itemId": "ITEM_BRIGHT_POWDER", + "price": 10, + "holdEffect": "HOLD_EFFECT_EVASION_UP", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nIt casts a tricky glare that lowers\\nthe opponent's accuracy.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "WHITE HERB", + "itemId": "ITEM_WHITE_HERB", + "price": 100, + "holdEffect": "HOLD_EFFECT_RESTORE_STATS", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt restores any lowered stat in\\nbattle. It can be used only once.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MACHO BRACE", + "itemId": "ITEM_MACHO_BRACE", + "price": 3000, + "holdEffect": "HOLD_EFFECT_MACHO_BRACE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt promotes strong growth but\\nlowers SPEED while it is held.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "EXP. SHARE", + "itemId": "ITEM_EXP_SHARE", + "price": 3000, + "holdEffect": "HOLD_EFFECT_EXP_SHARE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nThe holder gets a share of EXP.\\npoints without having to battle.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "QUICK CLAW", + "itemId": "ITEM_QUICK_CLAW", + "price": 100, + "holdEffect": "HOLD_EFFECT_QUICK_CLAW", + "holdEffectParam": 20, + "description_english": "An item to be held by a POKéMON.\\nA light and sharp claw. The holder\\nmay be able to strike first.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SOOTHE BELL", + "itemId": "ITEM_SOOTHE_BELL", + "price": 100, + "holdEffect": "HOLD_EFFECT_HAPPINESS_UP", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nA bell with a comforting chime that\\nmakes the holder calm and friendly.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MENTAL HERB", + "itemId": "ITEM_MENTAL_HERB", + "price": 100, + "holdEffect": "HOLD_EFFECT_CURE_ATTRACT", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt snaps the holder out of\\ninfatuation. It can be used once.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CHOICE BAND", + "itemId": "ITEM_CHOICE_BAND", + "price": 100, + "holdEffect": "HOLD_EFFECT_CHOICE_BAND", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt powers up one move, which\\nbecomes the only usable one.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "KING'S ROCK", + "itemId": "ITEM_KINGS_ROCK", + "price": 100, + "holdEffect": "HOLD_EFFECT_FLINCH", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nIt may cause the foe to flinch\\nupon taking damage.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SILVERPOWDER", + "itemId": "ITEM_SILVER_POWDER", + "price": 100, + "holdEffect": "HOLD_EFFECT_BUG_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA shiny silver powder that boosts\\nthe power of BUG-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "AMULET COIN", + "itemId": "ITEM_AMULET_COIN", + "price": 100, + "holdEffect": "HOLD_EFFECT_DOUBLE_PRIZE", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nIt doubles the battle money if the\\nholding POKéMON takes part.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CLEANSE TAG", + "itemId": "ITEM_CLEANSE_TAG", + "price": 200, + "holdEffect": "HOLD_EFFECT_REPEL", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt repels wild POKéMON if the\\nholder is first in the party.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SOUL DEW", + "itemId": "ITEM_SOUL_DEW", + "price": 200, + "holdEffect": "HOLD_EFFECT_SOUL_DEW", + "holdEffectParam": 0, + "description_english": "An orb to be held by a LATIOS or\\nLATIAS. It raises the SP. ATK\\nand SP. DEF stats.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "DEEPSEATOOTH", + "itemId": "ITEM_DEEP_SEA_TOOTH", + "price": 200, + "holdEffect": "HOLD_EFFECT_DEEP_SEA_TOOTH", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nA fang that gleams a sharp silver.\\nIt raises the SP. ATK stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "DEEPSEASCALE", + "itemId": "ITEM_DEEP_SEA_SCALE", + "price": 200, + "holdEffect": "HOLD_EFFECT_DEEP_SEA_SCALE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nA scale that shines a faint pink.\\nIt raises the SP. DEF stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SMOKE BALL", + "itemId": "ITEM_SMOKE_BALL", + "price": 200, + "holdEffect": "HOLD_EFFECT_CAN_ALWAYS_RUN", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nThe holding POKéMON can flee from\\nany wild POKéMON for sure.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "EVERSTONE", + "itemId": "ITEM_EVERSTONE", + "price": 200, + "holdEffect": "HOLD_EFFECT_PREVENT_EVOLVE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nThe holding POKéMON is prevented\\nfrom evolving.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "FOCUS BAND", + "itemId": "ITEM_FOCUS_BAND", + "price": 200, + "holdEffect": "HOLD_EFFECT_FOCUS_BAND", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nThe holding POKéMON may endure an\\nattack, leaving just 1 HP.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LUCKY EGG", + "itemId": "ITEM_LUCKY_EGG", + "price": 200, + "holdEffect": "HOLD_EFFECT_LUCKY_EGG", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nAn egg filled with happiness that\\nearns extra EXP. points in battle.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SCOPE LENS", + "itemId": "ITEM_SCOPE_LENS", + "price": 200, + "holdEffect": "HOLD_EFFECT_SCOPE_LENS", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nA lens that boosts the critical-hit\\nratio of the holding POKéMON.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "METAL COAT", + "itemId": "ITEM_METAL_COAT", + "price": 100, + "holdEffect": "HOLD_EFFECT_STEEL_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA special metallic film that boosts\\nthe power of STEEL-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LEFTOVERS", + "itemId": "ITEM_LEFTOVERS", + "price": 200, + "holdEffect": "HOLD_EFFECT_LEFTOVERS", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nThe holding POKéMON gradually\\nregains HP during battle.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "DRAGON SCALE", + "itemId": "ITEM_DRAGON_SCALE", + "price": 2100, + "holdEffect": "HOLD_EFFECT_DRAGON_SCALE", + "holdEffectParam": 10, + "description_english": "A thick and tough scale.\\nA DRAGON-type POKéMON may be\\nholding it.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LIGHT BALL", + "itemId": "ITEM_LIGHT_BALL", + "price": 100, + "holdEffect": "HOLD_EFFECT_LIGHT_BALL", + "holdEffectParam": 0, + "description_english": "An orb to be held by a PIKACHU\\nthat raises the SP. ATK stat.\\nTouching it may cause a shock.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SOFT SAND", + "itemId": "ITEM_SOFT_SAND", + "price": 100, + "holdEffect": "HOLD_EFFECT_GROUND_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA loose, silky sand that boosts the\\npower of GROUND-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "HARD STONE", + "itemId": "ITEM_HARD_STONE", + "price": 100, + "holdEffect": "HOLD_EFFECT_ROCK_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nAn unbreakable stone that boosts\\nthe power of ROCK-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MIRACLE SEED", + "itemId": "ITEM_MIRACLE_SEED", + "price": 100, + "holdEffect": "HOLD_EFFECT_GRASS_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA seed imbued with life that boosts\\nthe power of GRASS-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BLACKGLASSES", + "itemId": "ITEM_BLACK_GLASSES", + "price": 100, + "holdEffect": "HOLD_EFFECT_DARK_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA shady-looking pair of glasses\\nthat boosts DARK-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BLACK BELT", + "itemId": "ITEM_BLACK_BELT", + "price": 100, + "holdEffect": "HOLD_EFFECT_FIGHTING_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA belt that boosts determination\\nand FIGHTING-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MAGNET", + "itemId": "ITEM_MAGNET", + "price": 100, + "holdEffect": "HOLD_EFFECT_ELECTRIC_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA powerful magnet that boosts the\\npower of ELECTRIC-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MYSTIC WATER", + "itemId": "ITEM_MYSTIC_WATER", + "price": 100, + "holdEffect": "HOLD_EFFECT_WATER_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA teardrop-shaped gem that boosts\\nthe power of WATER-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SHARP BEAK", + "itemId": "ITEM_SHARP_BEAK", + "price": 100, + "holdEffect": "HOLD_EFFECT_FLYING_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA long, sharp beak that boosts the\\npower of FLYING-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "POISON BARB", + "itemId": "ITEM_POISON_BARB", + "price": 100, + "holdEffect": "HOLD_EFFECT_POISON_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA small, poisonous barb that boosts\\nthe power of POISON-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "NEVERMELTICE", + "itemId": "ITEM_NEVER_MELT_ICE", + "price": 100, + "holdEffect": "HOLD_EFFECT_ICE_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA piece of ice that repels heat\\nand boosts ICE-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SPELL TAG", + "itemId": "ITEM_SPELL_TAG", + "price": 100, + "holdEffect": "HOLD_EFFECT_GHOST_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA sinister, eerie tag that boosts\\nGHOST-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "TWISTEDSPOON", + "itemId": "ITEM_TWISTED_SPOON", + "price": 100, + "holdEffect": "HOLD_EFFECT_PSYCHIC_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA spoon imbued with telekinetic\\npower boosts PSYCHIC-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CHARCOAL", + "itemId": "ITEM_CHARCOAL", + "price": 9800, + "holdEffect": "HOLD_EFFECT_FIRE_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA combustible fuel that boosts the\\npower of FIRE-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "DRAGON FANG", + "itemId": "ITEM_DRAGON_FANG", + "price": 100, + "holdEffect": "HOLD_EFFECT_DRAGON_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA hard and sharp fang that boosts\\nthe power of DRAGON-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SILK SCARF", + "itemId": "ITEM_SILK_SCARF", + "price": 100, + "holdEffect": "HOLD_EFFECT_NORMAL_POWER", + "holdEffectParam": 10, + "description_english": "An item to be held by a POKéMON.\\nA sumptuous scarf that boosts the\\npower of NORMAL-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "UP-GRADE", + "itemId": "ITEM_UP_GRADE", + "price": 2100, + "holdEffect": "HOLD_EFFECT_UP_GRADE", + "holdEffectParam": 0, + "description_english": "A transparent device filled with all\\nsorts of data.\\nIt is made by SILPH CO.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SHELL BELL", + "itemId": "ITEM_SHELL_BELL", + "price": 200, + "holdEffect": "HOLD_EFFECT_SHELL_BELL", + "holdEffectParam": 8, + "description_english": "An item to be held by a POKéMON.\\nThe holding POKéMON regains some\\nHP upon striking the foe.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SEA INCENSE", + "itemId": "ITEM_SEA_INCENSE", + "price": 9600, + "holdEffect": "HOLD_EFFECT_WATER_POWER", + "holdEffectParam": 5, + "description_english": "An item to be held by a POKéMON.\\nIt slightly boosts the power of\\nWATER-type moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LAX INCENSE", + "itemId": "ITEM_LAX_INCENSE", + "price": 9600, + "holdEffect": "HOLD_EFFECT_EVASION_UP", + "holdEffectParam": 5, + "description_english": "An item to be held by a POKéMON.\\nIts tricky aroma slightly reduces\\nthe foe's accuracy.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LUCKY PUNCH", + "itemId": "ITEM_LUCKY_PUNCH", + "price": 10, + "holdEffect": "HOLD_EFFECT_LUCKY_PUNCH", + "holdEffectParam": 0, + "description_english": "A glove to be held by a CHANSEY.\\nIt raises CHANSEY's critical-hit\\nratio.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "METAL POWDER", + "itemId": "ITEM_METAL_POWDER", + "price": 10, + "holdEffect": "HOLD_EFFECT_METAL_POWDER", + "holdEffectParam": 0, + "description_english": "A fine, hard powder to be held by\\na DITTO.\\nIt raises DITTO's DEFENSE stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "THICK CLUB", + "itemId": "ITEM_THICK_CLUB", + "price": 500, + "holdEffect": "HOLD_EFFECT_THICK_CLUB", + "holdEffectParam": 0, + "description_english": "A hard bone of some sort to be\\nheld by a CUBONE or MAROWAK.\\nIt raises the ATTACK stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "STICK", + "itemId": "ITEM_STICK", + "price": 200, + "holdEffect": "HOLD_EFFECT_STICK", + "holdEffectParam": 0, + "description_english": "A stick of leek to be held by a\\nFARFETCH'D. It raises FARFETCH'D's\\ncritical-hit ratio.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RED SCARF", + "itemId": "ITEM_RED_SCARF", + "price": 100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt boosts the holding POKéMON's\\nCOOL condition in CONTESTS.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BLUE SCARF", + "itemId": "ITEM_BLUE_SCARF", + "price": 100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt boosts the holding POKéMON's\\nBEAUTY condition in CONTESTS.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "PINK SCARF", + "itemId": "ITEM_PINK_SCARF", + "price": 100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt boosts the holding POKéMON's\\nCUTE condition in CONTESTS.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "GREEN SCARF", + "itemId": "ITEM_GREEN_SCARF", + "price": 100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt boosts the holding POKéMON's\\nSMART condition in CONTESTS.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "YELLOW SCARF", + "itemId": "ITEM_YELLOW_SCARF", + "price": 100, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An item to be held by a POKéMON.\\nIt boosts the holding POKéMON's\\nTOUGH condition in CONTESTS.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MACH BIKE", + "itemId": "ITEM_MACH_BIKE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A folding bicycle that is at least\\ntwice as fast as walking.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "FieldUseFunc_MachBike", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "COIN CASE", + "itemId": "ITEM_COIN_CASE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A case for holding COINS obtained\\nat the GAME CORNER.\\nIt holds up to 9,999 COINS.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_CoinCase", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "ITEMFINDER", + "itemId": "ITEM_ITEMFINDER", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A device used for finding items.\\nIf there is a hidden item nearby\\nwhen it is used, it emits a signal.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "ItemUseOutOfBattle_Itemfinder", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "OLD ROD", + "itemId": "ITEM_OLD_ROD", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An old and beat-up fishing rod.\\nUse it by any body of water to \\nfish for wild POKéMON.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "FieldUseFunc_OldRod", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "GOOD ROD", + "itemId": "ITEM_GOOD_ROD", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A new, good-quality fishing rod.\\nUse it by any body of water to \\nfish for wild POKéMON.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "FieldUseFunc_OldRod", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 1 + }, + { + "english": "SUPER ROD", + "itemId": "ITEM_SUPER_ROD", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An awesome, high-tech fishing rod.\\nUse it by any body of water to fish\\nfor wild POKéMON.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "FieldUseFunc_OldRod", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 2 + }, + { + "english": "S.S. TICKET", + "itemId": "ITEM_SS_TICKET", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The ticket required for sailing on\\nthe ferry S.S. ANNE.\\nIt has a drawing of a ship on it.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CONTEST PASS", + "itemId": "ITEM_CONTEST_PASS", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The pass required for entering\\nPOKéMON CONTESTS. It has a\\ndrawing of an award ribbon on it.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "WAILMER PAIL", + "itemId": "ITEM_WAILMER_PAIL", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A nifty watering pail.\\nUse it to promote strong growth in\\nBERRIES planted in soft soil.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "DEVON GOODS", + "itemId": "ITEM_DEVON_GOODS", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A package that contains mechanical\\nparts of some sort made by the\\nDEVON CORPORATION.", + "importance": 2, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SOOT SACK", + "itemId": "ITEM_SOOT_SACK", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A sack used to collect volcanic\\nash automatically during walks\\nover deep ash.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BASEMENT KEY", + "itemId": "ITEM_BASEMENT_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The key to NEW MAUVILLE, which\\nwas constructed beneath MAUVILLE\\nCITY.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "ACRO BIKE", + "itemId": "ITEM_ACRO_BIKE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A folding bicycle that is capable\\nof stunts like jumps and wheelies.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "FieldUseFunc_MachBike", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 1 + }, + { + "english": "{POKEBLOCK} CASE", + "itemId": "ITEM_POKEBLOCK_CASE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A case for holding {POKEBLOCK}S made\\nwith a BERRY BLENDER. It releases\\none {POKEBLOCK} when shaken.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LETTER", + "itemId": "ITEM_LETTER", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An extremely important letter to\\nSTEVEN from the PRESIDENT of the\\nDEVON CORPORATION.", + "importance": 2, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "EON TICKET", + "itemId": "ITEM_EON_TICKET", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The ticket required for sailing on a\\nferry to a distant southern island.\\nIt features a drawing of an island.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 1 + }, + { + "english": "RED ORB", + "itemId": "ITEM_RED_ORB", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An orb that glows red.\\nIt is said to contain an incredible\\npower from ancient times.", + "importance": 2, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BLUE ORB", + "itemId": "ITEM_BLUE_ORB", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An orb that glows blue.\\nIt is said to contain an incredible\\npower from ancient times.", + "importance": 2, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SCANNER", + "itemId": "ITEM_SCANNER", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A device used to search for\\nlife-forms in water.\\nIt looks too difficult to use.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "GO-GOGGLES", + "itemId": "ITEM_GO_GOGGLES", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A pair of protective goggles.\\nThey enable a TRAINER to travel\\nthrough even desert sandstorms.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "METEORITE", + "itemId": "ITEM_METEORITE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A meteorite that fell from space\\nonto MT. MOON long ago.\\nIt is very lumpy and hard.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RM. 1 KEY", + "itemId": "ITEM_ROOM_1_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A key that opens the door to Room\\n1 inside the ABANDONED SHIP.\\nIt is old and looks easily broken.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RM. 2 KEY", + "itemId": "ITEM_ROOM_2_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A key that opens the door to Room\\n2 inside the ABANDONED SHIP.\\nIt is old and looks easily broken.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RM. 4 KEY", + "itemId": "ITEM_ROOM_4_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A key that opens the door to Room\\n4 inside the ABANDONED SHIP.\\nIt is old and looks easily broken.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RM. 6 KEY", + "itemId": "ITEM_ROOM_6_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A key that opens the door to Room\\n6 inside the ABANDONED SHIP.\\nIt is old and looks easily broken.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "STORAGE KEY", + "itemId": "ITEM_STORAGE_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A key that opens the storage hold\\ninside the ABANDONED SHIP.\\nIt is old and looks easily broken.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "ROOT FOSSIL", + "itemId": "ITEM_ROOT_FOSSIL", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A fossil of an ancient, seafloor-\\ndwelling POKéMON. It appears to be\\npart of a plant root.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CLAW FOSSIL", + "itemId": "ITEM_CLAW_FOSSIL", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A fossil of an ancient, seafloor-\\ndwelling POKéMON. It appears to be\\npart of a claw.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "DEVON SCOPE", + "itemId": "ITEM_DEVON_SCOPE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A scope that signals the presence\\nof any unseeable POKéMON.\\nIt is made by the DEVON CORP.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "TM01", + "itemId": "ITEM_TM01", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An extremely powerful attack.\\nHowever, if the user is hit before\\nusing the move, they will flinch.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "FocusPunch" + }, + { + "english": "TM02", + "itemId": "ITEM_TM02", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Sharp, huge claws hook and slash\\nthe foe quickly and with great\\npower.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "DragonClaw" + }, + { + "english": "TM03", + "itemId": "ITEM_TM03", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The foe is hit with a pulsing blast\\nof water. It may also confuse the\\ntarget.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "WaterPulse" + }, + { + "english": "TM04", + "itemId": "ITEM_TM04", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The user calms its spirit and\\nfocuses its mind to raise its\\nSP. ATK and SP. DEF stats.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "CalmMind" + }, + { + "english": "TM05", + "itemId": "ITEM_TM05", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A savage roar that causes the foe\\nto switch out of battle. In the\\nwild, ROAR ends the battle.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Roar" + }, + { + "english": "TM06", + "itemId": "ITEM_TM06", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A move that leaves the foe badly\\npoisoned. Its poison damage worsens\\nevery turn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Toxic" + }, + { + "english": "TM07", + "itemId": "ITEM_TM07", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Summons a hailstorm that lasts for\\nfive turns. The hailstorm damages\\nall types except the ICE type.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Hail" + }, + { + "english": "TM08", + "itemId": "ITEM_TM08", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The user tightens all its muscles\\nand bulks up, boosting both its\\nATTACK and DEFENSE stats.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "BulkUp" + }, + { + "english": "TM09", + "itemId": "ITEM_TM09", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The user shoots seeds at the foe\\nin rapid succession. Two to five\\nseeds are shot at once.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "BulletSeed" + }, + { + "english": "TM10", + "itemId": "ITEM_TM10", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A variable move that changes type\\nand power depending on the POKéMON\\nusing it.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "HiddenPower" + }, + { + "english": "TM11", + "itemId": "ITEM_TM11", + "price": 2000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The weather is turned sunny for\\nfive turns. Over that time, FIRE-\\ntype moves are powered up.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "SunnyDay" + }, + { + "english": "TM12", + "itemId": "ITEM_TM12", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A taunted foe may become enraged.\\nIt will then only be able to use\\nattack moves.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Taunt" + }, + { + "english": "TM13", + "itemId": "ITEM_TM13", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An icy-cold beam is shot at the\\nfoe. It may leave the target\\nfrozen.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "IceBeam" + }, + { + "english": "TM14", + "itemId": "ITEM_TM14", + "price": 5500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A vicious snow-and-wind attack that\\nstrikes all foes in battle. It may\\ncause freezing.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Blizzard" + }, + { + "english": "TM15", + "itemId": "ITEM_TM15", + "price": 7500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A harsh attack that inflicts severe\\ndamage on the foe. However, the\\nuser must rest the next turn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "HyperBeam" + }, + { + "english": "TM16", + "itemId": "ITEM_TM16", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A wall of light is created over\\nfive turns. It reduces damage from\\nSP. ATK attacks.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "LightScreen" + }, + { + "english": "TM17", + "itemId": "ITEM_TM17", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The user is completely protected\\nfrom attack in the turn it is used.\\nIt may fail if used in succession.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Protect" + }, + { + "english": "TM18", + "itemId": "ITEM_TM18", + "price": 2000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A heavy rain is summoned for five\\nturns. Over that time, WATER-type\\nmoves are powered up.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "RainDance" + }, + { + "english": "TM19", + "itemId": "ITEM_TM19", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The user strikes the foe with\\ntentacles or roots, stealing the\\ntarget's HP and healing itself.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "GigaDrain" + }, + { + "english": "TM20", + "itemId": "ITEM_TM20", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Protects the party with a shield\\nagainst all status problems over\\nfive turns.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Safeguard" + }, + { + "english": "TM21", + "itemId": "ITEM_TM21", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "This attack move grows more\\npowerful the more the POKéMON\\ndislikes its TRAINER.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Frustration" + }, + { + "english": "TM22", + "itemId": "ITEM_TM22", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A 2-turn attack that uses the first\\nturn for absorbing sunlight, then\\nblasting the foe in the next turn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "SolarBeam" + }, + { + "english": "TM23", + "itemId": "ITEM_TM23", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The foe is slammed with a sturdy\\ntail of steel. It may lower the\\ntarget's DEFENSE stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "IronTail" + }, + { + "english": "TM24", + "itemId": "ITEM_TM24", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A massive jolt of electricity is\\nlaunched at the foe. It may cause\\nparalysis.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Thunderbolt" + }, + { + "english": "TM25", + "itemId": "ITEM_TM25", + "price": 5500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Strikes the foe with a huge\\nthunderbolt. It may cause\\nparalysis.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Thunder" + }, + { + "english": "TM26", + "itemId": "ITEM_TM26", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Causes an earthquake that strikes\\nall POKéMON in battle, excluding\\nthe user.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Earthquake" + }, + { + "english": "TM27", + "itemId": "ITEM_TM27", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "This attack move grows more\\npowerful the more the POKéMON\\nlikes its TRAINER.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Return" + }, + { + "english": "TM28", + "itemId": "ITEM_TM28", + "price": 2000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A 2-turn attack in which the user\\ndigs underground, then strikes.\\nIt can be used to exit dungeons.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Dig" + }, + { + "english": "TM29", + "itemId": "ITEM_TM29", + "price": 2000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A powerful blast of telekinetic\\nenergy strikes the foe. It may\\nlower the target's SP. DEF stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Psychic" + }, + { + "english": "TM30", + "itemId": "ITEM_TM30", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The foe is attacked with a shadowy\\nlump. It may lower the target's\\nSP. DEF stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "ShadowBall" + }, + { + "english": "TM31", + "itemId": "ITEM_TM31", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Strikes the foe with a rock-hard\\nfist, etc. It shatters barriers such\\nas REFLECT and LIGHT SCREEN.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "BrickBreak" + }, + { + "english": "TM32", + "itemId": "ITEM_TM32", + "price": 2000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The user begins moving so quickly\\nthat it creates illusory copies to\\nraise its evasiveness.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "DoubleTeam" + }, + { + "english": "TM33", + "itemId": "ITEM_TM33", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A tough barrier is put up over five\\nturns. It reduces damage from\\nphysical attacks over that time.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Reflect" + }, + { + "english": "TM34", + "itemId": "ITEM_TM34", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A rapid jolt of electricity strikes\\nthe foe. This attack is impossible\\nto evade.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "ShockWave" + }, + { + "english": "TM35", + "itemId": "ITEM_TM35", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The foe is roasted with a heavy\\nblast of fire. It may leave the\\ntarget with a burn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Flamethrower" + }, + { + "english": "TM36", + "itemId": "ITEM_TM36", + "price": 1000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Toxic sludge is hurled at the foe\\nwith great force. It may also\\npoison the target.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "SludgeBomb" + }, + { + "english": "TM37", + "itemId": "ITEM_TM37", + "price": 2000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Summons a sandstorm that lasts for\\nfive turns. It damages all types\\nexcept ROCK, GROUND, and STEEL.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Sandstorm" + }, + { + "english": "TM38", + "itemId": "ITEM_TM38", + "price": 5500, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The foe is incinerated with an\\nintense flame. It may leave the\\ntarget with a burn.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "FireBlast" + }, + { + "english": "TM39", + "itemId": "ITEM_TM39", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Boulders are hurled at the foe.\\nIt also lowers the target's SPEED\\nstat if it hits.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "RockTomb" + }, + { + "english": "TM40", + "itemId": "ITEM_TM40", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An extremely fast attack against\\none target. It is impossible to\\nevade.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "AerialAce" + }, + { + "english": "TM41", + "itemId": "ITEM_TM41", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "If enraged by this move, the target\\nbecomes incapable of using the same\\nmove twice in a row.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Torment" + }, + { + "english": "TM42", + "itemId": "ITEM_TM42", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An attack move that becomes very\\npowerful if the user is poisoned,\\nburned, or paralyzed.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Facade" + }, + { + "english": "TM43", + "itemId": "ITEM_TM43", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An attack move that may have an\\nadditional effect depending on the\\nbattle terrain.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "SecretPower" + }, + { + "english": "TM44", + "itemId": "ITEM_TM44", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A move that makes the user fall\\nasleep over two turns to restore HP\\nand heal any status problems.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Rest" + }, + { + "english": "TM45", + "itemId": "ITEM_TM45", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The foe, if it is the opposite\\ngender as the user, becomes\\ninfatuated and may not attack.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Attract" + }, + { + "english": "TM46", + "itemId": "ITEM_TM46", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An attack that gives the user an\\nopportunity to steal the foe's hold\\nitem.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Thief" + }, + { + "english": "TM47", + "itemId": "ITEM_TM47", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The foe is struck with steel-hard\\nwings. It may also raise the user's\\nDEFENSE stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "SteelWing" + }, + { + "english": "TM48", + "itemId": "ITEM_TM48", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A special power is transmitted to\\nthe foe, causing it to switch\\nabilities with the user.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "SkillSwap" + }, + { + "english": "TM49", + "itemId": "ITEM_TM49", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A move that steals the effects of\\nany status-changing or healing move\\nthat the foe tries to use.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Snatch" + }, + { + "english": "TM50", + "itemId": "ITEM_TM50", + "price": 3000, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A maximum-power attack of great\\nferocity, but one that also sharply\\nreduces the user's SP. ATK stat.", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Overheat" + }, + { + "english": "HM01", + "itemId": "ITEM_HM01", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Attacks the foe with sharp blades\\nor claws. It can also cut down thin\\ntrees and grass outside of battle.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Cut" + }, + { + "english": "HM02", + "itemId": "ITEM_HM02", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The user flies up on the first turn,\\nthen attacks next turn. It can be\\nused to fly to any known town.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Fly" + }, + { + "english": "HM03", + "itemId": "ITEM_HM03", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Creates a huge wave, then crashes\\nit down on the foe. It can be used\\nfor traveling on water.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Surf" + }, + { + "english": "HM04", + "itemId": "ITEM_HM04", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The user builds enormous power,\\nthen slams the foe. It can be used\\nfor moving large, round boulders.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Strength" + }, + { + "english": "HM05", + "itemId": "ITEM_HM05", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Looses a powerful blast of light\\nthat reduces the foe's accuracy.\\nIt also lights up dark caves.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Flash" + }, + { + "english": "HM06", + "itemId": "ITEM_HM06", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Hits the foe with a rock-crushingly\\ntough attack. It can smash cracked\\nboulders.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "RockSmash" + }, + { + "english": "HM07", + "itemId": "ITEM_HM07", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A powerful charge attack. It can\\nbe used for climbing a torrential\\nwaterfall.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Waterfall" + }, + { + "english": "HM08", + "itemId": "ITEM_HM08", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A 2-turn attack in which the user\\ndives underwater on the first turn,\\nthen strikes in the next turn.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_TM_CASE", + "type": 1, + "fieldUseFunc": "NULL", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0, + "moveId": "Dive" + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "????????", + "itemId": "ITEM_NONE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "?????", + "importance": 0, + "exitsBagOnUse": 0, + "pocket": "POCKET_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "OAK'S PARCEL", + "itemId": "ITEM_OAKS_PARCEL", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A parcel to be delivered to PROF.\\nOAK from VIRIDIAN CITY's POKéMON\\nMART.", + "importance": 2, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "POK\u00e9 FLUTE", + "itemId": "ITEM_POKE_FLUTE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A flute that is said to instantly\\nawaken any POKéMON. It has a\\nlovely tone.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_PokeFlute", + "battleUsage": 2, + "battleUseFunc": "BattleUseFunc_PokeFlute", + "secondaryId": 0 + }, + { + "english": "SECRET KEY", + "itemId": "ITEM_SECRET_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "The key to CINNABAR ISLAND GYM's\\nfront door. It is colored red and\\ndecorated.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BIKE VOUCHER", + "itemId": "ITEM_BIKE_VOUCHER", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "Take this voucher to the BIKE SHOP\\nin CERULEAN CITY and exchange it\\nfor a bicycle.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "GOLD TEETH", + "itemId": "ITEM_GOLD_TEETH", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A set of false teeth lost by the\\nSAFARI ZONE'S WARDEN. It makes his\\nsmile sparkle.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "OLD AMBER", + "itemId": "ITEM_OLD_AMBER", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A piece of amber that contains\\nthe genes of an ancient POKéMON.\\nIt is clear with a reddish tint.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "CARD KEY", + "itemId": "ITEM_CARD_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A card-type key that unlocks doors\\nin SILPH CO.'s HEAD OFFICE in\\nSAFFRON CITY.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "LIFT KEY", + "itemId": "ITEM_LIFT_KEY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A key that operates the elevator\\nin TEAM ROCKET's HIDEOUT.\\nIt bears the TEAM ROCKET logo.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "HELIX FOSSIL", + "itemId": "ITEM_HELIX_FOSSIL", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A fossil of an ancient, seafloor-\\ndwelling POKéMON. It appears to be\\npart of a seashell.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "DOME FOSSIL", + "itemId": "ITEM_DOME_FOSSIL", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A fossil of an ancient, seafloor-\\ndwelling POKéMON. It appears to be\\npart of a shell.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SILPH SCOPE", + "itemId": "ITEM_SILPH_SCOPE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A scope that makes unseeable\\nPOKéMON visible.\\nIt is made by SILPH CO.", + "importance": 1, + "exitsBagOnUse": 0, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BICYCLE", + "itemId": "ITEM_BICYCLE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A folding bicycle that allows\\nfaster movement than the RUNNING\\nSHOES.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "FieldUseFunc_MachBike", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "TOWN MAP", + "itemId": "ITEM_TOWN_MAP", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A very convenient map that can be\\nviewed anytime. It even shows your \\npresent location.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_TownMap", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "VS SEEKER", + "itemId": "ITEM_VS_SEEKER", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A device that indicates TRAINERS\\nwho want to battle. The battery\\ncharges while traveling.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "FieldUseFunc_VsSeeker", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "FAME CHECKER", + "itemId": "ITEM_FAME_CHECKER", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A device that enables you to\\nrecall what you've heard and seen\\nabout famous people.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_FameChecker", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "TM CASE", + "itemId": "ITEM_TM_CASE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A case that holds TMs and HMs.\\nIt is attached to the BAG's\\ncompartment for important items.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_TmCase", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "BERRY POUCH", + "itemId": "ITEM_BERRY_POUCH", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A pouch for carrying BERRIES.\\nIt is attached to the BAG's\\ncompartment for important items.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_BerryPouch", + "battleUsage": 3, + "battleUseFunc": "BattleUseFunc_BerryPouch", + "secondaryId": 0 + }, + { + "english": "TEACHY TV", + "itemId": "ITEM_TEACHY_TV", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A television set that is tuned to\\na program with useful tips for\\nnovice TRAINERS.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 2, + "fieldUseFunc": "FieldUseFunc_TeachyTv", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "TRI-PASS", + "itemId": "ITEM_TRI_PASS", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A pass for ferries between ONE,\\nTWO, and THREE ISLAND.\\nIt has a drawing of three islands.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RAINBOW PASS", + "itemId": "ITEM_RAINBOW_PASS", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A pass for ferries between\\nVERMILION and the SEVII ISLANDS.\\nIt features a drawing of a rainbow.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "TEA", + "itemId": "ITEM_TEA", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An aromatic tea prepared by an old\\nlady. It will slake even the worst\\nthirst.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "MYSTICTICKET", + "itemId": "ITEM_MYSTIC_TICKET", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A ticket required to board the ship\\nto NAVEL ROCK.\\nIt glows with a mystic light.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "AURORATICKET", + "itemId": "ITEM_AURORA_TICKET", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A ticket required to board the ship\\nto BIRTH ISLAND.\\nIt glows beautifully.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "POWDER JAR", + "itemId": "ITEM_POWDER_JAR", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "A jar for storing BERRY POWDER\\nmade using a BERRY CRUSHER.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_PowderJar", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "RUBY", + "itemId": "ITEM_RUBY", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An exquisitely beautiful gem that\\nhas a red glow.\\nIt symbolizes passion.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + }, + { + "english": "SAPPHIRE", + "itemId": "ITEM_SAPPHIRE", + "price": 0, + "holdEffect": "HOLD_EFFECT_NONE", + "holdEffectParam": 0, + "description_english": "An exquisitely beautiful gem that\\nhas a blue glow.\\nIt symbolizes honesty.", + "importance": 1, + "exitsBagOnUse": 1, + "pocket": "POCKET_KEY_ITEMS", + "type": 4, + "fieldUseFunc": "FieldUseFunc_OakStopsYou", + "battleUsage": 0, + "battleUseFunc": "NULL", + "secondaryId": 0 + } + ] +}
\ No newline at end of file diff --git a/src/data/items.json.txt b/src/data/items.json.txt new file mode 100644 index 000000000..0daa783aa --- /dev/null +++ b/src/data/items.json.txt @@ -0,0 +1,31 @@ +{{ doNotModifyHeader }} +## for item in items +## if item.pocket == "POCKET_TM_CASE" +extern const u8 gMoveDescription_{{ item.moveId }}[]; +## endif +{% if item.itemId != "ITEM_NONE" %}const u8 gItemDescription_{{ item.itemId }}[] = _("{{ item.description_english }}");{% endif %} +## endfor +const u8 gItemDescription_ITEM_NONE[] = _("?????"); + +const struct Item gItems[] = { + {% for item in items %}{ + .name = _("{{ item.english }}"), + .itemId = {{ item.itemId }}, + .price = {{ item.price }}, + .holdEffect = {{ item.holdEffect }}, + .holdEffectParam = {{ item.holdEffectParam }}, +## if item.pocket == "POCKET_TM_CASE" + .description = gMoveDescription_{{ item.moveId }}, +## else + .description = gItemDescription_{{ item.itemId }}, +## endif + .importance = {{ item.importance }}, + .exitsBagOnUse = {{ item.exitsBagOnUse }}, + .pocket = {{ item.pocket }}, + .type = {{ item.type }}, + .fieldUseFunc = {{ item.fieldUseFunc }}, + .battleUsage = {{ item.battleUsage }}, + .battleUseFunc = {{ item.battleUseFunc }}, + .secondaryId = {{ item.secondaryId }} + }, {% endfor %} +}; diff --git a/src/data/pokemon/egg_moves.h b/src/data/pokemon/egg_moves.h new file mode 100644 index 000000000..f8c250c6d --- /dev/null +++ b/src/data/pokemon/egg_moves.h @@ -0,0 +1,1310 @@ +#define EGG_MOVES_SPECIES_OFFSET 20000 +#define EGG_MOVES_TERMINATOR 0xFFFF +#define egg_moves(species, moves...) (SPECIES_##species + EGG_MOVES_SPECIES_OFFSET), moves + +const u16 gEggMoves[] = { + egg_moves(BULBASAUR, + MOVE_LIGHT_SCREEN, + MOVE_SKULL_BASH, + MOVE_SAFEGUARD, + MOVE_CHARM, + MOVE_PETAL_DANCE, + MOVE_MAGICAL_LEAF, + MOVE_GRASS_WHISTLE, + MOVE_CURSE), + + egg_moves(CHARMANDER, + MOVE_BELLY_DRUM, + MOVE_ANCIENT_POWER, + MOVE_ROCK_SLIDE, + MOVE_BITE, + MOVE_OUTRAGE, + MOVE_BEAT_UP, + MOVE_SWORDS_DANCE, + MOVE_DRAGON_DANCE), + + egg_moves(SQUIRTLE, + MOVE_MIRROR_COAT, + MOVE_HAZE, + MOVE_MIST, + MOVE_FORESIGHT, + MOVE_FLAIL, + MOVE_REFRESH, + MOVE_MUD_SPORT, + MOVE_YAWN), + + egg_moves(PIDGEY, + MOVE_PURSUIT, + MOVE_FAINT_ATTACK, + MOVE_FORESIGHT, + MOVE_STEEL_WING, + MOVE_AIR_CUTTER), + + egg_moves(RATTATA, + MOVE_SCREECH, + MOVE_FLAME_WHEEL, + MOVE_FURY_SWIPES, + MOVE_BITE, + MOVE_COUNTER, + MOVE_REVERSAL, + MOVE_UPROAR, + MOVE_SWAGGER), + + egg_moves(SPEAROW, + MOVE_FAINT_ATTACK, + MOVE_FALSE_SWIPE, + MOVE_SCARY_FACE, + MOVE_QUICK_ATTACK, + MOVE_TRI_ATTACK, + MOVE_ASTONISH, + MOVE_SKY_ATTACK), + + egg_moves(EKANS, + MOVE_PURSUIT, + MOVE_SLAM, + MOVE_SPITE, + MOVE_BEAT_UP, + MOVE_POISON_FANG), + + egg_moves(SANDSHREW, + MOVE_FLAIL, + MOVE_SAFEGUARD, + MOVE_COUNTER, + MOVE_RAPID_SPIN, + MOVE_ROCK_SLIDE, + MOVE_METAL_CLAW, + MOVE_SWORDS_DANCE, + MOVE_CRUSH_CLAW), + + egg_moves(NIDORAN_F, + MOVE_SUPERSONIC, + MOVE_DISABLE, + MOVE_TAKE_DOWN, + MOVE_FOCUS_ENERGY, + MOVE_CHARM, + MOVE_COUNTER, + MOVE_BEAT_UP), + + egg_moves(NIDORAN_M, + MOVE_COUNTER, + MOVE_DISABLE, + MOVE_SUPERSONIC, + MOVE_TAKE_DOWN, + MOVE_AMNESIA, + MOVE_CONFUSION, + MOVE_BEAT_UP), + + egg_moves(VULPIX, + MOVE_FAINT_ATTACK, + MOVE_HYPNOSIS, + MOVE_FLAIL, + MOVE_SPITE, + MOVE_DISABLE, + MOVE_HOWL, + MOVE_PSYCH_UP, + MOVE_HEAT_WAVE), + + egg_moves(ZUBAT, + MOVE_QUICK_ATTACK, + MOVE_PURSUIT, + MOVE_FAINT_ATTACK, + MOVE_GUST, + MOVE_WHIRLWIND, + MOVE_CURSE), + + egg_moves(ODDISH, + MOVE_SWORDS_DANCE, + MOVE_RAZOR_LEAF, + MOVE_FLAIL, + MOVE_SYNTHESIS, + MOVE_CHARM, + MOVE_INGRAIN), + + egg_moves(PARAS, + MOVE_FALSE_SWIPE, + MOVE_SCREECH, + MOVE_COUNTER, + MOVE_PSYBEAM, + MOVE_FLAIL, + MOVE_SWEET_SCENT, + MOVE_LIGHT_SCREEN, + MOVE_PURSUIT), + + egg_moves(VENONAT, + MOVE_BATON_PASS, + MOVE_SCREECH, + MOVE_GIGA_DRAIN, + MOVE_SIGNAL_BEAM), + + egg_moves(DIGLETT, + MOVE_FAINT_ATTACK, + MOVE_SCREECH, + MOVE_ANCIENT_POWER, + MOVE_PURSUIT, + MOVE_BEAT_UP, + MOVE_UPROAR, + MOVE_ROCK_SLIDE), + + egg_moves(MEOWTH, + MOVE_SPITE, + MOVE_CHARM, + MOVE_HYPNOSIS, + MOVE_AMNESIA, + MOVE_PSYCH_UP, + MOVE_ASSIST), + + egg_moves(PSYDUCK, + MOVE_HYPNOSIS, + MOVE_PSYBEAM, + MOVE_FORESIGHT, + MOVE_LIGHT_SCREEN, + MOVE_FUTURE_SIGHT, + MOVE_PSYCHIC, + MOVE_CROSS_CHOP, + MOVE_REFRESH), + + egg_moves(MANKEY, + MOVE_ROCK_SLIDE, + MOVE_FORESIGHT, + MOVE_MEDITATE, + MOVE_COUNTER, + MOVE_REVERSAL, + MOVE_BEAT_UP, + MOVE_REVENGE, + MOVE_SMELLING_SALT), + + egg_moves(GROWLITHE, + MOVE_BODY_SLAM, + MOVE_SAFEGUARD, + MOVE_CRUNCH, + MOVE_THRASH, + MOVE_FIRE_SPIN, + MOVE_HOWL, + MOVE_HEAT_WAVE), + + egg_moves(POLIWAG, + MOVE_MIST, + MOVE_SPLASH, + MOVE_BUBBLE_BEAM, + MOVE_HAZE, + MOVE_MIND_READER, + MOVE_WATER_SPORT, + MOVE_ICE_BALL), + + egg_moves(ABRA, + MOVE_ENCORE, + MOVE_BARRIER, + MOVE_KNOCK_OFF, + MOVE_FIRE_PUNCH, + MOVE_THUNDER_PUNCH, + MOVE_ICE_PUNCH), + + egg_moves(MACHOP, + MOVE_LIGHT_SCREEN, + MOVE_MEDITATE, + MOVE_ROLLING_KICK, + MOVE_ENCORE, + MOVE_SMELLING_SALT, + MOVE_COUNTER, + MOVE_ROCK_SLIDE), + + egg_moves(BELLSPROUT, + MOVE_SWORDS_DANCE, + MOVE_ENCORE, + MOVE_REFLECT, + MOVE_SYNTHESIS, + MOVE_LEECH_LIFE, + MOVE_INGRAIN, + MOVE_MAGICAL_LEAF), + + egg_moves(TENTACOOL, + MOVE_AURORA_BEAM, + MOVE_MIRROR_COAT, + MOVE_RAPID_SPIN, + MOVE_HAZE, + MOVE_SAFEGUARD, + MOVE_CONFUSE_RAY), + + egg_moves(GEODUDE, + MOVE_MEGA_PUNCH, + MOVE_ROCK_SLIDE, + MOVE_BLOCK), + + egg_moves(PONYTA, + MOVE_FLAME_WHEEL, + MOVE_THRASH, + MOVE_DOUBLE_KICK, + MOVE_HYPNOSIS, + MOVE_CHARM, + MOVE_DOUBLE_EDGE), + + egg_moves(SLOWPOKE, + MOVE_SAFEGUARD, + MOVE_BELLY_DRUM, + MOVE_FUTURE_SIGHT, + MOVE_STOMP, + MOVE_MUD_SPORT, + MOVE_SLEEP_TALK, + MOVE_SNORE), + + egg_moves(FARFETCHD, + MOVE_STEEL_WING, + MOVE_FORESIGHT, + MOVE_MIRROR_MOVE, + MOVE_GUST, + MOVE_QUICK_ATTACK, + MOVE_FLAIL, + MOVE_FEATHER_DANCE, + MOVE_CURSE), + + egg_moves(DODUO, + MOVE_QUICK_ATTACK, + MOVE_SUPERSONIC, + MOVE_HAZE, + MOVE_FAINT_ATTACK, + MOVE_FLAIL, + MOVE_ENDEAVOR), + + egg_moves(SEEL, + MOVE_LICK, + MOVE_PERISH_SONG, + MOVE_DISABLE, + MOVE_HORN_DRILL, + MOVE_SLAM, + MOVE_ENCORE, + MOVE_FAKE_OUT, + MOVE_ICICLE_SPEAR), + + egg_moves(GRIMER, + MOVE_HAZE, + MOVE_MEAN_LOOK, + MOVE_LICK, + MOVE_IMPRISON, + MOVE_CURSE, + MOVE_SHADOW_PUNCH, + MOVE_EXPLOSION), + + egg_moves(SHELLDER, + MOVE_BUBBLE_BEAM, + MOVE_TAKE_DOWN, + MOVE_BARRIER, + MOVE_RAPID_SPIN, + MOVE_SCREECH, + MOVE_ICICLE_SPEAR), + + egg_moves(GASTLY, + MOVE_PSYWAVE, + MOVE_PERISH_SONG, + MOVE_HAZE, + MOVE_ASTONISH, + MOVE_WILL_O_WISP, + MOVE_GRUDGE, + MOVE_EXPLOSION), + + egg_moves(ONIX, + MOVE_ROCK_SLIDE, + MOVE_FLAIL, + MOVE_EXPLOSION, + MOVE_BLOCK), + + egg_moves(DROWZEE, + MOVE_BARRIER, + MOVE_ASSIST, + MOVE_ROLE_PLAY, + MOVE_FIRE_PUNCH, + MOVE_THUNDER_PUNCH, + MOVE_ICE_PUNCH), + + egg_moves(KRABBY, + MOVE_DIG, + MOVE_HAZE, + MOVE_AMNESIA, + MOVE_FLAIL, + MOVE_SLAM, + MOVE_KNOCK_OFF, + MOVE_SWORDS_DANCE), + + egg_moves(EXEGGCUTE, + MOVE_SYNTHESIS, + MOVE_MOONLIGHT, + MOVE_REFLECT, + MOVE_ANCIENT_POWER, + MOVE_PSYCH_UP, + MOVE_INGRAIN, + MOVE_CURSE), + + egg_moves(CUBONE, + MOVE_ROCK_SLIDE, + MOVE_ANCIENT_POWER, + MOVE_BELLY_DRUM, + MOVE_SCREECH, + MOVE_SKULL_BASH, + MOVE_PERISH_SONG, + MOVE_SWORDS_DANCE), + + egg_moves(LICKITUNG, + MOVE_BELLY_DRUM, + MOVE_MAGNITUDE, + MOVE_BODY_SLAM, + MOVE_CURSE, + MOVE_SMELLING_SALT, + MOVE_SLEEP_TALK, + MOVE_SNORE, + MOVE_SUBSTITUTE), + + egg_moves(KOFFING, + MOVE_SCREECH, + MOVE_PSYWAVE, + MOVE_PSYBEAM, + MOVE_DESTINY_BOND, + MOVE_PAIN_SPLIT, + MOVE_WILL_O_WISP), + + egg_moves(RHYHORN, + MOVE_CRUNCH, + MOVE_REVERSAL, + MOVE_ROCK_SLIDE, + MOVE_COUNTER, + MOVE_MAGNITUDE, + MOVE_SWORDS_DANCE, + MOVE_CURSE, + MOVE_CRUSH_CLAW), + + egg_moves(CHANSEY, + MOVE_PRESENT, + MOVE_METRONOME, + MOVE_HEAL_BELL, + MOVE_AROMATHERAPY, + MOVE_SUBSTITUTE), + + egg_moves(TANGELA, + MOVE_FLAIL, + MOVE_CONFUSION, + MOVE_MEGA_DRAIN, + MOVE_REFLECT, + MOVE_AMNESIA, + MOVE_LEECH_SEED, + MOVE_NATURE_POWER), + + egg_moves(KANGASKHAN, + MOVE_STOMP, + MOVE_FORESIGHT, + MOVE_FOCUS_ENERGY, + MOVE_SAFEGUARD, + MOVE_DISABLE, + MOVE_COUNTER, + MOVE_CRUSH_CLAW, + MOVE_SUBSTITUTE), + + egg_moves(HORSEA, + MOVE_FLAIL, + MOVE_AURORA_BEAM, + MOVE_OCTAZOOKA, + MOVE_DISABLE, + MOVE_SPLASH, + MOVE_DRAGON_RAGE, + MOVE_DRAGON_BREATH), + + egg_moves(GOLDEEN, + MOVE_PSYBEAM, + MOVE_HAZE, + MOVE_HYDRO_PUMP, + MOVE_SLEEP_TALK, + MOVE_MUD_SPORT), + + egg_moves(MR_MIME, + MOVE_FUTURE_SIGHT, + MOVE_HYPNOSIS, + MOVE_MIMIC, + MOVE_PSYCH_UP, + MOVE_FAKE_OUT, + MOVE_TRICK), + + egg_moves(SCYTHER, + MOVE_COUNTER, + MOVE_SAFEGUARD, + MOVE_BATON_PASS, + MOVE_RAZOR_WIND, + MOVE_REVERSAL, + MOVE_LIGHT_SCREEN, + MOVE_ENDURE, + MOVE_SILVER_WIND), + + egg_moves(PINSIR, + MOVE_FURY_ATTACK, + MOVE_FLAIL, + MOVE_FALSE_SWIPE, + MOVE_FAINT_ATTACK), + + egg_moves(LAPRAS, + MOVE_FORESIGHT, + MOVE_SUBSTITUTE, + MOVE_TICKLE, + MOVE_REFRESH, + MOVE_DRAGON_DANCE, + MOVE_CURSE, + MOVE_SLEEP_TALK, + MOVE_HORN_DRILL), + + egg_moves(EEVEE, + MOVE_CHARM, + MOVE_FLAIL, + MOVE_ENDURE, + MOVE_CURSE, + MOVE_TICKLE, + MOVE_WISH), + + egg_moves(OMANYTE, + MOVE_BUBBLE_BEAM, + MOVE_AURORA_BEAM, + MOVE_SLAM, + MOVE_SUPERSONIC, + MOVE_HAZE, + MOVE_ROCK_SLIDE, + MOVE_SPIKES), + + egg_moves(KABUTO, + MOVE_BUBBLE_BEAM, + MOVE_AURORA_BEAM, + MOVE_RAPID_SPIN, + MOVE_DIG, + MOVE_FLAIL, + MOVE_KNOCK_OFF, + MOVE_CONFUSE_RAY), + + egg_moves(AERODACTYL, + MOVE_WHIRLWIND, + MOVE_PURSUIT, + MOVE_FORESIGHT, + MOVE_STEEL_WING, + MOVE_DRAGON_BREATH, + MOVE_CURSE), + + egg_moves(SNORLAX, + MOVE_LICK, + MOVE_CHARM, + MOVE_DOUBLE_EDGE, + MOVE_CURSE, + MOVE_FISSURE, + MOVE_SUBSTITUTE), + + egg_moves(DRATINI, + MOVE_LIGHT_SCREEN, + MOVE_MIST, + MOVE_HAZE, + MOVE_SUPERSONIC, + MOVE_DRAGON_BREATH, + MOVE_DRAGON_DANCE), + + egg_moves(CHIKORITA, + MOVE_VINE_WHIP, + MOVE_LEECH_SEED, + MOVE_COUNTER, + MOVE_ANCIENT_POWER, + MOVE_FLAIL, + MOVE_NATURE_POWER, + MOVE_INGRAIN, + MOVE_GRASS_WHISTLE), + + egg_moves(CYNDAQUIL, + MOVE_FURY_SWIPES, + MOVE_QUICK_ATTACK, + MOVE_REVERSAL, + MOVE_THRASH, + MOVE_FORESIGHT, + MOVE_COVET, + MOVE_HOWL, + MOVE_CRUSH_CLAW), + + egg_moves(TOTODILE, + MOVE_CRUNCH, + MOVE_THRASH, + MOVE_HYDRO_PUMP, + MOVE_ANCIENT_POWER, + MOVE_ROCK_SLIDE, + MOVE_MUD_SPORT, + MOVE_WATER_SPORT, + MOVE_DRAGON_CLAW), + + egg_moves(SENTRET, + MOVE_DOUBLE_EDGE, + MOVE_PURSUIT, + MOVE_SLASH, + MOVE_FOCUS_ENERGY, + MOVE_REVERSAL, + MOVE_SUBSTITUTE, + MOVE_TRICK, + MOVE_ASSIST), + + egg_moves(HOOTHOOT, + MOVE_MIRROR_MOVE, + MOVE_SUPERSONIC, + MOVE_FAINT_ATTACK, + MOVE_WING_ATTACK, + MOVE_WHIRLWIND, + MOVE_SKY_ATTACK, + MOVE_FEATHER_DANCE), + + egg_moves(LEDYBA, + MOVE_PSYBEAM, + MOVE_BIDE, + MOVE_SILVER_WIND), + + egg_moves(SPINARAK, + MOVE_PSYBEAM, + MOVE_DISABLE, + MOVE_SONIC_BOOM, + MOVE_BATON_PASS, + MOVE_PURSUIT, + MOVE_SIGNAL_BEAM), + + egg_moves(CHINCHOU, + MOVE_FLAIL, + MOVE_SCREECH, + MOVE_AMNESIA), + + egg_moves(PICHU, + MOVE_REVERSAL, + MOVE_BIDE, + MOVE_PRESENT, + MOVE_ENCORE, + MOVE_DOUBLE_SLAP, + MOVE_WISH, + MOVE_CHARGE), + + egg_moves(CLEFFA, + MOVE_PRESENT, + MOVE_METRONOME, + MOVE_AMNESIA, + MOVE_BELLY_DRUM, + MOVE_SPLASH, + MOVE_MIMIC, + MOVE_WISH, + MOVE_SUBSTITUTE), + + egg_moves(IGGLYBUFF, + MOVE_PERISH_SONG, + MOVE_PRESENT, + MOVE_FAINT_ATTACK, + MOVE_WISH, + MOVE_FAKE_TEARS), + + egg_moves(TOGEPI, + MOVE_PRESENT, + MOVE_MIRROR_MOVE, + MOVE_PECK, + MOVE_FORESIGHT, + MOVE_FUTURE_SIGHT, + MOVE_SUBSTITUTE, + MOVE_PSYCH_UP), + + egg_moves(NATU, + MOVE_HAZE, + MOVE_DRILL_PECK, + MOVE_QUICK_ATTACK, + MOVE_FAINT_ATTACK, + MOVE_STEEL_WING, + MOVE_PSYCH_UP, + MOVE_FEATHER_DANCE, + MOVE_REFRESH), + + egg_moves(MAREEP, + MOVE_TAKE_DOWN, + MOVE_BODY_SLAM, + MOVE_SAFEGUARD, + MOVE_SCREECH, + MOVE_REFLECT, + MOVE_ODOR_SLEUTH, + MOVE_CHARGE), + + egg_moves(MARILL, + MOVE_LIGHT_SCREEN, + MOVE_PRESENT, + MOVE_AMNESIA, + MOVE_FUTURE_SIGHT, + MOVE_BELLY_DRUM, + MOVE_PERISH_SONG, + MOVE_SUPERSONIC, + MOVE_SUBSTITUTE), + + egg_moves(SUDOWOODO, + MOVE_SELF_DESTRUCT), + + egg_moves(HOPPIP, + MOVE_CONFUSION, + MOVE_ENCORE, + MOVE_DOUBLE_EDGE, + MOVE_REFLECT, + MOVE_AMNESIA, + MOVE_HELPING_HAND, + MOVE_PSYCH_UP), + + egg_moves(AIPOM, + MOVE_COUNTER, + MOVE_SCREECH, + MOVE_PURSUIT, + MOVE_AGILITY, + MOVE_SPITE, + MOVE_SLAM, + MOVE_DOUBLE_SLAP, + MOVE_BEAT_UP), + + egg_moves(SUNKERN, + MOVE_GRASS_WHISTLE, + MOVE_ENCORE, + MOVE_LEECH_SEED, + MOVE_NATURE_POWER, + MOVE_CURSE, + MOVE_HELPING_HAND), + + egg_moves(YANMA, + MOVE_WHIRLWIND, + MOVE_REVERSAL, + MOVE_LEECH_LIFE, + MOVE_SIGNAL_BEAM, + MOVE_SILVER_WIND), + + egg_moves(WOOPER, + MOVE_BODY_SLAM, + MOVE_ANCIENT_POWER, + MOVE_SAFEGUARD, + MOVE_CURSE, + MOVE_MUD_SPORT, + MOVE_STOCKPILE, + MOVE_SWALLOW, + MOVE_SPIT_UP), + + egg_moves(MURKROW, + MOVE_WHIRLWIND, + MOVE_DRILL_PECK, + MOVE_MIRROR_MOVE, + MOVE_WING_ATTACK, + MOVE_SKY_ATTACK, + MOVE_CONFUSE_RAY, + MOVE_FEATHER_DANCE, + MOVE_PERISH_SONG), + + egg_moves(MISDREAVUS, + MOVE_SCREECH, + MOVE_DESTINY_BOND, + MOVE_PSYCH_UP, + MOVE_IMPRISON), + + egg_moves(GIRAFARIG, + MOVE_TAKE_DOWN, + MOVE_AMNESIA, + MOVE_FORESIGHT, + MOVE_FUTURE_SIGHT, + MOVE_BEAT_UP, + MOVE_PSYCH_UP, + MOVE_WISH, + MOVE_MAGIC_COAT), + + egg_moves(PINECO, + MOVE_REFLECT, + MOVE_PIN_MISSILE, + MOVE_FLAIL, + MOVE_SWIFT, + MOVE_COUNTER, + MOVE_SAND_TOMB), + + egg_moves(DUNSPARCE, + MOVE_BIDE, + MOVE_ANCIENT_POWER, + MOVE_ROCK_SLIDE, + MOVE_BITE, + MOVE_HEADBUTT, + MOVE_ASTONISH, + MOVE_CURSE), + + egg_moves(GLIGAR, + MOVE_METAL_CLAW, + MOVE_WING_ATTACK, + MOVE_RAZOR_WIND, + MOVE_COUNTER, + MOVE_SAND_TOMB), + + egg_moves(SNUBBULL, + MOVE_METRONOME, + MOVE_FAINT_ATTACK, + MOVE_REFLECT, + MOVE_PRESENT, + MOVE_CRUNCH, + MOVE_HEAL_BELL, + MOVE_SNORE, + MOVE_SMELLING_SALT), + + egg_moves(QWILFISH, + MOVE_FLAIL, + MOVE_HAZE, + MOVE_BUBBLE_BEAM, + MOVE_SUPERSONIC, + MOVE_ASTONISH), + + egg_moves(SHUCKLE, + MOVE_SWEET_SCENT), + + egg_moves(HERACROSS, + MOVE_HARDEN, + MOVE_BIDE, + MOVE_FLAIL, + MOVE_FALSE_SWIPE), + + egg_moves(SNEASEL, + MOVE_COUNTER, + MOVE_SPITE, + MOVE_FORESIGHT, + MOVE_REFLECT, + MOVE_BITE, + MOVE_CRUSH_CLAW, + MOVE_FAKE_OUT), + + egg_moves(TEDDIURSA, + MOVE_CRUNCH, + MOVE_TAKE_DOWN, + MOVE_SEISMIC_TOSS, + MOVE_COUNTER, + MOVE_METAL_CLAW, + MOVE_FAKE_TEARS, + MOVE_YAWN, + MOVE_SLEEP_TALK), + + egg_moves(SLUGMA, + MOVE_ACID_ARMOR, + MOVE_HEAT_WAVE), + + egg_moves(SWINUB, + MOVE_TAKE_DOWN, + MOVE_BITE, + MOVE_BODY_SLAM, + MOVE_ROCK_SLIDE, + MOVE_ANCIENT_POWER, + MOVE_MUD_SHOT, + MOVE_ICICLE_SPEAR, + MOVE_DOUBLE_EDGE), + + egg_moves(CORSOLA, + MOVE_ROCK_SLIDE, + MOVE_SCREECH, + MOVE_MIST, + MOVE_AMNESIA, + MOVE_BARRIER, + MOVE_INGRAIN, + MOVE_CONFUSE_RAY, + MOVE_ICICLE_SPEAR), + + egg_moves(REMORAID, + MOVE_AURORA_BEAM, + MOVE_OCTAZOOKA, + MOVE_SUPERSONIC, + MOVE_HAZE, + MOVE_SCREECH, + MOVE_THUNDER_WAVE, + MOVE_ROCK_BLAST), + + egg_moves(DELIBIRD, + MOVE_AURORA_BEAM, + MOVE_QUICK_ATTACK, + MOVE_FUTURE_SIGHT, + MOVE_SPLASH, + MOVE_RAPID_SPIN, + MOVE_ICE_BALL), + + egg_moves(MANTINE, + MOVE_TWISTER, + MOVE_HYDRO_PUMP, + MOVE_HAZE, + MOVE_SLAM, + MOVE_MUD_SPORT, + MOVE_ROCK_SLIDE), + + egg_moves(SKARMORY, + MOVE_DRILL_PECK, + MOVE_PURSUIT, + MOVE_WHIRLWIND, + MOVE_SKY_ATTACK, + MOVE_CURSE), + + egg_moves(HOUNDOUR, + MOVE_FIRE_SPIN, + MOVE_RAGE, + MOVE_PURSUIT, + MOVE_COUNTER, + MOVE_SPITE, + MOVE_REVERSAL, + MOVE_BEAT_UP, + MOVE_WILL_O_WISP), + + egg_moves(PHANPY, + MOVE_FOCUS_ENERGY, + MOVE_BODY_SLAM, + MOVE_ANCIENT_POWER, + MOVE_SNORE, + MOVE_COUNTER, + MOVE_FISSURE), + + egg_moves(STANTLER, + MOVE_SPITE, + MOVE_DISABLE, + MOVE_BITE, + MOVE_SWAGGER, + MOVE_PSYCH_UP, + MOVE_EXTRASENSORY), + + egg_moves(TYROGUE, + MOVE_RAPID_SPIN, + MOVE_HI_JUMP_KICK, + MOVE_MACH_PUNCH, + MOVE_MIND_READER, + MOVE_HELPING_HAND), + + egg_moves(SMOOCHUM, + MOVE_MEDITATE, + MOVE_PSYCH_UP, + MOVE_FAKE_OUT, + MOVE_WISH, + MOVE_ICE_PUNCH), + + egg_moves(ELEKID, + MOVE_KARATE_CHOP, + MOVE_BARRIER, + MOVE_ROLLING_KICK, + MOVE_MEDITATE, + MOVE_CROSS_CHOP, + MOVE_FIRE_PUNCH, + MOVE_ICE_PUNCH), + + egg_moves(MAGBY, + MOVE_KARATE_CHOP, + MOVE_MEGA_PUNCH, + MOVE_BARRIER, + MOVE_SCREECH, + MOVE_CROSS_CHOP, + MOVE_THUNDER_PUNCH), + + egg_moves(MILTANK, + MOVE_PRESENT, + MOVE_REVERSAL, + MOVE_SEISMIC_TOSS, + MOVE_ENDURE, + MOVE_PSYCH_UP, + MOVE_CURSE, + MOVE_HELPING_HAND, + MOVE_SLEEP_TALK), + + egg_moves(LARVITAR, + MOVE_PURSUIT, + MOVE_STOMP, + MOVE_OUTRAGE, + MOVE_FOCUS_ENERGY, + MOVE_ANCIENT_POWER, + MOVE_DRAGON_DANCE, + MOVE_CURSE), + + egg_moves(TREECKO, + MOVE_CRUNCH, + MOVE_MUD_SPORT, + MOVE_ENDEAVOR, + MOVE_LEECH_SEED, + MOVE_DRAGON_BREATH, + MOVE_CRUSH_CLAW), + + egg_moves(TORCHIC, + MOVE_COUNTER, + MOVE_REVERSAL, + MOVE_ENDURE, + MOVE_SWAGGER, + MOVE_ROCK_SLIDE, + MOVE_SMELLING_SALT), + + egg_moves(MUDKIP, + MOVE_REFRESH, + MOVE_UPROAR, + MOVE_CURSE, + MOVE_STOMP, + MOVE_ICE_BALL, + MOVE_MIRROR_COAT), + + egg_moves(POOCHYENA, + MOVE_ASTONISH, + MOVE_POISON_FANG, + MOVE_COVET, + MOVE_LEER, + MOVE_YAWN), + + egg_moves(ZIGZAGOON, + MOVE_CHARM, + MOVE_PURSUIT, + MOVE_SUBSTITUTE, + MOVE_TICKLE, + MOVE_TRICK), + + egg_moves(LOTAD, + MOVE_SYNTHESIS, + MOVE_RAZOR_LEAF, + MOVE_SWEET_SCENT, + MOVE_LEECH_SEED, + MOVE_FLAIL, + MOVE_WATER_GUN), + + egg_moves(SEEDOT, + MOVE_LEECH_SEED, + MOVE_AMNESIA, + MOVE_QUICK_ATTACK, + MOVE_RAZOR_WIND, + MOVE_TAKE_DOWN, + MOVE_FALSE_SWIPE), + + egg_moves(NINCADA, + MOVE_ENDURE, + MOVE_FAINT_ATTACK, + MOVE_GUST, + MOVE_SILVER_WIND), + + egg_moves(TAILLOW, + MOVE_PURSUIT, + MOVE_SUPERSONIC, + MOVE_REFRESH, + MOVE_MIRROR_MOVE, + MOVE_RAGE, + MOVE_SKY_ATTACK), + + egg_moves(SHROOMISH, + MOVE_FAKE_TEARS, + MOVE_SWAGGER, + MOVE_CHARM, + MOVE_FALSE_SWIPE, + MOVE_HELPING_HAND), + + egg_moves(SPINDA, + MOVE_ENCORE, + MOVE_ROCK_SLIDE, + MOVE_ASSIST, + MOVE_DISABLE, + MOVE_BATON_PASS, + MOVE_WISH, + MOVE_TRICK, + MOVE_SMELLING_SALT), + + egg_moves(WINGULL, + MOVE_MIST, + MOVE_TWISTER, + MOVE_AGILITY, + MOVE_GUST, + MOVE_WATER_SPORT), + + egg_moves(SURSKIT, + MOVE_FORESIGHT, + MOVE_MUD_SHOT, + MOVE_PSYBEAM, + MOVE_HYDRO_PUMP, + MOVE_MIND_READER), + + egg_moves(WAILMER, + MOVE_DOUBLE_EDGE, + MOVE_THRASH, + MOVE_SWAGGER, + MOVE_SNORE, + MOVE_SLEEP_TALK, + MOVE_CURSE, + MOVE_FISSURE, + MOVE_TICKLE), + + egg_moves(SKITTY, + MOVE_HELPING_HAND, + MOVE_PSYCH_UP, + MOVE_UPROAR, + MOVE_FAKE_TEARS, + MOVE_WISH, + MOVE_BATON_PASS, + MOVE_SUBSTITUTE, + MOVE_TICKLE), + + egg_moves(KECLEON, + MOVE_DISABLE, + MOVE_MAGIC_COAT, + MOVE_TRICK), + + egg_moves(NOSEPASS, + MOVE_MAGNITUDE, + MOVE_ROLLOUT, + MOVE_EXPLOSION), + + egg_moves(TORKOAL, + MOVE_ERUPTION, + MOVE_ENDURE, + MOVE_SLEEP_TALK, + MOVE_YAWN), + + egg_moves(SABLEYE, + MOVE_PSYCH_UP, + MOVE_RECOVER, + MOVE_MOONLIGHT), + + egg_moves(BARBOACH, + MOVE_THRASH, + MOVE_WHIRLPOOL, + MOVE_SPARK), + + egg_moves(LUVDISC, + MOVE_SPLASH, + MOVE_SUPERSONIC, + MOVE_WATER_SPORT, + MOVE_MUD_SPORT), + + egg_moves(CORPHISH, + MOVE_MUD_SPORT, + MOVE_ENDEAVOR, + MOVE_BODY_SLAM, + MOVE_ANCIENT_POWER), + + egg_moves(FEEBAS, + MOVE_MIRROR_COAT, + MOVE_DRAGON_BREATH, + MOVE_MUD_SPORT, + MOVE_HYPNOSIS, + MOVE_LIGHT_SCREEN, + MOVE_CONFUSE_RAY), + + egg_moves(CARVANHA, + MOVE_HYDRO_PUMP, + MOVE_DOUBLE_EDGE, + MOVE_THRASH), + + egg_moves(TRAPINCH, + MOVE_FOCUS_ENERGY, + MOVE_QUICK_ATTACK, + MOVE_GUST), + + egg_moves(MAKUHITA, + MOVE_FAINT_ATTACK, + MOVE_DETECT, + MOVE_FORESIGHT, + MOVE_HELPING_HAND, + MOVE_CROSS_CHOP, + MOVE_REVENGE, + MOVE_DYNAMIC_PUNCH, + MOVE_COUNTER), + + egg_moves(ELECTRIKE, + MOVE_CRUNCH, + MOVE_HEADBUTT, + MOVE_UPROAR, + MOVE_CURSE, + MOVE_SWIFT), + + egg_moves(NUMEL, + MOVE_HOWL, + MOVE_SCARY_FACE, + MOVE_BODY_SLAM, + MOVE_ROLLOUT, + MOVE_DEFENSE_CURL, + MOVE_STOMP), + + egg_moves(SPHEAL, + MOVE_WATER_SPORT, + MOVE_STOCKPILE, + MOVE_SWALLOW, + MOVE_SPIT_UP, + MOVE_YAWN, + MOVE_ROCK_SLIDE, + MOVE_CURSE, + MOVE_FISSURE), + + egg_moves(CACNEA, + MOVE_GRASS_WHISTLE, + MOVE_ACID, + MOVE_TEETER_DANCE, + MOVE_DYNAMIC_PUNCH, + MOVE_COUNTER), + + egg_moves(SNORUNT, + MOVE_BLOCK, + MOVE_SPIKES), + + egg_moves(AZURILL, + MOVE_ENCORE, + MOVE_SING, + MOVE_REFRESH, + MOVE_SLAM, + MOVE_TICKLE), + + egg_moves(SPOINK, + MOVE_FUTURE_SIGHT, + MOVE_EXTRASENSORY, + MOVE_SUBSTITUTE, + MOVE_TRICK), + + egg_moves(PLUSLE, + MOVE_SUBSTITUTE, + MOVE_WISH), + + egg_moves(MINUN, + MOVE_SUBSTITUTE, + MOVE_WISH), + + egg_moves(MAWILE, + MOVE_SWORDS_DANCE, + MOVE_FALSE_SWIPE, + MOVE_POISON_FANG, + MOVE_PSYCH_UP, + MOVE_ANCIENT_POWER, + MOVE_TICKLE), + + egg_moves(MEDITITE, + MOVE_FIRE_PUNCH, + MOVE_THUNDER_PUNCH, + MOVE_ICE_PUNCH, + MOVE_FORESIGHT, + MOVE_FAKE_OUT, + MOVE_BATON_PASS, + MOVE_DYNAMIC_PUNCH), + + egg_moves(SWABLU, + MOVE_AGILITY, + MOVE_HAZE, + MOVE_PURSUIT, + MOVE_RAGE), + + egg_moves(DUSKULL, + MOVE_IMPRISON, + MOVE_DESTINY_BOND, + MOVE_PAIN_SPLIT, + MOVE_GRUDGE, + MOVE_MEMENTO, + MOVE_FAINT_ATTACK), + + egg_moves(ROSELIA, + MOVE_SPIKES, + MOVE_SYNTHESIS, + MOVE_PIN_MISSILE, + MOVE_COTTON_SPORE), + + egg_moves(SLAKOTH, + MOVE_PURSUIT, + MOVE_SLASH, + MOVE_BODY_SLAM, + MOVE_SNORE, + MOVE_CRUSH_CLAW, + MOVE_CURSE, + MOVE_SLEEP_TALK), + + egg_moves(GULPIN, + MOVE_DREAM_EATER, + MOVE_ACID_ARMOR, + MOVE_SMOG, + MOVE_PAIN_SPLIT), + + egg_moves(TROPIUS, + MOVE_HEADBUTT, + MOVE_SLAM, + MOVE_RAZOR_WIND, + MOVE_LEECH_SEED, + MOVE_NATURE_POWER), + + egg_moves(WHISMUR, + MOVE_TAKE_DOWN, + MOVE_SNORE, + MOVE_SWAGGER, + MOVE_EXTRASENSORY, + MOVE_SMELLING_SALT), + + egg_moves(CLAMPERL, + MOVE_REFRESH, + MOVE_MUD_SPORT, + MOVE_BODY_SLAM, + MOVE_SUPERSONIC, + MOVE_BARRIER, + MOVE_CONFUSE_RAY), + + egg_moves(ABSOL, + MOVE_BATON_PASS, + MOVE_FAINT_ATTACK, + MOVE_DOUBLE_EDGE, + MOVE_MAGIC_COAT, + MOVE_CURSE, + MOVE_SUBSTITUTE), + + egg_moves(SHUPPET, + MOVE_DISABLE, + MOVE_DESTINY_BOND, + MOVE_FORESIGHT, + MOVE_ASTONISH, + MOVE_IMPRISON), + + egg_moves(SEVIPER, + MOVE_STOCKPILE, + MOVE_SWALLOW, + MOVE_SPIT_UP, + MOVE_BODY_SLAM), + + egg_moves(ZANGOOSE, + MOVE_FLAIL, + MOVE_DOUBLE_KICK, + MOVE_RAZOR_WIND, + MOVE_COUNTER, + MOVE_ROAR, + MOVE_CURSE), + + egg_moves(RELICANTH, + MOVE_MAGNITUDE, + MOVE_SKULL_BASH, + MOVE_WATER_SPORT, + MOVE_AMNESIA, + MOVE_SLEEP_TALK, + MOVE_ROCK_SLIDE), + + egg_moves(ARON, + MOVE_ENDEAVOR, + MOVE_BODY_SLAM, + MOVE_STOMP, + MOVE_SMELLING_SALT), + + egg_moves(CASTFORM, + MOVE_FUTURE_SIGHT, + MOVE_PSYCH_UP), + + egg_moves(VOLBEAT, + MOVE_BATON_PASS, + MOVE_SILVER_WIND, + MOVE_TRICK), + + egg_moves(ILLUMISE, + MOVE_BATON_PASS, + MOVE_SILVER_WIND, + MOVE_GROWTH), + + egg_moves(LILEEP, + MOVE_BARRIER, + MOVE_RECOVER, + MOVE_MIRROR_COAT, + MOVE_ROCK_SLIDE), + + egg_moves(ANORITH, + MOVE_RAPID_SPIN, + MOVE_KNOCK_OFF, + MOVE_SWORDS_DANCE, + MOVE_ROCK_SLIDE), + + egg_moves(RALTS, + MOVE_DISABLE, + MOVE_WILL_O_WISP, + MOVE_MEAN_LOOK, + MOVE_MEMENTO, + MOVE_DESTINY_BOND), + + egg_moves(BAGON, + MOVE_HYDRO_PUMP, + MOVE_THRASH, + MOVE_DRAGON_RAGE, + MOVE_TWISTER, + MOVE_DRAGON_DANCE), + + egg_moves(CHIMECHO, + MOVE_DISABLE, + MOVE_CURSE, + MOVE_HYPNOSIS, + MOVE_DREAM_EATER), + + EGG_MOVES_TERMINATOR +}; diff --git a/src/daycare.c b/src/daycare.c new file mode 100644 index 000000000..206e0b383 --- /dev/null +++ b/src/daycare.c @@ -0,0 +1,2209 @@ +#include "global.h" +#include "pokemon.h" +#include "battle.h" +#include "daycare.h" +#include "string_util.h" +#include "constants/species.h" +#include "constants/items.h" +#include "mail.h" +#include "pokemon_storage_system.h" +#include "event_data.h" +#include "random.h" +#include "main.h" +#include "constants/moves.h" +#include "text.h" +#include "menu.h" +#include "new_menu_helpers.h" +#include "international_string_util.h" +#include "script.h" +#include "strings.h" +#include "task.h" +#include "window.h" +#include "party_menu.h" +#include "list_menu.h" +#include "overworld.h" +#include "pokedex.h" +#include "decompress.h" +#include "task.h" +#include "palette.h" +#include "main.h" +#include "sound.h" +#include "constants/songs.h" +#include "text_window.h" +#include "trig.h" +#include "malloc.h" +#include "dma3.h" +#include "gpu_regs.h" +#include "bg.h" +#include "m4a.h" +#include "graphics.h" +#include "constants/abilities.h" +#include "constants/species.h" +#include "scanline_effect.h" +#include "field_weather.h" +#include "naming_screen.h" +#include "field_screen_effect.h" +#include "help_system.h" +#include "field_fadetransition.h" + +#define EGG_MOVES_ARRAY_COUNT 10 +#define EGG_LVL_UP_MOVES_ARRAY_COUNT 50 + +struct EggHatchData +{ + u8 eggSpriteID; + u8 pokeSpriteID; + u8 CB2_state; + u8 CB2_PalCounter; + u8 eggPartyID; + u8 unused_5; + u8 unused_6; + u8 eggShardVelocityID; + u8 windowId; + u8 unused_9; + u8 unused_A; + u16 species; + struct TextColor textColor; +}; + +extern const u8 gText_MaleSymbol4[]; +extern const u8 gText_FemaleSymbol4[]; +extern const u8 gText_GenderlessSymbol[]; +extern const u8 gText_Lv[]; +extern const u8 gDaycareText_GetAlongVeryWell[]; +extern const u8 gDaycareText_GetAlong[]; +extern const u8 gDaycareText_DontLikeOther[]; +extern const u8 gDaycareText_PlayOther[]; +extern const u8 gExpandedPlaceholder_Empty[]; + +extern const u32 gUnknown_08331F60[]; // tilemap gameboy circle +extern const u8 gText_HatchedFromEgg[]; +extern const u8 gText_NickHatchPrompt[]; + +// this file's functions +static void ClearDaycareMonMail(struct DayCareMail *mail); +static void SetInitialEggData(struct Pokemon *mon, u16 species, struct DayCare *daycare); +static u8 GetDaycareCompatibilityScore(struct DayCare *daycare); +static void DaycarePrintMonInfo(u8 windowId, s32 daycareSlotId, u8 y); + +static void Task_EggHatch(u8 taskID); +static void CB2_EggHatch_0(void); +static void CB2_EggHatch_1(void); +static void SpriteCB_Egg_0(struct Sprite* sprite); +static void SpriteCB_Egg_1(struct Sprite* sprite); +static void SpriteCB_Egg_2(struct Sprite* sprite); +static void SpriteCB_Egg_3(struct Sprite* sprite); +static void SpriteCB_Egg_4(struct Sprite* sprite); +static void SpriteCB_Egg_5(struct Sprite* sprite); +static void SpriteCB_EggShard(struct Sprite* sprite); +static void EggHatchPrintMessage(u8 windowId, u8* string, u8 x, u8 y, u8 speed); +static void CreateRandomEggShardSprite(void); +static void CreateEggShardSprite(u8 x, u8 y, s16 data1, s16 data2, s16 data3, u8 spriteAnimIndex); + +// IWRAM bss +static IWRAM_DATA struct EggHatchData *sEggHatchData; + +// RAM buffers used to assist with BuildEggMoveset() +EWRAM_DATA static u16 sHatchedEggLevelUpMoves[EGG_LVL_UP_MOVES_ARRAY_COUNT] = {0}; +EWRAM_DATA static u16 sHatchedEggFatherMoves[4] = {0}; +EWRAM_DATA static u16 sHatchedEggFinalMoves[4] = {0}; +EWRAM_DATA static u16 sHatchedEggEggMoves[EGG_MOVES_ARRAY_COUNT] = {0}; +EWRAM_DATA static u16 sHatchedEggMotherMoves[4] = {0}; + +#include "data/pokemon/egg_moves.h" + +static const struct WindowTemplate sDaycareLevelMenuWindowTemplate = +{ + .bg = 0, + .tilemapLeft = 12, + .tilemapTop = 1, + .width = 17, + .height = 5, + .paletteNum = 15, + .baseBlock = 8 +}; + +static const struct ListMenuItem sLevelMenuItems[] = +{ + {gExpandedPlaceholder_Empty, 0}, + {gExpandedPlaceholder_Empty, 1}, + {gOtherText_Exit, 5} +}; + +static const struct ListMenuTemplate sDaycareListMenuLevelTemplate = +{ + .items = sLevelMenuItems, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = DaycarePrintMonInfo, + .totalItems = 3, + .maxShowed = 3, + .windowId = 0, + .header_X = 2, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 0, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 1, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 3, + .cursorKind = 0 +}; + +static const u8 *const sCompatibilityMessages[] = +{ + gDaycareText_GetAlongVeryWell, + gDaycareText_GetAlong, + gDaycareText_DontLikeOther, + gDaycareText_PlayOther +}; + +static const u8 sNewLineText[] = _("\n"); +static const u8 sJapaneseEggNickname[] = _("タマゴ"); // "tamago" ("egg" in Japanese) + +static const u16 sEggPalette[] = INCBIN_U16("graphics/pokemon/egg/normal.gbapal"); +static const u8 sEggHatchTiles[] = INCBIN_U8("graphics/misc/egg_hatch.4bpp"); +static const u8 sEggShardTiles[] = INCBIN_U8("graphics/misc/egg_shard.4bpp"); + +static const struct OamData sOamData_EggHatch = + { + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = SPRITE_SHAPE(32x32), + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(32x32), + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, + }; + +static const union AnimCmd sSpriteAnim_EggHatch0[] = + { + ANIMCMD_FRAME(0, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggHatch1[] = + { + ANIMCMD_FRAME(16, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggHatch2[] = + { + ANIMCMD_FRAME(32, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggHatch3[] = + { + ANIMCMD_FRAME(48, 5), + ANIMCMD_END + }; + +static const union AnimCmd *const sSpriteAnimTable_EggHatch[] = + { + sSpriteAnim_EggHatch0, + sSpriteAnim_EggHatch1, + sSpriteAnim_EggHatch2, + sSpriteAnim_EggHatch3, + }; + +static const struct SpriteSheet sEggHatch_Sheet = + { + .data = sEggHatchTiles, + .size = 2048, + .tag = 12345, + }; + +static const struct SpriteSheet sEggShards_Sheet = + { + .data = sEggShardTiles, + .size = 128, + .tag = 23456, + }; + +static const struct SpritePalette sEgg_SpritePalette = + { + .data = sEggPalette, + .tag = 54321 + }; + +static const struct SpriteTemplate sSpriteTemplate_EggHatch = + { + .tileTag = 12345, + .paletteTag = 54321, + .oam = &sOamData_EggHatch, + .anims = sSpriteAnimTable_EggHatch, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy + }; + +static const struct OamData sOamData_EggShard = + { + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = SPRITE_SHAPE(8x8), + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(8x8), + .tileNum = 0, + .priority = 2, + .paletteNum = 0, + .affineParam = 0, + }; + +static const union AnimCmd sSpriteAnim_EggShard0[] = + { + ANIMCMD_FRAME(0, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggShard1[] = + { + ANIMCMD_FRAME(1, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggShard2[] = + { + ANIMCMD_FRAME(2, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggShard3[] = + { + ANIMCMD_FRAME(3, 5), + ANIMCMD_END + }; + +static const union AnimCmd *const sSpriteAnimTable_EggShard[] = + { + sSpriteAnim_EggShard0, + sSpriteAnim_EggShard1, + sSpriteAnim_EggShard2, + sSpriteAnim_EggShard3, + }; + +static const struct SpriteTemplate sSpriteTemplate_EggShard = + { + .tileTag = 23456, + .paletteTag = 54321, + .oam = &sOamData_EggShard, + .anims = sSpriteAnimTable_EggShard, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_EggShard + }; + +static const struct BgTemplate sBgTemplates_EggHatch[2] = + { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 24, + .screenSize = 3, + .paletteMode = 0, + .priority = 0, + .baseTile = 0 + }, + + { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 8, + .screenSize = 1, + .paletteMode = 0, + .priority = 2, + .baseTile = 0 + }, + }; + +static const struct WindowTemplate sWinTemplates_EggHatch[2] = + { + { + .bg = 0, + .tilemapLeft = 2, + .tilemapTop = 15, + .width = 26, + .height = 4, + .paletteNum = 0, + .baseBlock = 64 + }, + DUMMY_WIN_TEMPLATE + }; + +static const struct WindowTemplate sYesNoWinTemplate = + { + .bg = 0, + .tilemapLeft = 21, + .tilemapTop = 9, + .width = 6, + .height = 4, + .paletteNum = 15, + .baseBlock = 424 + }; + +static const s16 sEggShardVelocities[][2] = + { + {Q_8_8(-1.5), Q_8_8(-3.75)}, + {Q_8_8(-5), Q_8_8(-3)}, + {Q_8_8(3.5), Q_8_8(-3)}, + {Q_8_8(-4), Q_8_8(-3.75)}, + {Q_8_8(2), Q_8_8(-1.5)}, + {Q_8_8(-0.5), Q_8_8(-6.75)}, + {Q_8_8(5), Q_8_8(-2.25)}, + {Q_8_8(-1.5), Q_8_8(-3.75)}, + {Q_8_8(4.5), Q_8_8(-1.5)}, + {Q_8_8(-1), Q_8_8(-6.75)}, + {Q_8_8(4), Q_8_8(-2.25)}, + {Q_8_8(-3.5), Q_8_8(-3.75)}, + {Q_8_8(1), Q_8_8(-1.5)}, + {Q_8_8(-3.515625), Q_8_8(-6.75)}, + {Q_8_8(4.5), Q_8_8(-2.25)}, + {Q_8_8(-0.5), Q_8_8(-7.5)}, + {Q_8_8(1), Q_8_8(-4.5)}, + {Q_8_8(-2.5), Q_8_8(-2.25)}, + {Q_8_8(2.5), Q_8_8(-7.5)}, + }; + +// code + +u8 *GetMonNick(struct Pokemon *mon, u8 *dest) +{ + u8 nickname[POKEMON_NAME_LENGTH * 2]; + + GetMonData(mon, MON_DATA_NICKNAME, nickname); + return StringCopy10(dest, nickname); +} + +u8 *GetBoxMonNick(struct BoxPokemon *mon, u8 *dest) +{ + u8 nickname[POKEMON_NAME_LENGTH * 2]; + + GetBoxMonData(mon, MON_DATA_NICKNAME, nickname); + return StringCopy10(dest, nickname); +} + +u8 CountPokemonInDaycare(struct DayCare *daycare) +{ + u8 i, count; + count = 0; + + for (i = 0; i < DAYCARE_MON_COUNT; i++) + { + if (GetBoxMonData(&daycare->mons[i].mon, MON_DATA_SPECIES) != 0) + count++; + } + + return count; +} + +void InitDaycareMailRecordMixing(struct DayCare *daycare, struct RecordMixingDayCareMail *daycareMail) +{ + u8 i; + u8 numDaycareMons = 0; + + for (i = 0; i < DAYCARE_MON_COUNT; i++) + { + if (GetBoxMonData(&daycare->mons[i].mon, MON_DATA_SPECIES) != SPECIES_NONE) + { + numDaycareMons++; + if (GetBoxMonData(&daycare->mons[i].mon, MON_DATA_HELD_ITEM) == ITEM_NONE) + { + daycareMail->holdsItem[i] = FALSE; + } + else + { + daycareMail->holdsItem[i] = TRUE; + } + } + else + { + daycareMail->holdsItem[i] = TRUE; + } + } + + daycareMail->numDaycareMons = numDaycareMons; +} + +static s8 Daycare_FindEmptySpot(struct DayCare *daycare) +{ + u8 i; + + for (i = 0; i < DAYCARE_MON_COUNT; i++) + { + if (GetBoxMonData(&daycare->mons[i].mon, MON_DATA_SPECIES) == 0) + return i; + } + + return -1; +} + +static void StorePokemonInDaycare(struct Pokemon *mon, struct DaycareMon *daycareMon) +{ + if (MonHasMail(mon)) + { + u8 mailId; + + StringCopy(daycareMon->mail.OT_name, gSaveBlock2Ptr->playerName); + GetMonNick(mon, daycareMon->mail.monName); +// StripExtCtrlCodes(daycareMon->mail.monName); +// daycareMon->mail.gameLanguage = LANGUAGE_ENGLISH; +// daycareMon->mail.monLanguage = GetMonData(mon, MON_DATA_LANGUAGE); + mailId = GetMonData(mon, MON_DATA_MAIL); + daycareMon->mail.message = gSaveBlock1Ptr->mail[mailId]; + TakeMailFromMon(mon); + } + + daycareMon->mon = mon->box; + BoxMonRestorePP(&daycareMon->mon); + daycareMon->steps = 0; + ZeroMonData(mon); + CompactPartySlots(); + CalculatePlayerPartyCount(); +} + +static void StorePokemonInEmptyDaycareSlot(struct Pokemon *mon, struct DayCare *daycare) +{ + s8 slotId = Daycare_FindEmptySpot(daycare); + StorePokemonInDaycare(mon, &daycare->mons[slotId]); +} + +void StoreSelectedPokemonInDaycare(void) +{ + u8 monId = GetCursorSelectionMonId(); + StorePokemonInEmptyDaycareSlot(&gPlayerParty[monId], &gSaveBlock1Ptr->daycare); +} + +// Shifts the second daycare pokemon slot into the first slot. +static void ShiftDaycareSlots(struct DayCare *daycare) +{ + // This condition is only satisfied when the player takes out the first pokemon from the daycare. + if (GetBoxMonData(&daycare->mons[1].mon, MON_DATA_SPECIES) != 0 + && GetBoxMonData(&daycare->mons[0].mon, MON_DATA_SPECIES) == 0) + { + daycare->mons[0].mon = daycare->mons[1].mon; + ZeroBoxMonData(&daycare->mons[1].mon); + + daycare->mons[0].mail = daycare->mons[1].mail; + daycare->mons[0].steps = daycare->mons[1].steps; + daycare->mons[1].steps = 0; + ClearDaycareMonMail(&daycare->mons[1].mail); + } +} + +static void ApplyDaycareExperience(struct Pokemon *mon) +{ + s32 i; + bool8 firstMove; + u16 learnedMove; + + for (i = 0; i < MAX_MON_LEVEL; i++) + { + // Add the mon's gained daycare experience level by level until it can't level up anymore. + if (TryIncrementMonLevel(mon)) + { + // Teach the mon new moves it learned while in the daycare. + firstMove = TRUE; + while ((learnedMove = MonTryLearningNewMove(mon, firstMove)) != 0) + { + firstMove = FALSE; + if (learnedMove == 0xFFFF) + { + // Mon already knows 4 moves. + DeleteFirstMoveAndGiveMoveToMon(mon, gMoveToLearn); + } + } + } + else + { + break; + } + } + + // Re-calculate the mons stats at its new level. + CalculateMonStats(mon); +} + +static u16 TakeSelectedPokemonFromDaycare(struct DaycareMon *daycareMon) +{ + u16 species; + u32 experience; + struct Pokemon pokemon; + + GetBoxMonNick(&daycareMon->mon, gStringVar1); + species = GetBoxMonData(&daycareMon->mon, MON_DATA_SPECIES); + BoxMonToMon(&daycareMon->mon, &pokemon); + + if (GetMonData(&pokemon, MON_DATA_LEVEL) != MAX_MON_LEVEL) + { + experience = GetMonData(&pokemon, MON_DATA_EXP) + daycareMon->steps; + SetMonData(&pokemon, MON_DATA_EXP, &experience); + ApplyDaycareExperience(&pokemon); + } + + gPlayerParty[PARTY_SIZE - 1] = pokemon; + if (daycareMon->mail.message.itemId) + { + GiveMailToMon2(&gPlayerParty[PARTY_SIZE - 1], &daycareMon->mail.message); + ClearDaycareMonMail(&daycareMon->mail); + } + + ZeroBoxMonData(&daycareMon->mon); + daycareMon->steps = 0; + CompactPartySlots(); + CalculatePlayerPartyCount(); + return species; +} + +static u16 TakeSelectedPokemonMonFromDaycareShiftSlots(struct DayCare *daycare, u8 slotId) +{ + u16 species = TakeSelectedPokemonFromDaycare(&daycare->mons[slotId]); + ShiftDaycareSlots(daycare); + return species; +} + +u16 TakePokemonFromDaycare(void) +{ + return TakeSelectedPokemonMonFromDaycareShiftSlots(&gSaveBlock1Ptr->daycare, gSpecialVar_0x8004); +} + +static u8 GetLevelAfterDaycareSteps(struct BoxPokemon *mon, u32 steps) +{ + struct BoxPokemon tempMon = *mon; + + u32 experience = GetBoxMonData(mon, MON_DATA_EXP) + steps; + SetBoxMonData(&tempMon, MON_DATA_EXP, &experience); + return GetLevelFromBoxMonExp(&tempMon); +} + +static u8 GetNumLevelsGainedFromSteps(struct DaycareMon *daycareMon) +{ + u8 levelBefore; + u8 levelAfter; + + levelBefore = GetLevelFromBoxMonExp(&daycareMon->mon); + levelAfter = GetLevelAfterDaycareSteps(&daycareMon->mon, daycareMon->steps); + return levelAfter - levelBefore; +} + +static u8 GetNumLevelsGainedForDaycareMon(struct DaycareMon *daycareMon) +{ + u8 numLevelsGained = GetNumLevelsGainedFromSteps(daycareMon); + ConvertIntToDecimalStringN(gStringVar2, numLevelsGained, STR_CONV_MODE_LEFT_ALIGN, 2); + GetBoxMonNick(&daycareMon->mon, gStringVar1); + return numLevelsGained; +} + +static u32 GetDaycareCostForSelectedMon(struct DaycareMon *daycareMon) +{ + u32 cost; + + u8 numLevelsGained = GetNumLevelsGainedFromSteps(daycareMon); + GetBoxMonNick(&daycareMon->mon, gStringVar1); + cost = 100 + 100 * numLevelsGained; + ConvertIntToDecimalStringN(gStringVar2, cost, STR_CONV_MODE_LEFT_ALIGN, 5); + return cost; +} + +static u16 GetDaycareCostForMon(struct DayCare *daycare, u8 slotId) +{ + return GetDaycareCostForSelectedMon(&daycare->mons[slotId]); +} + +void GetDaycareCost(void) +{ + gSpecialVar_0x8005 = GetDaycareCostForMon(&gSaveBlock1Ptr->daycare, gSpecialVar_0x8004); +} + +static void Debug_AddDaycareSteps(u16 numSteps) +{ + gSaveBlock1Ptr->daycare.mons[0].steps += numSteps; + gSaveBlock1Ptr->daycare.mons[1].steps += numSteps; + gSaveBlock1Ptr->route5DayCareMon.steps += numSteps; +} + +u8 GetNumLevelsGainedFromDaycare(void) +{ + if (GetBoxMonData(&gSaveBlock1Ptr->daycare.mons[gSpecialVar_0x8004], MON_DATA_SPECIES) != 0) + return GetNumLevelsGainedForDaycareMon(&gSaveBlock1Ptr->daycare.mons[gSpecialVar_0x8004]); + + return 0; +} + +static void ClearDaycareMonMail(struct DayCareMail *mail) +{ + s32 i; + + for (i = 0; i < PLAYER_NAME_LENGTH; i++) + mail->OT_name[i] = 0; + for (i = 0; i < POKEMON_NAME_LENGTH + 1; i++) + mail->monName[i] = 0; + + ClearMailStruct(&mail->message); +} + +static void ClearDaycareMon(struct DaycareMon *daycareMon) +{ + ZeroBoxMonData(&daycareMon->mon); + daycareMon->steps = 0; + ClearDaycareMonMail(&daycareMon->mail); +} + +static void ClearAllDaycareData(struct DayCare *daycare) +{ + u8 i; + + for (i = 0; i < DAYCARE_MON_COUNT; i++) + ClearDaycareMon(&daycare->mons[i]); + + daycare->offspringPersonality = 0; + daycare->stepCounter = 0; +} + +// Determines what the species of an Egg would be based on the given species. +// It determines this by working backwards through the evolution chain of the +// given species. +static u16 GetEggSpecies(u16 species) +{ + int i, j, k; + bool8 found; + + // Working backwards up to 5 times seems arbitrary, since the maximum number + // of times would only be 3 for 3-stage evolutions. + for (i = 0; i < EVOS_PER_MON; i++) + { + found = FALSE; + for (j = 1; j < NUM_SPECIES; j++) + { + for (k = 0; k < EVOS_PER_MON; k++) + { + if (gEvolutionTable[j][k].targetSpecies == species) + { + species = j; + found = TRUE; + break; + } + } + + if (found) + break; + } + + if (j == NUM_SPECIES) + break; + } + + return species; +} +// +//static s32 GetSlotToInheritNature(struct DayCare *daycare) +//{ +// u32 species[DAYCARE_MON_COUNT]; +// s32 i; +// s32 dittoCount; +// s32 slot = -1; +// +// // search for female gender +// for (i = 0; i < DAYCARE_MON_COUNT; i++) +// { +// if (GetBoxMonGender(&daycare->mons[i].mon) == MON_FEMALE) +// slot = i; +// } +// +// // search for ditto +// for (dittoCount = 0, i = 0; i < DAYCARE_MON_COUNT; i++) +// { +// species[i] = GetBoxMonData(&daycare->mons[i].mon, MON_DATA_SPECIES); +// if (species[i] == SPECIES_DITTO) +// dittoCount++, slot = i; +// } +// +// // coin flip on ...two Dittos +// if (dittoCount == 2) +// { +// if (Random() >= USHRT_MAX / 2) +// slot = 0; +// else +// slot = 1; +// } +// +// // nature inheritance only if holds everstone +// if (GetBoxMonData(&daycare->mons[slot].mon, MON_DATA_HELD_ITEM) != ITEM_EVERSTONE +// || Random() >= USHRT_MAX / 2) +// { +// return -1; +// } +// +// return slot; +//} + +static void _TriggerPendingDaycareEgg(struct DayCare *daycare) +{ +// s32 natureSlot; +// s32 natureTries = 0; +// +// SeedRng2(gMain.vblankCounter2); +// natureSlot = GetSlotToInheritNature(daycare); +// +// if (natureSlot < 0) +// { +// daycare->offspringPersonality = (Random2() << 0x10) | ((Random() % 0xfffe) + 1); +// } +// else +// { +// u8 wantedNature = GetNatureFromPersonality(GetBoxMonData(&daycare->mons[natureSlot].mon, MON_DATA_PERSONALITY, NULL)); +// u32 personality; +// +// do +// { +// personality = (Random2() << 0x10) | (Random()); +// if (wantedNature == GetNatureFromPersonality(personality) && personality != 0) +// break; // we found a personality with the same nature +// +// natureTries++; +// } while (natureTries <= 2400); +// +// daycare->offspringPersonality = personality; +// } + + daycare->offspringPersonality = ((Random()) % 0xFFFE) + 1; + FlagSet(FLAG_PENDING_DAYCARE_EGG); +} + +static void _TriggerPendingDaycareMaleEgg(struct DayCare *daycare) +{ + daycare->offspringPersonality = (Random()) | (0x8000); + FlagSet(FLAG_PENDING_DAYCARE_EGG); +} + +void TriggerPendingDaycareEgg(void) +{ + _TriggerPendingDaycareEgg(&gSaveBlock1Ptr->daycare); +} + +static void TriggerPendingDaycareMaleEgg(void) +{ + _TriggerPendingDaycareMaleEgg(&gSaveBlock1Ptr->daycare); +} + +// Removes the selected index from the given IV list and shifts the remaining +// elements to the left. +static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) +{ + s32 i, j; + u8 temp[NUM_STATS]; + + ivs[selectedIv] = 0xFF; + for (i = 0; i < NUM_STATS; i++) + { + temp[i] = ivs[i]; + } + + j = 0; + for (i = 0; i < NUM_STATS; i++) + { + if (temp[i] != 0xFF) + ivs[j++] = temp[i]; + } +} + +static void InheritIVs(struct Pokemon *egg, struct DayCare *daycare) +{ + u8 i; + u8 selectedIvs[3]; + u8 availableIVs[NUM_STATS]; + u8 whichParent[ARRAY_COUNT(selectedIvs)]; + u8 iv; + + // Initialize a list of IV indices. + for (i = 0; i < NUM_STATS; i++) + { + availableIVs[i] = i; + } + + // Select the 3 IVs that will be inherited. + for (i = 0; i < ARRAY_COUNT(selectedIvs); i++) + { + // Randomly pick an IV from the available list. + selectedIvs[i] = availableIVs[Random() % (NUM_STATS - i)]; + + // Remove the selected IV index from the available IV indices. + RemoveIVIndexFromList(availableIVs, selectedIvs[i]); + } + + // Determine which parent each of the selected IVs should inherit from. + for (i = 0; i < ARRAY_COUNT(selectedIvs); i++) + { + whichParent[i] = Random() % 2; + } + + // Set each of inherited IVs on the egg mon. + for (i = 0; i < ARRAY_COUNT(selectedIvs); i++) + { + switch (selectedIvs[i]) + { + case 0: + iv = GetBoxMonData(&daycare->mons[whichParent[i]].mon, MON_DATA_HP_IV); + SetMonData(egg, MON_DATA_HP_IV, &iv); + break; + case 1: + iv = GetBoxMonData(&daycare->mons[whichParent[i]].mon, MON_DATA_ATK_IV); + SetMonData(egg, MON_DATA_ATK_IV, &iv); + break; + case 2: + iv = GetBoxMonData(&daycare->mons[whichParent[i]].mon, MON_DATA_DEF_IV); + SetMonData(egg, MON_DATA_DEF_IV, &iv); + break; + case 3: + iv = GetBoxMonData(&daycare->mons[whichParent[i]].mon, MON_DATA_SPEED_IV); + SetMonData(egg, MON_DATA_SPEED_IV, &iv); + break; + case 4: + iv = GetBoxMonData(&daycare->mons[whichParent[i]].mon, MON_DATA_SPATK_IV); + SetMonData(egg, MON_DATA_SPATK_IV, &iv); + break; + case 5: + iv = GetBoxMonData(&daycare->mons[whichParent[i]].mon, MON_DATA_SPDEF_IV); + SetMonData(egg, MON_DATA_SPDEF_IV, &iv); + break; + } + } +} + +// Counts the number of egg moves a pokemon learns and stores the moves in +// the given array. +static u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves) +{ + u16 eggMoveIdx; + u16 numEggMoves; + u16 species; + u16 i; + + numEggMoves = 0; + eggMoveIdx = 0; + species = GetMonData(pokemon, MON_DATA_SPECIES); + for (i = 0; i < ARRAY_COUNT(gEggMoves) - 1; i++) + { + if (gEggMoves[i] == species + EGG_MOVES_SPECIES_OFFSET) + { + eggMoveIdx = i + 1; + break; + } + } + + for (i = 0; i < EGG_MOVES_ARRAY_COUNT; i++) + { + if (gEggMoves[eggMoveIdx + i] > EGG_MOVES_SPECIES_OFFSET) + { + // TODO: the curly braces around this if statement are required for a matching build. + break; + } + + eggMoves[i] = gEggMoves[eggMoveIdx + i]; + numEggMoves++; + } + + return numEggMoves; +} + +static void BuildEggMoveset(struct Pokemon *egg, struct BoxPokemon *father, struct BoxPokemon *mother) +{ + u16 numSharedParentMoves; + u32 numLevelUpMoves; + u16 numEggMoves; + u16 i, j; + + numSharedParentMoves = 0; + for (i = 0; i < MAX_MON_MOVES; i++) + { + sHatchedEggMotherMoves[i] = 0; + sHatchedEggFatherMoves[i] = 0; + sHatchedEggFinalMoves[i] = 0; + } + for (i = 0; i < EGG_MOVES_ARRAY_COUNT; i++) + sHatchedEggEggMoves[i] = 0; + for (i = 0; i < EGG_LVL_UP_MOVES_ARRAY_COUNT; i++) + sHatchedEggLevelUpMoves[i] = 0; + + numLevelUpMoves = GetLevelUpMovesBySpecies(GetMonData(egg, MON_DATA_SPECIES), sHatchedEggLevelUpMoves); + for (i = 0; i < MAX_MON_MOVES; i++) + { + sHatchedEggFatherMoves[i] = GetBoxMonData(father, MON_DATA_MOVE1 + i); + sHatchedEggMotherMoves[i] = GetBoxMonData(mother, MON_DATA_MOVE1 + i); + } + + numEggMoves = GetEggMoves(egg, sHatchedEggEggMoves); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (sHatchedEggFatherMoves[i] != MOVE_NONE) + { + for (j = 0; j < numEggMoves; j++) + { + if (sHatchedEggFatherMoves[i] == sHatchedEggEggMoves[j]) + { + if (GiveMoveToMon(egg, sHatchedEggFatherMoves[i]) == 0xFFFF) + DeleteFirstMoveAndGiveMoveToMon(egg, sHatchedEggFatherMoves[i]); + break; + } + } + } + else + { + break; + } + } + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (sHatchedEggFatherMoves[i] != MOVE_NONE) + { + for (j = 0; j < NUM_TECHNICAL_MACHINES + NUM_HIDDEN_MACHINES; j++) + { + if (sHatchedEggFatherMoves[i] == ItemIdToBattleMoveId(ITEM_TM01/*_FOCUS_PUNCH*/ + j) && CanMonLearnTMHM(egg, j)) + { + if (GiveMoveToMon(egg, sHatchedEggFatherMoves[i]) == 0xFFFF) + DeleteFirstMoveAndGiveMoveToMon(egg, sHatchedEggFatherMoves[i]); + } + } + } + } + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (sHatchedEggFatherMoves[i] == MOVE_NONE) + break; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (sHatchedEggFatherMoves[i] == sHatchedEggMotherMoves[j] && sHatchedEggFatherMoves[i] != MOVE_NONE) + sHatchedEggFinalMoves[numSharedParentMoves++] = sHatchedEggFatherMoves[i]; + } + } + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (sHatchedEggFinalMoves[i] == MOVE_NONE) + break; + for (j = 0; j < numLevelUpMoves; j++) + { + if (sHatchedEggLevelUpMoves[j] != MOVE_NONE && sHatchedEggFinalMoves[i] == sHatchedEggLevelUpMoves[j]) + { + if (GiveMoveToMon(egg, sHatchedEggFinalMoves[i]) == 0xFFFF) + DeleteFirstMoveAndGiveMoveToMon(egg, sHatchedEggFinalMoves[i]); + break; + } + } + } +} + +static void RemoveEggFromDayCare(struct DayCare *daycare) +{ + daycare->offspringPersonality = 0; + daycare->stepCounter = 0; +} + +void RejectEggFromDayCare(void) +{ + RemoveEggFromDayCare(&gSaveBlock1Ptr->daycare); +} + +static void AlterEggSpeciesWithIncenseItem(u16 *species, struct DayCare *daycare) +{ + u16 motherItem, fatherItem; + if (*species == SPECIES_WYNAUT || *species == SPECIES_AZURILL) + { + motherItem = GetBoxMonData(&daycare->mons[0].mon, MON_DATA_HELD_ITEM); + fatherItem = GetBoxMonData(&daycare->mons[1].mon, MON_DATA_HELD_ITEM); + if (*species == SPECIES_WYNAUT && motherItem != ITEM_LAX_INCENSE && fatherItem != ITEM_LAX_INCENSE) + { + *species = SPECIES_WOBBUFFET; + } + + if (*species == SPECIES_AZURILL && motherItem != ITEM_SEA_INCENSE && fatherItem != ITEM_SEA_INCENSE) + { + *species = SPECIES_MARILL; + } + } +} + +/*static void GiveVoltTackleIfLightBall(struct Pokemon *mon, struct DayCare *daycare) +{ + u32 motherItem = GetBoxMonData(&daycare->mons[0].mon, MON_DATA_HELD_ITEM); + u32 fatherItem = GetBoxMonData(&daycare->mons[1].mon, MON_DATA_HELD_ITEM); + + if (motherItem == ITEM_LIGHT_BALL || fatherItem == ITEM_LIGHT_BALL) + { + if (GiveMoveToMon(mon, MOVE_VOLT_TACKLE) == 0xFFFF) + DeleteFirstMoveAndGiveMoveToMon(mon, MOVE_VOLT_TACKLE); + } +}*/ + +static u16 DetermineEggSpeciesAndParentSlots(struct DayCare *daycare, u8 *parentSlots) +{ + u16 i; + u16 species[2]; + u16 eggSpecies; + + // Determine which of the daycare mons is the mother and father of the egg. + // The 0th index of the parentSlots array is considered the mother slot, and the + // 1st index is the father slot. + for (i = 0; i < 2; i++) + { + species[i] = GetBoxMonData(&daycare->mons[i].mon, MON_DATA_SPECIES); + if (species[i] == SPECIES_DITTO) + { + parentSlots[0] = i ^ 1; + parentSlots[1] = i; + } + else if (GetBoxMonGender(&daycare->mons[i].mon) == MON_FEMALE) + { + parentSlots[0] = i; + parentSlots[1] = i ^ 1; + } + } + + eggSpecies = GetEggSpecies(species[parentSlots[0]]); + if (eggSpecies == SPECIES_NIDORAN_F && daycare->offspringPersonality & 0x8000) + { + eggSpecies = SPECIES_NIDORAN_M; + } + if (eggSpecies == SPECIES_ILLUMISE && daycare->offspringPersonality & 0x8000) + { + eggSpecies = SPECIES_VOLBEAT; + } + + // Make Ditto the "mother" slot if the other daycare mon is male. + if (species[parentSlots[1]] == SPECIES_DITTO && GetBoxMonGender(&daycare->mons[parentSlots[0]].mon) != MON_FEMALE) + { + u8 temp = parentSlots[1]; + parentSlots[1] = parentSlots[0]; + parentSlots[0] = temp; + } + + return eggSpecies; +} + +static void _GiveEggFromDaycare(struct DayCare *daycare) // give_egg +{ + struct Pokemon egg; + u16 species; + u8 parentSlots[2]; // 0th index is "mother" daycare slot, 1st is "father" + bool8 isEgg; + + species = DetermineEggSpeciesAndParentSlots(daycare, parentSlots); + AlterEggSpeciesWithIncenseItem(&species, daycare); + SetInitialEggData(&egg, species, daycare); + InheritIVs(&egg, daycare); + BuildEggMoveset(&egg, &daycare->mons[parentSlots[1]].mon, &daycare->mons[parentSlots[0]].mon); + + /*if (species == SPECIES_PICHU) + GiveVoltTackleIfLightBall(&egg, daycare);*/ + + isEgg = TRUE; + SetMonData(&egg, MON_DATA_IS_EGG, &isEgg); + gPlayerParty[PARTY_SIZE - 1] = egg; + CompactPartySlots(); + CalculatePlayerPartyCount(); + RemoveEggFromDayCare(daycare); +} + +void CreateEgg(struct Pokemon *mon, u16 species, bool8 setHotSpringsLocation) +{ + u8 metLevel; + u16 ball; + u8 language; + u8 metLocation; + u8 isEgg; + + CreateMon(mon, species, EGG_HATCH_LEVEL, 0x20, FALSE, 0, FALSE, 0); + metLevel = 0; + ball = ITEM_POKE_BALL; + language = LANGUAGE_JAPANESE; + SetMonData(mon, MON_DATA_POKEBALL, &ball); + SetMonData(mon, MON_DATA_NICKNAME, sJapaneseEggNickname); + SetMonData(mon, MON_DATA_FRIENDSHIP, &gBaseStats[species].eggCycles); + SetMonData(mon, MON_DATA_MET_LEVEL, &metLevel); + SetMonData(mon, MON_DATA_LANGUAGE, &language); + if (setHotSpringsLocation) + { + metLocation = 253; // hot springs; see PokemonSummaryScreen_PrintEggTrainerMemo + SetMonData(mon, MON_DATA_MET_LOCATION, &metLocation); + } + + isEgg = TRUE; + SetMonData(mon, MON_DATA_IS_EGG, &isEgg); +} + +static void SetInitialEggData(struct Pokemon *mon, u16 species, struct DayCare *daycare) +{ + u32 personality; + u16 ball; + u8 metLevel; + u8 language; + + personality = daycare->offspringPersonality | (Random() << 16); + CreateMon(mon, species, EGG_HATCH_LEVEL, 0x20, TRUE, personality, FALSE, 0); + metLevel = 0; + ball = ITEM_POKE_BALL; + language = LANGUAGE_JAPANESE; + SetMonData(mon, MON_DATA_POKEBALL, &ball); + SetMonData(mon, MON_DATA_NICKNAME, sJapaneseEggNickname); + SetMonData(mon, MON_DATA_FRIENDSHIP, &gBaseStats[species].eggCycles); + SetMonData(mon, MON_DATA_MET_LEVEL, &metLevel); + SetMonData(mon, MON_DATA_LANGUAGE, &language); +} + +void GiveEggFromDaycare(void) +{ + _GiveEggFromDaycare(&gSaveBlock1Ptr->daycare); +} + +static bool8 _DoEggActions_CheckHatch(struct DayCare *daycare) +{ + u32 i, validEggs = 0; + + for (i = 0; i < DAYCARE_MON_COUNT; i++) + { + if (GetBoxMonData(&daycare->mons[i].mon, MON_DATA_SANITY_HAS_SPECIES)) + daycare->mons[i].steps++, validEggs++; + } + + // try to trigger poke sex + if (daycare->offspringPersonality == 0 && validEggs == 2 && (daycare->mons[1].steps & 0xFF) == 0xFF) + { + u8 loveScore = GetDaycareCompatibilityScore(daycare); + if (loveScore > (Random() * 100u) / USHRT_MAX) + TriggerPendingDaycareEgg(); + } + + if (++daycare->stepCounter == 255) // hatch an egg + { + u32 steps; + + for (i = 0; i < gPlayerPartyCount; i++) + { + if (!GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + continue; + if (GetMonData(&gPlayerParty[i], MON_DATA_SANITY_IS_BAD_EGG)) + continue; + + steps = GetMonData(&gPlayerParty[i], MON_DATA_FRIENDSHIP); + if (steps != 0) // subtract needed steps + { + steps -= 1; + + SetMonData(&gPlayerParty[i], MON_DATA_FRIENDSHIP, &steps); + } + else // hatch the egg + { + gSpecialVar_0x8004 = i; + return TRUE; + } + } + } + + return FALSE; // no hatching +} + +bool8 ShouldEggHatch(void) +{ + if (GetBoxMonData(&gSaveBlock1Ptr->route5DayCareMon.mon, MON_DATA_SANITY_HAS_SPECIES)) + gSaveBlock1Ptr->route5DayCareMon.steps++; + return _DoEggActions_CheckHatch(&gSaveBlock1Ptr->daycare); +} + +static bool8 IsEggPending(struct DayCare *daycare) +{ + return (daycare->offspringPersonality != 0); +} + +// gStringVar1 = first mon's nickname +// gStringVar2 = second mon's nickname +// gStringVar3 = first mon trainer's name +static void _GetDaycareMonNicknames(struct DayCare *daycare) +{ + u8 text[12]; + if (GetBoxMonData(&daycare->mons[0].mon, MON_DATA_SPECIES) != 0) + { + GetBoxMonNick(&daycare->mons[0].mon, gStringVar1); + GetBoxMonData(&daycare->mons[0].mon, MON_DATA_OT_NAME, text); + StringCopy(gStringVar3, text); + } + + if (GetBoxMonData(&daycare->mons[1].mon, MON_DATA_SPECIES) != 0) + { + GetBoxMonNick(&daycare->mons[1].mon, gStringVar2); + } +} + +u16 GetSelectedMonNickAndSpecies(void) +{ + GetBoxMonNick(&gPlayerParty[GetCursorSelectionMonId()].box, gStringVar1); + return GetBoxMonData(&gPlayerParty[GetCursorSelectionMonId()].box, MON_DATA_SPECIES); +} + +void GetDaycareMonNicknames(void) +{ + _GetDaycareMonNicknames(&gSaveBlock1Ptr->daycare); +} + +u8 GetDaycareState(void) +{ + // The daycare can be in 4 possible states: + // 0: default state--no deposited mons, no egg + // 1: there is an egg waiting for the player to pick it up + // 2: there is a single pokemon in the daycare + // 3: there are two pokemon in the daycare, no egg + + u8 numMons; + if (IsEggPending(&gSaveBlock1Ptr->daycare)) + { + // There is an Egg waiting for the player. + return 1; + } + + numMons = CountPokemonInDaycare(&gSaveBlock1Ptr->daycare); + if (numMons != 0) + { + return numMons + 1; + } + + return 0; +} + +u8 GetDaycarePokemonCount(void) +{ + u8 ret = CountPokemonInDaycare(&gSaveBlock1Ptr->daycare); + if (ret) + return ret; + + return 0; +} + +static bool8 EggGroupsOverlap(u16 *eggGroups1, u16 *eggGroups2) +{ + // Determine if the two given egg group lists contain any of the + // same egg groups. + s32 i, j; + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (eggGroups1[i] == eggGroups2[j]) + return TRUE; + } + } + + return FALSE; +} + +static u8 GetDaycareCompatibilityScore(struct DayCare *daycare) +{ + u32 i; + u16 eggGroups[2][2]; + u16 species[2]; + u32 trainerIds[2]; + u32 genders[2]; + + for (i = 0; i < 2; i++) + { + u32 personality; + + species[i] = GetBoxMonData(&daycare->mons[i].mon, MON_DATA_SPECIES); + trainerIds[i] = GetBoxMonData(&daycare->mons[i].mon, MON_DATA_OT_ID); + personality = GetBoxMonData(&daycare->mons[i].mon, MON_DATA_PERSONALITY); + genders[i] = GetGenderFromSpeciesAndPersonality(species[i], personality); + eggGroups[i][0] = gBaseStats[species[i]].eggGroup1; + eggGroups[i][1] = gBaseStats[species[i]].eggGroup2; + } + + // check unbreedable egg group + if (eggGroups[0][0] == EGG_GROUP_UNDISCOVERED || eggGroups[1][0] == EGG_GROUP_UNDISCOVERED) + return 0; + // two Ditto can't breed + if (eggGroups[0][0] == EGG_GROUP_DITTO && eggGroups[1][0] == EGG_GROUP_DITTO) + return 0; + + // now that we checked, one ditto can breed with any other mon + if (eggGroups[0][0] == EGG_GROUP_DITTO || eggGroups[1][0] == EGG_GROUP_DITTO) + { + if (trainerIds[0] == trainerIds[1]) // same trainer + return 20; + + return 50; // different trainers, more chance of poke sex + } + else + { + if (genders[0] == genders[1]) // no homo + return 0; + if (genders[0] == MON_GENDERLESS || genders[1] == MON_GENDERLESS) + return 0; + if (!EggGroupsOverlap(eggGroups[0], eggGroups[1])) // not compatible with each other + return 0; + + if (species[0] == species[1]) // same species + { + if (trainerIds[0] == trainerIds[1]) // same species and trainer + return 50; + + return 70; // different trainers, same species + } + else + { + if (trainerIds[0] != trainerIds[1]) // different trainers, different species + return 50; + + return 20; // different species, same trainer + } + } +} + +static u8 GetDaycareCompatibilityScoreFromSave(void) +{ + return GetDaycareCompatibilityScore(&gSaveBlock1Ptr->daycare); +} + +void SetDaycareCompatibilityString(void) +{ + u8 whichString; + u8 relationshipScore; + + relationshipScore = GetDaycareCompatibilityScoreFromSave(); + whichString = 0; + if (relationshipScore == 0) + whichString = 3; + if (relationshipScore == 20) + whichString = 2; + if (relationshipScore == 50) + whichString = 1; + if (relationshipScore == 70) + whichString = 0; + + StringCopy(gStringVar4, sCompatibilityMessages[whichString]); +} + +bool8 NameHasGenderSymbol(const u8 *name, u8 genderRatio) +{ + u8 i; + u8 symbolsCount[2]; // male, female + symbolsCount[0] = symbolsCount[1] = 0; + + for (i = 0; name[i] != EOS; i++) + { + if (name[i] == CHAR_MALE) + symbolsCount[0]++; + if (name[i] == CHAR_FEMALE) + symbolsCount[1]++; + } + + if (genderRatio == MON_MALE && symbolsCount[0] != 0 && symbolsCount[1] == 0) + return TRUE; + if (genderRatio == MON_FEMALE && symbolsCount[1] != 0 && symbolsCount[0] == 0) + return TRUE; + + return FALSE; +} + +static u8 *AppendGenderSymbol(u8 *name, u8 gender) +{ + if (gender == MON_MALE) + { + if (!NameHasGenderSymbol(name, MON_MALE)) + return StringAppend(name, gText_MaleSymbol4); + } + else if (gender == MON_FEMALE) + { + if (!NameHasGenderSymbol(name, MON_FEMALE)) + return StringAppend(name, gText_FemaleSymbol4); + } + + return StringAppend(name, gText_GenderlessSymbol); +} + +static u8 *AppendMonGenderSymbol(u8 *name, struct BoxPokemon *boxMon) +{ + return AppendGenderSymbol(name, GetBoxMonGender(boxMon)); +} + +static void GetDaycareLevelMenuText(struct DayCare *daycare, u8 *dest) +{ + u8 monNames[2][20]; + u8 i; + + *dest = EOS; + for (i = 0; i < 2; i++) + { + GetBoxMonNick(&daycare->mons[i].mon, monNames[i]); + AppendMonGenderSymbol(monNames[i], &daycare->mons[i].mon); + } + + StringCopy(dest, monNames[0]); + StringAppend(dest, sNewLineText); + StringAppend(dest, monNames[1]); + StringAppend(dest, sNewLineText); + StringAppend(dest, gOtherText_Exit); +} + +static void GetDaycareLevelMenuLevelText(struct DayCare *daycare, u8 *dest) +{ + u8 i; + u8 level; + u8 text[20]; + + *dest = EOS; + for (i = 0; i < 2; i++) + { + StringAppend(dest, gText_Lv); + level = GetLevelAfterDaycareSteps(&daycare->mons[i].mon, daycare->mons[i].steps); + ConvertIntToDecimalStringN(text, level, STR_CONV_MODE_LEFT_ALIGN, 3); + StringAppend(dest, text); + StringAppend(dest, sNewLineText); + } +} + +static void DaycareAddTextPrinter(u8 windowId, const u8 *text, u32 x, u32 y) +{ + struct TextPrinterTemplate printer; + + printer.currentChar = text; + printer.windowId = windowId; + printer.fontId = 3; + printer.x = x; + printer.y = y; + printer.currentX = x; + printer.currentY = y; + printer.unk = 0; + gTextFlags.useAlternateDownArrow = 0; + printer.letterSpacing = 1; + printer.lineSpacing = 1; + printer.fgColor = 2; + printer.bgColor = 1; + printer.shadowColor = 3; + + AddTextPrinter(&printer, 0xFF, NULL); +} + +static void DaycarePrintMonNick(struct DayCare *daycare, u8 windowId, u32 daycareSlotId, u32 y) +{ + u8 nick[POKEMON_NAME_LENGTH * 2]; + + GetBoxMonNick(&daycare->mons[daycareSlotId].mon, nick); + AppendMonGenderSymbol(nick, &daycare->mons[daycareSlotId].mon); + DaycareAddTextPrinter(windowId, nick, 8, y); +} + +static void DaycarePrintMonLvl(struct DayCare *daycare, u8 windowId, u32 daycareSlotId, u32 y) +{ + u8 level; + u32 x; + u8 lvlText[12]; + u8 intText[8]; + + strcpy((char *)lvlText, (const char *)gText_Lv); + level = GetLevelAfterDaycareSteps(&daycare->mons[daycareSlotId].mon, daycare->mons[daycareSlotId].steps); + ConvertIntToDecimalStringN(intText, level, STR_CONV_MODE_LEFT_ALIGN, 3); + StringAppend(lvlText, intText); + x = 132 - GetStringWidth(3, lvlText, 0); + DaycareAddTextPrinter(windowId, lvlText, x, y); +} + +static void DaycarePrintMonInfo(u8 windowId, s32 daycareSlotId, u8 y) +{ + if (daycareSlotId < (unsigned) DAYCARE_MON_COUNT) + { + DaycarePrintMonNick(&gSaveBlock1Ptr->daycare, windowId, daycareSlotId, y); + DaycarePrintMonLvl(&gSaveBlock1Ptr->daycare, windowId, daycareSlotId, y); + } +} + +#define tMenuListTaskId data[0] +#define tWindowId data[1] + +static void Task_HandleDaycareLevelMenuInput(u8 taskId) +{ + u32 input = ListMenuHandleInput(gTasks[taskId].tMenuListTaskId); + + if (gMain.newKeys & A_BUTTON) + { + switch (input) + { + case 0: + case 1: + gSpecialVar_Result = input; + break; + case 5: + gSpecialVar_Result = 2; + break; + } + DestroyListMenu(gTasks[taskId].tMenuListTaskId, NULL, NULL); + ClearStdWindowAndFrame(gTasks[taskId].tWindowId, TRUE); + RemoveWindow(gTasks[taskId].tWindowId); + DestroyTask(taskId); + EnableBothScriptContexts(); + } + else if (gMain.newKeys & B_BUTTON) + { + gSpecialVar_Result = 2; + DestroyListMenu(gTasks[taskId].tMenuListTaskId, NULL, NULL); + ClearStdWindowAndFrame(gTasks[taskId].tWindowId, TRUE); + RemoveWindow(gTasks[taskId].tWindowId); + DestroyTask(taskId); + EnableBothScriptContexts(); + } +} + +void ShowDaycareLevelMenu(void) +{ + struct ListMenuTemplate menuTemplate; + u8 windowId; + u8 listMenuTaskId; + u8 daycareMenuTaskId; + + windowId = AddWindow(&sDaycareLevelMenuWindowTemplate); + DrawStdWindowFrame(windowId, FALSE); + + menuTemplate = sDaycareListMenuLevelTemplate; + menuTemplate.windowId = windowId; + listMenuTaskId = ListMenuInit(&menuTemplate, 0, 0); + + CopyWindowToVram(windowId, 3); + + daycareMenuTaskId = CreateTask(Task_HandleDaycareLevelMenuInput, 3); + gTasks[daycareMenuTaskId].tMenuListTaskId = listMenuTaskId; + gTasks[daycareMenuTaskId].tWindowId = windowId; +} + +#undef tMenuListTaskId +#undef tWindowId + +void ChooseSendDaycareMon(void) +{ + sub_8128370(); + gMain.savedCallback = CB2_ReturnToField; +} + +// Route 5 Daycare + +void PutMonInRoute5Daycare(void) +{ + u8 monIdx = GetCursorSelectionMonId(); + StorePokemonInDaycare(&gPlayerParty[monIdx], &gSaveBlock1Ptr->route5DayCareMon); +} + +void GetCostToWithdrawRoute5DaycareMon(void) +{ + u16 cost = GetDaycareCostForSelectedMon(&gSaveBlock1Ptr->route5DayCareMon); + gSpecialVar_0x8005 = cost; +} + +bool8 IsThereMonInRoute5Daycare(void) +{ + if (GetBoxMonData(&gSaveBlock1Ptr->route5DayCareMon.mon, MON_DATA_SPECIES) != SPECIES_NONE) + return TRUE; + + return FALSE; +} + +u8 GetNumLevelsGainedForRoute5DaycareMon(void) +{ + return GetNumLevelsGainedForDaycareMon(&gSaveBlock1Ptr->route5DayCareMon); +} + +u16 TakePokemonFromRoute5Daycare(void) +{ + return TakeSelectedPokemonFromDaycare(&gSaveBlock1Ptr->route5DayCareMon); +} + +static void CreatedHatchedMon(struct Pokemon *egg, struct Pokemon *temp) +{ + u16 species; + u32 personality, pokerus; + u8 i, friendship, language, gameMet, markings, obedience; + u16 moves[4]; + u32 ivs[NUM_STATS]; + + + species = GetMonData(egg, MON_DATA_SPECIES); + + for (i = 0; i < 4; i++) + { + moves[i] = GetMonData(egg, MON_DATA_MOVE1 + i); + } + + personality = GetMonData(egg, MON_DATA_PERSONALITY); + + for (i = 0; i < NUM_STATS; i++) + { + ivs[i] = GetMonData(egg, MON_DATA_HP_IV + i); + } + +// language = GetMonData(egg, MON_DATA_LANGUAGE); + gameMet = GetMonData(egg, MON_DATA_MET_GAME); + markings = GetMonData(egg, MON_DATA_MARKINGS); + pokerus = GetMonData(egg, MON_DATA_POKERUS); + obedience = GetMonData(egg, MON_DATA_OBEDIENCE); + + CreateMon(temp, species, EGG_HATCH_LEVEL, 32, TRUE, personality, 0, 0); + + for (i = 0; i < 4; i++) + { + SetMonData(temp, MON_DATA_MOVE1 + i, &moves[i]); + } + + for (i = 0; i < NUM_STATS; i++) + { + SetMonData(temp, MON_DATA_HP_IV + i, &ivs[i]); + } + + language = GAME_LANGUAGE; + SetMonData(temp, MON_DATA_LANGUAGE, &language); + SetMonData(temp, MON_DATA_MET_GAME, &gameMet); + SetMonData(temp, MON_DATA_MARKINGS, &markings); + + friendship = 120; + SetMonData(temp, MON_DATA_FRIENDSHIP, &friendship); + SetMonData(temp, MON_DATA_POKERUS, &pokerus); + SetMonData(temp, MON_DATA_OBEDIENCE, &obedience); + + *egg = *temp; +} + +static void AddHatchedMonToParty(u8 id) +{ + u8 isEgg = 0x46; // ? + u16 pokeNum; + u8 name[12]; + u16 ball; + u16 caughtLvl; + u8 mapNameID; + struct Pokemon* mon = &gPlayerParty[id]; + + CreatedHatchedMon(mon, &gEnemyParty[0]); + SetMonData(mon, MON_DATA_IS_EGG, &isEgg); + + pokeNum = GetMonData(mon, MON_DATA_SPECIES); + GetSpeciesName(name, pokeNum); + SetMonData(mon, MON_DATA_NICKNAME, name); + + pokeNum = SpeciesToNationalPokedexNum(pokeNum); + GetSetPokedexFlag(pokeNum, FLAG_SET_SEEN); + GetSetPokedexFlag(pokeNum, FLAG_SET_CAUGHT); + + GetMonNick(mon, gStringVar1); + + ball = ITEM_POKE_BALL; + SetMonData(mon, MON_DATA_POKEBALL, &ball); + + caughtLvl = 0; + SetMonData(mon, MON_DATA_MET_LEVEL, &caughtLvl); + + mapNameID = GetCurrentRegionMapSectionId(); + SetMonData(mon, MON_DATA_MET_LOCATION, &mapNameID); + + MonRestorePP(mon); + CalculateMonStats(mon); +} + +void ScriptHatchMon(void) +{ + AddHatchedMonToParty(gSpecialVar_0x8004); +} + +static bool8 sub_8046E34(struct DayCare *daycare, u8 daycareId) +{ + u8 nick[0x20]; + struct DaycareMon *daycareMon = &daycare->mons[daycareId]; + + GetBoxMonNick(&daycareMon->mon, nick); + if (daycareMon->mail.message.itemId != 0 + && (StringCompare(nick, daycareMon->mail.monName) != 0 + || StringCompare(gSaveBlock2Ptr->playerName, daycareMon->mail.OT_name) != 0)) + { + StringCopy(gStringVar1, nick); + StringCopy(gStringVar2, daycareMon->mail.OT_name); + StringCopy(gStringVar3, daycareMon->mail.monName); + return TRUE; + } + return FALSE; +} + +bool8 sub_8046EAC(void) +{ + return sub_8046E34(&gSaveBlock1Ptr->daycare, gSpecialVar_0x8004); +} + +extern const struct CompressedSpriteSheet gMonFrontPicTable[]; + +static u8 EggHatchCreateMonSprite(u8 a0, u8 switchID, u8 pokeID, u16* speciesLoc) +{ + u8 r4 = 0; + u8 spriteID = 0; // r7 + struct Pokemon* mon = NULL; // r5 + + if (a0 == 0) + { + mon = &gPlayerParty[pokeID]; + r4 = 1; + } + if (a0 == 1) + { + mon = &gPlayerParty[pokeID]; + r4 = 3; + } + switch (switchID) + { + case 0: + { + u16 species = GetMonData(mon, MON_DATA_SPECIES); + u32 pid = GetMonData(mon, MON_DATA_PERSONALITY); + sub_800ECC4(&gMonFrontPicTable[species], gMonSpritesGfxPtr->sprites[(a0 * 2) + 1], species, pid); + LoadCompressedObjectPalette(GetMonSpritePalStruct(mon)); + *speciesLoc = species; + } + break; + case 1: + SetMultiuseSpriteTemplateToPokemon(GetMonSpritePalStruct(mon)->tag, r4); + spriteID = CreateSprite(&gMultiuseSpriteTemplate, 120, 70, 6); + gSprites[spriteID].invisible = TRUE; + gSprites[spriteID].callback = SpriteCallbackDummy; + break; + } + return spriteID; +} + +static void VBlankCB_EggHatch(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +void EggHatch(void) +{ + ScriptContext2_Enable(); + CreateTask(Task_EggHatch, 10); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, 0); + sub_812B478(); +} + +static void Task_EggHatch(u8 taskID) +{ + if (!gPaletteFade.active) + { + CleanupOverworldWindowsAndTilemaps(); + SetMainCallback2(CB2_EggHatch_0); + gFieldCallback = FieldCallback_ReturnToEventScript2; + DestroyTask(taskID); + } +} + +static void CB2_EggHatch_0(void) +{ + switch (gMain.state) + { + case 0: + SetGpuReg(REG_OFFSET_DISPCNT, 0); + + sEggHatchData = Alloc(sizeof(struct EggHatchData)); + AllocateMonSpritesGfx(); + sEggHatchData->eggPartyID = gSpecialVar_0x8004; + sEggHatchData->eggShardVelocityID = 0; + + SetVBlankCallback(VBlankCB_EggHatch); + gSpecialVar_0x8005 = GetCurrentMapMusic(); + + reset_temp_tile_data_buffers(); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBgTemplates_EggHatch, ARRAY_COUNT(sBgTemplates_EggHatch)); + + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(0, 0, 0); + ChangeBgY(0, 0, 0); + + SetBgAttribute(1, 7, 2); + SetBgTilemapBuffer(1, Alloc(0x1000)); + SetBgTilemapBuffer(0, Alloc(0x2000)); + + DeactivateAllTextPrinters(); + ResetPaletteFade(); + FreeAllSpritePalettes(); + ResetSpriteData(); + ResetTasks(); + ScanlineEffect_Stop(); + m4aSoundVSyncOn(); + gMain.state++; + break; + case 1: + InitWindows(sWinTemplates_EggHatch); + sEggHatchData->windowId = 0; + gMain.state++; + break; + case 2: + DecompressAndLoadBgGfxUsingHeap(0, gBattleTextboxTiles, 0, 0, 0); + CopyToBgTilemapBuffer(0, gFile_graphics_interface_menu_map_tilemap, 0, 0); + LoadCompressedPalette(gBattleTextboxPalette, 0, 0x20); + gMain.state++; + break; + case 3: + LoadSpriteSheet(&sEggHatch_Sheet); + LoadSpriteSheet(&sEggShards_Sheet); + LoadSpritePalette(&sEgg_SpritePalette); + gMain.state++; + break; + case 4: + CopyBgTilemapBufferToVram(0); + AddHatchedMonToParty(sEggHatchData->eggPartyID); + gMain.state++; + break; + case 5: + EggHatchCreateMonSprite(0, 0, sEggHatchData->eggPartyID, &sEggHatchData->species); + gMain.state++; + break; + case 6: + sEggHatchData->pokeSpriteID = EggHatchCreateMonSprite(0, 1, sEggHatchData->eggPartyID, &sEggHatchData->species); + gMain.state++; + break; + case 7: + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + LoadPalette(gTradeGba2_Pal, 0x10, 0xA0); + LoadBgTiles(1, gTradeGba_Gfx, 0x1420, 0); + CopyToBgTilemapBuffer(1, gUnknown_08331F60, 0x1000, 0); + CopyBgTilemapBufferToVram(1); + gMain.state++; + break; + case 8: + SetMainCallback2(CB2_EggHatch_1); + sEggHatchData->CB2_state = 0; + break; + } + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +static void EggHatchSetMonNickname(void) +{ + SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar3); + FreeMonSpritesGfx(); + Free(sEggHatchData); + sub_812B484(); + SetMainCallback2(CB2_ReturnToField); +} + +static void Task_EggHatchPlayBGM(u8 taskID) +{ + if (gTasks[taskID].data[0] == 0) + { + StopMapMusic(); + } + if (gTasks[taskID].data[0] == 1) + PlayBGM(MUS_ME_SHINKA); + if (gTasks[taskID].data[0] > 60) + { + PlayBGM(MUS_SHINKA); + DestroyTask(taskID); + // UB: task is destroyed, yet the value is incremented + } + gTasks[taskID].data[0]++; +} + +static void CB2_EggHatch_1(void) +{ + u16 species; + u8 gender; + u32 personality; + + switch (sEggHatchData->CB2_state) + { + case 0: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0x10, 0, RGB_BLACK); + sEggHatchData->eggSpriteID = CreateSprite(&sSpriteTemplate_EggHatch, 120, 75, 5); + ShowBg(0); + ShowBg(1); + sEggHatchData->CB2_state++; + CreateTask(Task_EggHatchPlayBGM, 5); + break; + case 1: + if (!gPaletteFade.active) + { + FillWindowPixelBuffer(sEggHatchData->windowId, 0x00); + sEggHatchData->CB2_PalCounter = 0; + sEggHatchData->CB2_state++; + } + break; + case 2: + if (++sEggHatchData->CB2_PalCounter > 30) + { + sEggHatchData->CB2_state++; + gSprites[sEggHatchData->eggSpriteID].callback = SpriteCB_Egg_0; + } + break; + case 3: + if (gSprites[sEggHatchData->eggSpriteID].callback == SpriteCallbackDummy) + { + PlayCry1(sEggHatchData->species, 0); + sEggHatchData->CB2_state++; + } + break; + case 4: + if (IsCryFinished()) + { + sEggHatchData->CB2_state++; + } + break; + case 5: + GetMonNick(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar1); + StringExpandPlaceholders(gStringVar4, gText_HatchedFromEgg); + EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 3, 0xFF); + PlayFanfare(MUS_FANFA5); + sEggHatchData->CB2_state++; + PutWindowTilemap(sEggHatchData->windowId); + CopyWindowToVram(sEggHatchData->windowId, 3); + break; + case 6: + if (IsFanfareTaskInactive()) + sEggHatchData->CB2_state++; + break; + case 7: + if (IsFanfareTaskInactive()) + sEggHatchData->CB2_state++; + break; + case 8: + GetMonNick(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar1); + StringExpandPlaceholders(gStringVar4, gText_NickHatchPrompt); + EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 2, 1); + sEggHatchData->CB2_state++; + break; + case 9: + if (!IsTextPrinterActive(sEggHatchData->windowId)) + { + LoadUserWindowBorderGfx(sEggHatchData->windowId, 0x140, 0xE0); + CreateYesNoMenu(&sYesNoWinTemplate, 3, 0, 2, 0x140, 0xE, 0); + sEggHatchData->CB2_state++; + } + break; + case 10: + switch (Menu_ProcessInputNoWrapClearOnChoose()) + { + case 0: + GetMonNick(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar3); + species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); + gender = GetMonGender(&gPlayerParty[sEggHatchData->eggPartyID]); + personality = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_PERSONALITY, 0); + DoNamingScreen(3, gStringVar3, species, gender, personality, EggHatchSetMonNickname); + break; + case 1: + case -1: + sEggHatchData->CB2_state++; + } + break; + case 11: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK); + sEggHatchData->CB2_state++; + break; + case 12: + if (!gPaletteFade.active) + { + RemoveWindow(sEggHatchData->windowId); + UnsetBgTilemapBuffer(0); + UnsetBgTilemapBuffer(1); + Free(sEggHatchData); + SetMainCallback2(CB2_ReturnToField); + sub_812B484(); + } + break; + } + + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +static void SpriteCB_Egg_0(struct Sprite* sprite) +{ + if (++sprite->data[0] > 20) + { + sprite->callback = SpriteCB_Egg_1; + sprite->data[0] = 0; + } + else + { + sprite->data[1] = (sprite->data[1] + 20) & 0xFF; + sprite->pos2.x = Sin(sprite->data[1], 1); + if (sprite->data[0] == 15) + { + PlaySE(SE_BOWA); + StartSpriteAnim(sprite, 1); + CreateRandomEggShardSprite(); + } + } +} + +static void SpriteCB_Egg_1(struct Sprite* sprite) +{ + if (++sprite->data[2] > 30) + { + if (++sprite->data[0] > 20) + { + sprite->callback = SpriteCB_Egg_2; + sprite->data[0] = 0; + sprite->data[2] = 0; + } + else + { + sprite->data[1] = (sprite->data[1] + 20) & 0xFF; + sprite->pos2.x = Sin(sprite->data[1], 2); + if (sprite->data[0] == 15) + { + PlaySE(SE_BOWA); + StartSpriteAnim(sprite, 2); + } + } + } +} + +struct UnkStruct_82349CC +{ + u8 field_0; + u8 field_1; + u8 field_2; + u8 field_3; +}; + +extern const struct UnkStruct_82349CC gUnknown_82349CC[NUM_SPECIES]; + +static void SpriteCB_Egg_2(struct Sprite* sprite) +{ + if (++sprite->data[2] > 30) + { + if (++sprite->data[0] > 38) + { + u16 species; + + sprite->callback = SpriteCB_Egg_3; + sprite->data[0] = 0; + species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); + gSprites[sEggHatchData->pokeSpriteID].pos2.x = 0; + gSprites[sEggHatchData->pokeSpriteID].pos2.y = gUnknown_82349CC[species].field_1; + } + else + { + sprite->data[1] = (sprite->data[1] + 20) & 0xFF; + sprite->pos2.x = Sin(sprite->data[1], 2); + if (sprite->data[0] == 15) + { + PlaySE(SE_BOWA); + StartSpriteAnim(sprite, 2); + CreateRandomEggShardSprite(); + CreateRandomEggShardSprite(); + } + if (sprite->data[0] == 30) + PlaySE(SE_BOWA); + } + } +} + +static void SpriteCB_Egg_3(struct Sprite* sprite) +{ + if (++sprite->data[0] > 50) + { + sprite->callback = SpriteCB_Egg_4; + sprite->data[0] = 0; + } +} + +static void SpriteCB_Egg_4(struct Sprite* sprite) +{ + s16 i; + if (sprite->data[0] == 0) + BeginNormalPaletteFade(0xFFFFFFFF, -1, 0, 0x10, 0xFFFF); + if (sprite->data[0] < 4u) + { + for (i = 0; i <= 3; i++) + CreateRandomEggShardSprite(); + } + sprite->data[0]++; + if (!gPaletteFade.active) + { + PlaySE(SE_JIHANKI); + sprite->invisible = TRUE; + sprite->callback = SpriteCB_Egg_5; + sprite->data[0] = 0; + } +} + +static void SpriteCB_Egg_5(struct Sprite* sprite) +{ + if (sprite->data[0] == 0) + { + gSprites[sEggHatchData->pokeSpriteID].invisible = FALSE; + StartSpriteAffineAnim(&gSprites[sEggHatchData->pokeSpriteID], 1); + } + if (sprite->data[0] == 8) + BeginNormalPaletteFade(0xFFFFFFFF, -1, 0x10, 0, 0xFFFF); + if (sprite->data[0] <= 9) + gSprites[sEggHatchData->pokeSpriteID].pos1.y -= 1; + if (sprite->data[0] > 40) + sprite->callback = SpriteCallbackDummy; + sprite->data[0]++; +} + +static void SpriteCB_EggShard(struct Sprite* sprite) +{ + sprite->data[4] += sprite->data[1]; + sprite->data[5] += sprite->data[2]; + + sprite->pos2.x = sprite->data[4] / 256; + sprite->pos2.y = sprite->data[5] / 256; + + sprite->data[2] += sprite->data[3]; + + if (sprite->pos1.y + sprite->pos2.y > sprite->pos1.y + 20 && sprite->data[2] > 0) + DestroySprite(sprite); +} + +static void CreateRandomEggShardSprite(void) +{ + u16 spriteAnimIndex; + + s16 velocity1 = sEggShardVelocities[sEggHatchData->eggShardVelocityID][0]; + s16 velocity2 = sEggShardVelocities[sEggHatchData->eggShardVelocityID][1]; + sEggHatchData->eggShardVelocityID++; + spriteAnimIndex = Random() % 4; + CreateEggShardSprite(120, 60, velocity1, velocity2, 100, spriteAnimIndex); +} + +static void CreateEggShardSprite(u8 x, u8 y, s16 data1, s16 data2, s16 data3, u8 spriteAnimIndex) +{ + u8 spriteID = CreateSprite(&sSpriteTemplate_EggShard, x, y, 4); + gSprites[spriteID].data[1] = data1; + gSprites[spriteID].data[2] = data2; + gSprites[spriteID].data[3] = data3; + StartSpriteAnim(&gSprites[spriteID], spriteAnimIndex); +} + +static void EggHatchPrintMessage(u8 windowId, u8* string, u8 x, u8 y, u8 speed) +{ + FillWindowPixelBuffer(windowId, 0xFF); + sEggHatchData->textColor.fgColor = 0; + sEggHatchData->textColor.bgColor = 5; + sEggHatchData->textColor.shadowColor = 6; + AddTextPrinterParameterized4(windowId, 3, x, y, 1, 1, &sEggHatchData->textColor, speed, string); +} diff --git a/src/dodrio_berry_picking_2.c b/src/dodrio_berry_picking_2.c new file mode 100644 index 000000000..fc6aa14c6 --- /dev/null +++ b/src/dodrio_berry_picking_2.c @@ -0,0 +1,23 @@ +#include "global.h" +#include "link.h" +#include "link_rfu.h" + +void sub_815A5BC(s32 a0) +{ + struct Padded_U8 data[2]; + data[0].value = 1; + data[1].value = a0; + sub_80F9E2C(data); +} + +u8 sub_815A5E8(s32 a0) +{ + u8 * r1; + if ((gRecvCmds[0][0] & 0xFF00) != 0x2F00) + return 0; + r1 = (u8 *)&gRecvCmds[a0][1]; + if (r1[0] == 1) + return r1[4]; + return 0; +} + diff --git a/src/egg_hatch.c b/src/egg_hatch.c new file mode 100644 index 000000000..5e27a6482 --- /dev/null +++ b/src/egg_hatch.c @@ -0,0 +1,878 @@ +#include "global.h" +#include "pokemon.h" +#include "egg_hatch.h" +#include "pokedex.h" +#include "constants/items.h" +#include "script.h" +#include "decompress.h" +#include "task.h" +#include "palette.h" +#include "main.h" +#include "event_data.h" +#include "sound.h" +#include "constants/songs.h" +#include "text.h" +#include "text_window.h" +#include "string_util.h" +#include "menu.h" +#include "trig.h" +#include "random.h" +#include "malloc.h" +#include "dma3.h" +#include "gpu_regs.h" +#include "bg.h" +#include "m4a.h" +#include "window.h" +#include "graphics.h" +#include "constants/abilities.h" +#include "constants/species.h" +#include "daycare.h" +#include "overworld.h" +#include "scanline_effect.h" +#include "field_weather.h" +#include "international_string_util.h" +#include "naming_screen.h" +#include "pokemon_storage_system.h" +#include "field_screen_effect.h" +#include "battle.h" // to get rid of later +#include "help_system.h" +#include "field_fadetransition.h" +#include "new_menu_helpers.h" + +struct EggHatchData +{ + u8 eggSpriteID; + u8 pokeSpriteID; + u8 CB2_state; + u8 CB2_PalCounter; + u8 eggPartyID; + u8 unused_5; + u8 unused_6; + u8 eggShardVelocityID; + u8 windowId; + u8 unused_9; + u8 unused_A; + u16 species; + struct TextColor textColor; +}; + +extern const u32 gUnknown_08331F60[]; // tilemap gameboy circle +extern const u8 gText_HatchedFromEgg[]; +extern const u8 gText_NickHatchPrompt[]; + +static void Task_EggHatch(u8 taskID); +static void CB2_EggHatch_0(void); +static void CB2_EggHatch_1(void); +static void SpriteCB_Egg_0(struct Sprite* sprite); +static void SpriteCB_Egg_1(struct Sprite* sprite); +static void SpriteCB_Egg_2(struct Sprite* sprite); +static void SpriteCB_Egg_3(struct Sprite* sprite); +static void SpriteCB_Egg_4(struct Sprite* sprite); +static void SpriteCB_Egg_5(struct Sprite* sprite); +static void SpriteCB_EggShard(struct Sprite* sprite); +static void EggHatchPrintMessage(u8 windowId, u8* string, u8 x, u8 y, u8 speed); +static void CreateRandomEggShardSprite(void); +static void CreateEggShardSprite(u8 x, u8 y, s16 data1, s16 data2, s16 data3, u8 spriteAnimIndex); + +// IWRAM bss +static IWRAM_DATA struct EggHatchData *sEggHatchData; + +// rom data +static const u16 sEggPalette[] = INCBIN_U16("graphics/pokemon/egg/normal.gbapal"); +static const u8 sEggHatchTiles[] = INCBIN_U8("graphics/misc/egg_hatch.4bpp"); +static const u8 sEggShardTiles[] = INCBIN_U8("graphics/misc/egg_shard.4bpp"); + +static const struct OamData sOamData_EggHatch = + { + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = SPRITE_SHAPE(32x32), + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(32x32), + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, + }; + +static const union AnimCmd sSpriteAnim_EggHatch0[] = + { + ANIMCMD_FRAME(0, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggHatch1[] = + { + ANIMCMD_FRAME(16, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggHatch2[] = + { + ANIMCMD_FRAME(32, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggHatch3[] = + { + ANIMCMD_FRAME(48, 5), + ANIMCMD_END + }; + +static const union AnimCmd *const sSpriteAnimTable_EggHatch[] = + { + sSpriteAnim_EggHatch0, + sSpriteAnim_EggHatch1, + sSpriteAnim_EggHatch2, + sSpriteAnim_EggHatch3, + }; + +static const struct SpriteSheet sEggHatch_Sheet = + { + .data = sEggHatchTiles, + .size = 2048, + .tag = 12345, + }; + +static const struct SpriteSheet sEggShards_Sheet = + { + .data = sEggShardTiles, + .size = 128, + .tag = 23456, + }; + +static const struct SpritePalette sEgg_SpritePalette = + { + .data = sEggPalette, + .tag = 54321 + }; + +static const struct SpriteTemplate sSpriteTemplate_EggHatch = + { + .tileTag = 12345, + .paletteTag = 54321, + .oam = &sOamData_EggHatch, + .anims = sSpriteAnimTable_EggHatch, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy + }; + +static const struct OamData sOamData_EggShard = + { + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = SPRITE_SHAPE(8x8), + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(8x8), + .tileNum = 0, + .priority = 2, + .paletteNum = 0, + .affineParam = 0, + }; + +static const union AnimCmd sSpriteAnim_EggShard0[] = + { + ANIMCMD_FRAME(0, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggShard1[] = + { + ANIMCMD_FRAME(1, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggShard2[] = + { + ANIMCMD_FRAME(2, 5), + ANIMCMD_END + }; + +static const union AnimCmd sSpriteAnim_EggShard3[] = + { + ANIMCMD_FRAME(3, 5), + ANIMCMD_END + }; + +static const union AnimCmd *const sSpriteAnimTable_EggShard[] = + { + sSpriteAnim_EggShard0, + sSpriteAnim_EggShard1, + sSpriteAnim_EggShard2, + sSpriteAnim_EggShard3, + }; + +static const struct SpriteTemplate sSpriteTemplate_EggShard = + { + .tileTag = 23456, + .paletteTag = 54321, + .oam = &sOamData_EggShard, + .anims = sSpriteAnimTable_EggShard, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_EggShard + }; + +static const struct BgTemplate sBgTemplates_EggHatch[2] = + { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 24, + .screenSize = 3, + .paletteMode = 0, + .priority = 0, + .baseTile = 0 + }, + + { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 8, + .screenSize = 1, + .paletteMode = 0, + .priority = 2, + .baseTile = 0 + }, + }; + +static const struct WindowTemplate sWinTemplates_EggHatch[2] = + { + { + .bg = 0, + .tilemapLeft = 2, + .tilemapTop = 15, + .width = 26, + .height = 4, + .paletteNum = 0, + .baseBlock = 64 + }, + DUMMY_WIN_TEMPLATE + }; + +static const struct WindowTemplate sYesNoWinTemplate = + { + .bg = 0, + .tilemapLeft = 21, + .tilemapTop = 9, + .width = 5, + .height = 4, + .paletteNum = 15, + .baseBlock = 424 + }; + +static const s16 sEggShardVelocities[][2] = + { + {Q_8_8(-1.5), Q_8_8(-3.75)}, + {Q_8_8(-5), Q_8_8(-3)}, + {Q_8_8(3.5), Q_8_8(-3)}, + {Q_8_8(-4), Q_8_8(-3.75)}, + {Q_8_8(2), Q_8_8(-1.5)}, + {Q_8_8(-0.5), Q_8_8(-6.75)}, + {Q_8_8(5), Q_8_8(-2.25)}, + {Q_8_8(-1.5), Q_8_8(-3.75)}, + {Q_8_8(4.5), Q_8_8(-1.5)}, + {Q_8_8(-1), Q_8_8(-6.75)}, + {Q_8_8(4), Q_8_8(-2.25)}, + {Q_8_8(-3.5), Q_8_8(-3.75)}, + {Q_8_8(1), Q_8_8(-1.5)}, + {Q_8_8(-3.515625), Q_8_8(-6.75)}, + {Q_8_8(4.5), Q_8_8(-2.25)}, + {Q_8_8(-0.5), Q_8_8(-7.5)}, + {Q_8_8(1), Q_8_8(-4.5)}, + {Q_8_8(-2.5), Q_8_8(-2.25)}, + {Q_8_8(2.5), Q_8_8(-7.5)}, + }; + +// code + +static void CreatedHatchedMon(struct Pokemon *egg, struct Pokemon *temp) +{ + u16 species; + u32 personality, pokerus; + u8 i, friendship, language, gameMet, markings, obedience; + u16 moves[4]; + u32 ivs[NUM_STATS]; + + + species = GetMonData(egg, MON_DATA_SPECIES); + + for (i = 0; i < 4; i++) + { + moves[i] = GetMonData(egg, MON_DATA_MOVE1 + i); + } + + personality = GetMonData(egg, MON_DATA_PERSONALITY); + + for (i = 0; i < NUM_STATS; i++) + { + ivs[i] = GetMonData(egg, MON_DATA_HP_IV + i); + } + +// language = GetMonData(egg, MON_DATA_LANGUAGE); + gameMet = GetMonData(egg, MON_DATA_MET_GAME); + markings = GetMonData(egg, MON_DATA_MARKINGS); + pokerus = GetMonData(egg, MON_DATA_POKERUS); + obedience = GetMonData(egg, MON_DATA_OBEDIENCE); + + CreateMon(temp, species, EGG_HATCH_LEVEL, 32, TRUE, personality, 0, 0); + + for (i = 0; i < 4; i++) + { + SetMonData(temp, MON_DATA_MOVE1 + i, &moves[i]); + } + + for (i = 0; i < NUM_STATS; i++) + { + SetMonData(temp, MON_DATA_HP_IV + i, &ivs[i]); + } + + language = GAME_LANGUAGE; + SetMonData(temp, MON_DATA_LANGUAGE, &language); + SetMonData(temp, MON_DATA_MET_GAME, &gameMet); + SetMonData(temp, MON_DATA_MARKINGS, &markings); + + friendship = 120; + SetMonData(temp, MON_DATA_FRIENDSHIP, &friendship); + SetMonData(temp, MON_DATA_POKERUS, &pokerus); + SetMonData(temp, MON_DATA_OBEDIENCE, &obedience); + + *egg = *temp; +} + +static void AddHatchedMonToParty(u8 id) +{ + u8 isEgg = 0x46; // ? + u16 pokeNum; + u8 name[12]; + u16 ball; + u16 caughtLvl; + u8 mapNameID; + struct Pokemon* mon = &gPlayerParty[id]; + + CreatedHatchedMon(mon, &gEnemyParty[0]); + SetMonData(mon, MON_DATA_IS_EGG, &isEgg); + + pokeNum = GetMonData(mon, MON_DATA_SPECIES); + GetSpeciesName(name, pokeNum); + SetMonData(mon, MON_DATA_NICKNAME, name); + + pokeNum = SpeciesToNationalPokedexNum(pokeNum); + GetSetPokedexFlag(pokeNum, FLAG_SET_SEEN); + GetSetPokedexFlag(pokeNum, FLAG_SET_CAUGHT); + + GetMonNick(mon, gStringVar1); + + ball = ITEM_POKE_BALL; + SetMonData(mon, MON_DATA_POKEBALL, &ball); + + caughtLvl = 0; + SetMonData(mon, MON_DATA_MET_LEVEL, &caughtLvl); + + mapNameID = GetCurrentRegionMapSectionId(); + SetMonData(mon, MON_DATA_MET_LOCATION, &mapNameID); + + MonRestorePP(mon); + CalculateMonStats(mon); +} + +void ScriptHatchMon(void) +{ + AddHatchedMonToParty(gSpecialVar_0x8004); +} + +static bool8 sub_8046E34(struct DayCare *daycare, u8 daycareId) +{ + u8 nick[0x20]; + struct DaycareMon *daycareMon = &daycare->mons[daycareId]; + + GetBoxMonNick(&daycareMon->mon, nick); + if (daycareMon->mail.message.itemId != 0 + && (StringCompare(nick, daycareMon->mail.monName) != 0 + || StringCompare(gSaveBlock2Ptr->playerName, daycareMon->mail.OT_name) != 0)) + { + StringCopy(gStringVar1, nick); + StringCopy(gStringVar2, daycareMon->mail.OT_name); + StringCopy(gStringVar3, daycareMon->mail.monName); + return TRUE; + } + return FALSE; +} + +bool8 sub_8046EAC(void) +{ + return sub_8046E34(&gSaveBlock1Ptr->daycare, gSpecialVar_0x8004); +} + +extern const struct CompressedSpriteSheet gMonFrontPicTable[]; + +static u8 EggHatchCreateMonSprite(u8 a0, u8 switchID, u8 pokeID, u16* speciesLoc) +{ + u8 r4 = 0; + u8 spriteID = 0; // r7 + struct Pokemon* mon = NULL; // r5 + + if (a0 == 0) + { + mon = &gPlayerParty[pokeID]; + r4 = 1; + } + if (a0 == 1) + { + mon = &gPlayerParty[pokeID]; + r4 = 3; + } + switch (switchID) + { + case 0: + { + u16 species = GetMonData(mon, MON_DATA_SPECIES); + u32 pid = GetMonData(mon, MON_DATA_PERSONALITY); + sub_800ECC4(&gMonFrontPicTable[species], gMonSpritesGfxPtr->sprites[(a0 * 2) + 1], species, pid); + LoadCompressedObjectPalette(GetMonSpritePalStruct(mon)); + *speciesLoc = species; + } + break; + case 1: + SetMultiuseSpriteTemplateToPokemon(GetMonSpritePalStruct(mon)->tag, r4); + spriteID = CreateSprite(&gMultiuseSpriteTemplate, 120, 70, 6); + gSprites[spriteID].invisible = TRUE; + gSprites[spriteID].callback = SpriteCallbackDummy; + break; + } + return spriteID; +} + +static void VBlankCB_EggHatch(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +void EggHatch(void) +{ + ScriptContext2_Enable(); + CreateTask(Task_EggHatch, 10); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, 0); + sub_812B478(); +} + +static void Task_EggHatch(u8 taskID) +{ + if (!gPaletteFade.active) + { + CleanupOverworldWindowsAndTilemaps(); + SetMainCallback2(CB2_EggHatch_0); + gFieldCallback = FieldCallback_ReturnToEventScript2; + DestroyTask(taskID); + } +} + +static void CB2_EggHatch_0(void) +{ + switch (gMain.state) + { + case 0: + SetGpuReg(REG_OFFSET_DISPCNT, 0); + + sEggHatchData = Alloc(sizeof(struct EggHatchData)); + AllocateMonSpritesGfx(); + sEggHatchData->eggPartyID = gSpecialVar_0x8004; + sEggHatchData->eggShardVelocityID = 0; + + SetVBlankCallback(VBlankCB_EggHatch); + gSpecialVar_0x8005 = GetCurrentMapMusic(); + + reset_temp_tile_data_buffers(); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBgTemplates_EggHatch, ARRAY_COUNT(sBgTemplates_EggHatch)); + + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(0, 0, 0); + ChangeBgY(0, 0, 0); + + SetBgAttribute(1, 7, 2); + SetBgTilemapBuffer(1, Alloc(0x1000)); + SetBgTilemapBuffer(0, Alloc(0x2000)); + + DeactivateAllTextPrinters(); + ResetPaletteFade(); + FreeAllSpritePalettes(); + ResetSpriteData(); + ResetTasks(); + ScanlineEffect_Stop(); + m4aSoundVSyncOn(); + gMain.state++; + break; + case 1: + InitWindows(sWinTemplates_EggHatch); + sEggHatchData->windowId = 0; + gMain.state++; + break; + case 2: + DecompressAndLoadBgGfxUsingHeap(0, gBattleTextboxTiles, 0, 0, 0); + CopyToBgTilemapBuffer(0, gFile_graphics_interface_menu_map_tilemap, 0, 0); + LoadCompressedPalette(gBattleTextboxPalette, 0, 0x20); + gMain.state++; + break; + case 3: + LoadSpriteSheet(&sEggHatch_Sheet); + LoadSpriteSheet(&sEggShards_Sheet); + LoadSpritePalette(&sEgg_SpritePalette); + gMain.state++; + break; + case 4: + CopyBgTilemapBufferToVram(0); + AddHatchedMonToParty(sEggHatchData->eggPartyID); + gMain.state++; + break; + case 5: + EggHatchCreateMonSprite(0, 0, sEggHatchData->eggPartyID, &sEggHatchData->species); + gMain.state++; + break; + case 6: + sEggHatchData->pokeSpriteID = EggHatchCreateMonSprite(0, 1, sEggHatchData->eggPartyID, &sEggHatchData->species); + gMain.state++; + break; + case 7: + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + LoadPalette(gTradeGba2_Pal, 0x10, 0xA0); + LoadBgTiles(1, gTradeGba_Gfx, 0x1420, 0); + CopyToBgTilemapBuffer(1, gUnknown_08331F60, 0x1000, 0); + CopyBgTilemapBufferToVram(1); + gMain.state++; + break; + case 8: + SetMainCallback2(CB2_EggHatch_1); + sEggHatchData->CB2_state = 0; + break; + } + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +static void EggHatchSetMonNickname(void) +{ + SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar3); + FreeMonSpritesGfx(); + Free(sEggHatchData); + sub_812B484(); + SetMainCallback2(CB2_ReturnToField); +} + +static void Task_EggHatchPlayBGM(u8 taskID) +{ + if (gTasks[taskID].data[0] == 0) + { + StopMapMusic(); + } + if (gTasks[taskID].data[0] == 1) + PlayBGM(MUS_ME_SHINKA); + if (gTasks[taskID].data[0] > 60) + { + PlayBGM(MUS_SHINKA); + DestroyTask(taskID); + // UB: task is destroyed, yet the value is incremented + } + gTasks[taskID].data[0]++; +} + +static void CB2_EggHatch_1(void) +{ + u16 species; + u8 gender; + u32 personality; + + switch (sEggHatchData->CB2_state) + { + case 0: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0x10, 0, RGB_BLACK); + sEggHatchData->eggSpriteID = CreateSprite(&sSpriteTemplate_EggHatch, 120, 75, 5); + ShowBg(0); + ShowBg(1); + sEggHatchData->CB2_state++; + CreateTask(Task_EggHatchPlayBGM, 5); + break; + case 1: + if (!gPaletteFade.active) + { + FillWindowPixelBuffer(sEggHatchData->windowId, 0x00); + sEggHatchData->CB2_PalCounter = 0; + sEggHatchData->CB2_state++; + } + break; + case 2: + if (++sEggHatchData->CB2_PalCounter > 30) + { + sEggHatchData->CB2_state++; + gSprites[sEggHatchData->eggSpriteID].callback = SpriteCB_Egg_0; + } + break; + case 3: + if (gSprites[sEggHatchData->eggSpriteID].callback == SpriteCallbackDummy) + { + PlayCry1(sEggHatchData->species, 0); + sEggHatchData->CB2_state++; + } + break; + case 4: + if (IsCryFinished()) + { + sEggHatchData->CB2_state++; + } + break; + case 5: + GetMonNick(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar1); + StringExpandPlaceholders(gStringVar4, gText_HatchedFromEgg); + EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 3, 0xFF); + PlayFanfare(MUS_FANFA5); + sEggHatchData->CB2_state++; + PutWindowTilemap(sEggHatchData->windowId); + CopyWindowToVram(sEggHatchData->windowId, 3); + break; + case 6: + if (IsFanfareTaskInactive()) + sEggHatchData->CB2_state++; + break; + case 7: + if (IsFanfareTaskInactive()) + sEggHatchData->CB2_state++; + break; + case 8: + GetMonNick(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar1); + StringExpandPlaceholders(gStringVar4, gText_NickHatchPrompt); + EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 2, 1); + sEggHatchData->CB2_state++; + break; + case 9: + if (!IsTextPrinterActive(sEggHatchData->windowId)) + { + LoadUserWindowBorderGfx(sEggHatchData->windowId, 0x140, 0xE0); + CreateYesNoMenu(&sYesNoWinTemplate, 3, 0, 2, 0x140, 0xE, 0); + sEggHatchData->CB2_state++; + } + break; + case 10: + switch (Menu_ProcessInputNoWrapClearOnChoose()) + { + case 0: + GetMonNick(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar3); + species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); + gender = GetMonGender(&gPlayerParty[sEggHatchData->eggPartyID]); + personality = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_PERSONALITY, 0); + DoNamingScreen(3, gStringVar3, species, gender, personality, EggHatchSetMonNickname); + break; + case 1: + case -1: + sEggHatchData->CB2_state++; + } + break; + case 11: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK); + sEggHatchData->CB2_state++; + break; + case 12: + if (!gPaletteFade.active) + { + RemoveWindow(sEggHatchData->windowId); + UnsetBgTilemapBuffer(0); + UnsetBgTilemapBuffer(1); + Free(sEggHatchData); + SetMainCallback2(CB2_ReturnToField); + sub_812B484(); + } + break; + } + + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +static void SpriteCB_Egg_0(struct Sprite* sprite) +{ + if (++sprite->data[0] > 20) + { + sprite->callback = SpriteCB_Egg_1; + sprite->data[0] = 0; + } + else + { + sprite->data[1] = (sprite->data[1] + 20) & 0xFF; + sprite->pos2.x = Sin(sprite->data[1], 1); + if (sprite->data[0] == 15) + { + PlaySE(SE_BOWA); + StartSpriteAnim(sprite, 1); + CreateRandomEggShardSprite(); + } + } +} + +static void SpriteCB_Egg_1(struct Sprite* sprite) +{ + if (++sprite->data[2] > 30) + { + if (++sprite->data[0] > 20) + { + sprite->callback = SpriteCB_Egg_2; + sprite->data[0] = 0; + sprite->data[2] = 0; + } + else + { + sprite->data[1] = (sprite->data[1] + 20) & 0xFF; + sprite->pos2.x = Sin(sprite->data[1], 2); + if (sprite->data[0] == 15) + { + PlaySE(SE_BOWA); + StartSpriteAnim(sprite, 2); + } + } + } +} + +struct UnkStruct_82349CC +{ + u8 field_0; + u8 field_1; + u8 field_2; + u8 field_3; +}; + +extern const struct UnkStruct_82349CC gUnknown_82349CC[NUM_SPECIES]; + +static void SpriteCB_Egg_2(struct Sprite* sprite) +{ + if (++sprite->data[2] > 30) + { + if (++sprite->data[0] > 38) + { + u16 species; + + sprite->callback = SpriteCB_Egg_3; + sprite->data[0] = 0; + species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); + gSprites[sEggHatchData->pokeSpriteID].pos2.x = 0; + gSprites[sEggHatchData->pokeSpriteID].pos2.y = gUnknown_82349CC[species].field_1; + } + else + { + sprite->data[1] = (sprite->data[1] + 20) & 0xFF; + sprite->pos2.x = Sin(sprite->data[1], 2); + if (sprite->data[0] == 15) + { + PlaySE(SE_BOWA); + StartSpriteAnim(sprite, 2); + CreateRandomEggShardSprite(); + CreateRandomEggShardSprite(); + } + if (sprite->data[0] == 30) + PlaySE(SE_BOWA); + } + } +} + +static void SpriteCB_Egg_3(struct Sprite* sprite) +{ + if (++sprite->data[0] > 50) + { + sprite->callback = SpriteCB_Egg_4; + sprite->data[0] = 0; + } +} + +static void SpriteCB_Egg_4(struct Sprite* sprite) +{ + s16 i; + if (sprite->data[0] == 0) + BeginNormalPaletteFade(0xFFFFFFFF, -1, 0, 0x10, 0xFFFF); + if (sprite->data[0] < 4u) + { + for (i = 0; i <= 3; i++) + CreateRandomEggShardSprite(); + } + sprite->data[0]++; + if (!gPaletteFade.active) + { + PlaySE(SE_JIHANKI); + sprite->invisible = TRUE; + sprite->callback = SpriteCB_Egg_5; + sprite->data[0] = 0; + } +} + +static void SpriteCB_Egg_5(struct Sprite* sprite) +{ + if (sprite->data[0] == 0) + { + gSprites[sEggHatchData->pokeSpriteID].invisible = FALSE; + StartSpriteAffineAnim(&gSprites[sEggHatchData->pokeSpriteID], 1); + } + if (sprite->data[0] == 8) + BeginNormalPaletteFade(0xFFFFFFFF, -1, 0x10, 0, 0xFFFF); + if (sprite->data[0] <= 9) + gSprites[sEggHatchData->pokeSpriteID].pos1.y -= 1; + if (sprite->data[0] > 40) + sprite->callback = SpriteCallbackDummy; + sprite->data[0]++; +} + +static void SpriteCB_EggShard(struct Sprite* sprite) +{ + sprite->data[4] += sprite->data[1]; + sprite->data[5] += sprite->data[2]; + + sprite->pos2.x = sprite->data[4] / 256; + sprite->pos2.y = sprite->data[5] / 256; + + sprite->data[2] += sprite->data[3]; + + if (sprite->pos1.y + sprite->pos2.y > sprite->pos1.y + 20 && sprite->data[2] > 0) + DestroySprite(sprite); +} + +static void CreateRandomEggShardSprite(void) +{ + u16 spriteAnimIndex; + + s16 velocity1 = sEggShardVelocities[sEggHatchData->eggShardVelocityID][0]; + s16 velocity2 = sEggShardVelocities[sEggHatchData->eggShardVelocityID][1]; + sEggHatchData->eggShardVelocityID++; + spriteAnimIndex = Random() % 4; + CreateEggShardSprite(120, 60, velocity1, velocity2, 100, spriteAnimIndex); +} + +static void CreateEggShardSprite(u8 x, u8 y, s16 data1, s16 data2, s16 data3, u8 spriteAnimIndex) +{ + u8 spriteID = CreateSprite(&sSpriteTemplate_EggShard, x, y, 4); + gSprites[spriteID].data[1] = data1; + gSprites[spriteID].data[2] = data2; + gSprites[spriteID].data[3] = data3; + StartSpriteAnim(&gSprites[spriteID], spriteAnimIndex); +} + +static void EggHatchPrintMessage(u8 windowId, u8* string, u8 x, u8 y, u8 speed) +{ + FillWindowPixelBuffer(windowId, 0xFF); + sEggHatchData->textColor.fgColor = 0; + sEggHatchData->textColor.bgColor = 5; + sEggHatchData->textColor.shadowColor = 6; + AddTextPrinterParameterized4(windowId, 3, x, y, 1, 1, &sEggHatchData->textColor, speed, string); +} diff --git a/src/ereader_helpers.c b/src/ereader_helpers.c new file mode 100644 index 000000000..2a9b9ea71 --- /dev/null +++ b/src/ereader_helpers.c @@ -0,0 +1,397 @@ +#include "global.h" +#include "link.h" +#include "unk_815c27c.h" + +enum { + EREADER_XFR_STATE_INIT, + EREADER_XFR_STATE_HANDSHAKE, + EREADER_XFR_STATE_START, + EREADER_XFR_STATE_TRANSFER, +}; + +struct SendRecvMgr +{ + u8 sendOrRecv; + u8 state; + u8 field_02; + u8 field_03; + u8 field_04; + u32 * dataptr; + int cursor; + int size; + u32 checksum; +}; + +static bool16 DetermineSendRecvState(u8); +static void SetUpTransferManager(size_t, const void *, void *); +static void StartTm3(void); +static void EnableSio(void); +static void DisableTm3(void); +static void GetKeyInput(void); + +static struct SendRecvMgr sSendRecvMgr; +static u16 sJoyNewOrRepeated; +static u16 sJoyNew; +static u16 sSendRecvStatus; +static u16 sCounter1; +static u32 sCounter2; +static u16 sSavedIme; +static u16 sSavedIe; +static u16 sSavedTm3Cnt; +static u16 sSavedSioCnt; +static u16 sSavedSioCnt; +static u16 sSavedRCnt; + +int EReader_Send(size_t r6, const void * r5) +{ + int result; + EReaderHelper_SaveRegsState(); + + while (1) + { + GetKeyInput(); + if (TEST_BUTTON(sJoyNew, B_BUTTON)) + gUnknown_3003F84 = 2; + + sSendRecvStatus = EReaderHandleTransfer(1, r6, r5, NULL); + if ((sSendRecvStatus & 0x13) == 0x10) + { + result = 0; + break; + } + else if (sSendRecvStatus & 8) + { + result = 1; + break; + } + else if (sSendRecvStatus & 4) + { + result = 2; + break; + } + else + { + gUnknown_3003F84 = 0; + VBlankIntrWait(); + } + } + + CpuFill32(0, &sSendRecvMgr, sizeof(sSendRecvMgr)); + EReaderHelper_RestoreRegsState(); + return result; +} + +int EReader_Recv(void * r5) +{ + int result; + EReaderHelper_SaveRegsState(); + + while (1) + { + GetKeyInput(); + if (TEST_BUTTON(sJoyNew, B_BUTTON)) + gUnknown_3003F84 = 2; + + sSendRecvStatus = EReaderHandleTransfer(0, 0, NULL, r5); + if ((sSendRecvStatus & 0x13) == 0x10) + { + result = 0; + break; + } + else if (sSendRecvStatus & 8) + { + result = 1; + break; + } + else if (sSendRecvStatus & 4) + { + result = 2; + break; + } + else + { + gUnknown_3003F84 = 0; + VBlankIntrWait(); + } + } + + CpuFill32(0, &sSendRecvMgr, sizeof(sSendRecvMgr)); + EReaderHelper_RestoreRegsState(); + return result; +} + +static void CloseSerial(void) +{ + REG_IME = 0; + REG_IE &= ~(INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); + REG_IME = 1; + REG_SIOCNT = 0; + REG_TM3CNT_H = 0; + REG_IF = INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL; +} + +static void OpenSerialMulti(void) +{ + REG_IME = 0; + REG_IE &= ~(INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); + REG_IME = 1; + REG_RCNT = 0; + REG_SIOCNT = SIO_MULTI_MODE; + REG_SIOCNT |= SIO_INTR_ENABLE | SIO_115200_BPS; + REG_IME = 0; + REG_IE |= INTR_FLAG_SERIAL; + REG_IME = 1; + if (sSendRecvMgr.state == 0) + CpuFill32(0, &sSendRecvMgr, sizeof(sSendRecvMgr)); +} + +static void OpenSerial32(void) +{ + REG_RCNT = 0; + REG_SIOCNT = SIO_INTR_ENABLE | SIO_32BIT_MODE; + REG_SIOCNT |= SIO_MULTI_SD; + gUnknown_3003F84 = 0; + sCounter1 = 0; + sCounter2 = 0; +} + +u16 EReaderHandleTransfer(u8 mode, size_t size, const void * data, void * recvBuffer) +{ + switch (sSendRecvMgr.state) + { + case 0: + OpenSerialMulti(); + sSendRecvMgr.field_02 = 1; + sSendRecvMgr.state = 1; + break; + case 1: + if (DetermineSendRecvState(mode)) + EnableSio(); + if (gUnknown_3003F84 == 2) + { + sSendRecvMgr.field_04 = 2; + sSendRecvMgr.state = 6; + } + break; + case 2: + OpenSerial32(); + SetUpTransferManager(size, data, recvBuffer); + sSendRecvMgr.state = 3; + // fallthrough + case 3: + if (gUnknown_3003F84 == 2) + { + sSendRecvMgr.field_04 = 2; + sSendRecvMgr.state = 6; + } + else + { + sCounter1++; + sCounter2++; + if (sSendRecvMgr.sendOrRecv == 0 && sCounter2 > 60) + { + sSendRecvMgr.field_04 = 1; + sSendRecvMgr.state = 6; + } + if (sSendRecvMgr.field_02 != 2) + { + if (sSendRecvMgr.sendOrRecv != 0 && sCounter1 > 2) + { + EnableSio(); + sSendRecvMgr.field_02 = 2; + } + else + { + EnableSio(); + sSendRecvMgr.field_02 = 2; + } + } + } + break; + case 4: + OpenSerialMulti(); + sSendRecvMgr.state = 5; + break; + case 5: + if (sSendRecvMgr.sendOrRecv == 1 && sCounter1 > 2) + EnableSio(); + if (++sCounter1 > 60) + { + sSendRecvMgr.field_04 = 1; + sSendRecvMgr.state = 6; + } + break; + case 6: + if (sSendRecvMgr.field_02 != 0) + { + CloseSerial(); + sSendRecvMgr.field_02 = 0; + } + break; + } + return sSendRecvMgr.field_02 | (sSendRecvMgr.field_04 << 2) | (sSendRecvMgr.field_03 << 4); +} + +static bool16 DetermineSendRecvState(u8 mode) +{ + bool16 resp; + if ((*(vu32 *)REG_ADDR_SIOCNT & (SIO_MULTI_SI | SIO_MULTI_SD)) == SIO_MULTI_SD && mode) + resp = sSendRecvMgr.sendOrRecv = TRUE; + else + resp = sSendRecvMgr.sendOrRecv = FALSE; + return resp; +} + +static void SetUpTransferManager(size_t size, const void * data, void * recvBuffer) +{ + if (sSendRecvMgr.sendOrRecv) + { + REG_SIOCNT |= SIO_38400_BPS; + sSendRecvMgr.dataptr = (void *)data; + REG_SIODATA32 = size; + sSendRecvMgr.size = size / 4 + 1; + StartTm3(); + } + else + { + REG_SIOCNT |= SIO_9600_BPS; + sSendRecvMgr.dataptr = recvBuffer; + } +} + +static void StartTm3(void) +{ + REG_TM3CNT_L = -601; + REG_TM3CNT_H = TIMER_INTR_ENABLE; + REG_IME = 0; + REG_IE |= INTR_FLAG_TIMER3; + REG_IME = 1; +} + +void EReaderHelper_Timer3Callback(void) +{ + DisableTm3(); + EnableSio(); +} + +void EReaderHelper_SerialCallback(void) +{ + u16 recv[4]; + u16 i; + u16 cnt1; + u16 cnt2; + u32 recv32; + + switch (sSendRecvMgr.state) + { + case 1: + REG_SIOMLT_SEND = 0xCCD0; + *(u64 *)recv = REG_SIOMLT_RECV; + for (i = 0, cnt1 = 0, cnt2 = 0; i < 4; i++) + { + if (recv[i] == 0xCCD0) + cnt1++; + else if (recv[i] != 0xFFFF) + cnt2++; + } + if (cnt1 == 2 && cnt2 == 0) + sSendRecvMgr.state = 2; + break; + case 3: + recv32 = REG_SIODATA32; + if (sSendRecvMgr.cursor == 0 && sSendRecvMgr.sendOrRecv == 0) + sSendRecvMgr.size = recv32 / 4 + 1; + if (sSendRecvMgr.sendOrRecv == 1) + { + if (sSendRecvMgr.cursor < sSendRecvMgr.size) + { + REG_SIODATA32 = sSendRecvMgr.dataptr[sSendRecvMgr.cursor]; + sSendRecvMgr.checksum += sSendRecvMgr.dataptr[sSendRecvMgr.cursor]; + } + else + REG_SIODATA32 = sSendRecvMgr.checksum; + } + else + { + if (sSendRecvMgr.cursor > 0 && sSendRecvMgr.cursor < sSendRecvMgr.size + 1) + { + sSendRecvMgr.dataptr[sSendRecvMgr.cursor - 1] = recv32; + sSendRecvMgr.checksum += recv32; + } + else if (sSendRecvMgr.cursor != 0) + { + if (sSendRecvMgr.checksum == recv32) + sSendRecvMgr.field_03 = 1; + else + sSendRecvMgr.field_03 = 2; + } + sCounter2 = 0; + } + sSendRecvMgr.cursor++; + if (sSendRecvMgr.cursor < sSendRecvMgr.size + 2) + { + if (sSendRecvMgr.sendOrRecv != 0) + REG_TM3CNT_H |= TIMER_ENABLE; + else + EnableSio(); + } + else + { + sSendRecvMgr.state = 4; + sCounter1 = 0; + } + break; + case 5: + if (sSendRecvMgr.sendOrRecv == 0) + REG_SIODATA8 = sSendRecvMgr.field_03; + *(vu64 *)recv = REG_SIOMLT_RECV; + if (recv[1] == 1 || recv[1] == 2) + { + if (sSendRecvMgr.sendOrRecv == 1) + sSendRecvMgr.field_03 = recv[1]; + sSendRecvMgr.state = 6; + } + break; + } +} + +static void EnableSio(void) +{ + REG_SIOCNT |= SIO_ENABLE; +} + +static void DisableTm3(void) +{ + REG_TM3CNT_H &= ~TIMER_ENABLE; + REG_TM3CNT_L = -601; +} + +static void GetKeyInput(void) +{ + u16 rawKeys = REG_KEYINPUT ^ 0x3FF; + sJoyNew = rawKeys & ~sJoyNewOrRepeated; + sJoyNewOrRepeated = rawKeys; +} + +void EReaderHelper_SaveRegsState(void) +{ + sSavedIme = REG_IME; + sSavedIe = REG_IE; + sSavedTm3Cnt = REG_TM3CNT_H; + sSavedSioCnt = REG_SIOCNT; + sSavedRCnt = REG_RCNT; +} + +void EReaderHelper_RestoreRegsState(void) +{ + REG_IME = sSavedIme; + REG_IE = sSavedIe; + REG_TM3CNT_H = sSavedTm3Cnt; + REG_SIOCNT = sSavedSioCnt; + REG_RCNT = sSavedRCnt; +} + +void EReaderHelper_ClearsSendRecvMgr(void) +{ + CpuFill32(0, &sSendRecvMgr, sizeof(sSendRecvMgr)); +} diff --git a/src/fame_checker.c b/src/fame_checker.c index bbbe02c58..bf99bdf56 100644 --- a/src/fame_checker.c +++ b/src/fame_checker.c @@ -8,7 +8,7 @@ #include "battle.h" #include "battle_setup.h" #include "menu.h" -#include "battle_dome_cards.h" +#include "trainer_pokemon_sprites.h" #include "scanline_effect.h" #include "new_menu_helpers.h" #include "item_menu.h" @@ -127,9 +127,9 @@ extern const u8 gFameCheckerText_Cancel[]; extern const u8 gFameCheckerText_ListMenuCursor[]; extern const u8 gFameCheckerText_FameCheckerWillBeClosed[]; extern const u8 gFameCheckerText_ClearTextbox[]; -extern const u8 gFameCheckerText_MainScreenUI[]; // "{KEYGFX_START_BUTTON}PICK {KEYGFX_DPAD_UP_DOWN}SELECT {KEYGFX_A_BUTTON}OK$" -extern const u8 gFameCheckerText_PickScreenUI[]; // "{KEYGFX_START_BUTTON}PICK {KEYGFX_DPAD_UP_DOWN}SELECT {KEYGFX_B_BUTTON}CANCEL$" -extern const u8 gFameCheckerText_FlavorTextUI[]; // "{KEYGFX_DPAD_ANY}PICK {KEYGFX_A_BUTTON}READ {KEYGFX_B_BUTTON}CANCEL$" +extern const u8 gFameCheckerText_MainScreenUI[]; // "{KEYGFX_DPAD_ANY}PICK {KEYGFX_DPAD_UP_DOWN}SELECT {KEYGFX_A_BUTTON}OK$" +extern const u8 gFameCheckerText_PickScreenUI[]; // "{KEYGFX_DPAD_ANY}PICK {KEYGFX_DPAD_UP_DOWN}SELECT {KEYGFX_B_BUTTON}CANCEL$" +extern const u8 gFameCheckerText_FlavorTextUI[]; // "{KEYGFX_START_BUTTON}PICK {KEYGFX_A_BUTTON}READ {KEYGFX_B_BUTTON}CANCEL$" extern const u8 gFameCheckerOakName[]; // "OAK$" extern const u8 gFameCheckerDaisyName[]; // "DAISY$" extern const u8 gFameCheckerBillName[]; // "BILL$" @@ -552,7 +552,7 @@ static void Task_TopMenuHandleInput(u8 taskId) if (FindTaskIdByFunc(Task_FCOpenOrCloseInfoBox) == 0xFF) { RunTextPrinters(); - if ((JOY_NEW(SELECT_BUTTON)) && !sFameCheckerData->inPickMode && sFameCheckerData->savedCallback != UseFameCheckerFromMenu) + if ((JOY_NEW(SELECT_BUTTON)) && !sFameCheckerData->inPickMode && sFameCheckerData->savedCallback != ReturnToBagFromKeyItem) task->func = Task_StartToCloseFameChecker; else if (JOY_NEW(START_BUTTON)) { @@ -639,7 +639,7 @@ static bool8 TryExitPickMode(u8 taskId) static void MessageBoxPrintEmptyText(void) { - AddTextPrinterParametrized(2, 2, gFameCheckerText_ClearTextbox, 0, NULL, 2, 1, 3); + AddTextPrinterParameterized2(2, 2, gFameCheckerText_ClearTextbox, 0, NULL, 2, 1, 3); } static void Task_EnterPickMode(u8 taskId) @@ -779,7 +779,7 @@ static void GetPickModeText(void) if (HasUnlockedAllFlavorTextsForCurrentPerson() == TRUE) offset = NUM_FAMECHECKER_PERSONS; StringExpandPlaceholders(gStringVar4, sFameCheckerNameAndQuotesPointers[sFameCheckerData->unlockedPersons[who] + offset]); - AddTextPrinterParametrized(FCWINDOWID_MSGBOX, 2, gStringVar4, sub_80F78A8(), NULL, 2, 1, 3); + AddTextPrinterParameterized2(FCWINDOWID_MSGBOX, 2, gStringVar4, GetTextSpeedSetting(), NULL, 2, 1, 3); FC_PutWindowTilemapAndCopyWindowToVramMode3(FCWINDOWID_MSGBOX); } } @@ -790,7 +790,7 @@ static void PrintSelectedNameInBrightGreen(u8 taskId) u16 cursorPos = FameCheckerGetCursorY(); FillWindowPixelRect(FCWINDOWID_MSGBOX, 0x11, 0, 0, 0xd0, 0x20); StringExpandPlaceholders(gStringVar4, sFameCheckerFlavorTextPointers[sFameCheckerData->unlockedPersons[cursorPos] * 6 + data[1]]); - AddTextPrinterParametrized(FCWINDOWID_MSGBOX, 2, gStringVar4, sub_80F78A8(), NULL, 2, 1, 3); + AddTextPrinterParameterized2(FCWINDOWID_MSGBOX, 2, gStringVar4, GetTextSpeedSetting(), NULL, 2, 1, 3); FC_PutWindowTilemapAndCopyWindowToVramMode3(FCWINDOWID_MSGBOX); } @@ -803,7 +803,7 @@ static void WipeMsgBoxAndTransfer(void) static void Setup_DrawMsgAndListBoxes(void) { sub_80F6E9C(); - sub_80F6EE4(FCWINDOWID_MSGBOX, TRUE); + DrawDialogueFrame(FCWINDOWID_MSGBOX, TRUE); FC_PutWindowTilemapAndCopyWindowToVramMode3(FCWINDOWID_MSGBOX); FC_PutWindowTilemapAndCopyWindowToVramMode3(FCWINDOWID_LIST); } @@ -853,7 +853,7 @@ static void Task_DestroyAssetsAndCloseFameChecker(u8 taskId) FreeQuestionMarkSpriteResources(); FreeListMenuSelectorArrowPairResources(); SetMainCallback2(sFameCheckerData->savedCallback); - sub_810713C(sFameCheckerData->listMenuTaskId, 0, 0); + DestroyListMenu(sFameCheckerData->listMenuTaskId, NULL, NULL); Free(sBg3TilemapBuffer); Free(sBg1TilemapBuffer); Free(sBg2TilemapBuffer); @@ -900,7 +900,7 @@ static void PrintUIHelp(u8 state) } width = GetStringWidth(0, src, 0); FillWindowPixelRect(FCWINDOWID_UIHELP, 0x00, 0, 0, 0xc0, 0x10); - AddTextPrinterParametrized2(FCWINDOWID_UIHELP, 0, 188 - width, 0, 0, 2, &sTextColor_White, -1, src); + AddTextPrinterParameterized4(FCWINDOWID_UIHELP, 0, 188 - width, 0, 0, 2, &sTextColor_White, -1, src); FC_PutWindowTilemapAndCopyWindowToVramMode3(FCWINDOWID_UIHELP); } @@ -1009,10 +1009,10 @@ static void FCSetup_ClearVideoRegisters(void) static void FCSetup_ResetTasksAndSpriteResources(void) { - remove_some_task(); + ScanlineEffect_Stop(); ResetTasks(); ResetSpriteData(); - dp13_810BB8C(); + ResetAllPicSprites(); ResetPaletteFade(); npc_paltag_set_load(0); gReservedSpritePaletteCount = 7; @@ -1181,7 +1181,7 @@ static u8 CreatePersonPicSprite(u8 fcPersonIdx) } else { - spriteId = sub_810C2A4(sFameCheckerTrainerPicIdxs[fcPersonIdx], 1, 0x94, 0x42, 6, 0xFFFF); + spriteId = CreateTrainerPicSprite(sFameCheckerTrainerPicIdxs[fcPersonIdx], 1, 0x94, 0x42, 6, 0xFFFF); } gSprites[spriteId].callback = SpriteCB_FCSpinningPokeball; if (gSaveBlock1Ptr->fameChecker[fcPersonIdx].pickState == FCPICKSTATE_SILHOUETTE) @@ -1202,7 +1202,7 @@ static void DestroyPersonPicSprite(u8 taskId, u16 who) ) DestroySprite(&gSprites[data[2]]); else - sub_810C2E8(data[2]); + FreeAndDestroyTrainerPicSprite(data[2]); } static void UpdateIconDescriptionBox(u8 whichText) @@ -1213,10 +1213,10 @@ static void UpdateIconDescriptionBox(u8 whichText) gIconDescriptionBoxIsOpen = 1; FillWindowPixelRect(FCWINDOWID_ICONDESC, 0x00, 0, 0, 0x58, 0x20); width = (0x54 - GetStringWidth(0, sFlavorTextOriginLocationTexts[idx], 0)) / 2; - AddTextPrinterParametrized2(FCWINDOWID_ICONDESC, 0, width, 0, 0, 2, &sTextColor_DkGrey, -1, sFlavorTextOriginLocationTexts[idx]); + AddTextPrinterParameterized4(FCWINDOWID_ICONDESC, 0, width, 0, 0, 2, &sTextColor_DkGrey, -1, sFlavorTextOriginLocationTexts[idx]); StringExpandPlaceholders(gStringVar1, sFlavorTextOriginObjectNameTexts[idx]); width = (0x54 - GetStringWidth(0, gStringVar1, 0)) / 2; - AddTextPrinterParametrized2(FCWINDOWID_ICONDESC, 0, width, 10, 0, 2, &sTextColor_DkGrey, -1, gStringVar1); + AddTextPrinterParameterized4(FCWINDOWID_ICONDESC, 0, width, 10, 0, 2, &sTextColor_DkGrey, -1, gStringVar1); FC_PutWindowTilemapAndCopyWindowToVramMode3(FCWINDOWID_ICONDESC); } @@ -1270,7 +1270,7 @@ static void FC_MoveCursorFunc(s32 itemIndex, bool8 onInit, struct ListMenu *list struct Task *task = &gTasks[taskId]; PlaySE(SE_SELECT); task->data[1] = 0; - get_coro_args_x18_x1A(sFameCheckerData->listMenuTaskId, &listMenuTopIdx, NULL); + ListMenuGetScrollAndRow(sFameCheckerData->listMenuTaskId, &listMenuTopIdx, NULL); sFameCheckerData->listMenuTopIdx = listMenuTopIdx; if (itemIndex != sFameCheckerData->numUnlockedPersons - 1) { @@ -1330,7 +1330,7 @@ static void Task_SwitchToPickMode(u8 taskId) static void PrintCancelDescription(void) { FillWindowPixelRect(FCWINDOWID_MSGBOX, 0x11, 0, 0, 0xd0, 0x20); - AddTextPrinterParametrized(FCWINDOWID_MSGBOX, 2, gFameCheckerText_FameCheckerWillBeClosed, 0, NULL, 2, 1, 3); + AddTextPrinterParameterized2(FCWINDOWID_MSGBOX, 2, gFameCheckerText_FameCheckerWillBeClosed, 0, NULL, 2, 1, 3); FC_PutWindowTilemapAndCopyWindowToVramMode3(FCWINDOWID_MSGBOX); } @@ -1339,16 +1339,16 @@ static void FC_DoMoveCursor(s32 itemIndex, bool8 onInit) u16 listY; u16 cursorY; u16 who; - get_coro_args_x18_x1A(sFameCheckerData->listMenuTaskId, &listY, &cursorY); + ListMenuGetScrollAndRow(sFameCheckerData->listMenuTaskId, &listY, &cursorY); who = listY + cursorY; - AddTextPrinterParametrized2(FCWINDOWID_LIST, 2, 8, 14 * cursorY + 4, 0, 0, &sTextColor_Green, 0, sListMenuItems[itemIndex].unk_00); + AddTextPrinterParameterized4(FCWINDOWID_LIST, 2, 8, 14 * cursorY + 4, 0, 0, &sTextColor_Green, 0, sListMenuItems[itemIndex].label); if (!onInit) { if (listY < sFameCheckerData->listMenuTopIdx2) sFameCheckerData->listMenuDrawnSelIdx++; else if (listY > sFameCheckerData->listMenuTopIdx2 && who != sFameCheckerData->numUnlockedPersons - 1) sFameCheckerData->listMenuDrawnSelIdx--; - AddTextPrinterParametrized2(FCWINDOWID_LIST, 2, 8, 14 * sFameCheckerData->listMenuDrawnSelIdx + 4, 0, 0, &sTextColor_DkGrey, 0, sListMenuItems[sFameCheckerData->listMenuCurIdx].unk_00); + AddTextPrinterParameterized4(FCWINDOWID_LIST, 2, 8, 14 * sFameCheckerData->listMenuDrawnSelIdx + 4, 0, 0, &sTextColor_DkGrey, 0, sListMenuItems[sFameCheckerData->listMenuCurIdx].label); } sFameCheckerData->listMenuCurIdx = itemIndex; @@ -1368,20 +1368,20 @@ static u8 FC_PopulateListMenu(void) { if (sTrainerIdxs[fameCheckerIdx] < FC_NONTRAINER_START) { - sListMenuItems[nitems].unk_00 = gTrainers[sTrainerIdxs[fameCheckerIdx]].trainerName; - sListMenuItems[nitems].unk_04 = nitems; + sListMenuItems[nitems].label = gTrainers[sTrainerIdxs[fameCheckerIdx]].trainerName; + sListMenuItems[nitems].index = nitems; } else { - sListMenuItems[nitems].unk_00 = sNonTrainerNamePointers[sTrainerIdxs[fameCheckerIdx] - FC_NONTRAINER_START]; - sListMenuItems[nitems].unk_04 = nitems; + sListMenuItems[nitems].label = sNonTrainerNamePointers[sTrainerIdxs[fameCheckerIdx] - FC_NONTRAINER_START]; + sListMenuItems[nitems].index = nitems; } sFameCheckerData->unlockedPersons[nitems] = fameCheckerIdx; nitems++; } } - sListMenuItems[nitems].unk_00 = gFameCheckerText_Cancel; - sListMenuItems[nitems].unk_04 = nitems; + sListMenuItems[nitems].label = gFameCheckerText_Cancel; + sListMenuItems[nitems].index = nitems; sFameCheckerData->unlockedPersons[nitems] = 0xFF; nitems++; gFameChecker_ListMenuTemplate.totalItems = nitems; @@ -1400,7 +1400,7 @@ static void FC_PutWindowTilemapAndCopyWindowToVramMode3_2(u8 windowId) static void FC_CreateScrollIndicatorArrowPair(void) { - struct ScrollIndicatorArrowPairTemplate template = { + struct ScrollArrowsTemplate template = { 2, 40, 26, @@ -1412,13 +1412,12 @@ static void FC_CreateScrollIndicatorArrowPair(void) SPRITETAG_SCROLL_INDICATORS, 0xFFFF, 1, - 0 }; if (sFameCheckerData->numUnlockedPersons > 5) { - template.unk_06 = 0; - template.unk_08 = sFameCheckerData->numUnlockedPersons - 5; + template.fullyUpThreshold = 0; + template.fullyDownThreshold = sFameCheckerData->numUnlockedPersons - 5; sFameCheckerData->scrollIndicatorPairTaskId = AddScrollIndicatorArrowPair(&template, &sFameCheckerData->listMenuTopIdx); } } @@ -1432,7 +1431,7 @@ static void FreeListMenuSelectorArrowPairResources(void) static u16 FameCheckerGetCursorY(void) { u16 listY, cursorY; - get_coro_args_x18_x1A(sFameCheckerData->listMenuTaskId, &listY, &cursorY); + ListMenuGetScrollAndRow(sFameCheckerData->listMenuTaskId, &listY, &cursorY); return listY + cursorY; } @@ -1547,7 +1546,7 @@ static void PlaceListMenuCursor(bool8 isActive) { u16 cursorY = ListMenuGetYCoordForPrintingArrowCursor(sFameCheckerData->listMenuTaskId); if (isActive == TRUE) - AddTextPrinterParametrized2(FCWINDOWID_LIST, 2, 0, cursorY, 0, 0, &sTextColor_DkGrey, 0, gFameCheckerText_ListMenuCursor); + AddTextPrinterParameterized4(FCWINDOWID_LIST, 2, 0, cursorY, 0, 0, &sTextColor_DkGrey, 0, gFameCheckerText_ListMenuCursor); else - AddTextPrinterParametrized2(FCWINDOWID_LIST, 2, 0, cursorY, 0, 0, &sTextColor_White, 0, gFameCheckerText_ListMenuCursor); + AddTextPrinterParameterized4(FCWINDOWID_LIST, 2, 0, cursorY, 0, 0, &sTextColor_White, 0, gFameCheckerText_ListMenuCursor); } diff --git a/src/fieldmap.c b/src/fieldmap.c new file mode 100644 index 000000000..5d11c7d99 --- /dev/null +++ b/src/fieldmap.c @@ -0,0 +1,1025 @@ +#include "global.h" +#include "bg.h" +#include "palette.h" +#include "overworld.h" +#include "script.h" +#include "menu.h" +#include "new_menu_helpers.h" +#include "quest_log.h" +#include "fieldmap.h" + +struct ConnectionFlags +{ + u8 south:1; + u8 north:1; + u8 west:1; + u8 east:1; +}; + +void sub_8058A00(struct MapHeader *mapHeader); +void map_copy_with_padding(u16 *map, u16 width, u16 height); +void mapheader_copy_mapdata_of_adjacent_maps(struct MapHeader *mapHeader); +void fillSouthConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset); +void fillNorthConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset); +void fillWestConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset); +void fillEastConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset); +void LoadSavedMapView(void); +struct MapConnection *sub_8059600(u8 direction, s32 x, s32 y); +bool8 sub_8059658(u8 direction, s32 x, s32 y, struct MapConnection *connection); +bool8 sub_80596BC(s32 x, s32 src_width, s32 dest_width, s32 offset); + +struct BackupMapData VMap; +EWRAM_DATA u16 gBackupMapData[VIRTUAL_MAP_SIZE] = {}; +EWRAM_DATA struct MapHeader gMapHeader = {}; +EWRAM_DATA struct Camera gCamera = {}; +EWRAM_DATA struct ConnectionFlags gMapConnectionFlags = {}; + +const struct ConnectionFlags sDummyConnectionFlags = {}; + +const u32 gUnknown_8352EF0[] = { + 0x1ff, + 0x3e00, + 0x3c000, + 0xfc0000, + 0x7000000, + 0x18000000, + 0x60000000, + 0x80000000 +}; + +const u8 gUnknown_8352F10[] = { + 0, + 9, + 14, + 18, + 24, + 27, + 29, + 31 +}; + +const struct MapHeader * mapconnection_get_mapheader(struct MapConnection * connection) +{ + return get_mapheader_by_bank_and_number(connection->mapGroup, connection->mapNum); +} + +void not_trainer_hill_battle_pyramid(void) +{ + sub_8058A00(&gMapHeader); + mapheader_run_script_with_tag_x1(); +} + +void sub_80589E8(void) +{ + sub_8058A00(&gMapHeader); + LoadSavedMapView(); + mapheader_run_script_with_tag_x1(); +} + +void sub_8058A00(struct MapHeader * mapHeader) +{ + const struct MapData * mapData = mapHeader->mapData; + CpuFastFill(0x03FF03FF, gBackupMapData, sizeof(gBackupMapData)); + VMap.map = gBackupMapData; + VMap.Xsize = mapData->width + 15; + VMap.Ysize = mapData->height + 14; + AGB_ASSERT_EX(VMap.Xsize * VMap.Ysize <= VIRTUAL_MAP_SIZE, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/fieldmap.c", 158); + map_copy_with_padding(mapData->map, mapData->width, mapData->height); + mapheader_copy_mapdata_of_adjacent_maps(mapHeader); +} + +void map_copy_with_padding(u16 *map, u16 width, u16 height) +{ + s32 y; + u16 *dest = VMap.map; + dest += VMap.Xsize * 7 + 7; + + for (y = 0; y < height; y++) + { + CpuCopy16(map, dest, width * sizeof(u16)); + dest += width + 15; + map += width; + } +} + +void mapheader_copy_mapdata_of_adjacent_maps(struct MapHeader *mapHeader) +{ + s32 count; + struct MapConnection *connection; + s32 i; + + gMapConnectionFlags = sDummyConnectionFlags; + + /* + * This null pointer check is new to FireRed. It was kept in + * Emerald, with the above struct assignment moved to after + * this check. + */ + if (mapHeader->connections) + { + count = mapHeader->connections->count; + connection = mapHeader->connections->connections; + // Emerald puts this line here instead: + // gMapConnectionFlags = sDummyConnectionFlags; + for (i = 0; i < count; i++, connection++) + { + struct MapHeader const *cMap = mapconnection_get_mapheader(connection); + u32 offset = connection->offset; + switch (connection->direction) + { + case CONNECTION_SOUTH: + fillSouthConnection(mapHeader, cMap, offset); + gMapConnectionFlags.south = 1; + break; + case CONNECTION_NORTH: + fillNorthConnection(mapHeader, cMap, offset); + gMapConnectionFlags.north = 1; + break; + case CONNECTION_WEST: + fillWestConnection(mapHeader, cMap, offset); + gMapConnectionFlags.west = 1; + break; + case CONNECTION_EAST: + fillEastConnection(mapHeader, cMap, offset); + gMapConnectionFlags.east = 1; + break; + } + } + } +} + +void sub_8058B54(s32 x, s32 y, const struct MapHeader *connectedMapHeader, s32 x2, s32 y2, s32 width, s32 height) +{ + s32 i; + u16 *src; + u16 *dest; + s32 mapWidth; + + mapWidth = connectedMapHeader->mapData->width; + src = &connectedMapHeader->mapData->map[mapWidth * y2 + x2]; + dest = &VMap.map[VMap.Xsize * y + x]; + + for (i = 0; i < height; i++) + { + CpuCopy16(src, dest, width * 2); + dest += VMap.Xsize; + src += mapWidth; + } +} + +void fillSouthConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset) +{ + s32 x, y; + s32 x2; + s32 width; + s32 cWidth; + + if (connectedMapHeader) + { + cWidth = connectedMapHeader->mapData->width; + x = offset + 7; + y = mapHeader->mapData->height + 7; + if (x < 0) + { + x2 = -x; + x += cWidth; + if (x < VMap.Xsize) + { + width = x; + } + else + { + width = VMap.Xsize; + } + x = 0; + } + else + { + x2 = 0; + if (x + cWidth < VMap.Xsize) + { + width = cWidth; + } + else + { + width = VMap.Xsize - x; + } + } + + sub_8058B54( + x, y, + connectedMapHeader, + x2, /*y2*/ 0, + width, /*height*/ 7); + } +} + +void fillNorthConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset) +{ + s32 x; + s32 x2, y2; + s32 width; + s32 cWidth, cHeight; + + if (connectedMapHeader) + { + cWidth = connectedMapHeader->mapData->width; + cHeight = connectedMapHeader->mapData->height; + x = offset + 7; + y2 = cHeight - 7; + if (x < 0) + { + x2 = -x; + x += cWidth; + if (x < VMap.Xsize) + { + width = x; + } + else + { + width = VMap.Xsize; + } + x = 0; + } + else + { + x2 = 0; + if (x + cWidth < VMap.Xsize) + { + width = cWidth; + } + else + { + width = VMap.Xsize - x; + } + } + + sub_8058B54( + x, /*y*/ 0, + connectedMapHeader, + x2, y2, + width, /*height*/ 7); + + } +} + +void fillWestConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset) +{ + s32 y; + s32 x2, y2; + s32 height; + s32 cWidth, cHeight; + if (connectedMapHeader) + { + cWidth = connectedMapHeader->mapData->width; + cHeight = connectedMapHeader->mapData->height; + y = offset + 7; + x2 = cWidth - 7; + if (y < 0) + { + y2 = -y; + if (y + cHeight < VMap.Ysize) + { + height = y + cHeight; + } + else + { + height = VMap.Ysize; + } + y = 0; + } + else + { + y2 = 0; + if (y + cHeight < VMap.Ysize) + { + height = cHeight; + } + else + { + height = VMap.Ysize - y; + } + } + + sub_8058B54( + /*x*/ 0, y, + connectedMapHeader, + x2, y2, + /*width*/ 7, height); + } +} + +void fillEastConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset) +{ + s32 x, y; + s32 y2; + s32 height; + s32 cHeight; + if (connectedMapHeader) + { + cHeight = connectedMapHeader->mapData->height; + x = mapHeader->mapData->width + 7; + y = offset + 7; + if (y < 0) + { + y2 = -y; + if (y + cHeight < VMap.Ysize) + { + height = y + cHeight; + } + else + { + height = VMap.Ysize; + } + y = 0; + } + else + { + y2 = 0; + if (y + cHeight < VMap.Ysize) + { + height = cHeight; + } + else + { + height = VMap.Ysize - y; + } + } + + sub_8058B54( + x, y, + connectedMapHeader, + /*x2*/ 0, y2, + /*width*/ 8, height); + } +} + +union Block +{ + struct + { + u16 block:10; + u16 collision:2; + u16 elevation:4; + } block; + u16 value; +}; + +#define MapGridGetBorderTileAt(x, y) ({ \ + u16 block; \ + s32 xprime; \ + s32 yprime; \ + \ + struct MapData *mapData = gMapHeader.mapData; \ + \ + xprime = x - 7; \ + xprime += 8 * mapData->unk18; \ + xprime %= mapData->unk18; \ + \ + yprime = y - 7; \ + yprime += 8 * mapData->unk19; \ + yprime %= mapData->unk19; \ + \ + block = mapData->border[xprime + yprime * mapData->unk18]; \ + block |= 0xC00; \ + block; \ +}) + +#define MapGridGetBorderTileAt2(x, y) ({ \ + u16 block; \ + s32 xprime; \ + s32 yprime; \ + \ + struct MapData *mapData = gMapHeader.mapData; \ + \ + xprime = x - 7; \ + xprime += 8 * mapData->unk18; \ + xprime %= mapData->unk18; \ + \ + yprime = y - 7; \ + yprime += 8 * mapData->unk19; \ + yprime %= mapData->unk19; \ + \ + block = mapData->border[xprime + yprime * mapData->unk18] | 0xC00; \ + block; \ +}) + +#define AreCoordsWithinMapGridBounds(x, y) (x >= 0 && x < VMap.Xsize && y >= 0 && y < VMap.Ysize) + +#define MapGridGetTileAt(x, y) (AreCoordsWithinMapGridBounds(x, y) ? VMap.map[x + VMap.Xsize * y] : MapGridGetBorderTileAt2(x, y)) + +u8 MapGridGetZCoordAt(s32 x, s32 y) +{ + u16 block = MapGridGetTileAt(x, y); + + if (block == 0x3ff) + { + return 0; + } + + return block >> 12; +} + +u8 MapGridIsImpassableAt(s32 x, s32 y) +{ + + u16 block = MapGridGetTileAt(x, y); + + if (block == 0x3ff) + { + return 1; + } + + return (block & 0xc00) >> 10; +} + +u32 MapGridGetMetatileIdAt(s32 x, s32 y) +{ + u16 block = MapGridGetTileAt(x, y); + + if (block == 0x3FF) + { + return MapGridGetBorderTileAt(x, y) & 0x3FF; + } + return block & 0x3FF; +} + +u32 sub_8058F1C(u32 original, u8 bit) +{ + if (bit >= 8) + return original; + + return (original & gUnknown_8352EF0[bit]) >> gUnknown_8352F10[bit]; +} + +u32 sub_8058F48(s16 x, s16 y, u8 z) +{ + u16 metatileId = MapGridGetMetatileIdAt(x, y); + return GetBehaviorByMetatileIdAndMapData(gMapHeader.mapData, metatileId, z); +} + +u32 MapGridGetMetatileBehaviorAt(s32 x, s32 y) +{ + return sub_8058F48(x, y, 0); +} + +u8 MapGridGetMetatileLayerTypeAt(s32 x, s32 y) +{ + return sub_8058F48(x, y, 6); +} + +void MapGridSetMetatileIdAt(s32 x, s32 y, u16 metatile) +{ + s32 i; + if (x >= 0 && x < VMap.Xsize + && y >= 0 && y < VMap.Ysize) + { + i = x + y * VMap.Xsize; + VMap.map[i] = (VMap.map[i] & 0xf000) | (metatile & 0xfff); + } +} + +void MapGridSetMetatileEntryAt(s32 x, s32 y, u16 metatile) +{ + s32 i; + if (x >= 0 && x < VMap.Xsize + && y >= 0 && y < VMap.Ysize) + { + i = x + VMap.Xsize * y; + VMap.map[i] = metatile; + } +} + +void sub_8059024(s32 x, s32 y, bool32 arg2) +{ + if (x >= 0 && x < VMap.Xsize + && y >= 0 && y < VMap.Ysize) + { + if (arg2) + { + VMap.map[x + VMap.Xsize * y] |= 0x0C00; + } + else + { + VMap.map[x + VMap.Xsize * y] &= ~0x0C00; + } + } +} + +u32 GetBehaviorByMetatileIdAndMapData(struct MapData *mapData, u16 metatile, u8 attr) +{ + u32 * attributes; + + if (metatile < NUM_METATILES_IN_PRIMARY) + { + attributes = mapData->primaryTileset->metatileAttributes; + return sub_8058F1C(attributes[metatile], attr); + } + else if (metatile < 0x400) + { + attributes = mapData->secondaryTileset->metatileAttributes; + return sub_8058F1C(attributes[metatile - NUM_METATILES_IN_PRIMARY], attr); + } + else + { + return 0xFF; + } +} + +void save_serialize_map(void) +{ + s32 i, j; + s32 x, y; + u16 *mapView; + s32 width; + mapView = gSaveBlock2Ptr->mapView; + width = VMap.Xsize; + x = gSaveBlock1Ptr->pos.x; + y = gSaveBlock1Ptr->pos.y; + for (i = y; i < y + 14; i++) + { + for (j = x; j < x + 15; j++) + { + *mapView++ = gBackupMapData[width * i + j]; + } + } +} + +bool32 SavedMapViewIsEmpty(void) +{ + u16 i; + u32 marker = 0; + + // BUG: This loop extends past the bounds of the mapView array. Its size is only 0x100. + for (i = 0; i < 0x200; i++) + marker |= gSaveBlock2Ptr->mapView[i]; + + if (marker == 0) + return TRUE; + else + return FALSE; +} + +void ClearSavedMapView(void) +{ + CpuFill16(0, gSaveBlock2Ptr->mapView, sizeof(gSaveBlock2Ptr->mapView)); +} + +void LoadSavedMapView(void) +{ + s32 i, j; + s32 x, y; + u16 *mapView; + s32 width; + mapView = gSaveBlock2Ptr->mapView; + if (!SavedMapViewIsEmpty()) + { + width = VMap.Xsize; + x = gSaveBlock1Ptr->pos.x; + y = gSaveBlock1Ptr->pos.y; + for (i = y; i < y + 14; i++) + { + for (j = x; j < x + 15; j++) + { + gBackupMapData[j + width * i] = *mapView; + mapView++; + } + } + ClearSavedMapView(); + } +} + +void sub_8059250(u8 a1) +{ + s32 width; + u16 *mapView; + s32 x0, y0; + s32 x2, y2; + u16 *src, *dest; + s32 srci, desti; + s32 r9, r8; + s32 x, y; + s32 i, j; + mapView = gSaveBlock2Ptr->mapView; + width = VMap.Xsize; + r9 = 0; + r8 = 0; + x0 = gSaveBlock1Ptr->pos.x; + y0 = gSaveBlock1Ptr->pos.y; + x2 = 15; + y2 = 14; + switch (a1) + { + case CONNECTION_NORTH: + y0 += 1; + y2 = 13; + break; + case CONNECTION_SOUTH: + r8 = 1; + y2 = 13; + break; + case CONNECTION_WEST: + x0 += 1; + x2 = 14; + break; + case CONNECTION_EAST: + r9 = 1; + x2 = 14; + break; + } + for (y = 0; y < y2; y++) + { + i = 0; + j = 0; + for (x = 0; x < x2; x++) + { + desti = width * (y + y0); + srci = (y + r8) * 15 + r9; + src = &mapView[srci + i]; + dest = &gBackupMapData[x0 + desti + j]; + *dest = *src; + i++; + j++; + } + } + ClearSavedMapView(); +} + +s32 GetMapBorderIdAt(s32 x, s32 y) +{ + if (MapGridGetTileAt(x, y) == 0x3FF) + { + return -1; + } + + if (x >= VMap.Xsize - 8) + { + if (!gMapConnectionFlags.east) + { + return -1; + } + return CONNECTION_EAST; + } + + if (x < 7) + { + if (!gMapConnectionFlags.west) + { + return -1; + } + return CONNECTION_WEST; + } + + if (y >= VMap.Ysize - 7) + { + if (!gMapConnectionFlags.south) + { + return -1; + } + return CONNECTION_SOUTH; + } + + if (y < 7) + { + if (!gMapConnectionFlags.north) + { + return -1; + } + return CONNECTION_NORTH; + } + + return 0; +} + +s32 GetPostCameraMoveMapBorderId(s32 x, s32 y) +{ + return GetMapBorderIdAt(7 + gSaveBlock1Ptr->pos.x + x, 7 + gSaveBlock1Ptr->pos.y + y); +} + +bool32 CanCameraMoveInDirection(s32 direction) +{ + s32 x, y; + + x = gSaveBlock1Ptr->pos.x + 7 + gDirectionToVectors[direction].x; + y = gSaveBlock1Ptr->pos.y + 7 + gDirectionToVectors[direction].y; + if (GetMapBorderIdAt(x, y) == -1) + { + return FALSE; + } + return TRUE; +} + +void sub_80594AC(struct MapConnection *connection, int direction, s32 x, s32 y) +{ + struct MapHeader const *mapHeader; + mapHeader = mapconnection_get_mapheader(connection); + switch (direction) + { + case CONNECTION_EAST: + gSaveBlock1Ptr->pos.x = -x; + gSaveBlock1Ptr->pos.y -= connection->offset; + break; + case CONNECTION_WEST: + gSaveBlock1Ptr->pos.x = mapHeader->mapData->width; + gSaveBlock1Ptr->pos.y -= connection->offset; + break; + case CONNECTION_SOUTH: + gSaveBlock1Ptr->pos.x -= connection->offset; + gSaveBlock1Ptr->pos.y = -y; + break; + case CONNECTION_NORTH: + gSaveBlock1Ptr->pos.x -= connection->offset; + gSaveBlock1Ptr->pos.y = mapHeader->mapData->height; + break; + } +} + +bool8 CameraMove(s32 x, s32 y) +{ + u32 direction; + struct MapConnection *connection; + s32 old_x, old_y; + gCamera.active = FALSE; + direction = GetPostCameraMoveMapBorderId(x, y); + if (direction + 1 <= 1) + { + gSaveBlock1Ptr->pos.x += x; + gSaveBlock1Ptr->pos.y += y; + } + else + { + save_serialize_map(); + old_x = gSaveBlock1Ptr->pos.x; + old_y = gSaveBlock1Ptr->pos.y; + connection = sub_8059600(direction, gSaveBlock1Ptr->pos.x, gSaveBlock1Ptr->pos.y); + sub_80594AC(connection, direction, x, y); + sub_8055864(connection->mapGroup, connection->mapNum); + gCamera.active = TRUE; + gCamera.x = old_x - gSaveBlock1Ptr->pos.x; + gCamera.y = old_y - gSaveBlock1Ptr->pos.y; + gSaveBlock1Ptr->pos.x += x; + gSaveBlock1Ptr->pos.y += y; + sub_8059250(direction); + } + return gCamera.active; +} + +struct MapConnection *sub_8059600(u8 direction, s32 x, s32 y) +{ + s32 count; + struct MapConnection *connection; + s32 i; + count = gMapHeader.connections->count; + connection = gMapHeader.connections->connections; + for (i = 0; i < count; i++, connection++) + { + if (connection->direction == direction && sub_8059658(direction, x, y, connection) == TRUE) + return connection; + } + return NULL; + +} + +bool8 sub_8059658(u8 direction, s32 x, s32 y, struct MapConnection *connection) +{ + struct MapHeader const *mapHeader; + mapHeader = mapconnection_get_mapheader(connection); + switch (direction) + { + case CONNECTION_SOUTH: + case CONNECTION_NORTH: + return sub_80596BC(x, gMapHeader.mapData->width, mapHeader->mapData->width, connection->offset); + case CONNECTION_WEST: + case CONNECTION_EAST: + return sub_80596BC(y, gMapHeader.mapData->height, mapHeader->mapData->height, connection->offset); + } + return FALSE; +} + +bool8 sub_80596BC(s32 x, s32 src_width, s32 dest_width, s32 offset) +{ + s32 offset2 = max(offset, 0); + + if (dest_width + offset < src_width) + src_width = dest_width + offset; + + if (offset2 <= x && x <= src_width) + return TRUE; + + return FALSE; +} + +bool32 sub_80596E8(s32 x, s32 width) +{ + if (x >= 0 && x < width) + return TRUE; + + return FALSE; +} + +s32 sub_80596FC(struct MapConnection *connection, s32 x, s32 y) +{ + struct MapHeader const *mapHeader; + mapHeader = mapconnection_get_mapheader(connection); + switch (connection->direction) + { + case CONNECTION_SOUTH: + case CONNECTION_NORTH: + return sub_80596E8(x - connection->offset, mapHeader->mapData->width); + case CONNECTION_WEST: + case CONNECTION_EAST: + return sub_80596E8(y - connection->offset, mapHeader->mapData->height); + } + return FALSE; +} + +struct MapConnection *sub_805973C(s16 x, s16 y) +{ + s32 count; + struct MapConnection *connection; + s32 i; + u8 direction; + if (!gMapHeader.connections) + { + return NULL; + } + else + { + count = gMapHeader.connections->count; + connection = gMapHeader.connections->connections; + for (i = 0; i < count; i++, connection++) + { + direction = connection->direction; + if ((direction == CONNECTION_DIVE || direction == CONNECTION_EMERGE) + || (direction == CONNECTION_NORTH && y > 6) + || (direction == CONNECTION_SOUTH && y < gMapHeader.mapData->height + 7) + || (direction == CONNECTION_WEST && x > 6) + || (direction == CONNECTION_EAST && x < gMapHeader.mapData->width + 7)) + { + continue; + } + if (sub_80596FC(connection, x - 7, y - 7) == TRUE) + { + return connection; + } + } + } + return NULL; +} + +void SetCameraFocusCoords(u16 x, u16 y) +{ + gSaveBlock1Ptr->pos.x = x - 7; + gSaveBlock1Ptr->pos.y = y - 7; +} + +void GetCameraFocusCoords(u16 *x, u16 *y) +{ + *x = gSaveBlock1Ptr->pos.x + 7; + *y = gSaveBlock1Ptr->pos.y + 7; +} + +void SetCameraCoords(u16 x, u16 y) +{ + gSaveBlock1Ptr->pos.x = x; + gSaveBlock1Ptr->pos.y = y; +} + +void GetCameraCoords(u16 *x, u16 *y) +{ + *x = gSaveBlock1Ptr->pos.x; + *y = gSaveBlock1Ptr->pos.y; +} +void copy_tileset_patterns_to_vram(struct Tileset const *tileset, u16 numTiles, u16 offset) +{ + if (tileset) + { + if (!tileset->isCompressed) + LoadBgTiles(2, tileset->tiles, numTiles * 32, offset); + else + sub_80F68F0(2, tileset->tiles, numTiles * 32, offset, 0); + } +} + +void copy_tileset_patterns_to_vram2(struct Tileset const *tileset, u16 numTiles, u16 offset) +{ + if (tileset) + { + if (!tileset->isCompressed) + LoadBgTiles(2, tileset->tiles, numTiles * 32, offset); + else + sub_80F69E8(2, tileset->tiles, numTiles * 32, offset, 0); + } +} + +void sub_80598CC(u16 a0, u16 a1) +{ + switch (gUnknown_2036E28) + { + case 0: + return; + case 1: + TintPalette_GrayScale(gPlttBufferUnfaded + a0, a1); + break; + case 2: + TintPalette_SepiaTone(gPlttBufferUnfaded + a0, a1); + break; + case 3: + sub_8111F38(a0, a1); + TintPalette_GrayScale(gPlttBufferUnfaded + a0, a1); + break; + default: + return; + } + CpuCopy16(gPlttBufferUnfaded + a0, gPlttBufferFaded + a0, a1 * sizeof(u16)); +} + +void sub_8059948(u8 a0, u8 a1) +{ + switch (gUnknown_2036E28) + { + case 0: + return; + case 1: + TintPalette_GrayScale(gPlttBufferUnfaded + a0 * 16, a1 * 16); + break; + case 2: + TintPalette_SepiaTone(gPlttBufferUnfaded + a0 * 16, a1 * 16); + break; + case 3: + sub_8111F38(a0 * 16, a1 * 16); + TintPalette_GrayScale(gPlttBufferUnfaded + a0 * 16, a1 * 16); + break; + default: + return; + } + CpuFastCopy(gPlttBufferUnfaded + a0 * 16, gPlttBufferFaded + a0 * 16, a1 * 16 * sizeof(u16)); +} + +void apply_map_tileset_palette(struct Tileset const *tileset, u16 destOffset, u16 size) +{ + u16 black = RGB_BLACK; + + if (tileset) + { + if (tileset->isSecondary == FALSE) + { + LoadPalette(&black, destOffset, 2); + LoadPalette(((u16*)tileset->palettes) + 1, destOffset + 1, size - 2); + sub_80598CC(destOffset + 1, (size - 2) >> 1); + } + else if (tileset->isSecondary == TRUE) + { + LoadPalette(((u16*)tileset->palettes) + (NUM_PALS_IN_PRIMARY * 16), destOffset, size); + sub_80598CC(destOffset, size >> 1); + } + else + { + LoadCompressedPalette((u32*)tileset->palettes, destOffset, size); + sub_80598CC(destOffset, size >> 1); + } + } +} + +void copy_map_tileset1_to_vram(const struct MapData *mapData) +{ + copy_tileset_patterns_to_vram(mapData->primaryTileset, NUM_TILES_IN_PRIMARY, 0); +} + +void copy_map_tileset2_to_vram(const struct MapData *mapData) +{ + copy_tileset_patterns_to_vram(mapData->secondaryTileset, NUM_TILES_TOTAL - NUM_TILES_IN_PRIMARY, NUM_TILES_IN_PRIMARY); +} + +void copy_map_tileset2_to_vram_2(const struct MapData *mapData) +{ + copy_tileset_patterns_to_vram2(mapData->secondaryTileset, NUM_TILES_TOTAL - NUM_TILES_IN_PRIMARY, NUM_TILES_IN_PRIMARY); +} + +void apply_map_tileset1_palette(const struct MapData *mapData) +{ + apply_map_tileset_palette(mapData->primaryTileset, 0, NUM_PALS_IN_PRIMARY * 16 * 2); +} + +void apply_map_tileset2_palette(const struct MapData *mapData) +{ + apply_map_tileset_palette(mapData->secondaryTileset, NUM_PALS_IN_PRIMARY * 16, (NUM_PALS_TOTAL - NUM_PALS_IN_PRIMARY) * 16 * 2); +} + +void copy_map_tileset1_tileset2_to_vram(struct MapData const *mapData) +{ + if (mapData) + { + copy_tileset_patterns_to_vram2(mapData->primaryTileset, NUM_TILES_IN_PRIMARY, 0); + copy_tileset_patterns_to_vram2(mapData->secondaryTileset, NUM_TILES_TOTAL - NUM_TILES_IN_PRIMARY, NUM_TILES_IN_PRIMARY); + } +} + +void apply_map_tileset1_tileset2_palette(struct MapData const *mapData) +{ + if (mapData) + { + apply_map_tileset1_palette(mapData); + apply_map_tileset2_palette(mapData); + } +} diff --git a/src/fldeff_berrytree.c b/src/fldeff_berrytree.c new file mode 100644 index 000000000..90ca36508 --- /dev/null +++ b/src/fldeff_berrytree.c @@ -0,0 +1,4 @@ +void nullsub_56(void) +{ + +} diff --git a/src/fldeff_softboiled.c b/src/fldeff_softboiled.c new file mode 100644 index 000000000..50c715388 --- /dev/null +++ b/src/fldeff_softboiled.c @@ -0,0 +1,109 @@ +#include "global.h" +#include "party_menu.h" +#include "sound.h" +#include "string_util.h" +#include "menu.h" +#include "constants/songs.h" + +void sub_80E57E8(u8 taskId); +void sub_80E583C(u8 taskId); +void sub_80E58A0(u8 taskId); +void sub_80E5934(u8 taskId); + +extern const u8 gUnknown_84169F8[]; +extern const u8 gUnknown_8416F27[]; + +bool8 hm_prepare_dive_probably(void) +{ + u16 maxHp = GetMonData(&gPlayerParty[GetCursorSelectionMonId()], MON_DATA_MAX_HP); + u16 curHp = GetMonData(&gPlayerParty[GetCursorSelectionMonId()], MON_DATA_HP); + + if (curHp > maxHp / 5) + return TRUE; + else + return FALSE; +} + +void sub_80E56DC(u8 taskId) +{ + gUnknown_203B0A0.unkB = 10; + gUnknown_203B0A0.unkA = gUnknown_203B0A0.unk9; + sub_811F818(GetCursorSelectionMonId(), 1); + sub_8121D0C(5); + gTasks[taskId].func = sub_811FB28; +} + +void sub_80E5724(u8 taskId) +{ + u8 r8 = gUnknown_203B0A0.unk9; + u8 r5 = gUnknown_203B0A0.unkA; + u16 curHp; + s16 delta; + + if (r5 > 6) + { + gUnknown_203B0A0.unkB = 0; + sub_8121D0C(0); + gTasks[taskId].func = sub_811FB28; + } + else + { + curHp = GetMonData(&gPlayerParty[r5], MON_DATA_HP); + if (curHp == 0 || r8 == r5 || GetMonData(&gPlayerParty[r5], MON_DATA_MAX_HP) == curHp) + { + sub_80E5934(taskId); + } + else + { + PlaySE(SE_KAIFUKU); + sub_8120760(taskId, r8, -1, GetMonData(&gPlayerParty[r8], MON_DATA_MAX_HP) / 5, sub_80E57E8); + } + } +} + +void sub_80E57E8(u8 taskId) +{ + PlaySE(SE_KAIFUKU); + sub_8120760(taskId, gUnknown_203B0A0.unkA, 1, GetMonData(&gPlayerParty[gUnknown_203B0A0.unk9], MON_DATA_MAX_HP) / 5, sub_80E583C); +} + +void sub_80E583C(u8 taskId) +{ + GetMonNickname(&gPlayerParty[gUnknown_203B0A0.unkA], gStringVar1); + StringExpandPlaceholders(gStringVar4, gUnknown_8416F27); + sub_81202F8(gStringVar4, 0); + schedule_bg_copy_tilemap_to_vram(2); + gTasks[taskId].func = sub_80E58A0; +} + +void sub_80E58A0(u8 taskId) +{ + if (sub_8120370() != TRUE) + { + gUnknown_203B0A0.unkB = 0; + sub_811F818(gUnknown_203B0A0.unk9, 0); + gUnknown_203B0A0.unk9 = gUnknown_203B0A0.unkA; + sub_811F818(gUnknown_203B0A0.unkA, 1); + ClearMenuWindow(6, 0); + ClearWindowTilemap(6); + sub_8121D0C(0); + gTasks[taskId].func = sub_811FB28; + } +} + +void sub_80E5900(u8 taskId) +{ + if (sub_8120370() != TRUE) + { + sub_8121D0C(5); + gTasks[taskId].func = sub_811FB28; + } +} + +void sub_80E5934(u8 taskId) +{ + PlaySE(SE_SELECT); + sub_81202F8(gUnknown_84169F8, 0); + schedule_bg_copy_tilemap_to_vram(2); + gTasks[taskId].func = sub_80E5900; +} diff --git a/src/fldeff_teleport.c b/src/fldeff_teleport.c new file mode 100644 index 000000000..74fad1110 --- /dev/null +++ b/src/fldeff_teleport.c @@ -0,0 +1,42 @@ +#include "global.h" +#include "field_effect.h" +#include "field_player_avatar.h" +#include "fldeff.h" +#include "party_menu.h" +#include "overworld.h" + +static void FieldCallback_Teleport(void); +static void StartTeleportFieldEffect(void); + +bool8 SetUpFieldMove_Teleport(void) +{ + if (Overworld_MapTypeAllowsTeleportAndFly(gMapHeader.mapType) == TRUE) + { + gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu; + gPostMenuFieldCallback = FieldCallback_Teleport; + return TRUE; + } + return FALSE; +} + +static void FieldCallback_Teleport(void) +{ + Overworld_ResetStateAfterTeleport(); + FieldEffectStart(FLDEFF_USE_TELEPORT); + gFieldEffectArguments[0] = (u32)GetCursorSelectionMonId(); +} + +bool8 FldEff_UseTeleport(void) +{ + u8 taskId = oei_task_add(); + gTasks[taskId].data[8] = (u32)StartTeleportFieldEffect >> 16; + gTasks[taskId].data[9] = (u32)StartTeleportFieldEffect; + SetPlayerAvatarTransitionFlags(PLAYER_AVATAR_FLAG_ON_FOOT); + return FALSE; +} + +static void StartTeleportFieldEffect(void) +{ + FieldEffectActiveListRemove(FLDEFF_USE_TELEPORT); + CreateTeleportFieldEffectTask(); +} diff --git a/src/heal_location.c b/src/heal_location.c new file mode 100644 index 000000000..9756f0951 --- /dev/null +++ b/src/heal_location.c @@ -0,0 +1,176 @@ +#include "global.h" +#include "heal_location.h" +#include "event_data.h" +#include "constants/vars.h" +#include "constants/maps.h" +#include "constants/spawn_points.h" + +void SetBlackoutRespawnHealerNpcAsLastTalked(u32 healLocationIdx); + +// This array defines the fly points for unlocked spawns. +static const struct HealLocation sSpawnPoints[] = { + [SPAWN_PALLET_TOWN - 1] = {MAP_GROUP(PALLET_TOWN), MAP_NUM(PALLET_TOWN), 0x06, 0x08}, + [SPAWN_VIRIDIAN_CITY - 1] = {MAP_GROUP(VIRIDIAN_CITY), MAP_NUM(VIRIDIAN_CITY), 0x1a, 0x1b}, + [SPAWN_PEWTER_CITY - 1] = {MAP_GROUP(PEWTER_CITY), MAP_NUM(PEWTER_CITY), 0x11, 0x1a}, + [SPAWN_CERULEAN_CITY - 1] = {MAP_GROUP(CERULEAN_CITY), MAP_NUM(CERULEAN_CITY), 0x16, 0x14}, + [SPAWN_LAVENDER_TOWN - 1] = {MAP_GROUP(LAVENDER_TOWN), MAP_NUM(LAVENDER_TOWN), 0x06, 0x06}, + [SPAWN_VERMILION_CITY - 1] = {MAP_GROUP(VERMILION_CITY), MAP_NUM(VERMILION_CITY), 0x0f, 0x07}, + [SPAWN_CELADON_CITY - 1] = {MAP_GROUP(CELADON_CITY), MAP_NUM(CELADON_CITY), 0x30, 0x0c}, + [SPAWN_FUCHSIA_CITY - 1] = {MAP_GROUP(FUCHSIA_CITY), MAP_NUM(FUCHSIA_CITY), 0x19, 0x20}, + [SPAWN_CINNABAR_ISLAND - 1] = {MAP_GROUP(CINNABAR_ISLAND), MAP_NUM(CINNABAR_ISLAND), 0x0e, 0x0c}, + [SPAWN_INDIGO_PLATEAU - 1] = {MAP_GROUP(INDIGO_PLATEAU_EXTERIOR), MAP_NUM(INDIGO_PLATEAU_EXTERIOR), 0x0b, 0x07}, + [SPAWN_SAFFRON_CITY - 1] = {MAP_GROUP(SAFFRON_CITY_DUPLICATE), MAP_NUM(SAFFRON_CITY_DUPLICATE), 0x18, 0x27}, + [SPAWN_ROUTE4 - 1] = {MAP_GROUP(ROUTE4), MAP_NUM(ROUTE4), 0x0c, 0x06}, + [SPAWN_ROUTE10 - 1] = {MAP_GROUP(ROUTE10), MAP_NUM(ROUTE10), 0x0d, 0x15}, + [SPAWN_ONE_ISLAND - 1] = {MAP_GROUP(ONE_ISLAND), MAP_NUM(ONE_ISLAND), 0x0e, 0x06}, + [SPAWN_TWO_ISLAND - 1] = {MAP_GROUP(TWO_ISLAND), MAP_NUM(TWO_ISLAND), 0x15, 0x08}, + [SPAWN_THREE_ISLAND - 1] = {MAP_GROUP(THREE_ISLAND), MAP_NUM(THREE_ISLAND), 0x0e, 0x1c}, + [SPAWN_FOUR_ISLAND - 1] = {MAP_GROUP(FOUR_ISLAND), MAP_NUM(FOUR_ISLAND), 0x12, 0x15}, + [SPAWN_FIVE_ISLAND - 1] = {MAP_GROUP(FIVE_ISLAND), MAP_NUM(FIVE_ISLAND), 0x12, 0x07}, + [SPAWN_SEVEN_ISLAND - 1] = {MAP_GROUP(SEVEN_ISLAND), MAP_NUM(SEVEN_ISLAND), 0x0c, 0x04}, + [SPAWN_SIX_ISLAND - 1] = {MAP_GROUP(SIX_ISLAND), MAP_NUM(SIX_ISLAND), 0x0b, 0x0c}, +}; + +// This array defines the map where you actually respawn when you black out, +// based on where you last checkpointed. +// This is either the player's house or a Pokémon Center. +// The data are u16 instead of u8 for reasons unknown. +const u16 sBlackoutRespawnHealCenterMapIdxs[][2] = { + [SPAWN_PALLET_TOWN - 1] = {MAP_GROUP(PALLET_TOWN_PLAYERS_HOUSE_1F), MAP_NUM(PALLET_TOWN_PLAYERS_HOUSE_1F)}, + [SPAWN_VIRIDIAN_CITY - 1] = {MAP_GROUP(VIRIDIAN_CITY_POKEMON_CENTER_1F), MAP_NUM(VIRIDIAN_CITY_POKEMON_CENTER_1F)}, + [SPAWN_PEWTER_CITY - 1] = {MAP_GROUP(PEWTER_CITY_POKEMON_CENTER_1F), MAP_NUM(PEWTER_CITY_POKEMON_CENTER_1F)}, + [SPAWN_CERULEAN_CITY - 1] = {MAP_GROUP(CERULEAN_CITY_POKEMON_CENTER_1F), MAP_NUM(CERULEAN_CITY_POKEMON_CENTER_1F)}, + [SPAWN_LAVENDER_TOWN - 1] = {MAP_GROUP(LAVENDER_TOWN_POKEMON_CENTER_1F), MAP_NUM(LAVENDER_TOWN_POKEMON_CENTER_1F)}, + [SPAWN_VERMILION_CITY - 1] = {MAP_GROUP(VERMILION_CITY_POKEMON_CENTER_1F), MAP_NUM(VERMILION_CITY_POKEMON_CENTER_1F)}, + [SPAWN_CELADON_CITY - 1] = {MAP_GROUP(CELADON_CITY_POKEMON_CENTER_1F), MAP_NUM(CELADON_CITY_POKEMON_CENTER_1F)}, + [SPAWN_FUCHSIA_CITY - 1] = {MAP_GROUP(FUCHSIA_CITY_POKEMON_CENTER_1F), MAP_NUM(FUCHSIA_CITY_POKEMON_CENTER_1F)}, + [SPAWN_CINNABAR_ISLAND - 1] = {MAP_GROUP(CINNABAR_ISLAND_POKEMON_CENTER_1F), MAP_NUM(CINNABAR_ISLAND_POKEMON_CENTER_1F)}, + [SPAWN_INDIGO_PLATEAU - 1] = {MAP_GROUP(INDIGO_PLATEAU_POKEMON_CENTER_1F), MAP_NUM(INDIGO_PLATEAU_POKEMON_CENTER_1F)}, + [SPAWN_SAFFRON_CITY - 1] = {MAP_GROUP(SAFFRON_CITY_POKEMON_CENTER_1F), MAP_NUM(SAFFRON_CITY_POKEMON_CENTER_1F)}, + [SPAWN_ROUTE4 - 1] = {MAP_GROUP(ROUTE4_POKEMON_CENTER_1F), MAP_NUM(ROUTE4_POKEMON_CENTER_1F)}, + [SPAWN_ROUTE10 - 1] = {MAP_GROUP(ROUTE10_POKEMON_CENTER_1F), MAP_NUM(ROUTE10_POKEMON_CENTER_1F)}, + [SPAWN_ONE_ISLAND - 1] = {MAP_GROUP(ONE_ISLAND_POKEMON_CENTER_1F), MAP_NUM(ONE_ISLAND_POKEMON_CENTER_1F)}, + [SPAWN_TWO_ISLAND - 1] = {MAP_GROUP(TWO_ISLAND_POKEMON_CENTER_1F), MAP_NUM(TWO_ISLAND_POKEMON_CENTER_1F)}, + [SPAWN_THREE_ISLAND - 1] = {MAP_GROUP(THREE_ISLAND_POKEMON_CENTER_1F), MAP_NUM(THREE_ISLAND_POKEMON_CENTER_1F)}, + [SPAWN_FOUR_ISLAND - 1] = {MAP_GROUP(FOUR_ISLAND_POKEMON_CENTER_1F), MAP_NUM(FOUR_ISLAND_POKEMON_CENTER_1F)}, + [SPAWN_FIVE_ISLAND - 1] = {MAP_GROUP(FIVE_ISLAND_POKEMON_CENTER_1F), MAP_NUM(FIVE_ISLAND_POKEMON_CENTER_1F)}, + [SPAWN_SEVEN_ISLAND - 1] = {MAP_GROUP(SEVEN_ISLAND_POKEMON_CENTER_1F), MAP_NUM(SEVEN_ISLAND_POKEMON_CENTER_1F)}, + [SPAWN_SIX_ISLAND - 1] = {MAP_GROUP(SIX_ISLAND_POKEMON_CENTER_1F), MAP_NUM(SIX_ISLAND_POKEMON_CENTER_1F)} +}; + +// When you respawn, your character scurries back to either their house +// or a Pokémon Center, and hands their fainted Pokémon to their mother +// or the Nurse for healing. +// This array defines the index of the NPC on the map defined above +// with whom your character interacts in this cutscene. +static const u8 sBlackoutRespawnHealerNpcIds[] = { + [SPAWN_PALLET_TOWN - 1] = 1, + [SPAWN_VIRIDIAN_CITY - 1] = 1, + [SPAWN_PEWTER_CITY - 1] = 3, + [SPAWN_CERULEAN_CITY - 1] = 1, + [SPAWN_LAVENDER_TOWN - 1] = 1, + [SPAWN_VERMILION_CITY - 1] = 1, + [SPAWN_CELADON_CITY - 1] = 1, + [SPAWN_FUCHSIA_CITY - 1] = 1, + [SPAWN_CINNABAR_ISLAND - 1] = 1, + [SPAWN_INDIGO_PLATEAU - 1] = 2, + [SPAWN_SAFFRON_CITY - 1] = 1, + [SPAWN_ROUTE4 - 1] = 1, + [SPAWN_ROUTE10 - 1] = 1, + [SPAWN_ONE_ISLAND - 1] = 1, + [SPAWN_TWO_ISLAND - 1] = 1, + [SPAWN_THREE_ISLAND - 1] = 1, + [SPAWN_FOUR_ISLAND - 1] = 1, + [SPAWN_FIVE_ISLAND - 1] = 1, + [SPAWN_SEVEN_ISLAND - 1] = 1, + [SPAWN_SIX_ISLAND - 1] = 1 +}; + +u32 GetHealLocationIndexFromMapGroupAndNum(u16 mapGroup, u16 mapNum) +{ + u32 i; + + for (i = 0; i < NELEMS(sSpawnPoints); i++) { + if (sSpawnPoints[i].group == mapGroup && sSpawnPoints[i].map == mapNum) + { + return i + 1; + } + } + + return 0; +} + +const struct HealLocation * GetHealLocationPointerFromMapGroupAndNum(u16 mapGroup, u16 mapNum) +{ + u32 i = GetHealLocationIndexFromMapGroupAndNum(mapGroup, mapNum); + if (i == 0) + return NULL; + + return &sSpawnPoints[i - 1]; +} + +const struct HealLocation * GetHealLocationPointer(u32 idx) +{ + if (idx == 0) + return NULL; + if (idx > NELEMS(sSpawnPoints)) + return NULL; + return &sSpawnPoints[idx - 1]; +} + +void SetBlackoutRespawnWarpAndHealerNpc(struct WarpData * warp) +{ + u32 healLocationIdx; + + if (VarGet(VAR_0x4082) == 1) + { + if (!gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_2) + VarSet(VAR_0x4082, 0); + gSpecialVar_LastTalked = 1; + warp->x = 4; + warp->y = 11; + warp->mapGroup = MAP_GROUP(SEVEN_ISLAND_TRAINER_TOWER_LOBBY); + warp->mapNum = MAP_NUM(SEVEN_ISLAND_TRAINER_TOWER_LOBBY); + warp->warpId = 0xFF; + } + else + { + healLocationIdx = GetHealLocationIndexFromMapGroupAndNum(gSaveBlock1Ptr->lastHealLocation.mapGroup, gSaveBlock1Ptr->lastHealLocation.mapNum); + warp->mapGroup = sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][0]; + warp->mapNum = sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][1]; + warp->warpId = 0xFF; + + if (sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][0] == MAP_GROUP(PALLET_TOWN_PLAYERS_HOUSE_1F) && sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][1] == MAP_NUM(PALLET_TOWN_PLAYERS_HOUSE_1F)) + { + warp->x = 8; + warp->y = 5; + } + else if (sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][0] == MAP_GROUP(INDIGO_PLATEAU_POKEMON_CENTER_1F) && sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][1] == MAP_NUM(INDIGO_PLATEAU_POKEMON_CENTER_1F)) + { + warp->x = 13; + warp->y = 12; + } + else if (sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][0] == MAP_GROUP(ONE_ISLAND_POKEMON_CENTER_1F) && sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][1] == MAP_NUM(ONE_ISLAND_POKEMON_CENTER_1F)) + { + warp->x = 5; + warp->y = 4; + } + else if (sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][0] == MAP_GROUP(SEVEN_ISLAND_TRAINER_TOWER_LOBBY) && sBlackoutRespawnHealCenterMapIdxs[healLocationIdx - 1][1] == MAP_NUM(SEVEN_ISLAND_TRAINER_TOWER_LOBBY)) + { + warp->x = 4; + warp->y = 11; + VarSet(VAR_0x4082, 0); + } + else + { + warp->x = 7; + warp->y = 4; + } + SetBlackoutRespawnHealerNpcAsLastTalked(healLocationIdx); + } +} + +void SetBlackoutRespawnHealerNpcAsLastTalked(u32 healLocationIdx) +{ + gSpecialVar_LastTalked = sBlackoutRespawnHealerNpcIds[healLocationIdx - 1]; +} diff --git a/src/help_system.c b/src/help_system.c new file mode 100644 index 000000000..1fd43fffa --- /dev/null +++ b/src/help_system.c @@ -0,0 +1,1202 @@ +#include "global.h" +#include "decompress.h" +#include "gpu_regs.h" +#include "main.h" +#include "m4a.h" +#include "dma3.h" +#include "help_system.h" +#include "list_menu.h" +#include "sound.h" +#include "strings.h" +#include "text.h" +#include "blit.h" +#include "event_data.h" +#include "constants/songs.h" +#include "constants/flags.h" + +extern u8 gGlyphInfo[]; + +struct HelpSystemVideoState +{ + /*0x00*/ MainCallback savedVblankCb; + /*0x04*/ MainCallback savedHblankCb; + /*0x08*/ u16 savedDispCnt; + /*0x0a*/ u16 savedBg0Cnt; + /*0x0c*/ u16 savedBg0Hofs; + /*0x0e*/ u16 savedBg0Vofs; + /*0x10*/ u16 savedBldCnt; + /*0x12*/ struct TextColor savedTextColor; + /*0x15*/ u8 state; +}; + +static EWRAM_DATA u8 sMapTilesBackup[BG_CHAR_SIZE] = {0}; +EWRAM_DATA u8 gUnknown_203F174 = 0; +EWRAM_DATA u8 gUnknown_203F175 = 0; +static EWRAM_DATA u8 sDelayTimer = 0; +static EWRAM_DATA u8 sInHelpSystem = 0; +static EWRAM_DATA struct HelpSystemVideoState sVideoState = {0}; +EWRAM_DATA struct HelpSystemListMenu gHelpSystemListMenu = {0}; +EWRAM_DATA struct ListMenuItem gHelpSystemListMenuItems[52] = {0}; + +static const u16 sTiles[] = INCBIN_U16("graphics/help_system/unk_8464008.4bpp"); +static const u16 sPals[] = INCBIN_U16("graphics/help_system/unk_8464008.gbapal"); + +u8 RunHelpSystemCallback(void) +{ + s32 i; + + switch (sVideoState.state) + { + case 0: + sInHelpSystem = 0; + if (gSaveBlock2Ptr->optionsButtonMode != OPTIONS_BUTTON_MODE_NORMAL) + return 0; + if (JOY_NEW(R_BUTTON) && gUnknown_203F175 == 1) + return 0; + if (JOY_NEW(L_BUTTON | R_BUTTON)) + { + if (!sub_812B45C() || !gUnknown_3005ECC) + { + PlaySE(SE_HELP_PAGE); + return 0; + } + m4aMPlayStop(&gMPlayInfo_SE1); + m4aMPlayStop(&gMPlayInfo_SE2); + PlaySE(SE_HELP_OPEN); + if (!gUnknown_203F174) + m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 0x80); + SaveCallbacks(); + sInHelpSystem = 1; + sVideoState.state = 1; + } + break; + case 1: + SaveMapTiles(); + SaveMapGPURegs(); + SaveMapTextColors(); + (*(vu16 *)PLTT) = sPals[15]; + SetGpuReg(REG_OFFSET_DISPCNT, 0); + sVideoState.state = 2; + break; + case 2: + RequestDma3Fill(0, (void *)BG_CHAR_ADDR(3), BG_CHAR_SIZE, 0); + RequestDma3Copy(sPals, (void *)PLTT, sizeof(sPals), 0); + RequestDma3Copy(sTiles, gDecompressionBuffer + 0x3EE0, sizeof(sTiles), 0); + sVideoState.state = 3; + break; + case 3: + sub_813BCF4(); + HelpSystem_FillPanel3(); + HelpSystem_FillPanel2(); + HelpSystem_PrintText_Row61(gString_Help); + sub_813BD14(1); + if (sub_812B40C() == TRUE) + sub_812BC54(&gHelpSystemListMenu, gHelpSystemListMenuItems); + else + sub_812BCA8(&gHelpSystemListMenu, gHelpSystemListMenuItems); + sub_813BE78(1); + sub_813BF50(1); + CommitTilemap(); + sVideoState.state = 4; + break; + case 4: + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BG0HOFS, 0); + SetGpuReg(REG_OFFSET_BG0VOFS, 0); + SetGpuReg(REG_OFFSET_BG0CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(3) | BGCNT_16COLOR | BGCNT_SCREENBASE(31)); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_BG0_ON); + sVideoState.state = 5; + break; + case 5: + if (!sub_812BB9C(&gHelpSystemListMenu, gHelpSystemListMenuItems)) + { + PlaySE(SE_HELP_CLOSE); + sVideoState.state = 6; + } + break; + case 6: + SetGpuReg(REG_OFFSET_DISPCNT, 0); + RestoreMapTiles(); + for (i = 0; i < 0x200; i += 2) + { + *((vu16 *)(PLTT + 0x000 + i)) = sPals[15]; + *((vu16 *)(PLTT + 0x200 + i)) = sPals[15]; + } + sVideoState.state = 7; + break; + case 7: + if (!gUnknown_203F174) + m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 0x100); + RestoreMapTextColors(); + RestoreGPURegs(); + sVideoState.state = 8; + break; + case 8: + RestoreCallbacks(); + sInHelpSystem = 0; + sVideoState.state = 0; + break; + } + return sVideoState.state; +} + +void SaveCallbacks(void) +{ + vu16 * dma; + sVideoState.savedVblankCb = gMain.vblankCallback; + sVideoState.savedHblankCb = gMain.hblankCallback; + gMain.vblankCallback = NULL; + gMain.hblankCallback = NULL; + + dma = (void *)REG_ADDR_DMA0; + dma[5] &= ~(DMA_START_MASK | DMA_DREQ_ON | DMA_REPEAT); + dma[5] &= ~DMA_ENABLE; + dma[5]; +} + +void SaveMapGPURegs(void) +{ + sVideoState.savedDispCnt = GetGpuReg(REG_OFFSET_DISPCNT); + sVideoState.savedBg0Cnt = GetGpuReg(REG_OFFSET_BG0CNT); + sVideoState.savedBg0Hofs = GetGpuReg(REG_OFFSET_BG0HOFS); + sVideoState.savedBg0Vofs = GetGpuReg(REG_OFFSET_BG0VOFS); + sVideoState.savedBldCnt = GetGpuReg(REG_OFFSET_BLDCNT); +} + +void SaveMapTiles(void) +{ + RequestDma3Copy((void *)BG_CHAR_ADDR(3), sMapTilesBackup, BG_CHAR_SIZE, 0); +} + +void SaveMapTextColors(void) +{ + SaveTextColors( + &sVideoState.savedTextColor.fgColor, + &sVideoState.savedTextColor.bgColor, + &sVideoState.savedTextColor.shadowColor + ); +} + +void RestoreCallbacks(void) +{ + gMain.vblankCallback = sVideoState.savedVblankCb; + gMain.hblankCallback = sVideoState.savedHblankCb; +} + +void RestoreGPURegs(void) +{ + SetGpuReg(REG_OFFSET_BLDCNT, sVideoState.savedBldCnt); + SetGpuReg(REG_OFFSET_BG0HOFS, sVideoState.savedBg0Hofs); + SetGpuReg(REG_OFFSET_BG0VOFS, sVideoState.savedBg0Vofs); + SetGpuReg(REG_OFFSET_BG0CNT, sVideoState.savedBg0Cnt); + SetGpuReg(REG_OFFSET_DISPCNT, sVideoState.savedDispCnt); +} + +void RestoreMapTiles(void) +{ + RequestDma3Copy(sMapTilesBackup, (void *)BG_CHAR_ADDR(3), BG_CHAR_SIZE, 0); +} + +void RestoreMapTextColors(void) +{ + RestoreTextColors( + &sVideoState.savedTextColor.fgColor, + &sVideoState.savedTextColor.bgColor, + &sVideoState.savedTextColor.shadowColor + ); +} + +void CommitTilemap(void) +{ + RequestDma3Copy(gDecompressionBuffer, (void *)BG_CHAR_ADDR(3), BG_CHAR_SIZE, 0); +} + +void HS_DrawBgTilemapRect(u16 baseTile, u8 left, u8 top, u8 width, u8 height, u16 increment) +{ + u16 i, j; + + for (i = top; i < top + height; i++) + { + for (j = left; j < left + width; j++) + { + *((u16 *)(gDecompressionBuffer + 0x3800 + 64 * i + 2 * j)) = baseTile; + baseTile += increment; + } + } + + CommitTilemap(); +} + +void sub_813BCF4(void) +{ + HS_DrawBgTilemapRect(0x1FF, 0, 0, 30, 20, 0); +} + +void sub_813BD14(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 1, 0, 7, 2, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x1E8, 1, 0, 7, 2, 1); + break; + } +} + +void sub_813BD5C(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 13, 0, 16, 2, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x1A0, 13, 0, 16, 2, 1); + break; + } +} + +void sub_813BDA4(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 2, 3, 26, 16, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x000, 2, 3, 26, 16, 1); + break; + } +} + +void sub_813BDE8(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 1, 3, 28, 16, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x1FA, 1, 3, 28, 17, 0); + break; + } +} + +void sub_813BE30(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 2, 14, 26, 5, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x11E, 2, 14, 26, 5, 1); + break; + } +} + +void sub_813BE78(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 1, 2, 28, 1, 0); + HS_DrawBgTilemapRect(0x1FF, 1, 19, 28, 1, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x1F7, 1, 2, 28, 1, 0); + HS_DrawBgTilemapRect(0x1F8, 1, 19, 28, 1, 0); + break; + } +} + +void sub_813BEE4(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 1, 2, 28, 1, 0); + HS_DrawBgTilemapRect(0x1FF, 1, 19, 28, 1, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x1FB, 1, 2, 28, 1, 0); + HS_DrawBgTilemapRect(0x1FC, 1, 19, 28, 1, 0); + break; + } +} + +void sub_813BF50(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 0, 0, 1, 20, 0); + HS_DrawBgTilemapRect(0x1FF, 29, 0, 1, 20, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x1F9, 0, 0, 1, 20, 0); + HS_DrawBgTilemapRect(0x1F9, 29, 0, 1, 20, 0); + break; + } +} + +void sub_813BFC0(u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 1, 5, 28, 1, 0); + break; + case 1: + HS_DrawBgTilemapRect(0x1FC, 1, 5, 28, 1, 0); + break; + } +} + +void sub_813C004(u8 a0, u8 mode) +{ + switch (mode) + { + case 0: + HS_DrawBgTilemapRect(0x1FF, 28, 3, 1, 1, 0); + HS_DrawBgTilemapRect(0x1FF, 28, 18, 1, 1, 0); + break; + case 1: + if (a0 == 0) + HS_DrawBgTilemapRect(0x1FE, 28, 3, 1, 1, 0); + else + HS_DrawBgTilemapRect(0x1FD, 28, 18, 1, 1, 0); + break; + } +} + +#define HelpSystemHandleRenderGlyph(character) ({\ + do {DecompressAndRenderGlyph(font, character, &srcBlit, &destBlit, dest, x, y, width, height);} while (0); font;\ +}) + +#ifdef NONMATCHING +void HelpSystemRenderText(u8 font, u8 * dest, const u8 * src, u8 x, u8 y, u8 width, u8 height) +{ + // font -> sp+24 + // dest -> sp+28 + // src -> r9 + // x -> sp+34 + // y -> r10 + // width -> sp+2C + // height -> sp+30 + struct Bitmap srcBlit; + struct Bitmap destBlit; + u8 i; + u8 orig_x = x; + s32 clearPixels; + + while (1) + { + u16 curChar = *src++; + switch (curChar) + { + case EOS: + return; + case PLACEHOLDER_BEGIN: + curChar = *src++; + if (curChar == 1) { + for (i = 0; i < 10; i++) + { + if (gSaveBlock2Ptr->playerName[i] == EOS) + break; + HelpSystemHandleRenderGlyph(gSaveBlock2Ptr->playerName[i]); + x += gGlyphInfo[0x80]; + } + } + else if (curChar == 2) + { + for (i = 0; ; i++) + { + if (FlagGet(FLAG_SYS_NOT_SOMEONES_PC) == TRUE) + { + if (gString_Bill[i] == EOS) + break; + HelpSystemHandleRenderGlyph(gString_Bill[i]); + } + else + { + if (gString_Someone[i] == EOS) + break; + HelpSystemHandleRenderGlyph(gString_Someone[i]); + } + x += gGlyphInfo[0x80]; + } + } + break; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + case CHAR_NEWLINE: + x = orig_x; + y += gGlyphInfo[0x81] + 1; + break; + case EXT_CTRL_CODE_BEGIN: + curChar = *src++; + switch (curChar) + { + case 4: + src++; + //fallthrough + case 11: + case 16: + src++; + //fallthrough + case 1: + case 2: + case 3: + case 5: + case 6: + case 8: + case 12: + case 13: + case 14: + src++; + break; + case 19: + clearPixels = *src + orig_x - x; + if (clearPixels > 0) + { + destBlit.pixels = dest; + destBlit.width = width * 8; + destBlit.height = height * 8; + FillBitmapRect4Bit(&destBlit, x, y, clearPixels, GetFontAttribute(font, 1), 0); + x += clearPixels; + } + src++; + break; + case 17: + case 18: + case 20: + src++; + break; + case 7: + case 9: + case 10: + case 15: + case 21: + case 22: + break; + } + break; + case CHAR_KEYPAD_ICON: + curChar = *src++; + srcBlit.pixels = (u8 *)gKeypadIconTiles + 0x20 * GetKeypadIconTileOffset(curChar); + srcBlit.width = 0x80; + srcBlit.height = 0x80; + destBlit.pixels = dest; + destBlit.width = width * 8; + destBlit.height = height * 8; + BlitBitmapRect4Bit(&srcBlit, &destBlit, 0, 0, x, y, GetKeypadIconWidth(curChar), GetKeypadIconHeight(curChar), 0); + x += GetKeypadIconWidth(curChar); + break; + case CHAR_EXTRA_EMOJI: + curChar = 0x100 | *src++; + //fallthrough + default: + if (curChar == CHAR_SPACE) + { + if (font == 0) + x += 5; + else + x += 4; + } + else + { + HelpSystemHandleRenderGlyph(curChar); + x += gGlyphInfo[0x80]; + } + break; + } + } +} +#else +NAKED +void HelpSystemRenderText(u8 font, u8 * dest, const u8 * src, u8 x, u8 y, u8 width, u8 height) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tmov r7, r10\n" + "\tmov r6, r9\n" + "\tmov r5, r8\n" + "\tpush {r5-r7}\n" + "\tsub sp, 0x38\n" + "\tstr r1, [sp, 0x28]\n" + "\tmov r9, r2\n" + "\tldr r1, [sp, 0x58]\n" + "\tldr r2, [sp, 0x5C]\n" + "\tldr r4, [sp, 0x60]\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tstr r0, [sp, 0x24]\n" + "\tlsls r3, 24\n" + "\tlsrs r7, r3, 24\n" + "\tlsls r1, 24\n" + "\tlsrs r1, 24\n" + "\tmov r10, r1\n" + "\tlsls r2, 24\n" + "\tlsrs r2, 24\n" + "\tstr r2, [sp, 0x2C]\n" + "\tlsls r4, 24\n" + "\tlsrs r4, 24\n" + "\tstr r4, [sp, 0x30]\n" + "\tstr r7, [sp, 0x34]\n" + "_0813C0AC_masterLoop:\n" + "\tmov r0, r9\n" + "\tldrb r1, [r0]\n" + "\tmovs r2, 0x1\n" + "\tadd r9, r2\n" + "\tadds r0, r1, 0\n" + "\tsubs r0, 0xF8\n" + "\tcmp r0, 0x7\n" + "\tbls _0813C0BE\n" + "\tb _0813C358\n" + "_0813C0BE:\n" + "\tlsls r0, 2\n" + "\tldr r1, _0813C0C8 @ =_0813C0CC\n" + "\tadds r0, r1\n" + "\tldr r0, [r0]\n" + "\tmov pc, r0\n" + "\t.align 2, 0\n" + "_0813C0C8: .4byte _0813C0CC\n" + "\t.align 2, 0\n" + "_0813C0CC:\n" + "\t.4byte _0813C2D4\n" + "\t.4byte _0813C348\n" + "\t.4byte _0813C1E4\n" + "\t.4byte _0813C1E4\n" + "\t.4byte _0813C200\n" + "\t.4byte _0813C0EC\n" + "\t.4byte _0813C1E4\n" + "\t.4byte _0813C39C\n" + "_0813C0EC:\n" + "\tmov r0, r9\n" + "\tldrb r1, [r0]\n" + "\tmovs r2, 0x1\n" + "\tadd r9, r2\n" + "\tcmp r1, 0x1\n" + "\tbne _0813C154\n" + "\tmovs r4, 0\n" + "\tldr r0, _0813C14C @ =gSaveBlock2Ptr\n" + "\tldr r1, [r0]\n" + "\tldrb r1, [r1]\n" + "\tcmp r1, 0xFF\n" + "\tbeq _0813C0AC_masterLoop\n" + "\tldr r5, _0813C150 @ =gGlyphInfo + 0x80\n" + "_0813C106:\n" + "\tldr r0, [r0]\n" + "\tadds r0, r4\n" + "\tldrb r1, [r0]\n" + "\tldr r0, [sp, 0x28]\n" + "\tstr r0, [sp]\n" + "\tstr r7, [sp, 0x4]\n" + "\tmov r2, r10\n" + "\tstr r2, [sp, 0x8]\n" + "\tldr r0, [sp, 0x2C]\n" + "\tstr r0, [sp, 0xC]\n" + "\tldr r2, [sp, 0x30]\n" + "\tstr r2, [sp, 0x10]\n" + "\tldr r0, [sp, 0x24]\n" + "\tadd r2, sp, 0x14\n" + "\tadd r3, sp, 0x1C\n" + "\tbl DecompressAndRenderGlyph\n" + "\tldr r0, [sp, 0x24]\n" + "\tldrb r0, [r5]\n" + "\tadds r0, r7, r0\n" + "\tlsls r0, 24\n" + "\tlsrs r7, r0, 24\n" + "\tadds r0, r4, 0x1\n" + "\tlsls r0, 24\n" + "\tlsrs r4, r0, 24\n" + "\tcmp r4, 0x9\n" + "\tbhi _0813C0AC_masterLoop\n" + "\tldr r0, _0813C14C @ =gSaveBlock2Ptr\n" + "\tldr r1, [r0]\n" + "\tadds r1, r4\n" + "\tldrb r1, [r1]\n" + "\tcmp r1, 0xFF\n" + "\tbne _0813C106\n" + "\tb _0813C0AC_masterLoop\n" + "\t.align 2, 0\n" + "_0813C14C: .4byte gSaveBlock2Ptr\n" + "_0813C150: .4byte gGlyphInfo + 0x80\n" + "_0813C154:\n" + "\tcmp r1, 0x2\n" + "\tbne _0813C0AC_masterLoop\n" + "\tmovs r4, 0\n" + "\tldr r5, _0813C160 @ =gGlyphInfo + 0x80\n" + "\tb _0813C1BC\n" + "\t.align 2, 0\n" + "_0813C160: .4byte gGlyphInfo + 0x80\n" + "_0813C164:\n" + "\tldrb r1, [r1]\n" + "\tldr r2, [sp, 0x28]\n" + "\tstr r2, [sp]\n" + "\tstr r7, [sp, 0x4]\n" + "\tmov r0, r10\n" + "\tstr r0, [sp, 0x8]\n" + "\tldr r2, [sp, 0x2C]\n" + "\tstr r2, [sp, 0xC]\n" + "\tldr r0, [sp, 0x30]\n" + "\tstr r0, [sp, 0x10]\n" + "\tldr r0, [sp, 0x24]\n" + "\tadd r2, sp, 0x14\n" + "\tadd r3, sp, 0x1C\n" + "\tbl DecompressAndRenderGlyph\n" + "\tb _0813C1AC\n" + "_0813C184:\n" + "\tldr r0, _0813C1D8 @ =gString_Someone\n" + "\tadds r1, r4, r0\n" + "\tldrb r0, [r1]\n" + "\tcmp r0, 0xFF\n" + "\tbeq _0813C0AC_masterLoop\n" + "\tadds r1, r0, 0\n" + "\tldr r2, [sp, 0x28]\n" + "\tstr r2, [sp]\n" + "\tstr r7, [sp, 0x4]\n" + "\tmov r0, r10\n" + "\tstr r0, [sp, 0x8]\n" + "\tldr r2, [sp, 0x2C]\n" + "\tstr r2, [sp, 0xC]\n" + "\tldr r0, [sp, 0x30]\n" + "\tstr r0, [sp, 0x10]\n" + "\tldr r0, [sp, 0x24]\n" + "\tadd r2, sp, 0x14\n" + "\tadd r3, sp, 0x1C\n" + "\tbl DecompressAndRenderGlyph\n" + "_0813C1AC:\n" + "\tldr r1, [sp, 0x24]\n" + "\tldrb r0, [r5]\n" + "\tadds r0, r7, r0\n" + "\tlsls r0, 24\n" + "\tlsrs r7, r0, 24\n" + "\tadds r0, r4, 0x1\n" + "\tlsls r0, 24\n" + "\tlsrs r4, r0, 24\n" + "_0813C1BC:\n" + "\tldr r0, _0813C1DC @ =0x00000834\n" + "\tbl FlagGet\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tcmp r0, 0x1\n" + "\tbne _0813C184\n" + "\tldr r0, _0813C1E0 @ =gString_Bill\n" + "\tadds r1, r4, r0\n" + "\tldrb r0, [r1]\n" + "\tcmp r0, 0xFF\n" + "\tbne _0813C164\n" + "\tb _0813C0AC_masterLoop\n" + "\t.align 2, 0\n" + "_0813C1D8: .4byte gString_Someone\n" + "_0813C1DC: .4byte 0x00000834\n" + "_0813C1E0: .4byte gString_Bill\n" + "_0813C1E4:\n" + "\tldr r7, [sp, 0x34]\n" + "\tldr r1, _0813C1FC @ =gGlyphInfo\n" + "\tadds r1, 0x81\n" + "\tmov r0, r10\n" + "\tadds r0, 0x1\n" + "\tldrb r1, [r1]\n" + "\tadds r0, r1\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tmov r10, r0\n" + "\tb _0813C0AC_masterLoop\n" + "\t.align 2, 0\n" + "_0813C1FC: .4byte gGlyphInfo\n" + "_0813C200:\n" + "\tmov r2, r9\n" + "\tldrb r1, [r2]\n" + "\tmovs r0, 0x1\n" + "\tadd r9, r0\n" + "\tsubs r0, r1, 0x1\n" + "\tcmp r0, 0x15\n" + "\tbls _0813C210\n" + "\tb _0813C0AC_masterLoop\n" + "_0813C210:\n" + "\tlsls r0, 2\n" + "\tldr r1, _0813C21C @ =_0813C220\n" + "\tadds r0, r1\n" + "\tldr r0, [r0]\n" + "\tmov pc, r0\n" + "\t.align 2, 0\n" + "_0813C21C: .4byte _0813C220\n" + "\t.align 2, 0\n" + "_0813C220:\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C278\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C0AC_masterLoop\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C0AC_masterLoop\n" + "\t.4byte _0813C0AC_masterLoop\n" + "\t.4byte _0813C27C\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C2C8\n" + "\t.4byte _0813C0AC_masterLoop\n" + "\t.4byte _0813C27C\n" + "\t.4byte _0813C2CE\n" + "\t.4byte _0813C2CE\n" + "\t.4byte _0813C282\n" + "\t.4byte _0813C2CE\n" + "\t.4byte _0813C0AC_masterLoop\n" + "\t.4byte _0813C0AC_masterLoop\n" + "_0813C278:\n" + "\tmovs r1, 0x1\n" + "\tadd r9, r1\n" + "_0813C27C:\n" + "\tmovs r2, 0x1\n" + "\tadd r9, r2\n" + "\tb _0813C2C8\n" + "_0813C282:\n" + "\tmov r2, r9\n" + "\tldrb r0, [r2]\n" + "\tldr r1, [sp, 0x34]\n" + "\tadds r0, r1\n" + "\tsubs r6, r0, r7\n" + "\tcmp r6, 0\n" + "\tble _0813C2C8\n" + "\tldr r2, [sp, 0x28]\n" + "\tstr r2, [sp, 0x1C]\n" + "\tldr r1, [sp, 0x2C]\n" + "\tlsls r0, r1, 3\n" + "\tadd r4, sp, 0x1C\n" + "\tmovs r5, 0\n" + "\tstrh r0, [r4, 0x4]\n" + "\tldr r2, [sp, 0x30]\n" + "\tlsls r0, r2, 3\n" + "\tstrh r0, [r4, 0x6]\n" + "\tldr r0, [sp, 0x24]\n" + "\tmovs r1, 0x1\n" + "\tbl GetFontAttribute\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tlsls r3, r6, 16\n" + "\tlsrs r3, 16\n" + "\tstr r0, [sp]\n" + "\tstr r5, [sp, 0x4]\n" + "\tadds r0, r4, 0\n" + "\tadds r1, r7, 0\n" + "\tmov r2, r10\n" + "\tbl FillBitmapRect4Bit\n" + "\tadds r0, r7, r6\n" + "\tlsls r0, 24\n" + "\tlsrs r7, r0, 24\n" + "_0813C2C8:\n" + "\tmovs r0, 0x1\n" + "\tadd r9, r0\n" + "\tb _0813C0AC_masterLoop\n" + "_0813C2CE:\n" + "\tmovs r1, 0x1\n" + "\tadd r9, r1\n" + "\tb _0813C0AC_masterLoop\n" + "_0813C2D4:\n" + "\tmov r2, r9\n" + "\tldrb r1, [r2]\n" + "\tmovs r0, 0x1\n" + "\tadd r9, r0\n" + "\tadds r6, r1, 0\n" + "\tadds r0, r6, 0\n" + "\tbl GetKeypadIconTileOffset\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 19\n" + "\tldr r1, _0813C344 @ =gKeypadIconTiles\n" + "\tadds r0, r1\n" + "\tstr r0, [sp, 0x14]\n" + "\tadd r1, sp, 0x14\n" + "\tmovs r2, 0\n" + "\tmov r8, r2\n" + "\tmovs r0, 0x80\n" + "\tstrh r0, [r1, 0x4]\n" + "\tstrh r0, [r1, 0x6]\n" + "\tldr r0, [sp, 0x28]\n" + "\tstr r0, [sp, 0x1C]\n" + "\tldr r1, [sp, 0x2C]\n" + "\tlsls r0, r1, 3\n" + "\tadd r5, sp, 0x1C\n" + "\tstrh r0, [r5, 0x4]\n" + "\tldr r2, [sp, 0x30]\n" + "\tlsls r0, r2, 3\n" + "\tstrh r0, [r5, 0x6]\n" + "\tadds r0, r6, 0\n" + "\tbl GetKeypadIconWidth\n" + "\tadds r4, r0, 0\n" + "\tlsls r4, 24\n" + "\tlsrs r4, 24\n" + "\tadds r0, r6, 0\n" + "\tbl GetKeypadIconHeight\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tstr r7, [sp]\n" + "\tmov r1, r10\n" + "\tstr r1, [sp, 0x4]\n" + "\tstr r4, [sp, 0x8]\n" + "\tstr r0, [sp, 0xC]\n" + "\tmov r2, r8\n" + "\tstr r2, [sp, 0x10]\n" + "\tadd r0, sp, 0x14\n" + "\tadds r1, r5, 0\n" + "\tmovs r2, 0\n" + "\tmovs r3, 0\n" + "\tbl BlitBitmapRect4Bit\n" + "\tadds r0, r6, 0\n" + "\tbl GetKeypadIconWidth\n" + "\tb _0813C38E\n" + "\t.align 2, 0\n" + "_0813C344: .4byte gKeypadIconTiles\n" + "_0813C348:\n" + "\tmov r0, r9\n" + "\tldrb r1, [r0]\n" + "\tmovs r2, 0x80\n" + "\tlsls r2, 1\n" + "\tadds r0, r2, 0\n" + "\torrs r1, r0\n" + "\tmovs r0, 0x1\n" + "\tadd r9, r0\n" + "_0813C358:\n" + "\tcmp r1, 0\n" + "\tbne _0813C36A\n" + "\tldr r1, [sp, 0x24]\n" + "\tcmp r1, 0\n" + "\tbne _0813C366\n" + "\tadds r0, r7, 0x5\n" + "\tb _0813C390\n" + "_0813C366:\n" + "\tadds r0, r7, 0x4\n" + "\tb _0813C390\n" + "_0813C36A:\n" + "\tadd r3, sp, 0x1C\n" + "\tldr r2, [sp, 0x28]\n" + "\tstr r2, [sp]\n" + "\tstr r7, [sp, 0x4]\n" + "\tmov r0, r10\n" + "\tstr r0, [sp, 0x8]\n" + "\tldr r2, [sp, 0x2C]\n" + "\tstr r2, [sp, 0xC]\n" + "\tldr r0, [sp, 0x30]\n" + "\tstr r0, [sp, 0x10]\n" + "\tldr r0, [sp, 0x24]\n" + "\tadd r2, sp, 0x14\n" + "\tbl DecompressAndRenderGlyph\n" + "\tldr r1, [sp, 0x24]\n" + "\tldr r0, _0813C398 @ =gGlyphInfo\n" + "\tadds r0, 0x80\n" + "\tldrb r0, [r0]\n" + "_0813C38E:\n" + "\tadds r0, r7, r0\n" + "_0813C390:\n" + "\tlsls r0, 24\n" + "\tlsrs r7, r0, 24\n" + "\tb _0813C0AC_masterLoop\n" + "\t.align 2, 0\n" + "_0813C398: .4byte gGlyphInfo\n" + "_0813C39C:\n" + "\tadd sp, 0x38\n" + "\tpop {r3-r5}\n" + "\tmov r8, r3\n" + "\tmov r9, r4\n" + "\tmov r10, r5\n" + "\tpop {r4-r7}\n" + "\tpop {r0}\n" + "\tbx r0"); +} +#endif //NONMATCHING + +void DecompressAndRenderGlyph(u8 font, u16 glyph, struct Bitmap *srcBlit, struct Bitmap *destBlit, u8 *destBuffer, u8 x, u8 y, u8 width, u8 height) +{ + if (font == 0) + DecompressGlyphFont0(glyph, FALSE); + else if (font == 5) + DecompressGlyphFont5(glyph, FALSE); + else + DecompressGlyphFont2(glyph, FALSE); + srcBlit->pixels = gGlyphInfo; + srcBlit->width = 16; + srcBlit->height = 16; + destBlit->pixels = destBuffer; + destBlit->width = width * 8; + destBlit->height = height * 8; + BlitBitmapRect4Bit(srcBlit, destBlit, 0, 0, x, y, gGlyphInfo[0x80], gGlyphInfo[0x81], 0); +} + +void HelpSystem_PrintText_Row61(const u8 * str) +{ + GenerateFontHalfRowLookupTable(1, 15, 2); + HelpSystemRenderText(5, gDecompressionBuffer + 0x3D00, str, 6, 2, 7, 2); +} + +void HelpSystem_PrintTextRightAlign_Row52(const u8 * str) +{ + s32 left = 0x7C - GetStringWidth(0, str, 0); + GenerateFontHalfRowLookupTable(1, 15, 2); + HelpSystemRenderText(0, gDecompressionBuffer + 0x3400, str, left, 2, 16, 2); +} + +void HelpSystem_PrintTextAt(const u8 * str, u8 x, u8 y) +{ + GenerateFontHalfRowLookupTable(1, 15, 2); + HelpSystemRenderText(2, gDecompressionBuffer + 0x0000, str, x, y, 26, 16); +} + +void HelpSystem_PrintTwoStrings(const u8 * str1, const u8 * str2) +{ + CpuFill16(0xEEEE, gDecompressionBuffer + 0x0000, 0x3400); + GenerateFontHalfRowLookupTable(1, 14, 2); + HelpSystemRenderText(2, gDecompressionBuffer + 0x0000, str1, 0, 0, 26, 16); + HelpSystemRenderText(2, gDecompressionBuffer + 0x09C0, str2, 0, 0, 26, 13); +} + +void HelpSystem_PrintText_813C584(const u8 * str) +{ + CpuFill16(0x1111, gDecompressionBuffer + 0x23C0, 0x1040); + GenerateFontHalfRowLookupTable(2, 1, 3); + HelpSystemRenderText(2, gDecompressionBuffer + 0x23C0, str, 2, 6, 26, 5); +} + +void HelpSystem_FillPanel3(void) +{ + CpuFill16(0xFFFF, gDecompressionBuffer + 0x3D00, 0x1C0); +} + +void HelpSystem_FillPanel2(void) +{ + CpuFill16(0xFFFF, gDecompressionBuffer + 0x3400, 0x400); +} + +void HelpSystem_FillPanel1(void) +{ + CpuFill16(0xFFFF, gDecompressionBuffer + 0x0000, 0x3400); +} + +void HelpSystem_InitListMenuController(struct HelpSystemListMenu * a0, u8 a1, u8 a2) +{ + gHelpSystemListMenu.sub = a0->sub; + gHelpSystemListMenu.field_0C = a1; + gHelpSystemListMenu.field_0D = a2; + gHelpSystemListMenu.field_0E = 0; + if (gHelpSystemListMenu.sub.totalItems < gHelpSystemListMenu.sub.maxShowed) + gHelpSystemListMenu.sub.maxShowed = gHelpSystemListMenu.sub.totalItems; + sub_813BDA4(0); + HelpSystem_FillPanel1(); + PrintListMenuItems(); + PlaceListMenuCursor(); +} + +void HelpSystem_SetInputDelay(u8 a0) +{ + sDelayTimer = a0; +} + +s32 HelpSystem_GetMenuInput(void) +{ + if (sDelayTimer != 0) + { + sDelayTimer--; + return -1; + } + else if (JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + return gHelpSystemListMenu.sub.items[gHelpSystemListMenu.field_0C + gHelpSystemListMenu.field_0D].index; + } + else if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + return -2; + } + else if (JOY_NEW(L_BUTTON | R_BUTTON)) + { + return -6; + } + else if (JOY_REPT(DPAD_UP)) + { + if (!MoveCursor(1, 0)) + PlaySE(SE_SELECT); + return -4; + } + else if (JOY_REPT(DPAD_DOWN)) + { + if (!MoveCursor(1, 1)) + PlaySE(SE_SELECT); + return -5; + } + else if (JOY_REPT(DPAD_LEFT)) + { + if (!MoveCursor(7, 0)) + PlaySE(SE_SELECT); + return -4; + } + else if (JOY_REPT(DPAD_RIGHT)) + { + if (!MoveCursor(7, 1)) + PlaySE(SE_SELECT); + return -5; + } + else + return -1; +} + +void sub_813C75C(void) +{ + u8 r6 = gHelpSystemListMenu.sub.totalItems - 7; + if (gHelpSystemListMenu.sub.totalItems > 7) + { + s32 r4 = gHelpSystemListMenu.field_0C + gHelpSystemListMenu.field_0D; + sub_813C004(0, 0); + if (r4 == 0) + sub_813C004(1, 1); + else if (gHelpSystemListMenu.field_0C == 0 && gHelpSystemListMenu.field_0D != 0) + sub_813C004(1, 1); + else if (gHelpSystemListMenu.field_0C == r6) + sub_813C004(0, 1); + else if (gHelpSystemListMenu.field_0C != 0) + { + sub_813C004(0, 1); + sub_813C004(1, 1); + } + } +} + +void PrintListMenuItems(void) +{ + u8 glyphHeight = GetFontAttribute(2, 1) + 1; + s32 i; + s32 r5 = gHelpSystemListMenu.field_0C; + + for (i = 0; i < gHelpSystemListMenu.sub.maxShowed; i++) + { + u8 x = gHelpSystemListMenu.sub.left + 8; + u8 y = gHelpSystemListMenu.sub.top + glyphHeight * i; + HelpSystem_PrintTextAt(gHelpSystemListMenu.sub.items[r5].label, x, y); + r5++; + } +} + +void PlaceListMenuCursor(void) +{ + u8 glyphHeight = GetFontAttribute(2, 1) + 1; + u8 x = gHelpSystemListMenu.sub.left; + u8 y = gHelpSystemListMenu.sub.top + glyphHeight * gHelpSystemListMenu.field_0D; + HelpSystem_PrintTextAt(gFameCheckerText_ListMenuCursor, x, y); +} + +void sub_813C860(u8 i) +{ + u8 glyphHeight = GetFontAttribute(2, 1) + 1; + u8 x = gHelpSystemListMenu.sub.left; + u8 y = gHelpSystemListMenu.sub.top + i * glyphHeight; + HelpSystem_PrintTextAt(gString_HelpSystem_ClearTo8, x, y); +} + +u8 TryMoveCursor1(u8 dirn) +{ + u16 r4; + if (dirn == 0) + { + if (gHelpSystemListMenu.sub.maxShowed == 1) + r4 = 0; + else + r4 = gHelpSystemListMenu.sub.maxShowed - (gHelpSystemListMenu.sub.maxShowed / 2 + (gHelpSystemListMenu.sub.maxShowed & 1)) - 1; + if (gHelpSystemListMenu.field_0C == 0) + { + if (gHelpSystemListMenu.field_0D != 0) + { + gHelpSystemListMenu.field_0D--; + return 1; + } + else + return 0; + } + if (gHelpSystemListMenu.field_0D > r4) + { + gHelpSystemListMenu.field_0D--; + return 1; + } + else + { + gHelpSystemListMenu.field_0C--; + return 2; + } + } + else + { + if (gHelpSystemListMenu.sub.maxShowed == 1) + r4 = 0; + else + r4 = gHelpSystemListMenu.sub.maxShowed / 2 + (gHelpSystemListMenu.sub.maxShowed & 1); + if (gHelpSystemListMenu.field_0C == gHelpSystemListMenu.sub.totalItems - gHelpSystemListMenu.sub.maxShowed) + { + if (gHelpSystemListMenu.field_0D < gHelpSystemListMenu.sub.maxShowed - 1) + { + gHelpSystemListMenu.field_0D++; + return 1; + } + else + return 0; + } + else if (gHelpSystemListMenu.field_0D < r4) + { + gHelpSystemListMenu.field_0D++; + return 1; + } + else + { + gHelpSystemListMenu.field_0C++; + return 2; + } + } +} + +bool8 MoveCursor(u8 by, u8 dirn) +{ + u8 r7 = gHelpSystemListMenu.field_0D; + u8 flags = 0; + s32 i; + for (i = 0; i < by; i++) + flags |= TryMoveCursor1(dirn); + + switch (flags) + { + case 0: + default: + // neither changed + return TRUE; + case 1: + // changed field_0D only + sub_813C860(r7); + PlaceListMenuCursor(); + CommitTilemap(); + break; + case 2: + case 3: + // changed field_0C + if (sub_812BF88() == TRUE) + { + HelpSystem_SetInputDelay(2); + HelpSystem_FillPanel1(); + PrintListMenuItems(); + PlaceListMenuCursor(); + sub_812BDEC(); + sub_813C75C(); + } + else + { + sub_813BDA4(0); + HelpSystem_FillPanel1(); + PrintListMenuItems(); + PlaceListMenuCursor(); + sub_813BDA4(1); + } + CommitTilemap(); + break; + } + return FALSE; +} diff --git a/src/help_system_812B1E0.c b/src/help_system_812B1E0.c new file mode 100644 index 000000000..98d6ce8be --- /dev/null +++ b/src/help_system_812B1E0.c @@ -0,0 +1,1580 @@ +#include "global.h" +#include "event_data.h" +#include "event_scripts.h" +#include "field_player_avatar.h" +#include "help_system.h" +#include "item.h" +#include "link.h" +#include "overworld.h" +#include "pokedex.h" +#include "quest_log.h" +#include "save.h" +#include "save_location.h" +#include "sound.h" +#include "strings.h" +#include "constants/items.h" +#include "constants/maps.h" +#include "constants/songs.h" + +static EWRAM_DATA u16 gUnknown_203B0EC = 0; +static EWRAM_DATA u8 gUnknown_203B0EE = 0; + +u8 gUnknown_3005E9C[4]; +u16 gUnknown_3005EA0; + +static bool32 sub_812B27C(const u16 * mapIdxs); +static void sub_812B520(struct HelpSystemListMenu * a0, struct ListMenuItem * a1); +static void sub_812B614(struct HelpSystemListMenu * a0, struct ListMenuItem * a1); +static bool8 sub_812B754(void); +static bool8 sub_812B780(u8); +static bool8 sub_812BB10(void); + +static void sub_812BF5C(void); +static void sub_812BF74(const u8 *); +static void sub_812BF94(struct HelpSystemListMenu * a0); +static void sub_812BF9C(struct HelpSystemListMenu * a0, struct ListMenuItem * a1); + +static const u8 *const gUnknown_845B080[] = { + gUnknown_81B2DF8, + gUnknown_81B2E1C, + gUnknown_81B2E2E, + gUnknown_81B2E48, + gUnknown_81B2E58, + gUnknown_81B2E6A +}; + +static const u8 *const gUnknown_845B098[] = { + gUnknown_81B2E88, + gUnknown_81B2EC8, + gUnknown_81B2F00, + gUnknown_81B2F43, + gUnknown_81B2F74, + gUnknown_81B2FA9 +}; + +static const u8 *const gUnknown_845B0B0[] = { + NULL, + gUnknown_81B3083, + gUnknown_81B30A9, + gUnknown_81B30C1, + gUnknown_81B30DC, + gUnknown_81B30FC, + gUnknown_81B311F, + gUnknown_81B3140, + gUnknown_81B314F, + gUnknown_81B3168, + gUnknown_81B3189, + gUnknown_81B31AE, + gUnknown_81B31D3, + gUnknown_81B31EC, + gUnknown_81B31FF, + gUnknown_81B3215, + gUnknown_81B3226, + gUnknown_81B3243, + gUnknown_81B3261, + gUnknown_81B3276, + gUnknown_81B3290, + gUnknown_81B32B6, + gUnknown_81B32CD, + gUnknown_81B32E3, + gUnknown_81B32F9, + gUnknown_81B330B, + gUnknown_81B332B, + gUnknown_81B3344, + gUnknown_81B335C, + gUnknown_81B3373, + gUnknown_81B338C, + gUnknown_81B33A6, + gUnknown_81B33CA, + gUnknown_81B33EA, + gUnknown_81B3402, + gUnknown_81B3427, + gUnknown_81B3440, + gUnknown_81B3457, + gUnknown_81B346F, + gUnknown_81B3481, + gUnknown_81B349B, + gUnknown_81B34B7, + gUnknown_81B34D6, + gUnknown_81B34F6, + gUnknown_81B3516 +}; + +static const u8 *const gUnknown_845B164[] = { + NULL, + gUnknown_81B3525, + gUnknown_81B35E6, + gUnknown_81B36EB, + gUnknown_81B379A, + gUnknown_81B3849, + gUnknown_81B3876, + gUnknown_81B3972, + gUnknown_81B3A51, + gUnknown_81B3ACC, + gUnknown_81B3BB6, + gUnknown_81B3C99, + gUnknown_81B3D1B, + gUnknown_81B3DE3, + gUnknown_81B3EBC, + gUnknown_81B3F7F, + gUnknown_81B406C, + gUnknown_81B410B, + gUnknown_81B41D7, + gUnknown_81B42B3, + gUnknown_81B439D, + gUnknown_81B4483, + gUnknown_81B457C, + gUnknown_81B4645, + gUnknown_81B470A, + gUnknown_81B47F0, + gUnknown_81B48C6, + gUnknown_81B497A, + gUnknown_81B4A72, + gUnknown_81B4B65, + gUnknown_81B4C54, + gUnknown_81B4D26, + gUnknown_81B4E0B, + gUnknown_81B4ED8, + gUnknown_81B4FB2, + gUnknown_81B4FFD, + gUnknown_81B50FF, + gUnknown_81B51B1, + gUnknown_81B5272, + gUnknown_81B5325, + gUnknown_81B5382, + gUnknown_81B547C, + gUnknown_81B54E1, + gUnknown_81B5589, + gUnknown_81B55F4 +}; + +static const u8 *const gUnknown_845B218[] = { + NULL, + gUnknown_81B56E3, + gUnknown_81B56F4, + gUnknown_81B5705, + gUnknown_81B5717, + gUnknown_81B5728, + gUnknown_81B5737, + gUnknown_81B5744, + gUnknown_81B5754, + gUnknown_81B5767, + gUnknown_81B577B, + gUnknown_81B5787, + gUnknown_81B5795, + gUnknown_81B57A5, + gUnknown_81B57B8, + gUnknown_81B57CF, + gUnknown_81B57DE, + gUnknown_81B57EE, + gUnknown_81B580D, + gUnknown_81B5824, + gUnknown_81B5834, + gUnknown_81B583F, + gUnknown_81B5850, + gUnknown_81B5863, + gUnknown_81B5875, + gUnknown_81B5884, + gUnknown_81B5893, + gUnknown_81B58A4, + gUnknown_81B58BC, + gUnknown_81B58D3, + gUnknown_81B58E5, + gUnknown_81B58FD, + gUnknown_81B590E, + gUnknown_81B591D, + gUnknown_81B592E, + gUnknown_81B593E, + gUnknown_81B5950, + gUnknown_81B595D, + gUnknown_81B5974, + gUnknown_81B5989, + gUnknown_81B59A7, + gUnknown_81B59BF, + gUnknown_81B59D6, + gUnknown_81B59E8, + gUnknown_81B59F5, + gUnknown_81B5A0D, + gUnknown_81B5A1B, + gUnknown_81B5A29, + gUnknown_81B5A37 +}; + +static const u8 *const gUnknown_845B2DC[] = { + NULL, + gUnknown_81B5A4D, + gUnknown_81B5B0C, + gUnknown_81B5B7D, + gUnknown_81B5C13, + gUnknown_81B5CDF, + gUnknown_81B5D87, + gUnknown_81B5E41, + gUnknown_81B5F10, + gUnknown_81B5FA6, + gUnknown_81B606C, + gUnknown_81B6140, + gUnknown_81B6203, + gUnknown_81B62E4, + gUnknown_81B6397, + gUnknown_81B6478, + gUnknown_81B6525, + gUnknown_81B65E7, + gUnknown_81B66BA, + gUnknown_81B678E, + gUnknown_81B6883, + gUnknown_81B68CD, + gUnknown_81B69B9, + gUnknown_81B6A9A, + gUnknown_81B6B6E, + gUnknown_81B6C4F, + gUnknown_81B6D4A, + gUnknown_81B6E02, + gUnknown_81B6EC1, + gUnknown_81B6FA8, + gUnknown_81B7075, + gUnknown_81B7108, + gUnknown_81B71EA, + gUnknown_81B723B, + gUnknown_81B7319, + gUnknown_81B73E8, + gUnknown_81B747E, + gUnknown_81B752C, + gUnknown_81B7611, + gUnknown_81B7692, + gUnknown_81B771E, + gUnknown_81B77DD, + gUnknown_81B7884, + gUnknown_81B7931, + gUnknown_81B79CB, + gUnknown_81B7A60, + gUnknown_81B7AEE, + gUnknown_81B7BBE, + gUnknown_81B7C57 +}; + +static const u8 *const gUnknown_845B3A0[] = { + NULL, + gUnknown_81B7CC1, + gUnknown_81B7CC4, + gUnknown_81B7CD9, + gUnknown_81B7CDF, + gUnknown_81B7CE6, + gUnknown_81B7CEE, + gUnknown_81B7CF6, + gUnknown_81B7CFE, + gUnknown_81B7D04, + gUnknown_81B7D12, + gUnknown_81B7D17, + gUnknown_81B7D1A, + gUnknown_81B7D1F, + gUnknown_81B7D27, + gUnknown_81B7D2D, + gUnknown_81B7D37, + gUnknown_81B7D3E, + gUnknown_81B7D45, + gUnknown_81B7D48, + gUnknown_81B7D4E, + gUnknown_81B7D57, + gUnknown_81B7D5B, + gUnknown_81B7D61, + gUnknown_81B7D6B, + gUnknown_81B7D76, + gUnknown_81B7D7E, + gUnknown_81B7D88, + gUnknown_81B7D8F, + gUnknown_81B7D9A, + gUnknown_81B7DA7, + gUnknown_81B7DB4, + gUnknown_81B7DBA, + gUnknown_81B7DC6, + gUnknown_81B7DCC, + gUnknown_81B7DD3, + gUnknown_81B7DD6, + gUnknown_81B7DD9, + gUnknown_81B7DE1, + gUnknown_81B7DEB, + gUnknown_81B7DFA, + gUnknown_81B7E02, + gUnknown_81B7E09, + gUnknown_81B7E0F +}; + +static const u8 *const gUnknown_845B450[] = { + NULL, + gUnknown_81B7E16, + gUnknown_81B7F0A, + gUnknown_81B800A, + gUnknown_81B80EC, + gUnknown_81B81C2, + gUnknown_81B8256, + gUnknown_81B8348, + gUnknown_81B83EF, + gUnknown_81B847B, + gUnknown_81B8550, + gUnknown_81B8647, + gUnknown_81B86E2, + gUnknown_81B87B8, + gUnknown_81B8897, + gUnknown_81B8924, + gUnknown_81B8A04, + gUnknown_81B8A84, + gUnknown_81B8B62, + gUnknown_81B8C18, + gUnknown_81B8C94, + gUnknown_81B8D1D, + gUnknown_81B8DD4, + gUnknown_81B8E67, + gUnknown_81B8F4D, + gUnknown_81B901B, + gUnknown_81B90A7, + gUnknown_81B90E8, + gUnknown_81B9170, + gUnknown_81B91C2, + gUnknown_81B91F9, + gUnknown_81B92B8, + gUnknown_81B92ED, + gUnknown_81B93D8, + gUnknown_81B9439, + gUnknown_81B9497, + gUnknown_81B9560, + gUnknown_81B9656, + gUnknown_81B9749, + gUnknown_81B984F, + gUnknown_81B991C, + gUnknown_81B99C4, + gUnknown_81B9AA2, + gUnknown_81B9B2F +}; + +static const u8 *const gUnknown_845B500[] = { + NULL, + gUnknown_81B9BB7, + gUnknown_81B9BC7, + gUnknown_81B9BD0, + gUnknown_81B9BE1, + gUnknown_81B9BF5, + gUnknown_81B9C09, + gUnknown_81B9C1D +}; + +static const u8 *const gUnknown_845B520[] = { + NULL, + gUnknown_81B9C2F, + gUnknown_81B9D04, + gUnknown_81B9DC5, + gUnknown_81B9E75, + gUnknown_81B9F09, + gUnknown_81B9FCE, + gUnknown_81BA027 +}; + +static const u8 *const gUnknown_845B540[] = { + NULL, + gUnknown_81BA0F1, + gUnknown_81BA10D, + gUnknown_81BA121, + gUnknown_81BA138, + gUnknown_81BA14C, + gUnknown_81BA163, + gUnknown_81BA17A, + gUnknown_81BA194, + gUnknown_81BA1AC, + gUnknown_81BA1C7, + gUnknown_81BA1DC, + gUnknown_81BA1F4, + gUnknown_81BA209, + gUnknown_81BA221, + gUnknown_81BA234, + gUnknown_81BA24A, + gUnknown_81BA260, + gUnknown_81BA279, + gUnknown_81BA291, + gUnknown_81BA2AC, + gUnknown_81BA2C2, + gUnknown_81BA2DB, + gUnknown_81BA2F1, + gUnknown_81BA30A, + gUnknown_81BA320, + gUnknown_81BA339, + gUnknown_81BA34E, + gUnknown_81BA366, + gUnknown_81BA37C, + gUnknown_81BA395, + gUnknown_81BA3A9, + gUnknown_81BA3C0, + gUnknown_81BA3D5, + gUnknown_81BA3ED, + gUnknown_81BA400 +}; + +static const u8 *const gUnknown_845B5D0[] = { + NULL, + gUnknown_81BA416, + gUnknown_81BA4E6, + gUnknown_81BA539, + gUnknown_81BA595, + gUnknown_81BA5F2, + gUnknown_81BA66F, + gUnknown_81BA6C9, + gUnknown_81BA71F, + gUnknown_81BA796, + gUnknown_81BA7E9, + gUnknown_81BA862, + gUnknown_81BA8D3, + gUnknown_81BA92A, + gUnknown_81BA98D, + gUnknown_81BA9F1, + gUnknown_81BAA44, + gUnknown_81BAAB6, + gUnknown_81BAB18, + gUnknown_81BAB7A, + gUnknown_81BABCC, + gUnknown_81BAC29, + gUnknown_81BAC89, + gUnknown_81BACC4, + gUnknown_81BAD20, + gUnknown_81BAD60, + gUnknown_81BADA2, + gUnknown_81BADF7, + gUnknown_81BAEA8, + gUnknown_81BAF01, + gUnknown_81BAF6B, + gUnknown_81BAFCA, + gUnknown_81BB02E, + gUnknown_81BB084, + gUnknown_81BB0DF, + gUnknown_81BB156 +}; + + +static const u8 gUnknown_845B660[] = { + 0x01, 0x02, 0x03, 0xff +}; + +static const u8 gUnknown_845B664[] = { + 0x01, 0x02, 0x03, 0xff +}; + +static const u8 gUnknown_845B668[] = { + 0x13, 0xff +}; + +static const u8 gUnknown_845B66A[] = { + 0x01, 0x02, 0x03, 0xff +}; + +static const u8 gUnknown_845B66E[] = { + 0x01, 0x25, 0xff +}; + +static const u8 gUnknown_845B671[] = { + 0x02, 0x03, 0x04, 0x05, 0x11, 0xff +}; + +static const u8 gUnknown_845B677[] = { + 0x09, 0x01, 0xff +}; + +static const u8 gUnknown_845B67A[] = { + 0x02, 0x03, 0xff +}; + +static const u8 gUnknown_845B67D[] = { + 0x09, 0x0a, 0x0b, 0x11, 0x0c, 0x10, 0xff +}; + +static const u8 gUnknown_845B684[] = { + 0x09, 0x01, 0x04, 0x05, 0x06, 0x07, 0x08, 0x02, 0x0d, 0xff +}; + +static const u8 gUnknown_845B68E[] = { + 0x09, 0x03, 0x0a, 0x0f, 0x12, 0x13, 0x14, 0xff +}; + +static const u8 gUnknown_845B696[] = { + 0x06, 0x07, 0x08, 0x2c, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x12, 0xff +}; + +static const u8 gUnknown_845B6A1[] = { + 0x16, 0x17, 0x18, 0xff +}; + +static const u8 gUnknown_845B6A5[] = { + 0x0a, 0xff +}; + +static const u8 gUnknown_845B6A7[] = { + 0x11, 0x0e, 0x19, 0x1a, 0x1b, 0xff +}; + +static const u8 gUnknown_845B6AD[] = { + 0x0a, 0xff +}; + +static const u8 gUnknown_845B6AF[] = { + 0x0b, 0xff +}; + +static const u8 gUnknown_845B6B1[] = { + 0x2b, 0x19, 0x1a, 0xff +}; + +static const u8 gUnknown_845B6B5[] = { + 0x0c, 0xff +}; + +static const u8 gUnknown_845B6B7[] = { + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0xff +}; + +static const u8 gUnknown_845B6BF[] = { + 0x02, 0x03, 0x04, 0xff +}; + +static const u8 gUnknown_845B6C3[] = { + 0x01, 0x02, 0x03, 0x07, 0xff +}; + +static const u8 gUnknown_845B6C8[] = { + 0x02, 0x04, 0x05, 0x09, 0x25, 0xff +}; + +static const u8 gUnknown_845B6CE[] = { + 0x1f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x2c, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x0b, 0x0c, 0x11, 0xff +}; + +static const u8 gUnknown_845B6E2[] = { + 0x09, 0x01, 0x02, 0x03, 0x0a, 0x28, 0xff +}; + +static const u8 gUnknown_845B6E9[] = { + 0x02, 0x05, 0x06, 0x0a, 0x23, 0x24, 0x09, 0x25, 0xff +}; + +static const u8 gUnknown_845B6F2[] = { + 0x1f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x2c, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x0b, 0x0c, 0x11, 0x14, 0xff +}; + +static const u8 gUnknown_845B707[] = { + 0x09, 0x01, 0x02, 0x03, 0x0a, 0x28, 0xff +}; + +static const u8 gUnknown_845B70E[] = { + 0x03, 0x07, 0x04, 0x05, 0x06, 0xff +}; + +static const u8 gUnknown_845B714[] = { + 0x02, 0x05, 0x06, 0x0a, 0x23, 0x24, 0x09, 0x25, 0xff +}; + +static const u8 gUnknown_845B71D[] = { + 0x1f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x2c, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x0b, 0x0c, 0x11, 0xff +}; + +static const u8 gUnknown_845B731[] = { + 0x09, 0x01, 0x02, 0x03, 0x0a, 0x0c, 0x0e, 0x16, 0x17, 0x18, 0x15, 0xff +}; + +static const u8 gUnknown_845B73D[] = { + 0x06, 0x0a, 0x23, 0x24, 0x09, 0x25, 0xff +}; + +static const u8 gUnknown_845B744[] = { + 0x1f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x2c, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x0b, 0x0c, 0x11, 0xff +}; + +static const u8 gUnknown_845B758[] = { + 0x09, 0x01, 0x02, 0x03, 0x0a, 0x15, 0xff +}; + +static const u8 gUnknown_845B75F[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0xff +}; + +static const u8 gUnknown_845B783[] = { + 0x02, 0x0a, 0x04, 0x05, 0x06, 0x07, 0x0d, 0x27, 0x08, 0x0b, 0x21, 0x23, 0x24, 0x2c, 0x09, 0x0e, 0x16, 0x17, 0x0f, 0x10, 0x11, 0x1a, 0x15, 0x1f, 0x20, 0x12, 0x13, 0x14, 0x18, 0x19, 0x1b, 0x1e, 0x1c, 0x28, 0x25, 0xff +}; + +static const u8 gUnknown_845B7A7[] = { + 0x1f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x2c, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x0b, 0x0c, 0x11, 0xff +}; + +static const u8 gUnknown_845B7BB[] = { + 0x09, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0x0d, 0x15, 0xff +}; + +static const u8 gUnknown_845B7C4[] = { + 0x02, 0x0a, 0x04, 0x05, 0x06, 0x07, 0x0d, 0x27, 0x08, 0x0b, 0x21, 0x23, 0x24, 0x2c, 0x09, 0x0e, 0x16, 0x17, 0x0f, 0x10, 0x11, 0x1a, 0x15, 0x1f, 0x20, 0x12, 0x13, 0x14, 0x18, 0x19, 0x1b, 0x1e, 0x1c, 0x28, 0x25, 0xff +}; + +static const u8 gUnknown_845B7E8[] = { + 0x1f, 0x01, 0x02, 0x06, 0x0a, 0x0b, 0x0c, 0x11, 0xff +}; + +static const u8 gUnknown_845B7F1[] = { + 0x09, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0x0d, 0x15, 0x28, 0xff +}; + +static const u8 gUnknown_845B7FB[] = { + 0x0a, 0x07, 0x0d, 0x27, 0x08, 0x0b, 0x21, 0x23, 0x24, 0x2c, 0x09, 0x0e, 0x16, 0x0f, 0x10, 0x11, 0x1a, 0x15, 0x1f, 0x20, 0x12, 0x13, 0x14, 0x18, 0x19, 0x1b, 0x1e, 0x1c, 0x28, 0x25, 0xff +}; + +static const u8 gUnknown_845B81A[] = { + 0x1f, 0x01, 0x02, 0x06, 0x0a, 0x0b, 0x0c, 0x11, 0xff +}; + +static const u8 gUnknown_845B823[] = { + 0x09, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0x0d, 0x15, 0xff +}; + +static const u8 gUnknown_845B82C[] = { + 0x07, 0x27, 0x08, 0x2c, 0x15, 0x1f, 0x20, 0x12, 0x13, 0x14, 0x18, 0x19, 0x1b, 0x1e, 0x1c, 0x28, 0x25, 0xff +}; + +static const u8 gUnknown_845B83E[] = { + 0x1f, 0x01, 0x02, 0x06, 0x0a, 0x0b, 0x0c, 0x11, 0xff +}; + +static const u8 gUnknown_845B847[] = { + 0x09, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0x0d, 0x15, 0xff +}; + +static const u8 gUnknown_845B850[] = { + 0x0f, 0x1b, 0x1d, 0x11, 0x12, 0x15, 0x17, 0x16, 0x1f, 0x20, 0x13, 0x14, 0xff +}; + +static const u8 gUnknown_845B85D[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x07, 0x09, 0x2b, 0xff +}; + +static const u8 gUnknown_845B866[] = { + 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, 0x0d, 0x0f, 0x12, 0x13, 0x14, 0x27, 0x15, 0xff +}; + +static const u8 gUnknown_845B878[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0xff +}; + +static const u8 gUnknown_845B89C[] = { + 0x0f, 0x1b, 0x1d, 0x11, 0x12, 0x16, 0x1f, 0x20, 0x13, 0x14, 0xff +}; + +static const u8 gUnknown_845B8A7[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x07, 0x2b, 0xff +}; + +static const u8 gUnknown_845B8AF[] = { + 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, 0x0d, 0x0f, 0x12, 0x13, 0x14, 0x27, 0x15, 0xff +}; + +static const u8 gUnknown_845B8C1[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0xff +}; + +static const u8 gUnknown_845B8E5[] = { + 0x0f, 0x1b, 0x1d, 0x11, 0x12, 0x16, 0x1f, 0x20, 0x13, 0x14, 0xff +}; + +static const u8 gUnknown_845B8F0[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x07, 0x2b, 0xff +}; + +static const u8 gUnknown_845B8F8[] = { + 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, 0x0d, 0x0f, 0x12, 0x13, 0x14, 0x27, 0x15, 0xff +}; + +static const u8 gUnknown_845B90A[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0xff +}; + +static const u8 gUnknown_845B92E[] = { + 0x29, 0x2a, 0x2b, 0xff +}; + +static const u8 gUnknown_845B932[] = { + 0x2d, 0x2e, 0x2f, 0x2b, 0xff +}; + +static const u8 gUnknown_845B937[] = { + 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, 0x0d, 0x0f, 0x12, 0x13, 0x14, 0xff +}; + +static const u8 gUnknown_845B947[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0xff +}; + +static const u8 gUnknown_845B96B[] = { + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x30, 0xff +}; + +static const u8 gUnknown_845B978[] = { + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x30, 0xff +}; + +static const u8 gUnknown_845B985[] = { + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x30, 0xff +}; + +static const u8 gUnknown_845B992[] = { + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x30, 0xff +}; + +static const u8 gUnknown_845B99F[] = { + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x30, 0xff +}; + +static const u8 gUnknown_845B9AC[] = { + 0x26, 0x27, 0x28, 0x29, 0x2a, 0xff +}; + +static const u8 gUnknown_845B9B2[] = { + 0x26, 0x27, 0x28, 0x29, 0x2a, 0xff +}; + +static const u8 gUnknown_845B9B8[] = { + 0x26, 0x27, 0x28, 0x29, 0x2a, 0xff +}; + +static const u8 gUnknown_845B9BE[] = { + 0x09, 0x01, 0x02, 0x03, 0x23, 0x25, 0x24, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x27, 0x15, 0x26, 0x16, 0x17, 0x18, 0x1a, 0x0e, 0x1b, 0xff +}; + +static const u8 *const gUnknown_845B9E0[] = { + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, gUnknown_845B660, NULL, + NULL, NULL, NULL, gUnknown_845B664, NULL, + NULL, gUnknown_845B668, NULL, gUnknown_845B66A, NULL, + NULL, gUnknown_845B66E, NULL, NULL, NULL, + NULL, gUnknown_845B671, gUnknown_845B677, NULL, NULL, + NULL, gUnknown_845B67A, gUnknown_845B67D, NULL, NULL, + NULL, NULL, gUnknown_845B684, NULL, NULL, + NULL, NULL, gUnknown_845B68E, NULL, NULL, + NULL, gUnknown_845B696, gUnknown_845B6A1, NULL, NULL, + NULL, gUnknown_845B6A5, gUnknown_845B6A7, NULL, NULL, + NULL, gUnknown_845B6AD, NULL, NULL, NULL, + NULL, gUnknown_845B6AF, gUnknown_845B6B1, NULL, NULL, + NULL, gUnknown_845B6B5, gUnknown_845B6B7, NULL, NULL, + gUnknown_845B6BF, NULL, NULL, gUnknown_845B6C3, NULL, + gUnknown_845B6C8, gUnknown_845B6CE, gUnknown_845B6E2, NULL, NULL, + gUnknown_845B6E9, gUnknown_845B6F2, gUnknown_845B707, gUnknown_845B70E, NULL, + gUnknown_845B714, gUnknown_845B71D, gUnknown_845B731, NULL, NULL, + gUnknown_845B73D, gUnknown_845B744, gUnknown_845B758, NULL, gUnknown_845B75F, + gUnknown_845B783, gUnknown_845B7A7, gUnknown_845B7BB, NULL, NULL, + gUnknown_845B7C4, gUnknown_845B7E8, gUnknown_845B7F1, NULL, NULL, + gUnknown_845B7FB, gUnknown_845B81A, gUnknown_845B823, NULL, NULL, + gUnknown_845B82C, gUnknown_845B83E, gUnknown_845B847, NULL, NULL, + gUnknown_845B850, gUnknown_845B85D, gUnknown_845B866, NULL, gUnknown_845B878, + gUnknown_845B89C, gUnknown_845B8A7, gUnknown_845B8AF, NULL, gUnknown_845B8C1, + gUnknown_845B8E5, gUnknown_845B8F0, gUnknown_845B8F8, NULL, gUnknown_845B90A, + gUnknown_845B92E, gUnknown_845B932, gUnknown_845B937, NULL, gUnknown_845B947, + NULL, gUnknown_845B96B, NULL, NULL, NULL, + NULL, gUnknown_845B978, NULL, NULL, NULL, + NULL, gUnknown_845B985, NULL, NULL, NULL, + NULL, gUnknown_845B992, NULL, NULL, NULL, + NULL, gUnknown_845B99F, NULL, NULL, NULL, + NULL, gUnknown_845B9AC, NULL, NULL, NULL, + NULL, gUnknown_845B9B2, NULL, NULL, NULL, + NULL, gUnknown_845B9B8, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL +}; + +static const u16 unref_845BCB0[] = INCBIN_U16("graphics/help_system/unk_845BCB0.bin"); + +static const u8 gUnknown_845C4B0[] = { + 3, 0, 1, 2, 4, 5 +}; + +static const u8 gUnknown_845C4B6[][6] = { + {0, 0, 0, 0, 0, 1}, + {0, 0, 0, 1, 0, 1}, + {0, 0, 0, 1, 0, 1}, + {0, 1, 0, 1, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 1, 0, 0, 1}, + {0, 1, 1, 0, 0, 1}, + {0, 0, 1, 0, 0, 1}, + {0, 0, 1, 0, 0, 1}, + {0, 1, 1, 0, 0, 1}, + {0, 1, 1, 0, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 1, 0, 0, 1}, + {0, 1, 1, 0, 0, 1}, + {1, 0, 0, 1, 0, 1}, + {1, 1, 1, 0, 0, 1}, + {1, 1, 1, 1, 0, 1}, + {1, 1, 1, 0, 0, 1}, + {1, 1, 1, 0, 1, 1}, + {1, 1, 1, 0, 0, 1}, + {1, 1, 1, 0, 0, 1}, + {1, 1, 1, 0, 0, 1}, + {1, 1, 1, 0, 0, 1}, + {1, 1, 1, 0, 1, 1}, + {1, 1, 1, 0, 1, 1}, + {1, 1, 1, 0, 1, 1}, + {1, 1, 1, 0, 1, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 1, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +static const u16 gUnknown_845C594[] = { + MAP_VIRIDIAN_CITY_MART, + MAP_PEWTER_CITY_MART, + MAP_CERULEAN_CITY_MART, + MAP_LAVENDER_TOWN_MART, + MAP_VERMILION_CITY_MART, + MAP_CELADON_CITY_DEPARTMENT_STORE_1F, + MAP_CELADON_CITY_DEPARTMENT_STORE_2F, + MAP_CELADON_CITY_DEPARTMENT_STORE_3F, + MAP_CELADON_CITY_DEPARTMENT_STORE_4F, + MAP_CELADON_CITY_DEPARTMENT_STORE_5F, + MAP_CELADON_CITY_DEPARTMENT_STORE_ROOF, + MAP_CELADON_CITY_DEPARTMENT_STORE_ELEVATOR, + MAP_FUCHSIA_CITY_MART, + MAP_CINNABAR_ISLAND_MART, + MAP_SAFFRON_CITY_MART, + MAP_THREE_ISLAND_MART, + MAP_FOUR_ISLAND_MART, + MAP_SEVEN_ISLAND_MART, + MAP_SIX_ISLAND_MART, + MAP_UNDEFINED +}; + +static const u16 gUnknown_845C5BC[] = { + MAP_PEWTER_CITY_GYM, + MAP_CERULEAN_CITY_GYM, + MAP_VERMILION_CITY_GYM, + MAP_CELADON_CITY_GYM, + MAP_FUCHSIA_CITY_GYM, + MAP_SAFFRON_CITY_GYM, + MAP_CINNABAR_ISLAND_GYM, + MAP_VIRIDIAN_CITY_GYM, + MAP_UNDEFINED +}; + +static const u8 gUnknown_845C5CE[][3] = { + { MAP_GROUP(VIRIDIAN_FOREST), MAP_NUM(VIRIDIAN_FOREST), 1 }, + { MAP_GROUP(MT_MOON_1F), MAP_NUM(MT_MOON_1F), 3 }, + { MAP_GROUP(ROCK_TUNNEL_1F), MAP_NUM(ROCK_TUNNEL_1F), 2 }, + { MAP_GROUP(DIGLETTS_CAVE_NORTH_ENTRANCE), MAP_NUM(DIGLETTS_CAVE_NORTH_ENTRANCE), 3 }, + { MAP_GROUP(SEAFOAM_ISLANDS_1F), MAP_NUM(SEAFOAM_ISLANDS_1F), 5 }, + { MAP_GROUP(VICTORY_ROAD_1F), MAP_NUM(VICTORY_ROAD_1F), 3 }, + { MAP_GROUP(CERULEAN_CAVE_1F), MAP_NUM(CERULEAN_CAVE_1F), 3 }, + { MAP_GROUP(MT_EMBER_RUBY_PATH_B4F), MAP_NUM(MT_EMBER_RUBY_PATH_B4F), 1 }, + { MAP_GROUP(MT_EMBER_SUMMIT_PATH_1F), MAP_NUM(MT_EMBER_SUMMIT_PATH_1F), 3 }, + { MAP_GROUP(MT_EMBER_RUBY_PATH_B5F), MAP_NUM(MT_EMBER_RUBY_PATH_B5F), 7 }, + { MAP_GROUP(THREE_ISLAND_BERRY_FOREST), MAP_NUM(THREE_ISLAND_BERRY_FOREST), 1 }, + { MAP_GROUP(SIX_ISLAND_PATTERN_BUSH), MAP_NUM(SIX_ISLAND_PATTERN_BUSH), 1 }, + { MAP_GROUP(FIVE_ISLAND_LOST_CAVE_ENTRANCE), MAP_NUM(FIVE_ISLAND_LOST_CAVE_ENTRANCE), 15 }, + { MAP_GROUP(FOUR_ISLAND_ICEFALL_CAVE_ENTRANCE), MAP_NUM(FOUR_ISLAND_ICEFALL_CAVE_ENTRANCE), 4 }, + { MAP_GROUP(SIX_ISLAND_ALTERING_CAVE), MAP_NUM(SIX_ISLAND_ALTERING_CAVE), 1 }, + { MAP_GROUP(SEVEN_ISLAND_TANOBY_RUINS_MONEAN_CHAMBER), MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_MONEAN_CHAMBER), 7 } +}; + +void sub_812B1E0(u8 a0) +{ + gUnknown_203B0EC = a0; +} + +void HelpSystem_SetSomeVariable2(u8 a0) +{ + switch (gUnknown_203B0EC) + { + case 23: + case 24: + case 25: + case 26: + if (a0 == 9 || a0 == 5 || a0 == 6 || a0 == 7 || a0 == 8) + break; + // fallthrough + default: + gUnknown_203B0EC = a0; + break; + } +} + +void sub_812B220(void) +{ + gUnknown_203B0EC = gSpecialVar_0x8004; +} + +void sub_812B234(void) +{ + gUnknown_3005EA0 = gUnknown_203B0EC; +} + +void sub_812B248(void) +{ + gUnknown_203B0EC = gUnknown_3005EA0; +} + +static bool32 sub_812B25C(void) +{ + return sub_812B27C(gUnknown_845C594); +} + +static bool32 sub_812B26C(void) +{ + return sub_812B27C(gUnknown_845C5BC); +} + +static bool32 sub_812B27C(const u16 * mapIdxs) +{ + u16 mapIdx = (gSaveBlock1Ptr->location.mapGroup << 8) + gSaveBlock1Ptr->location.mapNum; + s32 i; + + for (i = 0; mapIdxs[i] != MAP_UNDEFINED; i++) + { + if (mapIdxs[i] == mapIdx) + return TRUE; + } + + return FALSE; +} + +static bool8 sub_812B2C4(void) +{ + u8 i, j; + + for (i = 0; i < 16; i++) + { + for (j = 0; j < gUnknown_845C5CE[i][2]; j++) + { + if ( + gUnknown_845C5CE[i][0] == gSaveBlock1Ptr->location.mapGroup + && gUnknown_845C5CE[i][1] + j == gSaveBlock1Ptr->location.mapNum + && (i != 15 || FlagGet(FLAG_0x849) == TRUE) + ) + return TRUE; + } + } + + return FALSE; +} + +void sub_812B35C(void) +{ + sub_812B4B8(); + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING)) + HelpSystem_SetSomeVariable2(0x16); + else if (sub_812B2C4()) + HelpSystem_SetSomeVariable2(0x15); + else if (is_light_level_8_or_9(gMapHeader.mapType)) + { + if ((gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(PALLET_TOWN_PLAYERS_HOUSE_1F) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(PALLET_TOWN_PLAYERS_HOUSE_1F)) || (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(PALLET_TOWN_PLAYERS_HOUSE_2F) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(PALLET_TOWN_PLAYERS_HOUSE_2F))) + HelpSystem_SetSomeVariable2(0x0E); + else if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(PALLET_TOWN_PROFESSOR_OAKS_LAB) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(PALLET_TOWN_PROFESSOR_OAKS_LAB)) + HelpSystem_SetSomeVariable2(0x0F); + else if (IsCurMapPokeCenter() == TRUE) + HelpSystem_SetSomeVariable2(0x10); + else if (sub_812B25C() == TRUE) + HelpSystem_SetSomeVariable2(0x11); + else if (sub_812B26C() == TRUE) + HelpSystem_SetSomeVariable2(0x12); + else + HelpSystem_SetSomeVariable2(0x13); + } + else + HelpSystem_SetSomeVariable2(0x14); +} + +bool8 sub_812B40C(void) +{ + if (gUnknown_203B0EE == 1) + return FALSE; + + if (gSaveFileStatus != SAVE_STATUS_EMPTY && gSaveFileStatus != SAVE_STATUS_INVALID && FlagGet(FLAG_0x83C)) + return FALSE; + + FlagSet(FLAG_0x83C); + gUnknown_203B0EE = 1; + return TRUE; +} + +bool8 sub_812B45C(void) +{ + if (gReceivedRemoteLinkPlayers == 1) + return FALSE; + return TRUE; +} + +void sub_812B478(void) +{ + gUnknown_3005ECC = 0; +} + +void sub_812B484(void) +{ + if (gUnknown_203ADFA != 2 && gUnknown_203ADFA != 3) + { + gUnknown_3005ECC = 1; + sub_812B4B8(); + } +} + +void sub_812B4AC(void) +{ + gUnknown_203F175 = 1; +} + +void sub_812B4B8(void) +{ + gUnknown_203F175 = 0; +} + +static void sub_812B4C4(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + a0->sub.items = a1; + a0->sub.totalItems = 1; + a0->sub.maxShowed = 1; + a0->sub.left = 1; + a0->sub.top = 4; +} + +static void sub_812B4D8(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + sub_812B4C4(a0, a1); + sub_812B520(a0, a1); + sub_812BF74(gUnknown_841DFAC); + HelpSystem_InitListMenuController(a0, 0, gUnknown_3005E9C[2]); + sub_812BF9C(a0, a1); + sub_813BDA4(1); + sub_813BD5C(1); +} + +static void sub_812B520(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + u8 i; + u8 r4 = 0; + for (i = 0; i < 6; i++) + { + if (gUnknown_845C4B6[gUnknown_203B0EC][gUnknown_845C4B0[i]] == 1) + { + a1[r4].label = gUnknown_845B080[gUnknown_845C4B0[i]]; + a1[r4].index = gUnknown_845C4B0[i]; + r4++; + } + } + a1[r4 - 1].index = -2; + a0->sub.totalItems = r4; + a0->sub.maxShowed = r4; + a0->sub.left = 0; +} + +static void sub_812B5A8(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + sub_813BDE8(0); + sub_813BFC0(0); + sub_813BE78(1); + sub_812B4C4(a0, a1); + sub_812B614(a0, a1); + sub_812BF74(gUnknown_841DFC9); + HelpSystem_InitListMenuController(a0, a0->field_0C, a0->field_0D); + HelpSystem_PrintTextAt(gUnknown_845B080[gUnknown_3005E9C[1]], 0, 0); + sub_813BDA4(1); + sub_813BD5C(1); +} + +static void sub_812B614(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + u8 r6 = 0; + const u8 * r3 = gUnknown_845B9E0[gUnknown_203B0EC * 5 + gUnknown_3005E9C[1]]; + u8 i; + for (i = 0; r3[i] != 0xFF; i++) + { + if (sub_812B780(r3[i]) == TRUE) + { + if (gUnknown_3005E9C[1] == 0) + a1[r6].label = gUnknown_845B0B0[r3[i]]; + else if (gUnknown_3005E9C[1] == 1) + a1[r6].label = gUnknown_845B218[r3[i]]; + else if (gUnknown_3005E9C[1] == 2) + a1[r6].label = gUnknown_845B3A0[r3[i]]; + else if (gUnknown_3005E9C[1] == 3) + a1[r6].label = gUnknown_845B500[r3[i]]; + else + a1[r6].label = gUnknown_845B540[r3[i]]; + a1[r6].index = r3[i]; + r6++; + } + } + if (sub_812B754() == TRUE) + { + for (i = 0, r3 = gUnknown_845B9BE; r3[i] != 0xFF; i++) + { + a1[r6].label = gUnknown_845B3A0[r3[i]]; + a1[r6].index = r3[i]; + r6++; + } + } + a1[r6].label = gUnknown_81B2E6F; + a1[r6].index = -2; + r6++; + a0->sub.totalItems = r6; + a0->sub.maxShowed = 7; + a0->sub.left = 0; + a0->sub.top = 21; +} + +static bool8 sub_812B754(void) +{ + if (FlagGet(FLAG_0x4B0) == TRUE && gUnknown_3005E9C[1] == 2) + return TRUE; + return FALSE; +} + +static bool8 sub_812B780(u8 id) +{ + u8 i = 0; + + if (gUnknown_3005E9C[1] == 0) + { + switch (id) + { + case 1: + case 2: + case 3: + case 5: + case 8: + case 34: + case 38: + case 41: + case 42: + case 43: + return TRUE; + case 4: + return FlagGet(FLAG_0x2CF); + case 6: + case 10: + case 16: + case 19: + case 22: + case 35: + case 36: + return FlagGet(FLAG_WORLD_MAP_VIRIDIAN_CITY); + case 7: + return FlagGet(FLAG_WORLD_MAP_VERMILION_CITY); + case 11: + case 24: + return FlagGet(FLAG_0x8A4); + case 9: + case 13: + case 14: + case 15: + case 17: + case 18: + case 20: + case 26: + case 29: + case 31: + case 37: + return FlagGet(FLAG_0x828); + case 21: + case 23: + return FlagGet(FLAG_0x829); + case 12: + case 25: + case 27: + case 30: + case 32: + case 33: + return FlagGet(FLAG_UNK820); + case 28: + case 40: + return sub_812BB10(); + case 39: + return FlagGet(FLAG_0x29B); + case 44: + return FlagGet(FLAG_WORLD_MAP_PEWTER_CITY); + } + return FALSE; + } + if (gUnknown_3005E9C[1] == 1) + { + switch (id) + { + case 06: + case 10: + case 11: + case 12: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 31: + case 36: + case 38: + case 39: + case 40: + case 41: + case 42: + case 45: + case 46: + case 47: + return TRUE; + case 1: + case 30: + case 37: + return FlagGet(FLAG_0x829); + case 14: + return CheckBagHasItem(ITEM_TOWN_MAP, 1); + case 2: + case 3: + case 5: + case 7: + case 8: + case 9: + case 13: + case 32: + case 33: + case 35: + case 43: + case 44: + return FlagGet(FLAG_0x828); + case 4: + case 34: + if (sub_8088EDC(1) > 1) + return TRUE; + return FALSE; + case 15: + return FlagGet(FLAG_UNK820); + case 16: + case 17: + return sub_812BB10(); + case 18: + return FlagGet(FLAG_0x271); + case 48: + return FlagGet(FLAG_0x82C); + } + return FALSE; + } + if (gUnknown_3005E9C[1] == 2) + { + if (sub_812B754() == TRUE) + { + for (i = 0; gUnknown_845B9BE[i] != 0xFF; i++) + { + if (gUnknown_845B9BE[i] == id) + return FALSE; + } + } + switch (id) + { + case 14: + case 17: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 38: + return TRUE; + case 1: + case 2: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 19: + case 20: + case 21: + return FlagGet(FLAG_0x828); + case 36: + case 37: + return sub_812BB10(); + case 3: + case 15: + case 18: + case 39: + return FlagGet(FLAG_0x8A4); + } + return TRUE; + } + if (gUnknown_3005E9C[1] == 3) + { + switch (id) + { + case 5: + return FlagGet(FLAG_UNK820); + case 6: + return FlagGet(FLAG_0x821); + } + return TRUE; + } + if (gUnknown_3005E9C[1] == 4) + { + return TRUE; + } + + return FALSE; +} + +static bool8 sub_812BB10(void) +{ + if (FlagGet(FLAG_0x237) == TRUE) + return TRUE; + if (FlagGet(FLAG_0x238) == TRUE) + return TRUE; + if (FlagGet(FLAG_0x239) == TRUE) + return TRUE; + if (FlagGet(FLAG_0x23A) == TRUE) + return TRUE; + if (FlagGet(FLAG_0x23B) == TRUE) + return TRUE; + if (FlagGet(FLAG_0x2EF) == TRUE) + return TRUE; + if (FlagGet(FLAG_0x1F1) == TRUE) + return TRUE; + return FALSE; +} + +bool8 sub_812BB9C(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + switch (a0->field_0E) + { + case 8: + return sub_812BC54(a0, a1); + case 9: + return sub_812BC80(a0, a1); + case 10: + return sub_812BCA8(a0, a1); + case 0: + return sub_812BCD0(a0, a1); + case 1: + return sub_812BD2C(a0, a1); + case 2: + return sub_812BD64(a0, a1); + case 3: + return sub_812BD98(a0, a1); + case 4: + return sub_812BE10(a0, a1); + case 5: + return sub_812BEEC(a0, a1); + case 6: + return sub_812BF18(a0, a1); + } + return FALSE; +} + +bool8 sub_812BC54(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + sub_812BF74(gUnknown_841DFA5); + sub_812BF5C(); + sub_813BDA4(1); + sub_813BD5C(1); + a0->field_0E = 9; + return TRUE; +} + +bool8 sub_812BC80(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + if (JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + a0->field_0E = 10; + } + return TRUE; +} + +bool8 sub_812BCA8(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + gUnknown_3005E9C[2] = 0; + sub_812BF94(a0); + sub_812B4D8(a0, a1); + a0->field_0E = 0; + return TRUE; +} + +bool8 sub_812BCD0(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + s32 v0 = HelpSystem_GetMenuInput(); + switch (v0) + { + case -6: + case -2: + return FALSE; + case -5: + case -4: + sub_812BF9C(a0, a1); + break; + case -3: + case -1: + break; + default: + gUnknown_3005E9C[1] = v0; + a0->field_0E = 1; + break; + } + return TRUE; +} + +bool8 sub_812BD2C(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + gUnknown_3005E9C[0] = 1; + gUnknown_3005E9C[2] = a0->field_0D; + sub_812BF94(a0); + sub_812B5A8(a0, a1); + sub_813C75C(); + HelpSystem_SetInputDelay(2); + a0->field_0E = 3; + return TRUE; +} + +bool8 sub_812BD64(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + sub_813C004(0, 0); + sub_813C004(1, 0); + gUnknown_3005E9C[0] = 0; + sub_812B4D8(a0, a1); + a0->field_0E = 0; + return TRUE; +} + +bool8 sub_812BD98(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + s32 v0 = HelpSystem_GetMenuInput(); + switch (v0) + { + case -6: + return FALSE; + case -2: + a0->field_0E = 2; + break; + case -5: + case -4: + case -3: + case -1: + break; + default: + gUnknown_3005E9C[3] = v0; + a0->field_0E = 4; + break; + } + return TRUE; +} + +void sub_812BDEC(void) +{ + HelpSystem_PrintTextAt(gUnknown_845B080[gUnknown_3005E9C[1]], 0, 0); +} + +bool8 sub_812BE10(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + gUnknown_3005E9C[0] = 2; + sub_813BDA4(0); + HelpSystem_FillPanel1(); + sub_812BF74(gUnknown_841DFBE); + sub_813BDE8(1); + sub_813BEE4(1); + + if (gUnknown_3005E9C[1] == 0) + { + HelpSystem_PrintTwoStrings(gUnknown_845B0B0[gUnknown_3005E9C[3]], gUnknown_845B164[gUnknown_3005E9C[3]]); + } + else if (gUnknown_3005E9C[1] == 1) + { + HelpSystem_PrintTwoStrings(gUnknown_845B218[gUnknown_3005E9C[3]], gUnknown_845B2DC[gUnknown_3005E9C[3]]); + } + else if (gUnknown_3005E9C[1] == 2) + { + HelpSystem_PrintTwoStrings(gUnknown_845B3A0[gUnknown_3005E9C[3]], gUnknown_845B450[gUnknown_3005E9C[3]]); + } + else if (gUnknown_3005E9C[1] == 3) + { + HelpSystem_PrintTwoStrings(gUnknown_845B500[gUnknown_3005E9C[3]], gUnknown_845B520[gUnknown_3005E9C[3]]); + } + else + { + HelpSystem_PrintTwoStrings(gUnknown_845B540[gUnknown_3005E9C[3]], gUnknown_845B5D0[gUnknown_3005E9C[3]]); + } + sub_813BDA4(1); + sub_813BD5C(1); + a0->field_0E = 6; + return TRUE; +} + +bool8 sub_812BEEC(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + gUnknown_3005E9C[0] = 1; + sub_812B5A8(a0, a1); + sub_813C75C(); + HelpSystem_SetInputDelay(2); + a0->field_0E = 3; + return TRUE; +} + +bool8 sub_812BF18(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + if (JOY_NEW(B_BUTTON) || JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + a0->field_0E = 5; + return TRUE; + } + if (JOY_NEW(L_BUTTON | R_BUTTON)) + return FALSE; + return TRUE; +} + +static void sub_812BF5C(void) +{ + HelpSystem_FillPanel1(); + HelpSystem_PrintTextAt(gUnknown_81B2FC9, 0, 0); +} + +static void sub_812BF74(const u8 * str) +{ + HelpSystem_FillPanel2(); + HelpSystem_PrintTextRightAlign_Row52(str); +} + +u8 sub_812BF88(void) +{ + return gUnknown_3005E9C[0]; +} + +static void sub_812BF94(struct HelpSystemListMenu * a0) +{ + a0->field_0C = 0; + a0->field_0D = 0; +} + +static void sub_812BF9C(struct HelpSystemListMenu * a0, struct ListMenuItem * a1) +{ + s32 index = a1[a0->field_0C + a0->field_0D].index; + if (index == -2) + HelpSystem_PrintText_813C584(gUnknown_845B098[5]); + else + HelpSystem_PrintText_813C584(gUnknown_845B098[index]); + sub_813BE30(1); +} diff --git a/src/item.c b/src/item.c new file mode 100644 index 000000000..3f33f464d --- /dev/null +++ b/src/item.c @@ -0,0 +1,684 @@ +#include "global.h" +#include "berry.h" +#include "event_data.h" +#include "item.h" +#include "item_use.h" +#include "load_save.h" +#include "malloc.h" +#include "quest_log.h" +#include "string_util.h" +#include "strings.h" +#include "constants/hold_effects.h" +#include "constants/items.h" +#include "constants/maps.h" + +void SortAndCompactBagPocket(struct BagPocket * pocket); + +// Item descriptions and data +#include "data/items.h" + +u16 GetBagItemQuantity(u16 * ptr) +{ + return gSaveBlock2Ptr->encryptionKey ^ *ptr; +} + +void SetBagItemQuantity(u16 * ptr, u16 value) +{ + *ptr = value ^ gSaveBlock2Ptr->encryptionKey; +} + +u16 GetPcItemQuantity(u16 * ptr) +{ + return 0 ^ *ptr; +} + +void SetPcItemQuantity(u16 * ptr, u16 value) +{ + *ptr = value ^ 0; +} + +void ApplyNewEncryptionKeyToBagItems(u32 key) +{ + u32 i, j; + + for (i = 0; i < NUM_BAG_POCKETS; i++) + { + for (j = 0; j < gBagPockets[i].capacity; j++) + { + ApplyNewEncryptionKeyToHword(&gBagPockets[i].itemSlots[j].quantity, key); + } + } +} + +void ApplyNewEncryptionKeyToBagItems_(u32 key) +{ + ApplyNewEncryptionKeyToBagItems(key); +} + +void SetBagPocketsPointers(void) +{ + gBagPockets[POCKET_ITEMS - 1].itemSlots = gSaveBlock1Ptr->bagPocket_Items; + gBagPockets[POCKET_ITEMS - 1].capacity = BAG_ITEMS_COUNT; + gBagPockets[POCKET_KEY_ITEMS - 1].itemSlots = gSaveBlock1Ptr->bagPocket_KeyItems; + gBagPockets[POCKET_KEY_ITEMS - 1].capacity = BAG_KEYITEMS_COUNT; + gBagPockets[POCKET_POKE_BALLS - 1].itemSlots = gSaveBlock1Ptr->bagPocket_PokeBalls; + gBagPockets[POCKET_POKE_BALLS - 1].capacity = BAG_POKEBALLS_COUNT; + gBagPockets[POCKET_TM_CASE - 1].itemSlots = gSaveBlock1Ptr->bagPocket_TMHM; + gBagPockets[POCKET_TM_CASE - 1].capacity = BAG_TMHM_COUNT; + gBagPockets[POCKET_BERRY_POUCH - 1].itemSlots = gSaveBlock1Ptr->bagPocket_Berries; + gBagPockets[POCKET_BERRY_POUCH - 1].capacity = BAG_BERRIES_COUNT; +} + +void CopyItemName(u16 itemId, u8 * dest) +{ + if (itemId == ITEM_ENIGMA_BERRY) + { + StringCopy(dest, sub_809C8A0(43)->name); + StringAppend(dest, gUnknown_84162BD); + } + else + { + StringCopy(dest, ItemId_GetName(itemId)); + } +} + +s8 BagPocketGetFirstEmptySlot(u8 pocketId) +{ + u16 i; + + for (i = 0; i < gBagPockets[pocketId].capacity; i++) + { + if (gBagPockets[pocketId].itemSlots[i].itemId == ITEM_NONE) + return i; + } + + return -1; +} + +bool8 IsPocketNotEmpty(u8 pocketId) +{ + u8 i; + + for (i = 0; i < gBagPockets[pocketId - 1].capacity; i++) + { + if (gBagPockets[pocketId - 1].itemSlots[i].itemId != ITEM_NONE) + return TRUE; + } + + return FALSE; +} + +bool8 CheckBagHasItem(u16 itemId, u16 count) +{ + u8 i; + u8 pocket; + + if (ItemId_GetPocket(itemId) == 0) + return FALSE; + + pocket = ItemId_GetPocket(itemId) - 1; + // Check for item slots that contain the item + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == itemId) + { + u16 quantity; + // Does this item slot contain enough of the item? + quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); + if (quantity >= count) + return TRUE; + // RS and Emerald check whether there is enough of the + // item across all stacks. + // For whatever reason, FR/LG assume there's only one + // stack of the item. + else + return FALSE; + } + } + return FALSE; +} + +bool8 CheckHasAtLeastOneBerry(void) +{ + u8 itemId; + bool8 exists; + + exists = CheckBagHasItem(ITEM_BERRY_POUCH, 1); + if (!exists) + { + gSpecialVar_Result = FALSE; + return FALSE; + } + for (itemId = FIRST_BERRY_INDEX; itemId <= LAST_BERRY_INDEX; itemId++) + { + exists = CheckBagHasItem(itemId, 1); + if (exists) + { + gSpecialVar_Result = TRUE; + return TRUE; + } + } + + gSpecialVar_Result = FALSE; + return FALSE; +} + +bool8 CheckBagHasSpace(u16 itemId, u16 count) +{ + u8 i; + u8 pocket; + + if (ItemId_GetPocket(itemId) == 0) + return FALSE; + + pocket = ItemId_GetPocket(itemId) - 1; + // Check for item slots that contain the item + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == itemId) + { + u16 quantity; + // Does this stack have room for more?? + quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); + if (quantity + count <= 999) + return TRUE; + // RS and Emerald check whether there is enough of the + // item across all stacks. + // For whatever reason, FR/LG assume there's only one + // stack of the item. + else + return FALSE; + } + } + + if (BagPocketGetFirstEmptySlot(pocket) != -1) + return TRUE; + + return FALSE; +} + +bool8 AddBagItem(u16 itemId, u16 count) +{ + u8 i; + u8 pocket; + s8 idx; + + if (ItemId_GetPocket(itemId) == 0) + return FALSE; + + pocket = ItemId_GetPocket(itemId) - 1; + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == itemId) + { + u16 quantity; + // Does this stack have room for more?? + quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); + if (quantity + count <= 999) + { + quantity += count; + SetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity, quantity); + return TRUE; + } + // RS and Emerald check whether there is enough of the + // item across all stacks. + // For whatever reason, FR/LG assume there's only one + // stack of the item. + else + return FALSE; + } + } + + if (pocket == POCKET_TM_CASE - 1 && !CheckBagHasItem(ITEM_TM_CASE, 1)) + { + idx = BagPocketGetFirstEmptySlot(POCKET_KEY_ITEMS - 1); + if (idx == -1) + return FALSE; + gBagPockets[POCKET_KEY_ITEMS - 1].itemSlots[idx].itemId = ITEM_TM_CASE; + SetBagItemQuantity(&gBagPockets[POCKET_KEY_ITEMS - 1].itemSlots[idx].quantity, 1); + } + + if (pocket == POCKET_BERRY_POUCH - 1 && !CheckBagHasItem(ITEM_BERRY_POUCH, 1)) + { + idx = BagPocketGetFirstEmptySlot(POCKET_KEY_ITEMS - 1); + if (idx == -1) + return FALSE; + gBagPockets[POCKET_KEY_ITEMS - 1].itemSlots[idx].itemId = ITEM_BERRY_POUCH; + SetBagItemQuantity(&gBagPockets[POCKET_KEY_ITEMS - 1].itemSlots[idx].quantity, 1); + FlagSet(FLAG_0x847); + } + + if (itemId == ITEM_BERRY_POUCH) + FlagSet(FLAG_0x847); + + idx = BagPocketGetFirstEmptySlot(pocket); + if (idx == -1) + return FALSE; + + gBagPockets[pocket].itemSlots[idx].itemId = itemId; + SetBagItemQuantity(&gBagPockets[pocket].itemSlots[idx].quantity, count); + return TRUE; +} + +bool8 RemoveBagItem(u16 itemId, u16 count) +{ + u8 i; + u8 pocket; + + if (ItemId_GetPocket(itemId) == 0) + return FALSE; + + if (itemId == ITEM_NONE) + return FALSE; + + pocket = ItemId_GetPocket(itemId) - 1; + // Check for item slots that contain the item + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == itemId) + { + u16 quantity; + // Does this item slot contain enough of the item? + quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); + if (quantity >= count) + { + quantity -= count; + SetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity, quantity); + if (quantity == 0) + gBagPockets[pocket].itemSlots[i].itemId = ITEM_NONE; + return TRUE; + } + // RS and Emerald check whether there is enough of the + // item across all stacks. + // For whatever reason, FR/LG assume there's only one + // stack of the item. + else + return FALSE; + } + } + return FALSE; +} + +u8 GetPocketByItemId(u16 itemId) +{ + return ItemId_GetPocket(itemId); // wow such important +} + +void ClearItemSlots(struct ItemSlot * slots, u8 capacity) +{ + u16 i; + + for (i = 0; i < capacity; i++) + { + slots[i].itemId = ITEM_NONE; + SetBagItemQuantity(&slots[i].quantity, 0); + } +} + +void ClearPCItemSlots(void) +{ + u16 i; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + gSaveBlock1Ptr->pcItems[i].itemId = ITEM_NONE; + SetPcItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity, 0); + } +} + +void ClearItemSlotsInAllBagPockets(void) +{ + u16 i; + + for (i = 0; i < 5; i++) + { + ClearItemSlots(gBagPockets[i].itemSlots, gBagPockets[i].capacity); + } +} + +s8 PCItemsGetFirstEmptySlot(void) +{ + s8 i; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == ITEM_NONE) + return i; + } + + return -1; +} + +u8 CountItemsInPC(void) +{ + u8 count = 0; + u8 i; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId != ITEM_NONE) + count++; + } + + return count; +} + +bool8 CheckPCHasItem(u16 itemId, u16 count) +{ + u8 i; + u16 quantity; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == itemId) + { + quantity = GetPcItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity); + if (quantity >= count) + return TRUE; + } + } + + return FALSE; +} + +bool8 AddPCItem(u16 itemId, u16 count) +{ + u8 i; + u16 quantity; + s8 idx; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == itemId) + { + quantity = GetPcItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity); + if (quantity + count <= 999) + { + quantity += count; + SetPcItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity, quantity); + return TRUE; + } + else + return FALSE; + } + } + + idx = PCItemsGetFirstEmptySlot(); + if (idx == -1) + return FALSE; + + gSaveBlock1Ptr->pcItems[idx].itemId = itemId; + SetPcItemQuantity(&gSaveBlock1Ptr->pcItems[idx].quantity, count); + return TRUE; +} + +void RemoveItemFromPC(u16 itemId, u16 count) +{ + u32 i; + u16 quantity; + + if (itemId == ITEM_NONE) + return; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == itemId) + break; + } + + if (i != PC_ITEMS_COUNT) + { + quantity = GetPcItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity) - count; + SetPcItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity, quantity); + if (quantity == 0) + gSaveBlock1Ptr->pcItems[i].itemId = ITEM_NONE; + } +} + +void ItemPcCompaction(void) +{ + u16 i, j; + struct ItemSlot tmp; + + for (i = 0; i < PC_ITEMS_COUNT - 1; i++) + { + for (j = i + 1; j < PC_ITEMS_COUNT; j++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == ITEM_NONE) + { + tmp = gSaveBlock1Ptr->pcItems[i]; + gSaveBlock1Ptr->pcItems[i] = gSaveBlock1Ptr->pcItems[j]; + gSaveBlock1Ptr->pcItems[j] = tmp; + } + } + } +} + +void RegisteredItemHandleBikeSwap(void) +{ + switch (gSaveBlock1Ptr->registeredItem) + { + case ITEM_MACH_BIKE: + gSaveBlock1Ptr->registeredItem = ITEM_ACRO_BIKE; + break; + case ITEM_ACRO_BIKE: + gSaveBlock1Ptr->registeredItem = ITEM_MACH_BIKE; + break; + } +} + +void SwapItemSlots(struct ItemSlot * a, struct ItemSlot * b) +{ + struct ItemSlot c; + c = *a; + *a = *b; + *b = c; +} + +void BagPocketCompaction(struct ItemSlot * slots, u8 capacity) +{ + u16 i, j; + + for (i = 0; i < capacity - 1; i++) + { + for (j = i + 1; j < capacity; j++) + { + if (GetBagItemQuantity(&slots[i].quantity) == 0) + { + SwapItemSlots(&slots[i], &slots[j]); + } + } + } +} + +void SortPocketAndPlaceHMsFirst(struct BagPocket * pocket) +{ + u16 i; + u16 j = 0; + u16 k; + struct ItemSlot * buff; + + SortAndCompactBagPocket(pocket); + + for (i = 0; i < pocket->capacity; i++) + { + if (pocket->itemSlots[i].itemId == ITEM_NONE && GetBagItemQuantity(&pocket->itemSlots[i].quantity) == 0) + return; + if (pocket->itemSlots[i].itemId >= ITEM_HM01 && GetBagItemQuantity(&pocket->itemSlots[i].quantity) != 0) + { + for (j = i + 1; j < pocket->capacity; j++) + { + if (pocket->itemSlots[j].itemId == ITEM_NONE && GetBagItemQuantity(&pocket->itemSlots[j].quantity) == 0) + break; + } + break; + } + } + + for (k = 0; k < pocket->capacity; k++) + pocket->itemSlots[k].quantity = GetBagItemQuantity(&pocket->itemSlots[k].quantity); + buff = AllocZeroed(pocket->capacity * sizeof(struct ItemSlot)); + CpuCopy16(pocket->itemSlots + i, buff, (j - i) * sizeof(struct ItemSlot)); + CpuCopy16(pocket->itemSlots, buff + (j - i), i * sizeof(struct ItemSlot)); + CpuCopy16(buff, pocket->itemSlots, pocket->capacity * sizeof(struct ItemSlot)); + for (k = 0; k < pocket->capacity; k++) + SetBagItemQuantity(&pocket->itemSlots[k].quantity, pocket->itemSlots[k].quantity); + Free(buff); +} + +void SortAndCompactBagPocket(struct BagPocket * pocket) +{ + u16 i, j; + + for (i = 0; i < pocket->capacity; i++) + { + for (j = i + 1; j < pocket->capacity; j++) + { + if (GetBagItemQuantity(&pocket->itemSlots[i].quantity) == 0 || (GetBagItemQuantity(&pocket->itemSlots[j].quantity) != 0 && pocket->itemSlots[i].itemId > pocket->itemSlots[j].itemId)) + SwapItemSlots(&pocket->itemSlots[i], &pocket->itemSlots[j]); + } + } +} + +u16 BagGetItemIdByPocketPosition(u8 pocketId, u16 slotId) +{ + return gBagPockets[pocketId - 1].itemSlots[slotId].itemId; +} + +u16 BagGetQuantityByPocketPosition(u8 pocketId, u16 slotId) +{ + return GetBagItemQuantity(&gBagPockets[pocketId - 1].itemSlots[slotId].quantity); +} + +u16 BagGetQuantityByItemId(u16 itemId) +{ + u16 i; + struct BagPocket * pocket = &gBagPockets[ItemId_GetPocket(itemId) - 1]; + + for (i = 0; i < pocket->capacity; i++) + { + if (pocket->itemSlots[i].itemId == itemId) + return GetBagItemQuantity(&pocket->itemSlots[i].quantity); + } + + return 0; +} + +void sub_809A824(u16 itemId) +{ + struct QuestLogStruct_809A824 + { + u16 itemId; + u8 mapSectionId; + } * ptr; + if + ( + itemId == ITEM_OAKS_PARCEL + || itemId == ITEM_POKE_FLUTE + || itemId == ITEM_SECRET_KEY + || itemId == ITEM_BIKE_VOUCHER + || itemId == ITEM_GOLD_TEETH + || itemId == ITEM_OLD_AMBER + || itemId == ITEM_CARD_KEY + || itemId == ITEM_LIFT_KEY + || itemId == ITEM_HELIX_FOSSIL + || itemId == ITEM_DOME_FOSSIL + || itemId == ITEM_SILPH_SCOPE + || itemId == ITEM_BICYCLE + || itemId == ITEM_TOWN_MAP + || itemId == ITEM_VS_SEEKER + || itemId == ITEM_TEACHY_TV + || itemId == ITEM_RAINBOW_PASS + || itemId == ITEM_TEA + || itemId == ITEM_POWDER_JAR + || itemId == ITEM_RUBY + || itemId == ITEM_SAPPHIRE + ) + { + if (itemId != ITEM_TOWN_MAP || (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(PALLET_TOWN_GARYS_HOUSE) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(PALLET_TOWN_GARYS_HOUSE))) + { + ptr = malloc(sizeof(*ptr)); + ptr->itemId = itemId; + ptr->mapSectionId = gMapHeader.regionMapSectionId; + sub_8113550(40, (void *)ptr); + free(ptr); + } + } +} + +u16 SanitizeItemId(u16 itemId) +{ + if (itemId >= ITEM_N_A) + return ITEM_NONE; + return itemId; +} + +const u8 * ItemId_GetName(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].name; +} + +u16 itemid_get_number(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].itemId; +} + +u16 itemid_get_market_price(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].price; +} + +u8 ItemId_GetHoldEffect(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].holdEffect; +} + +u8 ItemId_GetHoldEffectParam(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].holdEffectParam; +} + +const u8 * ItemId_GetDescription(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].description; +} + +bool8 itemid_is_unique(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].importance; +} + +u8 itemid_get_x19(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].exitsBagOnUse; +} + +u8 ItemId_GetPocket(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].pocket; +} + +u8 ItemId_GetType(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].type; +} + +ItemUseFunc ItemId_GetFieldFunc(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].fieldUseFunc; +} + +bool8 ItemId_GetBattleUsage(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].battleUsage; +} + +ItemUseFunc ItemId_GetBattleFunc(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].battleUseFunc; +} + +u8 ItemId_GetSecondaryId(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].secondaryId; +} diff --git a/src/item_menu_icons.c b/src/item_menu_icons.c new file mode 100644 index 000000000..a244a1075 --- /dev/null +++ b/src/item_menu_icons.c @@ -0,0 +1,783 @@ +#include "global.h" +#include "decompress.h" +#include "graphics.h" +#include "item_menu_icons.h" +#include "malloc.h" +#include "constants/items.h" + +static EWRAM_DATA u8 gUnknown_2039878[12] = {0}; +EWRAM_DATA void * gUnknown_2039884 = NULL; +static EWRAM_DATA void * gUnknown_2039888 = NULL; + +static void sub_8098560(struct Sprite * sprite); +static void sub_80985BC(struct Sprite * sprite); + +static const struct OamData gUnknown_83D416C = { + .affineMode = ST_OAM_AFFINE_NORMAL, + .shape = ST_OAM_SQUARE, + .size = 3, + .priority = 1, + .paletteNum = 0 +}; + +static const union AnimCmd gUnknown_83D4174[] = { + ANIMCMD_FRAME( 0, 5), + ANIMCMD_FRAME(0x40, 0), + ANIMCMD_END +}; + +static const union AnimCmd gUnknown_83D4180[] = { + ANIMCMD_FRAME( 0, 5), + ANIMCMD_FRAME(0x80, 0), + ANIMCMD_END +}; + +static const union AnimCmd gUnknown_83D418C[] = { + ANIMCMD_FRAME( 0, 5), + ANIMCMD_FRAME(0xc0, 0), + ANIMCMD_END +}; + +static const union AnimCmd *const gUnknown_83D4198[] = { + gUnknown_83D4180, + gUnknown_83D418C, + gUnknown_83D4174 +}; + +static const union AffineAnimCmd gUnknown_83D41A4[] = { + AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd gUnknown_83D41B4[] = { + AFFINEANIMCMD_FRAME(0, 0, -2, 2), + AFFINEANIMCMD_FRAME(0, 0, 2, 4), + AFFINEANIMCMD_FRAME(0, 0, -2, 4), + AFFINEANIMCMD_FRAME(0, 0, 2, 2), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd *const gUnknown_83D41DC[] = { + gUnknown_83D41A4, + gUnknown_83D41B4 +}; + +const struct CompressedSpriteSheet gUnknown_83D41E4 = { + gUnknown_8E8362C, + 0x2000, + 100 +}; + +const struct CompressedSpriteSheet gUnknown_83D41EC = { + gUnknown_8E83DBC, + 0x2000, + 100 +}; + +const struct CompressedSpritePalette gUnknown_83D41F4 = { + gUnknown_8E84560, + 100 +}; + +static const struct SpriteTemplate gUnknown_83D41FC = { + 100, + 100, + &gUnknown_83D416C, + gUnknown_83D4198, + NULL, + gUnknown_83D41DC, + SpriteCallbackDummy +}; + +static const struct OamData gUnknown_83D4214 = { + .affineMode = ST_OAM_AFFINE_OFF, + .shape = ST_OAM_SQUARE, + .size = 1, + .priority = 1, + .paletteNum = 1 +}; + +static const union AnimCmd gUnknown_83D421C[] = { + ANIMCMD_FRAME(0, 0), + ANIMCMD_END +}; + +static const union AnimCmd gUnknown_83D4224[] = { + ANIMCMD_FRAME(4, 0), + ANIMCMD_END +}; + +static const union AnimCmd gUnknown_83D422C[] = { + ANIMCMD_FRAME(0, 0, .hFlip = TRUE), + ANIMCMD_END +}; + +static const union AnimCmd *const gUnknown_83D4234[] = { + gUnknown_83D421C, + gUnknown_83D4224, + gUnknown_83D422C +}; + +const struct CompressedSpriteSheet gBagSwapSpriteSheet = { + gFile_graphics_interface_bag_swap_sheet, + 0x100, + 101 +}; + +const struct CompressedSpritePalette gBagSwapSpritePalette = { + gFile_graphics_interface_bag_swap_palette, + 101 +}; + +static const struct SpriteTemplate gUnknown_83D4250 = { + 101, + 101, + &gUnknown_83D4214, + gUnknown_83D4234, + NULL, + gDummySpriteAffineAnimTable, + SpriteCallbackDummy +}; + +static const struct OamData gUnknown_83D4268 = { + .affineMode = ST_OAM_AFFINE_OFF, + .shape = ST_OAM_SQUARE, + .size = 2, + .priority = 1, + .paletteNum = 2 +}; + +static const union AnimCmd gUnknown_83D4270[] = { + ANIMCMD_FRAME(0, 0), + ANIMCMD_END +}; + +static const union AnimCmd *const gUnknown_83D4278[] = { + gUnknown_83D4270 +}; + +static const struct SpriteTemplate gUnknown_83D427C = { + 102, + 102, + &gUnknown_83D4268, + gUnknown_83D4278, + NULL, + gDummySpriteAffineAnimTable, + SpriteCallbackDummy +}; + +static const void *const gUnknown_83D4294[][2] = { + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_master_ball_sheet, gFile_graphics_items_icon_palettes_master_ball_palette}, + {gFile_graphics_items_icons_ultra_ball_sheet, gFile_graphics_items_icon_palettes_ultra_ball_palette}, + {gFile_graphics_items_icons_great_ball_sheet, gFile_graphics_items_icon_palettes_great_ball_palette}, + {gFile_graphics_items_icons_poke_ball_sheet, gFile_graphics_items_icon_palettes_poke_ball_palette}, + {gFile_graphics_items_icons_safari_ball_sheet, gFile_graphics_items_icon_palettes_safari_ball_palette}, + {gFile_graphics_items_icons_net_ball_sheet, gFile_graphics_items_icon_palettes_net_ball_palette}, + {gFile_graphics_items_icons_dive_ball_sheet, gFile_graphics_items_icon_palettes_dive_ball_palette}, + {gFile_graphics_items_icons_nest_ball_sheet, gFile_graphics_items_icon_palettes_nest_ball_palette}, + {gFile_graphics_items_icons_repeat_ball_sheet, gFile_graphics_items_icon_palettes_repeat_ball_palette}, + {gFile_graphics_items_icons_timer_ball_sheet, gFile_graphics_items_icon_palettes_repeat_ball_palette}, + {gFile_graphics_items_icons_luxury_ball_sheet, gFile_graphics_items_icon_palettes_luxury_ball_palette}, + {gFile_graphics_items_icons_premier_ball_sheet, gFile_graphics_items_icon_palettes_luxury_ball_palette}, + {gFile_graphics_items_icons_potion_sheet, gFile_graphics_items_icon_palettes_potion_palette}, + {gFile_graphics_items_icons_antidote_sheet, gFile_graphics_items_icon_palettes_antidote_palette}, + {gFile_graphics_items_icons_status_heal_sheet, gFile_graphics_items_icon_palettes_burn_heal_palette}, + {gFile_graphics_items_icons_status_heal_sheet, gFile_graphics_items_icon_palettes_ice_heal_palette}, + {gFile_graphics_items_icons_status_heal_sheet, gFile_graphics_items_icon_palettes_awakening_palette}, + {gFile_graphics_items_icons_status_heal_sheet, gFile_graphics_items_icon_palettes_paralyze_heal_palette}, + {gFile_graphics_items_icons_large_potion_sheet, gFile_graphics_items_icon_palettes_full_restore_palette}, + {gFile_graphics_items_icons_large_potion_sheet, gFile_graphics_items_icon_palettes_max_potion_palette}, + {gFile_graphics_items_icons_potion_sheet, gFile_graphics_items_icon_palettes_hyper_potion_palette}, + {gFile_graphics_items_icons_potion_sheet, gFile_graphics_items_icon_palettes_super_potion_palette}, + {gFile_graphics_items_icons_full_heal_sheet, gFile_graphics_items_icon_palettes_full_heal_palette}, + {gFile_graphics_items_icons_revive_sheet, gFile_graphics_items_icon_palettes_revive_palette}, + {gFile_graphics_items_icons_max_revive_sheet, gFile_graphics_items_icon_palettes_revive_palette}, + {gFile_graphics_items_icons_fresh_water_sheet, gFile_graphics_items_icon_palettes_fresh_water_palette}, + {gFile_graphics_items_icons_soda_pop_sheet, gFile_graphics_items_icon_palettes_soda_pop_palette}, + {gFile_graphics_items_icons_lemonade_sheet, gFile_graphics_items_icon_palettes_lemonade_palette}, + {gFile_graphics_items_icons_moomoo_milk_sheet, gFile_graphics_items_icon_palettes_moomoo_milk_palette}, + {gFile_graphics_items_icons_powder_sheet, gFile_graphics_items_icon_palettes_energy_powder_palette}, + {gFile_graphics_items_icons_energy_root_sheet, gFile_graphics_items_icon_palettes_energy_root_palette}, + {gFile_graphics_items_icons_powder_sheet, gFile_graphics_items_icon_palettes_heal_powder_palette}, + {gFile_graphics_items_icons_revival_herb_sheet, gFile_graphics_items_icon_palettes_revival_herb_palette}, + {gFile_graphics_items_icons_ether_sheet, gFile_graphics_items_icon_palettes_ether_palette}, + {gFile_graphics_items_icons_ether_sheet, gFile_graphics_items_icon_palettes_max_ether_palette}, + {gFile_graphics_items_icons_ether_sheet, gFile_graphics_items_icon_palettes_elixir_palette}, + {gFile_graphics_items_icons_ether_sheet, gFile_graphics_items_icon_palettes_max_elixir_palette}, + {gFile_graphics_items_icons_lava_cookie_sheet, gFile_graphics_items_icon_palettes_lava_cookie_and_letter_palette}, + {gFile_graphics_items_icons_flute_sheet, gFile_graphics_items_icon_palettes_blue_flute_palette}, + {gFile_graphics_items_icons_flute_sheet, gFile_graphics_items_icon_palettes_yellow_flute_palette}, + {gFile_graphics_items_icons_flute_sheet, gFile_graphics_items_icon_palettes_red_flute_palette}, + {gFile_graphics_items_icons_flute_sheet, gFile_graphics_items_icon_palettes_black_flute_palette}, + {gFile_graphics_items_icons_flute_sheet, gFile_graphics_items_icon_palettes_white_flute_palette}, + {gFile_graphics_items_icons_berry_juice_sheet, gFile_graphics_items_icon_palettes_berry_juice_palette}, + {gFile_graphics_items_icons_sacred_ash_sheet, gFile_graphics_items_icon_palettes_sacred_ash_palette}, + {gFile_graphics_items_icons_powder_sheet, gFile_graphics_items_icon_palettes_shoal_salt_palette}, + {gFile_graphics_items_icons_shoal_shell_sheet, gFile_graphics_items_icon_palettes_shell_palette}, + {gFile_graphics_items_icons_shard_sheet, gFile_graphics_items_icon_palettes_red_shard_palette}, + {gFile_graphics_items_icons_shard_sheet, gFile_graphics_items_icon_palettes_blue_shard_palette}, + {gFile_graphics_items_icons_shard_sheet, gFile_graphics_items_icon_palettes_yellow_shard_palette}, + {gFile_graphics_items_icons_shard_sheet, gFile_graphics_items_icon_palettes_green_shard_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_hp_up_sheet, gFile_graphics_items_icon_palettes_hp_up_palette}, + {gFile_graphics_items_icons_vitamin_sheet, gFile_graphics_items_icon_palettes_protein_palette}, + {gFile_graphics_items_icons_vitamin_sheet, gFile_graphics_items_icon_palettes_iron_palette}, + {gFile_graphics_items_icons_vitamin_sheet, gFile_graphics_items_icon_palettes_carbos_palette}, + {gFile_graphics_items_icons_vitamin_sheet, gFile_graphics_items_icon_palettes_calcium_palette}, + {gFile_graphics_items_icons_rare_candy_sheet, gFile_graphics_items_icon_palettes_rare_candy_palette}, + {gFile_graphics_items_icons_pp_up_sheet, gFile_graphics_items_icon_palettes_pp_up_palette}, + {gFile_graphics_items_icons_vitamin_sheet, gFile_graphics_items_icon_palettes_zinc_palette}, + {gFile_graphics_items_icons_pp_max_sheet, gFile_graphics_items_icon_palettes_pp_max_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_battle_stat_item_sheet, gFile_graphics_items_icon_palettes_guard_spec_palette}, + {gFile_graphics_items_icons_battle_stat_item_sheet, gFile_graphics_items_icon_palettes_dire_hit_palette}, + {gFile_graphics_items_icons_battle_stat_item_sheet, gFile_graphics_items_icon_palettes_x_attack_palette}, + {gFile_graphics_items_icons_battle_stat_item_sheet, gFile_graphics_items_icon_palettes_x_defend_palette}, + {gFile_graphics_items_icons_battle_stat_item_sheet, gFile_graphics_items_icon_palettes_x_speed_palette}, + {gFile_graphics_items_icons_battle_stat_item_sheet, gFile_graphics_items_icon_palettes_x_accuracy_palette}, + {gFile_graphics_items_icons_battle_stat_item_sheet, gFile_graphics_items_icon_palettes_x_special_palette}, + {gFile_graphics_items_icons_poke_doll_sheet, gFile_graphics_items_icon_palettes_poke_doll_palette}, + {gFile_graphics_items_icons_fluffy_tail_sheet, gFile_graphics_items_icon_palettes_fluffy_tail_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_repel_sheet, gFile_graphics_items_icon_palettes_super_repel_palette}, + {gFile_graphics_items_icons_repel_sheet, gFile_graphics_items_icon_palettes_max_repel_palette}, + {gFile_graphics_items_icons_escape_rope_sheet, gFile_graphics_items_icon_palettes_escape_rope_palette}, + {gFile_graphics_items_icons_repel_sheet, gFile_graphics_items_icon_palettes_repel_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_sun_stone_sheet, gFile_graphics_items_icon_palettes_sun_stone_palette}, + {gFile_graphics_items_icons_moon_stone_sheet, gFile_graphics_items_icon_palettes_moon_stone_palette}, + {gFile_graphics_items_icons_fire_stone_sheet, gFile_graphics_items_icon_palettes_fire_stone_palette}, + {gFile_graphics_items_icons_thunder_stone_sheet, gFile_graphics_items_icon_palettes_thunder_stone_palette}, + {gFile_graphics_items_icons_water_stone_sheet, gFile_graphics_items_icon_palettes_water_stone_palette}, + {gFile_graphics_items_icons_leaf_stone_sheet, gFile_graphics_items_icon_palettes_leaf_stone_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_tiny_mushroom_sheet, gFile_graphics_items_icon_palettes_mushroom_palette}, + {gFile_graphics_items_icons_big_mushroom_sheet, gFile_graphics_items_icon_palettes_mushroom_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_pearl_sheet, gFile_graphics_items_icon_palettes_pearl_palette}, + {gFile_graphics_items_icons_big_pearl_sheet, gFile_graphics_items_icon_palettes_pearl_palette}, + {gFile_graphics_items_icons_stardust_sheet, gFile_graphics_items_icon_palettes_star_palette}, + {gFile_graphics_items_icons_star_piece_sheet, gFile_graphics_items_icon_palettes_star_palette}, + {gFile_graphics_items_icons_nugget_sheet, gFile_graphics_items_icon_palettes_nugget_palette}, + {gFile_graphics_items_icons_heart_scale_sheet, gFile_graphics_items_icon_palettes_heart_scale_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_orange_mail_sheet, gFile_graphics_items_icon_palettes_orange_mail_palette}, + {gFile_graphics_items_icons_harbor_mail_sheet, gFile_graphics_items_icon_palettes_harbor_mail_palette}, + {gFile_graphics_items_icons_glitter_mail_sheet, gFile_graphics_items_icon_palettes_glitter_mail_palette}, + {gFile_graphics_items_icons_mech_mail_sheet, gFile_graphics_items_icon_palettes_mech_mail_palette}, + {gFile_graphics_items_icons_wood_mail_sheet, gFile_graphics_items_icon_palettes_wood_mail_palette}, + {gFile_graphics_items_icons_wave_mail_sheet, gFile_graphics_items_icon_palettes_wave_mail_palette}, + {gFile_graphics_items_icons_bead_mail_sheet, gFile_graphics_items_icon_palettes_bead_mail_palette}, + {gFile_graphics_items_icons_shadow_mail_sheet, gFile_graphics_items_icon_palettes_shadow_mail_palette}, + {gFile_graphics_items_icons_tropic_mail_sheet, gFile_graphics_items_icon_palettes_tropic_mail_palette}, + {gFile_graphics_items_icons_dream_mail_sheet, gFile_graphics_items_icon_palettes_dream_mail_palette}, + {gFile_graphics_items_icons_fab_mail_sheet, gFile_graphics_items_icon_palettes_fab_mail_palette}, + {gFile_graphics_items_icons_retro_mail_sheet, gFile_graphics_items_icon_palettes_retro_mail_palette}, + {gFile_graphics_items_icons_cheri_berry_sheet, gFile_graphics_items_icon_palettes_cheri_berry_palette}, + {gFile_graphics_items_icons_chesto_berry_sheet, gFile_graphics_items_icon_palettes_chesto_berry_palette}, + {gFile_graphics_items_icons_pecha_berry_sheet, gFile_graphics_items_icon_palettes_pecha_berry_palette}, + {gFile_graphics_items_icons_rawst_berry_sheet, gFile_graphics_items_icon_palettes_rawst_berry_palette}, + {gFile_graphics_items_icons_aspear_berry_sheet, gFile_graphics_items_icon_palettes_aspear_berry_palette}, + {gFile_graphics_items_icons_leppa_berry_sheet, gFile_graphics_items_icon_palettes_leppa_berry_palette}, + {gFile_graphics_items_icons_oran_berry_sheet, gFile_graphics_items_icon_palettes_oran_berry_palette}, + {gFile_graphics_items_icons_persim_berry_sheet, gFile_graphics_items_icon_palettes_persim_berry_palette}, + {gFile_graphics_items_icons_lum_berry_sheet, gFile_graphics_items_icon_palettes_lum_berry_palette}, + {gFile_graphics_items_icons_sitrus_berry_sheet, gFile_graphics_items_icon_palettes_sitrus_berry_palette}, + {gFile_graphics_items_icons_figy_berry_sheet, gFile_graphics_items_icon_palettes_figy_berry_palette}, + {gFile_graphics_items_icons_wiki_berry_sheet, gFile_graphics_items_icon_palettes_wiki_berry_palette}, + {gFile_graphics_items_icons_mago_berry_sheet, gFile_graphics_items_icon_palettes_mago_berry_palette}, + {gFile_graphics_items_icons_aguav_berry_sheet, gFile_graphics_items_icon_palettes_aguav_berry_palette}, + {gFile_graphics_items_icons_iapapa_berry_sheet, gFile_graphics_items_icon_palettes_iapapa_berry_palette}, + {gFile_graphics_items_icons_razz_berry_sheet, gFile_graphics_items_icon_palettes_razz_berry_palette}, + {gFile_graphics_items_icons_bluk_berry_sheet, gFile_graphics_items_icon_palettes_bluk_berry_palette}, + {gFile_graphics_items_icons_nanab_berry_sheet, gFile_graphics_items_icon_palettes_nanab_berry_palette}, + {gFile_graphics_items_icons_wepear_berry_sheet, gFile_graphics_items_icon_palettes_wepear_berry_palette}, + {gFile_graphics_items_icons_pinap_berry_sheet, gFile_graphics_items_icon_palettes_pinap_berry_palette}, + {gFile_graphics_items_icons_pomeg_berry_sheet, gFile_graphics_items_icon_palettes_pomeg_berry_palette}, + {gFile_graphics_items_icons_kelpsy_berry_sheet, gFile_graphics_items_icon_palettes_kelpsy_berry_palette}, + {gFile_graphics_items_icons_qualot_berry_sheet, gFile_graphics_items_icon_palettes_qualot_berry_palette}, + {gFile_graphics_items_icons_hondew_berry_sheet, gFile_graphics_items_icon_palettes_hondew_berry_palette}, + {gFile_graphics_items_icons_grepa_berry_sheet, gFile_graphics_items_icon_palettes_grepa_berry_palette}, + {gFile_graphics_items_icons_tamato_berry_sheet, gFile_graphics_items_icon_palettes_tamato_berry_palette}, + {gFile_graphics_items_icons_cornn_berry_sheet, gFile_graphics_items_icon_palettes_cornn_berry_palette}, + {gFile_graphics_items_icons_magost_berry_sheet, gFile_graphics_items_icon_palettes_magost_berry_palette}, + {gFile_graphics_items_icons_rabuta_berry_sheet, gFile_graphics_items_icon_palettes_rabuta_berry_palette}, + {gFile_graphics_items_icons_nomel_berry_sheet, gFile_graphics_items_icon_palettes_nomel_berry_palette}, + {gFile_graphics_items_icons_spelon_berry_sheet, gFile_graphics_items_icon_palettes_spelon_berry_palette}, + {gFile_graphics_items_icons_pamtre_berry_sheet, gFile_graphics_items_icon_palettes_pamtre_berry_palette}, + {gFile_graphics_items_icons_watmel_berry_sheet, gFile_graphics_items_icon_palettes_watmel_berry_palette}, + {gFile_graphics_items_icons_durin_berry_sheet, gFile_graphics_items_icon_palettes_durin_berry_palette}, + {gFile_graphics_items_icons_belue_berry_sheet, gFile_graphics_items_icon_palettes_belue_berry_palette}, + {gFile_graphics_items_icons_liechi_berry_sheet, gFile_graphics_items_icon_palettes_liechi_berry_palette}, + {gFile_graphics_items_icons_ganlon_berry_sheet, gFile_graphics_items_icon_palettes_ganlon_berry_palette}, + {gFile_graphics_items_icons_salac_berry_sheet, gFile_graphics_items_icon_palettes_salac_berry_palette}, + {gFile_graphics_items_icons_petaya_berry_sheet, gFile_graphics_items_icon_palettes_petaya_berry_palette}, + {gFile_graphics_items_icons_apicot_berry_sheet, gFile_graphics_items_icon_palettes_apicot_berry_palette}, + {gFile_graphics_items_icons_lansat_berry_sheet, gFile_graphics_items_icon_palettes_lansat_berry_palette}, + {gFile_graphics_items_icons_starf_berry_sheet, gFile_graphics_items_icon_palettes_starf_berry_palette}, + {gFile_graphics_items_icons_enigma_berry_sheet, gFile_graphics_items_icon_palettes_enigma_berry_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_bright_powder_sheet, gFile_graphics_items_icon_palettes_bright_powder_palette}, + {gFile_graphics_items_icons_in_battle_herb_sheet, gFile_graphics_items_icon_palettes_white_herb_palette}, + {gFile_graphics_items_icons_macho_brace_sheet, gFile_graphics_items_icon_palettes_macho_brace_palette}, + {gFile_graphics_items_icons_exp_share_sheet, gFile_graphics_items_icon_palettes_exp_share_palette}, + {gFile_graphics_items_icons_quick_claw_sheet, gFile_graphics_items_icon_palettes_quick_claw_palette}, + {gFile_graphics_items_icons_soothe_bell_sheet, gFile_graphics_items_icon_palettes_soothe_bell_palette}, + {gFile_graphics_items_icons_in_battle_herb_sheet, gFile_graphics_items_icon_palettes_mental_herb_palette}, + {gFile_graphics_items_icons_choice_band_sheet, gFile_graphics_items_icon_palettes_choice_band_palette}, + {gFile_graphics_items_icons_kings_rock_sheet, gFile_graphics_items_icon_palettes_kings_rock_palette}, + {gFile_graphics_items_icons_silver_powder_sheet, gFile_graphics_items_icon_palettes_silver_powder_palette}, + {gFile_graphics_items_icons_amulet_coin_sheet, gFile_graphics_items_icon_palettes_amulet_coin_palette}, + {gFile_graphics_items_icons_cleanse_tag_sheet, gFile_graphics_items_icon_palettes_cleanse_tag_palette}, + {gFile_graphics_items_icons_soul_dew_sheet, gFile_graphics_items_icon_palettes_soul_dew_palette}, + {gFile_graphics_items_icons_deep_sea_tooth_sheet, gFile_graphics_items_icon_palettes_deep_sea_tooth_palette}, + {gFile_graphics_items_icons_deep_sea_scale_sheet, gFile_graphics_items_icon_palettes_deep_sea_scale_palette}, + {gFile_graphics_items_icons_smoke_ball_sheet, gFile_graphics_items_icon_palettes_smoke_ball_palette}, + {gFile_graphics_items_icons_everstone_sheet, gFile_graphics_items_icon_palettes_everstone_palette}, + {gFile_graphics_items_icons_focus_band_sheet, gFile_graphics_items_icon_palettes_focus_band_palette}, + {gFile_graphics_items_icons_lucky_egg_sheet, gFile_graphics_items_icon_palettes_lucky_egg_palette}, + {gFile_graphics_items_icons_scope_lens_sheet, gFile_graphics_items_icon_palettes_scope_lens_palette}, + {gFile_graphics_items_icons_metal_coat_sheet, gFile_graphics_items_icon_palettes_metal_coat_palette}, + {gFile_graphics_items_icons_leftovers_sheet, gFile_graphics_items_icon_palettes_leftovers_palette}, + {gFile_graphics_items_icons_dragon_scale_sheet, gFile_graphics_items_icon_palettes_dragon_scale_palette}, + {gFile_graphics_items_icons_light_ball_sheet, gFile_graphics_items_icon_palettes_light_ball_palette}, + {gFile_graphics_items_icons_soft_sand_sheet, gFile_graphics_items_icon_palettes_soft_sand_palette}, + {gFile_graphics_items_icons_hard_stone_sheet, gFile_graphics_items_icon_palettes_hard_stone_palette}, + {gFile_graphics_items_icons_miracle_seed_sheet, gFile_graphics_items_icon_palettes_miracle_seed_palette}, + {gFile_graphics_items_icons_black_glasses_sheet, gFile_graphics_items_icon_palettes_black_type_enhancing_item_palette}, + {gFile_graphics_items_icons_black_belt_sheet, gFile_graphics_items_icon_palettes_black_type_enhancing_item_palette}, + {gFile_graphics_items_icons_magnet_sheet, gFile_graphics_items_icon_palettes_magnet_palette}, + {gFile_graphics_items_icons_mystic_water_sheet, gFile_graphics_items_icon_palettes_mystic_water_palette}, + {gFile_graphics_items_icons_sharp_beak_sheet, gFile_graphics_items_icon_palettes_sharp_beak_palette}, + {gFile_graphics_items_icons_poison_barb_sheet, gFile_graphics_items_icon_palettes_poison_barb_palette}, + {gFile_graphics_items_icons_never_melt_ice_sheet, gFile_graphics_items_icon_palettes_never_melt_ice_palette}, + {gFile_graphics_items_icons_spell_tag_sheet, gFile_graphics_items_icon_palettes_spell_tag_palette}, + {gFile_graphics_items_icons_twisted_spoon_sheet, gFile_graphics_items_icon_palettes_twisted_spoon_palette}, + {gFile_graphics_items_icons_charcoal_sheet, gFile_graphics_items_icon_palettes_charcoal_palette}, + {gFile_graphics_items_icons_dragon_fang_sheet, gFile_graphics_items_icon_palettes_dragon_fang_palette}, + {gFile_graphics_items_icons_silk_scarf_sheet, gFile_graphics_items_icon_palettes_silk_scarf_palette}, + {gFile_graphics_items_icons_up_grade_sheet, gFile_graphics_items_icon_palettes_up_grade_palette}, + {gFile_graphics_items_icons_shell_bell_sheet, gFile_graphics_items_icon_palettes_shell_palette}, + {gFile_graphics_items_icons_sea_incense_sheet, gFile_graphics_items_icon_palettes_sea_incense_palette}, + {gFile_graphics_items_icons_lax_incense_sheet, gFile_graphics_items_icon_palettes_lax_incense_palette}, + {gFile_graphics_items_icons_lucky_punch_sheet, gFile_graphics_items_icon_palettes_lucky_punch_palette}, + {gFile_graphics_items_icons_metal_powder_sheet, gFile_graphics_items_icon_palettes_metal_powder_palette}, + {gFile_graphics_items_icons_thick_club_sheet, gFile_graphics_items_icon_palettes_thick_club_palette}, + {gFile_graphics_items_icons_stick_sheet, gFile_graphics_items_icon_palettes_stick_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_scarf_sheet, gFile_graphics_items_icon_palettes_red_scarf_palette}, + {gFile_graphics_items_icons_scarf_sheet, gFile_graphics_items_icon_palettes_blue_scarf_palette}, + {gFile_graphics_items_icons_scarf_sheet, gFile_graphics_items_icon_palettes_pink_scarf_palette}, + {gFile_graphics_items_icons_scarf_sheet, gFile_graphics_items_icon_palettes_green_scarf_palette}, + {gFile_graphics_items_icons_scarf_sheet, gFile_graphics_items_icon_palettes_yellow_scarf_palette}, + {gFile_graphics_items_icons_mach_bike_sheet, gFile_graphics_items_icon_palettes_mach_bike_palette}, + {gFile_graphics_items_icons_coin_case_sheet, gFile_graphics_items_icon_palettes_coin_case_palette}, + {gFile_graphics_items_icons_itemfinder_sheet, gFile_graphics_items_icon_palettes_itemfinder_palette}, + {gFile_graphics_items_icons_old_rod_sheet, gFile_graphics_items_icon_palettes_old_rod_palette}, + {gFile_graphics_items_icons_good_rod_sheet, gFile_graphics_items_icon_palettes_good_rod_palette}, + {gFile_graphics_items_icons_super_rod_sheet, gFile_graphics_items_icon_palettes_super_rod_palette}, + {gFile_graphics_items_icons_ss_ticket_sheet, gFile_graphics_items_icon_palettes_ss_ticket_palette}, + {gFile_graphics_items_icons_contest_pass_sheet, gFile_graphics_items_icon_palettes_contest_pass_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_wailmer_pail_sheet, gFile_graphics_items_icon_palettes_wailmer_pail_palette}, + {gFile_graphics_items_icons_devon_goods_sheet, gFile_graphics_items_icon_palettes_devon_goods_palette}, + {gFile_graphics_items_icons_soot_sack_sheet, gFile_graphics_items_icon_palettes_soot_sack_palette}, + {gFile_graphics_items_icons_basement_key_sheet, gFile_graphics_items_icon_palettes_old_key_palette}, + {gFile_graphics_items_icons_acro_bike_sheet, gFile_graphics_items_icon_palettes_acro_bike_palette}, + {gFile_graphics_items_icons_pokeblock_case_sheet, gFile_graphics_items_icon_palettes_pokeblock_case_palette}, + {gFile_graphics_items_icons_letter_sheet, gFile_graphics_items_icon_palettes_lava_cookie_and_letter_palette}, + {gFile_graphics_items_icons_eon_ticket_sheet, gFile_graphics_items_icon_palettes_eon_ticket_palette}, + {gFile_graphics_items_icons_orb_sheet, gFile_graphics_items_icon_palettes_red_orb_palette}, + {gFile_graphics_items_icons_orb_sheet, gFile_graphics_items_icon_palettes_blue_orb_palette}, + {gFile_graphics_items_icons_scanner_sheet, gFile_graphics_items_icon_palettes_scanner_palette}, + {gFile_graphics_items_icons_go_goggles_sheet, gFile_graphics_items_icon_palettes_go_goggles_palette}, + {gFile_graphics_items_icons_meteorite_sheet, gFile_graphics_items_icon_palettes_meteorite_palette}, + {gFile_graphics_items_icons_room1_key_sheet, gFile_graphics_items_icon_palettes_key_palette}, + {gFile_graphics_items_icons_room2_key_sheet, gFile_graphics_items_icon_palettes_key_palette}, + {gFile_graphics_items_icons_room4_key_sheet, gFile_graphics_items_icon_palettes_key_palette}, + {gFile_graphics_items_icons_room6_key_sheet, gFile_graphics_items_icon_palettes_key_palette}, + {gFile_graphics_items_icons_storage_key_sheet, gFile_graphics_items_icon_palettes_old_key_palette}, + {gFile_graphics_items_icons_root_fossil_sheet, gFile_graphics_items_icon_palettes_hoenn_fossil_palette}, + {gFile_graphics_items_icons_claw_fossil_sheet, gFile_graphics_items_icon_palettes_hoenn_fossil_palette}, + {gFile_graphics_items_icons_devon_scope_sheet, gFile_graphics_items_icon_palettes_devon_scope_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_fighting_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_dragon_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_water_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_psychic_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_poison_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_ice_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_fighting_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_grass_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_fire_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_dark_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_ice_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_ice_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_psychic_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_water_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_grass_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_grass_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_steel_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_electric_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_electric_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_ground_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_ground_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_psychic_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_ghost_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_fighting_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_psychic_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_electric_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_fire_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_poison_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_rock_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_fire_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_rock_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_flying_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_dark_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_psychic_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_dark_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_steel_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_psychic_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_dark_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_fire_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_flying_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_water_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_normal_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_fighting_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_water_tm_hm_palette}, + {gFile_graphics_items_icons_tm_sheet, gFile_graphics_items_icon_palettes_water_tm_hm_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_question_mark_sheet, gFile_graphics_items_icon_palettes_question_mark_palette}, + {gFile_graphics_items_icons_oaks_parcel_sheet, gFile_graphics_items_icon_palettes_oaks_parcel_palette}, + {gFile_graphics_items_icons_poke_flute_sheet, gFile_graphics_items_icon_palettes_poke_flute_palette}, + {gFile_graphics_items_icons_secret_key_sheet, gFile_graphics_items_icon_palettes_secret_key_palette}, + {gFile_graphics_items_icons_bike_voucher_sheet, gFile_graphics_items_icon_palettes_bike_voucher_palette}, + {gFile_graphics_items_icons_gold_teeth_sheet, gFile_graphics_items_icon_palettes_gold_teeth_palette}, + {gFile_graphics_items_icons_old_amber_sheet, gFile_graphics_items_icon_palettes_old_amber_palette}, + {gFile_graphics_items_icons_card_key_sheet, gFile_graphics_items_icon_palettes_card_key_palette}, + {gFile_graphics_items_icons_lift_key_sheet, gFile_graphics_items_icon_palettes_key_palette}, + {gFile_graphics_items_icons_helix_fossil_sheet, gFile_graphics_items_icon_palettes_kanto_fossil_palette}, + {gFile_graphics_items_icons_dome_fossil_sheet, gFile_graphics_items_icon_palettes_kanto_fossil_palette}, + {gFile_graphics_items_icons_silph_scope_sheet, gFile_graphics_items_icon_palettes_silph_scope_palette}, + {gFile_graphics_items_icons_bicycle_sheet, gFile_graphics_items_icon_palettes_bicycle_palette}, + {gFile_graphics_items_icons_town_map_sheet, gFile_graphics_items_icon_palettes_town_map_palette}, + {gFile_graphics_items_icons_vs_seeker_sheet, gFile_graphics_items_icon_palettes_vs_seeker_palette}, + {gFile_graphics_items_icons_fame_checker_sheet, gFile_graphics_items_icon_palettes_fame_checker_palette}, + {gFile_graphics_items_icons_tm_case_sheet, gFile_graphics_items_icon_palettes_tm_case_palette}, + {gFile_graphics_items_icons_berry_pouch_sheet, gFile_graphics_items_icon_palettes_berry_pouch_palette}, + {gFile_graphics_items_icons_teachy_tv_sheet, gFile_graphics_items_icon_palettes_teachy_tv_palette}, + {gFile_graphics_items_icons_tri_pass_sheet, gFile_graphics_items_icon_palettes_tri_pass_palette}, + {gFile_graphics_items_icons_rainbow_pass_sheet, gFile_graphics_items_icon_palettes_rainbow_pass_palette}, + {gFile_graphics_items_icons_tea_sheet, gFile_graphics_items_icon_palettes_tea_palette}, + {gFile_graphics_items_icons_mystic_ticket_sheet, gFile_graphics_items_icon_palettes_mystic_ticket_palette}, + {gFile_graphics_items_icons_aurora_ticket_sheet, gFile_graphics_items_icon_palettes_aurora_ticket_palette}, + {gFile_graphics_items_icons_powder_jar_sheet, gFile_graphics_items_icon_palettes_powder_jar_palette}, + {gFile_graphics_items_icons_gem_sheet, gFile_graphics_items_icon_palettes_ruby_palette}, + {gFile_graphics_items_icons_gem_sheet, gFile_graphics_items_icon_palettes_sapphire_palette}, + {gFile_graphics_items_icons_return_to_field_arrow_sheet, gFile_graphics_items_icon_palettes_return_to_field_arrow_palette} +}; + +void ResetItemMenuIconState(void) +{ + u16 i; + + for (i = 0; i < NELEMS(gUnknown_2039878); i++) + gUnknown_2039878[i] = 0xFF; +} + +void sub_80984FC(u8 animNum) +{ + gUnknown_2039878[0] = CreateSprite(&gUnknown_83D41FC, 40, 68, 0); + sub_8098528(animNum); +} + +void sub_8098528(u8 animNum) +{ + struct Sprite * sprite = &gSprites[gUnknown_2039878[0]]; + sprite->pos2.y = -5; + sprite->callback = sub_8098560; + StartSpriteAnim(sprite, animNum); +} + +static void sub_8098560(struct Sprite * sprite) +{ + if (sprite->pos2.y != 0) + sprite->pos2.y++; + else + sprite->callback = SpriteCallbackDummy; +} + +void sub_8098580(void) +{ + struct Sprite * sprite = &gSprites[gUnknown_2039878[0]]; + if (sprite->affineAnimEnded) + { + StartSpriteAffineAnim(sprite, 1); + sprite->callback = sub_80985BC; + } +} + +static void sub_80985BC(struct Sprite * sprite) +{ + if (sprite->affineAnimEnded) + { + StartSpriteAffineAnim(sprite, 0); + sprite->callback = SpriteCallbackDummy; + } +} + +void sub_80985E4(void) +{ + u8 i; + u8 * ptr = &gUnknown_2039878[1]; + + for (i = 0; i < 9; i++) + { + ptr[i] = CreateSprite(&gUnknown_83D4250, i * 16 + 0x60, 7, 0); + if (i != 0) + { + if (i == 8) + StartSpriteAnim(&gSprites[ptr[i]], 2); + else + StartSpriteAnim(&gSprites[ptr[i]], 1); + } + gSprites[ptr[i]].invisible = TRUE; + } +} + +void sub_8098660(u8 flag) +{ + u8 i; + u8 * ptr = &gUnknown_2039878[1]; + + for (i = 0; i < 9; i++) + { + gSprites[ptr[i]].invisible = flag; + } +} + +void sub_80986A8(s16 x, u16 y) +{ + u8 i; + u8 * ptr = &gUnknown_2039878[1]; + + for (i = 0; i < 9; i++) + { + gSprites[ptr[i]].pos2.x = x; + gSprites[ptr[i]].pos1.y = y + 7; + } +} + +static bool8 sub_80986EC(void) +{ + void ** ptr1, ** ptr2; + + ptr1 = &gUnknown_2039884; + *ptr1 = Alloc(0x120); + if (*ptr1 == NULL) + return FALSE; + ptr2 = &gUnknown_2039888; + *ptr2 = AllocZeroed(0x200); + if (*ptr2 == NULL) + { + Free(*ptr1); + return FALSE; + } + return TRUE; +} + +void CopyItemIconPicTo4x4Buffer(const void * src, void * dest) +{ + u8 i; + + for (i = 0; i < 3; i++) + { + CpuCopy16(src + 0x60 * i, dest + 0x80 * i, 0x60); + } +} + +u8 AddItemIconObject(u16 tilesTag, u16 paletteTag, u16 itemId) +{ + struct SpriteTemplate template; + struct SpriteSheet spriteSheet; + struct CompressedSpritePalette spritePalette; + u8 spriteId; + + if (!sub_80986EC()) + return MAX_SPRITES; + + LZDecompressWram(sub_8098974(itemId, 0), gUnknown_2039884); + CopyItemIconPicTo4x4Buffer(gUnknown_2039884, gUnknown_2039888); + spriteSheet.data = gUnknown_2039888; + spriteSheet.size = 0x200; + spriteSheet.tag = tilesTag; + LoadSpriteSheet(&spriteSheet); + + spritePalette.data = sub_8098974(itemId, 1); + spritePalette.tag = paletteTag; + LoadCompressedObjectPalette(&spritePalette); + + CpuCopy16(&gUnknown_83D427C, &template, sizeof(struct SpriteTemplate)); + template.tileTag = tilesTag; + template.paletteTag = paletteTag; + spriteId = CreateSprite(&template, 0, 0, 0); + + Free(gUnknown_2039884); + Free(gUnknown_2039888); + return spriteId; +} + +u8 AddItemIconObjectWithCustomObjectTemplate(const struct SpriteTemplate * origTemplate, u16 tilesTag, u16 paletteTag, u16 itemId) +{ + struct SpriteTemplate template; + struct SpriteSheet spriteSheet; + struct CompressedSpritePalette spritePalette; + u8 spriteId; + + if (!sub_80986EC()) + return MAX_SPRITES; + + LZDecompressWram(sub_8098974(itemId, 0), gUnknown_2039884); + CopyItemIconPicTo4x4Buffer(gUnknown_2039884, gUnknown_2039888); + spriteSheet.data = gUnknown_2039888; + spriteSheet.size = 0x200; + spriteSheet.tag = tilesTag; + LoadSpriteSheet(&spriteSheet); + + spritePalette.data = sub_8098974(itemId, 1); + spritePalette.tag = paletteTag; + LoadCompressedObjectPalette(&spritePalette); + + CpuCopy16(origTemplate, &template, sizeof(struct SpriteTemplate)); + template.tileTag = tilesTag; + template.paletteTag = paletteTag; + spriteId = CreateSprite(&template, 0, 0, 0); + + Free(gUnknown_2039884); + Free(gUnknown_2039888); + return spriteId; +} + +void CreateItemMenuIcon(u16 itemId, u8 idx) +{ + u8 * ptr = &gUnknown_2039878[10]; + u8 spriteId; + + if (ptr[idx] == 0xFF) + { + FreeSpriteTilesByTag(102 + idx); + FreeSpritePaletteByTag(102 + idx); + spriteId = AddItemIconObject(102 + idx, 102 + idx, itemId); + if (spriteId != MAX_SPRITES) + { + ptr[idx] = spriteId; + gSprites[spriteId].pos2.x = 24; + gSprites[spriteId].pos2.y = 140; + } + } +} + +void DestroyItemMenuIcon(u8 idx) +{ + u8 * ptr = &gUnknown_2039878[10]; + + if (ptr[idx] != 0xFF) + { + DestroySpriteAndFreeResources(&gSprites[ptr[idx]]); + ptr[idx] = 0xFF; + } +} + +const void * sub_8098974(u16 itemId, u8 attrId) +{ + if (itemId > ITEM_N_A) + itemId = ITEM_NONE; + return gUnknown_83D4294[itemId][attrId]; +} + +void sub_80989A0(u16 itemId, u8 idx) +{ + u8 * ptr = &gUnknown_2039878[10]; + u8 spriteId; + + if (ptr[idx] == 0xFF) + { + FreeSpriteTilesByTag(102 + idx); + FreeSpritePaletteByTag(102 + idx); + spriteId = AddItemIconObject(102 + idx, 102 + idx, itemId); + if (spriteId != MAX_SPRITES) + { + ptr[idx] = spriteId; + gSprites[spriteId].pos2.x = 24; + gSprites[spriteId].pos2.y = 147; + } + } +} diff --git a/src/item_pc.c b/src/item_pc.c new file mode 100644 index 000000000..e2fa33f0a --- /dev/null +++ b/src/item_pc.c @@ -0,0 +1,1150 @@ +#include "global.h" +#include "bg.h" +#include "data2.h" +#include "decompress.h" +#include "gpu_regs.h" +#include "graphics.h" +#include "help_system.h" +#include "item.h" +#include "item_menu.h" +#include "item_menu_icons.h" +#include "list_menu.h" +#include "item_pc.h" +#include "item_use.h" +#include "main.h" +#include "malloc.h" +#include "menu.h" +#include "menu_helpers.h" +#include "menu_indicators.h" +#include "new_menu_helpers.h" +#include "palette.h" +#include "party_menu.h" +#include "pc_screen_effect.h" +#include "scanline_effect.h" +#include "sound.h" +#include "string_util.h" +#include "strings.h" +#include "task.h" +#include "text_window.h" +#include "constants/items.h" +#include "constants/songs.h" + +struct ItemPcResources +{ + MainCallback savedCallback; + u8 moveModeOrigPos; + u8 itemMenuIconSlot; + u8 maxShowed; + u8 nItems; + u8 scrollIndicatorArrowPairId; + u16 withdrawQuantitySubmenuCursorPos; + s16 data[3]; +}; + +struct ItemPcStaticResources +{ + MainCallback savedCallback; + u16 scroll; + u16 row; + u8 initialized; +}; + +static EWRAM_DATA struct ItemPcResources * sStateDataPtr = NULL; +static EWRAM_DATA u8 * sBg1TilemapBuffer = NULL; +static EWRAM_DATA struct ListMenuItem * sListMenuItems = NULL; +static EWRAM_DATA u8 * sUnusedStringAllocation = NULL; +static EWRAM_DATA struct ItemPcStaticResources sListMenuState = {}; +static EWRAM_DATA u8 sSubmenuWindowIds[3] = {}; + +extern const struct CompressedSpriteSheet gBagSwapSpriteSheet; +extern const struct CompressedSpritePalette gBagSwapSpritePalette; + +static void ItemPc_RunSetup(void); +static bool8 ItemPc_DoGfxSetup(void); +static void ItemPc_FadeAndBail(void); +static void Task_ItemPcWaitFadeAndBail(u8 taskId); +static bool8 ItemPc_InitBgs(void); +static bool8 ItemPc_LoadGraphics(void); +static bool8 ItemPc_AllocateResourcesForListMenu(void); +static void ItemPc_BuildListMenuTemplate(void); +static void ItemPc_MoveCursorFunc(s32 itemIndex, bool8 onInit, struct ListMenu * list); +static void ItemPc_ItemPrintFunc(u8 windowId, s32 itemId, u8 y); +static void ItemPc_PrintOrRemoveCursorAt(u8 y, u8 state); +static void ItemPc_PrintWithdrawItem(void); +static void ItemPc_PlaceTopMenuScrollIndicatorArrows(void); +static void ItemPc_SetCursorPosition(void); +static void ItemPc_FreeResources(void); +static void Task_ItemPcTurnOff2(u8 taskId); +static u16 ItemPc_GetItemIdBySlotId(u16 itemIndex); +static u16 ItemPc_GetItemQuantityBySlotId(u16 itemIndex); +static void ItemPc_CountPcItems(void); +static void ItemPc_SetScrollPosition(void); +static void Task_ItemPcMain(u8 taskId); +static void ItemPc_MoveItemModeInit(u8 taskId, s16 pos); +static void Task_ItemPcMoveItemModeRun(u8 taskId); +static void ItemPc_InsertItemIntoNewSlot(u8 taskId, u32 pos); +static void ItemPc_MoveItemModeCancel(u8 taskId, u32 pos); +static void Task_ItemPcSubmenuInit(u8 taskId); +static void Task_ItemPcSubmenuRun(u8 taskId); +static void Task_ItemPcWithdraw(u8 taskId); +static void ItemPc_DoWithdraw(u8 taskId); +static void Task_ItemPcWaitButtonAndFinishWithdrawMultiple(u8 taskId); +static void Task_ItemPcWaitButtonWithdrawMultipleFailed(u8 taskId); +static void Task_ItemPcCleanUpWithdraw(u8 taskId); +static void ItemPc_WithdrawMultipleInitWindow(u16 slotId); +static void Task_ItemPcHandleWithdrawMultiple(u8 taskId); +static void Task_ItemPcGive(u8 taskId); +static void ItemPc_CB2_SwitchToPartyMenu(void); +static void ItemPc_CB2_ReturnFromPartyMenu(void); +static void gTask_ItemPcWaitButtonAndExitSubmenu(u8 taskId); +static void Task_ItemPcCancel(u8 taskId); +static void ItemPc_InitWindows(void); +static void ItemPc_AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 * str, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, u8 speed, u8 colorIdx); +static void ItemPc_SetBorderStyleOnWindow(u8 windowId); +static u8 ItemPc_GetOrCreateSubwindow(u8 idx); +static void ItemPc_DestroySubwindow(u8 idx); +static void ItemPc_PrintOnWindow5WithContinueTask(u8 taskId, const u8 * str, TaskFunc taskFunc); + +static const struct BgTemplate sBgTemplates[2] = { + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .priority = 0 + }, { + .bg = 1, + .charBaseIndex = 3, + .mapBaseIndex = 30, + .priority = 1 + } +}; + +static const struct MenuAction sItemPcSubmenuOptions[] = { + {gText_Withdraw, {.void_u8 = Task_ItemPcWithdraw}}, + {gOtherText_Give, {.void_u8 = Task_ItemPcGive}}, + {gFameCheckerText_Cancel, {.void_u8 = Task_ItemPcCancel}} +}; + +static const struct TextColor gUnknown_8453F8C[] = { + {0, 1, 2}, + {0, 2, 3}, + {0, 3, 2}, + {0, 10, 2} +}; + +static const struct WindowTemplate gUnknown_8453F98[] = { + { + .bg = 0, + .tilemapLeft = 0x07, + .tilemapTop = 0x01, + .width = 0x13, + .height = 0x0c, + .paletteNum = 0x0f, + .baseBlock = 0x02bf + }, { + .bg = 0, + .tilemapLeft = 0x05, + .tilemapTop = 0x0e, + .width = 0x19, + .height = 0x06, + .paletteNum = 0x0d, + .baseBlock = 0x0229 + }, { + .bg = 0, + .tilemapLeft = 0x01, + .tilemapTop = 0x01, + .width = 0x05, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x0215 + }, { + .bg = 0, + .tilemapLeft = 0x18, + .tilemapTop = 0x0f, + .width = 0x05, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x0201 + }, { + .bg = 0, + .tilemapLeft = 0x16, + .tilemapTop = 0x0d, + .width = 0x07, + .height = 0x06, + .paletteNum = 0x0f, + .baseBlock = 0x01d7 + }, { + .bg = 0, + .tilemapLeft = 0x02, + .tilemapTop = 0x0f, + .width = 0x1a, + .height = 0x04, + .paletteNum = 0x0b, + .baseBlock = 0x016f + }, DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate gUnknown_8453FD0[] = { + { + .bg = 0, + .tilemapLeft = 0x06, + .tilemapTop = 0x0f, + .width = 0x0e, + .height = 0x04, + .paletteNum = 0x0c, + .baseBlock = 0x0137 + }, { + .bg = 0, + .tilemapLeft = 0x06, + .tilemapTop = 0x0f, + .width = 0x10, + .height = 0x04, + .paletteNum = 0x0c, + .baseBlock = 0x0137 + }, { + .bg = 0, + .tilemapLeft = 0x06, + .tilemapTop = 0x0f, + .width = 0x17, + .height = 0x04, + .paletteNum = 0x0c, + .baseBlock = 0x009b + } +}; + +void ItemPc_Init(u8 a0, MainCallback callback) +{ + u8 i; + + if (a0 >= 2) + { + SetMainCallback2(callback); + return; + } + if ((sStateDataPtr = Alloc(sizeof(struct ItemPcResources))) == NULL) + { + SetMainCallback2(callback); + return; + } + if (a0 != 1) + { + sListMenuState.savedCallback = callback; + sListMenuState.scroll = sListMenuState.row = 0; + } + sStateDataPtr->moveModeOrigPos = 0xFF; + sStateDataPtr->itemMenuIconSlot = 0; + sStateDataPtr->scrollIndicatorArrowPairId = 0xFF; + sStateDataPtr->savedCallback = 0; + for (i = 0; i < 3; i++) + { + sStateDataPtr->data[i] = 0; + } + SetMainCallback2(ItemPc_RunSetup); +} + +static void ItemPc_MainCB(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +static void ItemPc_VBlankCB(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void ItemPc_RunSetup(void) +{ + while (1) + { + if (ItemPc_DoGfxSetup() == TRUE) + break; + if (MenuHelpers_LinkSomething() == TRUE) + break; + } +} + +static bool8 ItemPc_DoGfxSetup(void) +{ + u8 taskId; + switch (gMain.state) + { + case 0: + VblankHblankHandlerSetZero(); + clear_scheduled_bg_copies_to_vram(); + gMain.state++; + break; + case 1: + ScanlineEffect_Stop(); + gMain.state++; + break; + case 2: + FreeAllSpritePalettes(); + gMain.state++; + break; + case 3: + ResetPaletteFade(); + gMain.state++; + break; + case 4: + ResetSpriteData(); + gMain.state++; + break; + case 5: + ResetItemMenuIconState(); + gMain.state++; + break; + case 6: + ResetTasks(); + gMain.state++; + break; + case 7: + if (ItemPc_InitBgs()) + { + sStateDataPtr->data[0] = 0; + gMain.state++; + } + else + { + ItemPc_FadeAndBail(); + return TRUE; + } + break; + case 8: + if (ItemPc_LoadGraphics() == TRUE) + gMain.state++; + break; + case 9: + ItemPc_InitWindows(); + gMain.state++; + break; + case 10: + ItemPc_CountPcItems(); + ItemPc_SetCursorPosition(); + ItemPc_SetScrollPosition(); + gMain.state++; + break; + case 11: + if (ItemPc_AllocateResourcesForListMenu()) + gMain.state++; + else + { + ItemPc_FadeAndBail(); + return TRUE; + } + break; + case 12: + ItemPc_BuildListMenuTemplate(); + gMain.state++; + break; + case 13: + ItemPc_PrintWithdrawItem(); + gMain.state++; + break; + case 14: + sub_80985E4(); + gMain.state++; + break; + case 15: + taskId = CreateTask(Task_ItemPcMain, 0); + gTasks[taskId].data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sListMenuState.scroll, sListMenuState.row); + gMain.state++; + break; + case 16: + ItemPc_PlaceTopMenuScrollIndicatorArrows(); + gMain.state++; + break; + case 17: + HelpSystem_SetSomeVariable2(29); + gMain.state++; + break; + case 18: + if (sListMenuState.initialized == 1) + { + BlendPalettes(0xFFFFFFFF, 16, RGB_BLACK); + } + gMain.state++; + break; + case 19: + if (sListMenuState.initialized == 1) + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB_BLACK); + } + else + { + sub_80A0A48(0, 0, 0); + ItemPc_SetInitializedFlag(1); + PlaySE(SE_PC_LOGON); + } + gMain.state++; + break; + case 20: + if (sub_80BF72C() != TRUE) + gMain.state++; + break; + default: + SetVBlankCallback(ItemPc_VBlankCB); + SetMainCallback2(ItemPc_MainCB); + return TRUE; + } + return FALSE; +} + +static void ItemPc_FadeAndBail(void) +{ + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); + CreateTask(Task_ItemPcWaitFadeAndBail, 0); + SetVBlankCallback(ItemPc_VBlankCB); + SetMainCallback2(ItemPc_MainCB); +} + +static void Task_ItemPcWaitFadeAndBail(u8 taskId) +{ + if (!gPaletteFade.active) + { + SetMainCallback2(sListMenuState.savedCallback); + ItemPc_FreeResources(); + DestroyTask(taskId); + } +} + +static bool8 ItemPc_InitBgs(void) +{ + InitBgReg(); + sBg1TilemapBuffer = Alloc(0x800); + if (sBg1TilemapBuffer == NULL) + return FALSE; + memset(sBg1TilemapBuffer, 0, 0x800); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBgTemplates, NELEMS(sBgTemplates)); + SetBgTilemapBuffer(1, sBg1TilemapBuffer); + schedule_bg_copy_tilemap_to_vram(1); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); + SetGpuReg(REG_OFFSET_BLDCNT , 0); + ShowBg(0); + ShowBg(1); + return TRUE; +} + +static bool8 ItemPc_LoadGraphics(void) +{ + switch (sStateDataPtr->data[0]) + { + case 0: + reset_temp_tile_data_buffers(); + decompress_and_copy_tile_data_to_vram(1, gItemPcTiles, 0, 0, 0); + sStateDataPtr->data[0]++; + break; + case 1: + if (free_temp_tile_data_buffers_if_possible() != TRUE) + { + LZDecompressWram(gItemPcTilemap, sBg1TilemapBuffer); + sStateDataPtr->data[0]++; + } + break; + case 2: + LoadCompressedPalette(gItemPcBgPals, 0x00, 0x60); + sStateDataPtr->data[0]++; + break; + case 3: + LoadCompressedObjectPic(&gBagSwapSpriteSheet); + sStateDataPtr->data[0]++; + break; + default: + LoadCompressedObjectPalette(&gBagSwapSpritePalette); + sStateDataPtr->data[0] = 0; + return TRUE; + } + return FALSE; +} + +#define try_alloc(ptr__, size) ({ \ + void ** ptr = (void **)&(ptr__); \ + *ptr = Alloc(size); \ + if (*ptr == NULL) \ + { \ + ItemPc_FreeResources(); \ + ItemPc_FadeAndBail(); \ + return FALSE; \ + } \ +}) + +static bool8 ItemPc_AllocateResourcesForListMenu(void) +{ + try_alloc(sListMenuItems, sizeof(struct ListMenuItem) * (PC_ITEMS_COUNT + 1)); + try_alloc(sUnusedStringAllocation, 14 * (PC_ITEMS_COUNT + 1)); + return TRUE; +} + +static void ItemPc_BuildListMenuTemplate(void) +{ + u16 i; + + for (i = 0; i < sStateDataPtr->nItems; i++) + { + sListMenuItems[i].label = ItemId_GetName(gSaveBlock1Ptr->pcItems[i].itemId); + sListMenuItems[i].index = i; + } + sListMenuItems[i].label = gFameCheckerText_Cancel; + sListMenuItems[i].index = -2; + + gMultiuseListMenuTemplate.items = sListMenuItems; + gMultiuseListMenuTemplate.totalItems = sStateDataPtr->nItems + 1; + gMultiuseListMenuTemplate.windowId = 0; + gMultiuseListMenuTemplate.header_X = 0; + gMultiuseListMenuTemplate.item_X = 9; + gMultiuseListMenuTemplate.cursor_X = 1; + gMultiuseListMenuTemplate.lettersSpacing = 1; + gMultiuseListMenuTemplate.itemVerticalPadding = 2; + gMultiuseListMenuTemplate.upText_Y = 2; + gMultiuseListMenuTemplate.maxShowed = sStateDataPtr->maxShowed; + gMultiuseListMenuTemplate.fontId = 2; + gMultiuseListMenuTemplate.cursorPal = 2; + gMultiuseListMenuTemplate.fillValue = 0; + gMultiuseListMenuTemplate.cursorShadowPal = 3; + gMultiuseListMenuTemplate.moveCursorFunc = ItemPc_MoveCursorFunc; + gMultiuseListMenuTemplate.itemPrintFunc = ItemPc_ItemPrintFunc; + gMultiuseListMenuTemplate.scrollMultiple = 0; + gMultiuseListMenuTemplate.cursorKind = 0; +} + +static void ItemPc_MoveCursorFunc(s32 itemIndex, bool8 onInit, struct ListMenu * list) +{ + u16 itemId; + const u8 * desc; + if (onInit != TRUE) + PlaySE(SE_SELECT); + + if (sStateDataPtr->moveModeOrigPos == 0xFF) + { + DestroyItemMenuIcon(sStateDataPtr->itemMenuIconSlot ^ 1); + if (itemIndex != -2) + { + itemId = ItemPc_GetItemIdBySlotId(itemIndex); + CreateItemMenuIcon(itemId, sStateDataPtr->itemMenuIconSlot); + if (ItemId_GetPocket(itemId) == POCKET_TM_CASE) + desc = gMoveNames[ItemIdToBattleMoveId(itemId)]; + else + desc = ItemId_GetDescription(itemId); + } + else + { + CreateItemMenuIcon(ITEM_N_A, sStateDataPtr->itemMenuIconSlot); + desc = gText_ReturnToPC; + } + sStateDataPtr->itemMenuIconSlot ^= 1; + FillWindowPixelBuffer(1, 0); + ItemPc_AddTextPrinterParameterized(1, 2, desc, 0, 3, 2, 0, 0, 3); + } +} + +static void ItemPc_ItemPrintFunc(u8 windowId, s32 itemId, u8 y) +{ + if (sStateDataPtr->moveModeOrigPos != 0xFF) + { + if (sStateDataPtr->moveModeOrigPos == (u8)itemId) + ItemPc_PrintOrRemoveCursorAt(y, 2); + else + ItemPc_PrintOrRemoveCursorAt(y, 0xFF); + } + if (itemId != -2) + { + u16 quantity = ItemPc_GetItemQuantityBySlotId(itemId); + ConvertIntToDecimalStringN(gStringVar1, quantity, STR_CONV_MODE_RIGHT_ALIGN, 3); + StringExpandPlaceholders(gStringVar4, gText_TimesStrVar1); + ItemPc_AddTextPrinterParameterized(windowId, 0, gStringVar4, 110, y, 0, 0, 0xFF, 1); + } +} + +static void ItemPc_PrintOrRemoveCursor(u8 listMenuId, u8 colorIdx) +{ + ItemPc_PrintOrRemoveCursorAt(ListMenuGetYCoordForPrintingArrowCursor(listMenuId), colorIdx); +} + +static void ItemPc_PrintOrRemoveCursorAt(u8 y, u8 colorIdx) +{ + if (colorIdx == 0xFF) + { + u8 maxWidth = GetFontAttribute(2, FONTATTR_MAX_LETTER_WIDTH); + u8 maxHeight = GetFontAttribute(2, FONTATTR_MAX_LETTER_HEIGHT); + FillWindowPixelRect(0, 0, 0, y, maxWidth, maxHeight); + } + else + { + ItemPc_AddTextPrinterParameterized(0, 2, gFameCheckerText_ListMenuCursor, 0, y, 0, 0, 0, colorIdx); + } +} + +static void ItemPc_PrintWithdrawItem(void) +{ + ItemPc_AddTextPrinterParameterized(2, 0, gText_WithdrawItem, 0, 1, 0, 1, 0, 0); +} + +static void ItemPc_PlaceTopMenuScrollIndicatorArrows(void) +{ + sStateDataPtr->scrollIndicatorArrowPairId = AddScrollIndicatorArrowPairParameterized(2, 128, 8, 104, sStateDataPtr->nItems - sStateDataPtr->maxShowed + 1, 110, 110, &sListMenuState.scroll); +} + +static void ItemPc_PlaceWithdrawQuantityScrollIndicatorArrows(void) +{ + sStateDataPtr->withdrawQuantitySubmenuCursorPos = 1; + sStateDataPtr->scrollIndicatorArrowPairId = AddScrollIndicatorArrowPairParameterized(2, 212, 120, 152, 2, 110, 110, &sStateDataPtr->withdrawQuantitySubmenuCursorPos); +} + +static void ItemPc_RemoveScrollIndicatorArrowPair(void) +{ + if (sStateDataPtr->scrollIndicatorArrowPairId != 0xFF) + { + RemoveScrollIndicatorArrowPair(sStateDataPtr->scrollIndicatorArrowPairId); + sStateDataPtr->scrollIndicatorArrowPairId = 0xFF; + } +} + +static void ItemPc_SetCursorPosition(void) +{ + if (sListMenuState.scroll != 0 && sListMenuState.scroll + sStateDataPtr->maxShowed > sStateDataPtr->nItems + 1) + sListMenuState.scroll = (sStateDataPtr->nItems + 1) - sStateDataPtr->maxShowed; + if (sListMenuState.scroll + sListMenuState.row >= sStateDataPtr->nItems + 1) + { + if (sStateDataPtr->nItems + 1 < 2) + sListMenuState.row = 0; + else + sListMenuState.row = sStateDataPtr->nItems; + } +} + +#define try_free(ptr) ({ \ + void ** ptr__ = (void **)&(ptr); \ + if (*ptr__ != NULL) \ + Free(*ptr__); \ +}) + +static void ItemPc_FreeResources(void) +{ + try_free(sStateDataPtr); + try_free(sBg1TilemapBuffer); + try_free(sListMenuItems); + try_free(sUnusedStringAllocation); + FreeAllWindowBuffers(); +} + +static void Task_ItemPcTurnOff1(u8 taskId) +{ + if (sListMenuState.initialized == 1) + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); + } + else + { + sub_80A0A70(0, 0, 0); + PlaySE(SE_PC_OFF); + } + gTasks[taskId].func = Task_ItemPcTurnOff2; +} + +static void Task_ItemPcTurnOff2(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!gPaletteFade.active && !sub_80A0AAC()) + { + DestroyListMenu(data[0], &sListMenuState.scroll, &sListMenuState.row); + if (sStateDataPtr->savedCallback != NULL) + SetMainCallback2(sStateDataPtr->savedCallback); + else + SetMainCallback2(sListMenuState.savedCallback); + ItemPc_RemoveScrollIndicatorArrowPair(); + ItemPc_FreeResources(); + DestroyTask(taskId); + } +} + +static u8 ItemPc_GetCursorPosition(void) +{ + return sListMenuState.scroll + sListMenuState.row; +} + +static u16 ItemPc_GetItemIdBySlotId(u16 idx) +{ + return gSaveBlock1Ptr->pcItems[idx].itemId; +} + +static u16 ItemPc_GetItemQuantityBySlotId(u16 idx) +{ + return GetPcItemQuantity(&gSaveBlock1Ptr->pcItems[idx].quantity); +} + +static void ItemPc_CountPcItems(void) +{ + u16 i; + + ItemPcCompaction(); + sStateDataPtr->nItems = 0; + for (i = 0; i < PC_ITEMS_COUNT; sStateDataPtr->nItems++, i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == ITEM_NONE) + break; + } + sStateDataPtr->maxShowed = sStateDataPtr->nItems + 1 <= 6 ? sStateDataPtr->nItems + 1 : 6; +} + +static void ItemPc_SetScrollPosition(void) +{ + u8 i; + + if (sListMenuState.row > 3) + { + for (i = 0; i <= sListMenuState.row - 3; sListMenuState.row--, sListMenuState.scroll++, i++) + { + if (sListMenuState.scroll + sStateDataPtr->maxShowed == sStateDataPtr->nItems + 1) + break; + } + } +} + +static void ItemPc_SetMessageWindowPalette(int a0) +{ + SetBgRectPal(1, 0, 14, 30, 6, a0 + 1); + schedule_bg_copy_tilemap_to_vram(1); +} + +void ItemPc_SetInitializedFlag(u8 a0) +{ + sListMenuState.initialized = a0; +} + +static void Task_ItemPcMain(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u16 scroll; + u16 row; + s32 input; + + if (!gPaletteFade.active && !sub_80A0A98()) + { + if (JOY_NEW(SELECT_BUTTON)) + { + ListMenuGetScrollAndRow(data[0], &scroll, &row); + if (scroll + row != sStateDataPtr->nItems) + { + PlaySE(SE_SELECT); + ItemPc_MoveItemModeInit(taskId, scroll + row); + return; + } + } + input = ListMenuHandleInput(data[0]); + ListMenuGetScrollAndRow(data[0], &sListMenuState.scroll, &sListMenuState.row); + switch (input) + { + case -1: + break; + case -2: + PlaySE(SE_SELECT); + ItemPc_SetInitializedFlag(0); + gTasks[taskId].func = Task_ItemPcTurnOff1; + break; + default: + PlaySE(SE_SELECT); + ItemPc_SetMessageWindowPalette(1); + ItemPc_RemoveScrollIndicatorArrowPair(); + data[1] = input; + data[2] = ItemPc_GetItemQuantityBySlotId(input); + ItemPc_PrintOrRemoveCursor(data[0], 2); + gTasks[taskId].func = Task_ItemPcSubmenuInit; + break; + } + } +} + +static void ItemPc_ReturnFromSubmenu(u8 taskId) +{ + ItemPc_SetMessageWindowPalette(0); + ItemPc_PlaceTopMenuScrollIndicatorArrows(); + gTasks[taskId].func = Task_ItemPcMain; +} + +static void ItemPc_MoveItemModeInit(u8 taskId, s16 pos) +{ + s16 * data = gTasks[taskId].data; + + sub_8107BD0(data[0], 16, 1); + data[1] = pos; + sStateDataPtr->moveModeOrigPos = pos; + StringCopy(gStringVar1, ItemId_GetName(ItemPc_GetItemIdBySlotId(data[1]))); + StringExpandPlaceholders(gStringVar4, gOtherText_WhereShouldTheStrVar1BePlaced); + FillWindowPixelBuffer(1, 0x00); + ItemPc_AddTextPrinterParameterized(1, 2, gStringVar4, 0, 3, 2, 3, 0, 0); + sub_80986A8(-32, ListMenuGetYCoordForPrintingArrowCursor(data[0])); + sub_8098660(0); + ItemPc_PrintOrRemoveCursor(data[0], 2); + gTasks[taskId].func = Task_ItemPcMoveItemModeRun; +} + +static void Task_ItemPcMoveItemModeRun(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + ListMenuHandleInput(data[0]); + ListMenuGetScrollAndRow(data[0], &sListMenuState.scroll, &sListMenuState.row); + sub_80986A8(-32, ListMenuGetYCoordForPrintingArrowCursor(data[0])); + if (JOY_NEW(A_BUTTON | SELECT_BUTTON)) + { + PlaySE(SE_SELECT); + sStateDataPtr->moveModeOrigPos = 0xFF; + ItemPc_InsertItemIntoNewSlot(taskId, sListMenuState.scroll + sListMenuState.row); + } + else if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + sStateDataPtr->moveModeOrigPos = 0xFF; + ItemPc_MoveItemModeCancel(taskId, sListMenuState.scroll + sListMenuState.row); + } +} + +static void ItemPc_InsertItemIntoNewSlot(u8 taskId, u32 pos) +{ + s16 * data = gTasks[taskId].data; + if (data[1] == pos || data[1] == pos - 1) + ItemPc_MoveItemModeCancel(taskId, pos); + else + { + ItemMenu_MoveItemSlotToNewPositionInArray(gSaveBlock1Ptr->pcItems, data[1], pos); + DestroyListMenu(data[0], &sListMenuState.scroll, &sListMenuState.row); + if (data[1] < pos) + sListMenuState.row--; + ItemPc_BuildListMenuTemplate(); + data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sListMenuState.scroll, sListMenuState.row); + sub_8098660(1); + gTasks[taskId].func = Task_ItemPcMain; + } +} + +static void ItemPc_MoveItemModeCancel(u8 taskId, u32 pos) +{ + s16 * data = gTasks[taskId].data; + + DestroyListMenu(data[0], &sListMenuState.scroll, &sListMenuState.row); + if (data[1] < pos) + sListMenuState.row--; + ItemPc_BuildListMenuTemplate(); + data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sListMenuState.scroll, sListMenuState.row); + sub_8098660(1); + gTasks[taskId].func = Task_ItemPcMain; +} + +static void Task_ItemPcSubmenuInit(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u8 windowId; + + ItemPc_SetBorderStyleOnWindow(4); + windowId = ItemPc_GetOrCreateSubwindow(0); + PrintTextArray(4, 2, 8, 2, GetFontAttribute(2, FONTATTR_MAX_LETTER_HEIGHT) + 2, 3, sItemPcSubmenuOptions); + ProgramAndPlaceMenuCursorOnWindow(4, 2, 0, 2, GetFontAttribute(2, FONTATTR_MAX_LETTER_HEIGHT) + 2, 3, 0); + CopyItemName(ItemPc_GetItemIdBySlotId(data[1]), gStringVar1); + StringExpandPlaceholders(gStringVar4, gOtherText_StrVar1); + ItemPc_AddTextPrinterParameterized(windowId, 2, gStringVar4, 0, 2, 1, 0, 0, 1); + schedule_bg_copy_tilemap_to_vram(0); + gTasks[taskId].func = Task_ItemPcSubmenuRun; +} + +static void Task_ItemPcSubmenuRun(u8 taskId) +{ + s8 input = ProcessMenuInputNoWrapAround(); + switch (input) + { + case -1: + PlaySE(SE_SELECT); + Task_ItemPcCancel(taskId); + break; + case -2: + break; + default: + PlaySE(SE_SELECT); + sItemPcSubmenuOptions[input].func.void_u8(taskId); + } +} + +static void Task_ItemPcWithdraw(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + ClearMenuWindow(4, FALSE); + ItemPc_DestroySubwindow(0); + ClearWindowTilemap(4); + data[8] = 1; + if (ItemPc_GetItemQuantityBySlotId(data[1]) == 1) + { + PutWindowTilemap(0); + schedule_bg_copy_tilemap_to_vram(0); + ItemPc_DoWithdraw(taskId); + } + else + { + PutWindowTilemap(0); + ItemPc_WithdrawMultipleInitWindow(data[1]); + ItemPc_PlaceWithdrawQuantityScrollIndicatorArrows(); + gTasks[taskId].func = Task_ItemPcHandleWithdrawMultiple; + } +} + +static void ItemPc_DoWithdraw(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u16 itemId = ItemPc_GetItemIdBySlotId(data[1]); + u8 windowId; + + if (AddBagItem(itemId, data[8]) == TRUE) + { + ItemUse_SetQuestLogEvent(29, NULL, itemId, 0xFFFF); + CopyItemName(itemId, gStringVar1); + ConvertIntToDecimalStringN(gStringVar2, data[8], STR_CONV_MODE_LEFT_ALIGN, 3); + StringExpandPlaceholders(gStringVar4, gText_WithdrewQuantItem); + windowId = ItemPc_GetOrCreateSubwindow(2); + AddTextPrinterParameterized(windowId, 2, gStringVar4, 0, 2, 0, NULL); + gTasks[taskId].func = Task_ItemPcWaitButtonAndFinishWithdrawMultiple; + } + else + { + windowId = ItemPc_GetOrCreateSubwindow(2); + AddTextPrinterParameterized(windowId, 2, gText_NoMoreRoomInBag, 0, 2, 0, NULL); + gTasks[taskId].func = Task_ItemPcWaitButtonWithdrawMultipleFailed; + } +} + +static void Task_ItemPcWaitButtonAndFinishWithdrawMultiple(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u16 itemId; + + if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + itemId = ItemPc_GetItemIdBySlotId(data[1]); + RemoveItemFromPC(itemId, data[8]); + ItemPcCompaction(); + Task_ItemPcCleanUpWithdraw(taskId); + } +} + +static void Task_ItemPcWaitButtonWithdrawMultipleFailed(u8 taskId) +{ + if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + Task_ItemPcCleanUpWithdraw(taskId); + } +} + +static void Task_ItemPcCleanUpWithdraw(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + ItemPc_DestroySubwindow(2); + PutWindowTilemap(1); + DestroyListMenu(data[0], &sListMenuState.scroll, &sListMenuState.row); + ItemPc_CountPcItems(); + ItemPc_SetCursorPosition(); + ItemPc_BuildListMenuTemplate(); + data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sListMenuState.scroll, sListMenuState.row); + schedule_bg_copy_tilemap_to_vram(0); + ItemPc_ReturnFromSubmenu(taskId); +} + +static void ItemPc_WithdrawMultipleInitWindow(u16 slotId) +{ + u16 itemId = ItemPc_GetItemIdBySlotId(slotId); + + CopyItemName(itemId, gStringVar1); + StringExpandPlaceholders(gStringVar4, gText_WithdrawHowMany); + AddTextPrinterParameterized(ItemPc_GetOrCreateSubwindow(1), 2, gStringVar4, 0, 2, 0, NULL); + ConvertIntToDecimalStringN(gStringVar1, 1, STR_CONV_MODE_LEADING_ZEROS, 3); + StringExpandPlaceholders(gStringVar4, gText_TimesStrVar1); + ItemPc_SetBorderStyleOnWindow(3); + ItemPc_AddTextPrinterParameterized(3, 0, gStringVar4, 8, 10, 1, 0, 0, 1); + schedule_bg_copy_tilemap_to_vram(0); +} + +static void sub_810E670(s16 quantity) +{ + FillWindowPixelRect(3, 0x11, 10, 10, 28, 12); + ConvertIntToDecimalStringN(gStringVar1, quantity, STR_CONV_MODE_LEADING_ZEROS, 3); + StringExpandPlaceholders(gStringVar4, gText_TimesStrVar1); + ItemPc_AddTextPrinterParameterized(3, 0, gStringVar4, 8, 10, 1, 0, 0, 1); +} + +static void Task_ItemPcHandleWithdrawMultiple(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (sub_80BF848(&data[8], data[2]) == TRUE) + sub_810E670(data[8]); + else if (JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + ItemPc_DestroySubwindow(1); + ClearWindowTilemap(3); + PutWindowTilemap(0); + ItemPc_PrintOrRemoveCursor(data[0], 1); + schedule_bg_copy_tilemap_to_vram(0); + ItemPc_RemoveScrollIndicatorArrowPair(); + ItemPc_DoWithdraw(taskId); + } + else if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + ClearMenuWindow(3, FALSE); + ItemPc_DestroySubwindow(1); + ClearWindowTilemap(3); + PutWindowTilemap(0); + PutWindowTilemap(1); + ItemPc_PrintOrRemoveCursor(data[0], 1); + schedule_bg_copy_tilemap_to_vram(0); + ItemPc_RemoveScrollIndicatorArrowPair(); + ItemPc_ReturnFromSubmenu(taskId); + } +} + +static void Task_ItemPcGive(u8 taskId) +{ + if (CalculatePlayerPartyCount() == 0) + { + ClearMenuWindow(4, FALSE); + ItemPc_DestroySubwindow(0); + ClearWindowTilemap(4); + PutWindowTilemap(0); + ItemPc_PrintOnWindow5WithContinueTask(taskId, gText_ThereIsNoPokemon, gTask_ItemPcWaitButtonAndExitSubmenu); + } + else + { + sStateDataPtr->savedCallback = ItemPc_CB2_SwitchToPartyMenu; + Task_ItemPcTurnOff1(taskId); + } +} + +static void ItemPc_CB2_SwitchToPartyMenu(void) +{ + PartyMenuInit(0, 0, 6, 0, 6, sub_811FB28, ItemPc_CB2_ReturnFromPartyMenu); + gUnknown_203B0A0.unkC = ItemPc_GetItemIdBySlotId(ItemPc_GetCursorPosition()); +} + +static void ItemPc_CB2_ReturnFromPartyMenu(void) +{ + ItemPc_Init(1, NULL); +} + +static void gTask_ItemPcWaitButtonAndExitSubmenu(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + ClearMenuWindow_BorderThickness2(5, 0); + ClearWindowTilemap(5); + PutWindowTilemap(1); + ItemPc_PrintOrRemoveCursor(data[0], 1); + schedule_bg_copy_tilemap_to_vram(0); + ItemPc_ReturnFromSubmenu(taskId); + } +} + +static void Task_ItemPcCancel(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + ClearMenuWindow(4, FALSE); + ItemPc_DestroySubwindow(0); + ClearWindowTilemap(4); + PutWindowTilemap(0); + PutWindowTilemap(1); + ItemPc_PrintOrRemoveCursor(data[0], 1); + schedule_bg_copy_tilemap_to_vram(0); + ItemPc_ReturnFromSubmenu(taskId); +} + +static void ItemPc_InitWindows(void) +{ + u8 i; + + InitWindows(gUnknown_8453F98); + DeactivateAllTextPrinters(); + TextWindow_SetUserSelectedFrame(0, 0x3C0, 0xE0); + TextWindow_SetStdFrame0_WithPal(0, 0x3A3, 0xC0); + TextWindow_SetBubbleFrame_841F1C8(0, 0x3AC, 0xB0); + LoadPalette(stdpal_get(2), 0xD0, 0x20); + LoadPalette(gTMCaseMainWindowPalette, 0xF0, 0x20); + for (i = 0; i < 3; i++) + { + FillWindowPixelBuffer(i, 0x00); + PutWindowTilemap(i); + } + schedule_bg_copy_tilemap_to_vram(0); + for (i = 0; i < 3; i++) + sSubmenuWindowIds[i] = 0xFF; +} + +static void unused_ItemPc_AddTextPrinterParameterized(u8 windowId, const u8 * string, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, u8 speed) +{ + struct TextPrinterTemplate template; + + template.currentChar = string; + template.windowId = windowId; + template.fontId = 3; + template.x = x; + template.y = y; + template.currentX = x; + template.currentY = y; + template.fgColor = 2; + template.bgColor = 0; + template.shadowColor = 3; + template.unk = GetFontAttribute(3, FONTATTR_UNKNOWN); + template.letterSpacing = letterSpacing + GetFontAttribute(3, FONTATTR_LETTER_SPACING); + template.lineSpacing = lineSpacing + GetFontAttribute(3, FONTATTR_LINE_SPACING); + AddTextPrinter(&template, speed, NULL); +} + +static void ItemPc_AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 * str, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, u8 speed, u8 colorIdx) +{ + AddTextPrinterParameterized4(windowId, fontId, x, y, letterSpacing, lineSpacing, &gUnknown_8453F8C[colorIdx], speed, str); +} + +static void ItemPc_SetBorderStyleOnWindow(u8 windowId) +{ + SetWindowBorderStyle(windowId, FALSE, 0x3C0, 0x0E); +} + +static u8 ItemPc_GetOrCreateSubwindow(u8 idx) +{ + if (sSubmenuWindowIds[idx] == 0xFF) + { + sSubmenuWindowIds[idx] = AddWindow(&gUnknown_8453FD0[idx]); + SetWindowBorderStyle(sSubmenuWindowIds[idx], TRUE, 0x3A3, 0x0C); + } + + return sSubmenuWindowIds[idx]; +} + +static void ItemPc_DestroySubwindow(u8 idx) +{ + ClearMenuWindow(sSubmenuWindowIds[idx], FALSE); + ClearWindowTilemap(sSubmenuWindowIds[idx]); // redundant + RemoveWindow(sSubmenuWindowIds[idx]); + sSubmenuWindowIds[idx] = 0xFF; +} + +static u8 ItemPc_GetSubwindow(u8 idx) +{ + return sSubmenuWindowIds[idx]; +} + +static void ItemPc_PrintOnWindow5WithContinueTask(u8 taskId, const u8 * str, TaskFunc taskFunc) +{ + DisplayMessageAndContinueTask(taskId, 5, 0x3AC, 0x0B, 2, GetTextSpeedSetting(), str, taskFunc); + schedule_bg_copy_tilemap_to_vram(0); +} diff --git a/src/item_use.c b/src/item_use.c new file mode 100644 index 000000000..a7146b65e --- /dev/null +++ b/src/item_use.c @@ -0,0 +1,880 @@ +#include "global.h" +#include "battle.h" +#include "berry_pouch.h" +#include "berry_powder.h" +#include "bike.h" +#include "coins.h" +#include "event_data.h" +#include "field_effect.h" +#include "field_fadetransition.h" +#include "field_map_obj_helpers.h" +#include "field_player_avatar.h" +#include "field_specials.h" +#include "field_weather.h" +#include "fieldmap.h" +#include "item.h" +#include "item_menu.h" +#include "item_use.h" +#include "itemfinder.h" +#include "mail.h" +#include "main.h" +#include "malloc.h" +#include "map_obj_80688E4.h" +#include "map_obj_lock.h" +#include "metatile_behavior.h" +#include "new_menu_helpers.h" +#include "overworld.h" +#include "palette.h" +#include "party_menu.h" +#include "quest_log.h" +#include "region_map.h" +#include "script.h" +#include "sound.h" +#include "string_util.h" +#include "strings.h" +#include "task.h" +#include "teachy_tv.h" +#include "tm_case.h" +#include "vs_seeker.h" +#include "constants/fanfares.h" +#include "constants/flags.h" +#include "constants/items.h" +#include "constants/maps.h" +#include "constants/moves.h" +#include "constants/songs.h" + +EWRAM_DATA void (*sItemUseOnFieldCB)(u8 taskId) = NULL; + +void sub_80A1084(void); +void sub_80A109C(u8 taskId); +void sub_80A112C(u8 taskId); +void sub_80A11C0(u8 taskId); +bool8 sub_80A1194(void); +void sub_80A1208(void); +void ItemUseOnFieldCB_Bicycle(u8 taskId); +bool8 ItemUseCheckFunc_Rod(void); +void ItemUseOnFieldCB_Rod(u8 taskId); +void FieldUseFunc_EvoItem(u8 taskId); +void sub_80A1648(u8 taskId); +void sub_80A1674(u8 taskId); +void InitTMCaseFromBag(void); +void Task_InitTMCaseFromField(u8 taskId); +void InitBerryPouchFromBag(void); +void Task_InitBerryPouchFromField(u8 taskId); +void InitBerryPouchFromBattle(void); +void InitTeachyTvFromBag(void); +void Task_InitTeachyTvFromField(u8 taskId); +void sub_80A19E8(u8 taskId); +void sub_80A1A44(void); +void sub_80A1B48(u8 taskId); +void sub_80A1C08(u8 taskId); +void sub_80A1C44(u8 taskId); +void sub_80A1CAC(void); +void sub_80A1CC0(u8 taskId); +void sub_80A1D58(void); +void sub_80A1D68(u8 taskId); +void Task_BattleUse_StatBooster_DelayAndPrint(u8 taskId); +void Task_BattleUse_StatBooster_WaitButton_ReturnToBattle(u8 taskId); + +extern void (*const gUnknown_83E2954[])(void); + +void sub_80A0FBC(u8 taskId) +{ + u8 itemType; + if (gSpecialVar_ItemId == ITEM_ENIGMA_BERRY) + itemType = gTasks[taskId].data[4] - 1; + else + itemType = ItemId_GetType(gSpecialVar_ItemId) - 1; + if (GetPocketByItemId(gSpecialVar_ItemId) == POCKET_BERRY_POUCH) + { + BerryPouch_SetExitCallback(gUnknown_83E2954[itemType]); + BerryPouch_StartFadeToExitCallback(taskId); + } + else + { + ItemMenu_SetExitCallback(gUnknown_83E2954[itemType]); + if (itemType == 1) + sub_8108CB4(); + ItemMenu_StartFadeToExitCallback(taskId); + } +} + +void sub_80A103C(u8 taskId) +{ + if (gTasks[taskId].data[3] != 1) + { + gFieldCallback = sub_80A1084; + sub_80A0FBC(taskId); + } + else + sItemUseOnFieldCB(taskId); +} + +void sub_80A1084(void) +{ + sub_807DC00(); + CreateTask(sub_80A109C, 8); +} + +void sub_80A109C(u8 taskId) +{ + if (sub_807AA70() == TRUE) + { + sItemUseOnFieldCB(taskId); + } +} + +void sub_80A10C4(u8 taskId, bool8 a1, u8 a2, const u8 * str) +{ + StringExpandPlaceholders(gStringVar4, str); + if (a1 == FALSE) + DisplayItemMessageInBag(taskId, a2, gStringVar4, sub_810A1F8); + else + DisplayItemMessageOnField(taskId, a2, gStringVar4, sub_80A112C); +} + +void sub_80A1110(u8 taskId, bool8 a1) +{ + sub_80A10C4(taskId, a1, 4, gUnknown_8416425); +} + +void sub_80A112C(u8 taskId) +{ + ClearDialogWindowAndFrame(0, 1); + DestroyTask(taskId); + sub_80696C0(); + ScriptContext2_Disable(); +} + +u8 GetItemCompatibilityRule(u16 itemId) +{ + if (ItemId_GetPocket(itemId) == POCKET_TM_CASE) + return 1; + else if (ItemId_GetFieldFunc(itemId) == FieldUseFunc_EvoItem) + return 2; + else + return 0; +} + +void sub_80A1184(void) +{ + gFieldCallback2 = sub_80A1194; +} + +bool8 sub_80A1194(void) +{ + player_bitmagic(); + ScriptContext2_Enable(); + sub_807DC00(); + CreateTask(sub_80A11C0, 10); + gUnknown_2031DE0 = 0; + return TRUE; +} + +void sub_80A11C0(u8 taskId) +{ + if (sub_807AA70() == TRUE) + { + UnfreezeMapObjects(); + ScriptContext2_Disable(); + DestroyTask(taskId); + } +} + +void FieldUseFunc_OrangeMail(u8 taskId) +{ + ItemMenu_SetExitCallback(sub_80A1208); + ItemMenu_StartFadeToExitCallback(taskId); +} + +void sub_80A1208(void) +{ + struct MailStruct mail; + + mail.itemId = gSpecialVar_ItemId; + sub_80BEBEC(&mail, ReturnToBagFromKeyItem, 0); +} + +void FieldUseFunc_MachBike(u8 taskId) +{ + s16 x, y; + u8 behavior; + + PlayerGetDestCoords(&x, &y); + behavior = MapGridGetMetatileBehaviorAt(x, y); + + if (FlagGet(FLAG_0x830) == TRUE + || MetatileBehavior_ReturnFalse_17(behavior) == TRUE + || MetatileBehavior_ReturnFalse_18(behavior) == TRUE + || MetatileBehavior_ReturnFalse_15(behavior) == TRUE + || MetatileBehavior_ReturnFalse_16(behavior) == TRUE) + sub_80A10C4(taskId, gTasks[taskId].data[3], 2, gUnknown_8416451); + else if (sub_8055C9C() == TRUE && !sub_80BD540()) + { + sItemUseOnFieldCB = ItemUseOnFieldCB_Bicycle; + sub_80A103C(taskId); + } + else + sub_80A1110(taskId, gTasks[taskId].data[3]); +} + +void ItemUseOnFieldCB_Bicycle(u8 taskId) +{ + if (!TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE)) + PlaySE(SE_JITENSYA); + StartTransitionToFlipBikeState(PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE); + sub_80696C0(); + ScriptContext2_Disable(); + DestroyTask(taskId); +} + +void FieldUseFunc_OldRod(u8 taskId) +{ + if (ItemUseCheckFunc_Rod() == TRUE) + { + sItemUseOnFieldCB = ItemUseOnFieldCB_Rod; + sub_80A103C(taskId); + } + else + sub_80A1110(taskId, gTasks[taskId].data[3]); +} + +bool8 ItemUseCheckFunc_Rod(void) +{ + s16 x, y; + u16 behavior; + + GetXYCoordsOneStepInFrontOfPlayer(&x, &y); + behavior = MapGridGetMetatileBehaviorAt(x, y); + + if (MetatileBehavior_IsWaterfall(behavior)) + return FALSE; + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_4)) + return FALSE; + if (!TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING)) + { + if (IsPlayerFacingSurfableFishableWater()) + return TRUE; + } + else + { + if (MetatileBehavior_IsSurfable(behavior) && !MapGridIsImpassableAt(x, y)) + return TRUE; + if (MetatileBehavior_ReturnFalse_6(behavior) == TRUE) + return TRUE; + } + return FALSE; +} + +void ItemUseOnFieldCB_Rod(u8 taskId) +{ + sub_805D2C0(ItemId_GetSecondaryId(gSpecialVar_ItemId)); + DestroyTask(taskId); +} + +void ItemUseOutOfBattle_Itemfinder(u8 taskId) +{ + IncrementGameStat(GAME_STAT_USED_ITEMFINDER); + sItemUseOnFieldCB = sub_813EC8C; + sub_80A103C(taskId); +} + +void FieldUseFunc_CoinCase(u8 taskId) +{ + ConvertIntToDecimalStringN(gStringVar1, GetCoins(), STR_CONV_MODE_LEFT_ALIGN, 4); + StringExpandPlaceholders(gStringVar4, gUnknown_8416537); + ItemUse_SetQuestLogEvent(4, NULL, gSpecialVar_ItemId, 0xFFFF); + if (gTasks[taskId].data[3] == 0) + DisplayItemMessageInBag(taskId, 2, gStringVar4, sub_810A1F8); + else + DisplayItemMessageOnField(taskId, 2, gStringVar4, sub_80A112C); +} + +void FieldUseFunc_PowderJar(u8 taskId) +{ + ConvertIntToDecimalStringN(gStringVar1, GetBerryPowder(), STR_CONV_MODE_LEFT_ALIGN, 5); + StringExpandPlaceholders(gStringVar4, gUnknown_8416644); + ItemUse_SetQuestLogEvent(4, NULL, gSpecialVar_ItemId, 0xFFFF); + if (gTasks[taskId].data[3] == 0) + DisplayItemMessageInBag(taskId, 2, gStringVar4, sub_810A1F8); + else + DisplayItemMessageOnField(taskId, 2, gStringVar4, sub_80A112C); +} + +void FieldUseFunc_PokeFlute(u8 taskId) +{ + bool8 wokeSomeoneUp = FALSE; + u8 i; + + for (i = 0; i < CalculatePlayerPartyCount(); i++) + { + if (!ExecuteTableBasedItemEffect(&gPlayerParty[i], ITEM_AWAKENING, i, MOVE_NONE)) + wokeSomeoneUp = TRUE; + } + + if (wokeSomeoneUp) + { + ItemUse_SetQuestLogEvent(4, NULL, gSpecialVar_ItemId, 0xFFFF); + if (gTasks[taskId].data[3] == 0) + DisplayItemMessageInBag(taskId, 2, gUnknown_8416690, sub_80A1648); + else + DisplayItemMessageOnField(taskId, 2, gUnknown_8416690, sub_80A1648); + } + else + { + // Now that's a catchy tune! + if (gTasks[taskId].data[3] == 0) + DisplayItemMessageInBag(taskId, 2, gUnknown_841665C, sub_810A1F8); + else + DisplayItemMessageOnField(taskId, 2, gUnknown_841665C, sub_80A112C); + } +} + +void sub_80A1648(u8 taskId) +{ + PlayFanfareByFanfareNum(FANFARE_POKEFLUTE); + gTasks[taskId].func = sub_80A1674; +} + +void sub_80A1674(u8 taskId) +{ + if (WaitFanfare(FALSE)) + { + if (gTasks[taskId].data[3] == 0) + DisplayItemMessageInBag(taskId, 2, gUnknown_84166A7, sub_810A1F8); + else + DisplayItemMessageOnField(taskId, 2, gUnknown_84166A7, sub_80A112C); + } +} + +void sub_80A16D0(u8 taskId) +{ + sub_80A0FBC(taskId); +} + +void FieldUseFunc_Medicine(u8 taskId) +{ + gUnknown_3005E98 = sub_81252D0; + sub_80A16D0(taskId); +} + +void FieldUseFunc_Ether(u8 taskId) +{ + gUnknown_3005E98 = ItemUseCB_PpRestore; + sub_80A16D0(taskId); +} + +void FieldUseFunc_PpUp(u8 taskId) +{ + gUnknown_3005E98 = dp05_pp_up; + sub_80A16D0(taskId); +} + +void FieldUseFunc_RareCandy(u8 taskId) +{ + gUnknown_3005E98 = dp05_rare_candy; + sub_80A16D0(taskId); +} + +void FieldUseFunc_EvoItem(u8 taskId) +{ + gUnknown_3005E98 = sub_8126B60; + sub_80A16D0(taskId); +} + +void FieldUseFunc_SacredAsh(u8 taskId) +{ + gUnknown_3005E98 = sub_8126894; + sub_80A0FBC(taskId); +} + +void FieldUseFunc_TmCase(u8 taskId) +{ + if (gTasks[taskId].data[3] == 0) + { + ItemMenu_SetExitCallback(InitTMCaseFromBag); + ItemMenu_StartFadeToExitCallback(taskId); + } + else + { + sub_80CCB68(); + fade_screen(1, 0); + gTasks[taskId].func = Task_InitTMCaseFromField; + } +} + +void InitTMCaseFromBag(void) +{ + InitTMCase(0, ReturnToBagFromKeyItem, 0); +} + +void Task_InitTMCaseFromField(u8 taskId) +{ + if (!gPaletteFade.active) + { + CleanupOverworldWindowsAndTilemaps(); + sub_80A1184(); + InitTMCase(0, CB2_ReturnToField, 1); + DestroyTask(taskId); + } +} + +void FieldUseFunc_BerryPouch(u8 taskId) +{ + if (gTasks[taskId].data[3] == 0) + { + ItemMenu_SetExitCallback(InitBerryPouchFromBag); + ItemMenu_StartFadeToExitCallback(taskId); + } + else + { + sub_80CCB68(); + fade_screen(1, 0); + gTasks[taskId].func = Task_InitBerryPouchFromField; + } +} + +void InitBerryPouchFromBag(void) +{ + InitBerryPouch(0, ReturnToBagFromKeyItem, 0); +} + +void Task_InitBerryPouchFromField(u8 taskId) +{ + if (!gPaletteFade.active) + { + CleanupOverworldWindowsAndTilemaps(); + sub_80A1184(); + InitBerryPouch(0, CB2_ReturnToField, 1); + DestroyTask(taskId); + } +} + +void BattleUseFunc_BerryPouch(u8 taskId) +{ + ItemMenu_SetExitCallback(InitBerryPouchFromBattle); + ItemMenu_StartFadeToExitCallback(taskId); +} + +void InitBerryPouchFromBattle(void) +{ + InitBerryPouch(4, sub_8107ECC, 0); +} + +void FieldUseFunc_TeachyTv(u8 taskId) +{ + ItemUse_SetQuestLogEvent(4, NULL, gSpecialVar_ItemId, 0xFFFF); + if (gTasks[taskId].data[3] == 0) + { + ItemMenu_SetExitCallback(InitTeachyTvFromBag); + ItemMenu_StartFadeToExitCallback(taskId); + } + else + { + sub_80CCB68(); + fade_screen(1, 0); + gTasks[taskId].func = Task_InitTeachyTvFromField; + } +} + +void InitTeachyTvFromBag(void) +{ + InitTeachyTvController(0, ReturnToBagFromKeyItem); +} + +void Task_InitTeachyTvFromField(u8 taskId) +{ + if (!gPaletteFade.active) + { + CleanupOverworldWindowsAndTilemaps(); + sub_80A1184(); + InitTeachyTvController(0, CB2_ReturnToField); + DestroyTask(taskId); + } +} + +void FieldUseFunc_SuperRepel(u8 taskId) +{ + if (VarGet(VAR_REPEL_STEP_COUNT) == 0) + { + PlaySE(SE_RU_GASYAN); + gTasks[taskId].func = sub_80A19E8; + } + else + // An earlier repel is still in effect + DisplayItemMessageInBag(taskId, 2, gUnknown_841659E, sub_810A1F8); +} + +void sub_80A19E8(u8 taskId) +{ + if (!IsSEPlaying()) + { + ItemUse_SetQuestLogEvent(4, NULL, gSpecialVar_ItemId, 0xFFFF); + VarSet(VAR_REPEL_STEP_COUNT, ItemId_GetHoldEffectParam(gSpecialVar_ItemId)); + sub_80A1A44(); + DisplayItemMessageInBag(taskId, 2, gStringVar4, sub_810A1F8); + } +} + +void sub_80A1A44(void) +{ + RemoveBagItem(gSpecialVar_ItemId, 1); + sub_8108DC8(ItemId_GetPocket(gSpecialVar_ItemId)); + sub_81089F4(ItemId_GetPocket(gSpecialVar_ItemId)); + CopyItemName(gSpecialVar_ItemId, gStringVar2); + StringExpandPlaceholders(gStringVar4, gUnknown_841658C); +} + +void FieldUseFunc_BlackFlute(u8 taskId) +{ + ItemUse_SetQuestLogEvent(4, NULL, gSpecialVar_ItemId, 0xFFFF); + if (gSpecialVar_ItemId == ITEM_WHITE_FLUTE) + { + FlagSet(FLAG_WHITE_FLUTE_ACTIVE); + FlagClear(FLAG_BLACK_FLUTE_ACTIVE); + CopyItemName(gSpecialVar_ItemId, gStringVar2); + StringExpandPlaceholders(gStringVar4, gUnknown_84165D2); + gTasks[taskId].func = sub_80A1B48; + gTasks[taskId].data[8] = 0; + } + else if (gSpecialVar_ItemId == ITEM_BLACK_FLUTE) + { + FlagSet(FLAG_BLACK_FLUTE_ACTIVE); + FlagClear(FLAG_WHITE_FLUTE_ACTIVE); + CopyItemName(gSpecialVar_ItemId, gStringVar2); + StringExpandPlaceholders(gStringVar4, gUnknown_8416600); + gTasks[taskId].func = sub_80A1B48; + gTasks[taskId].data[8] = 0; + } +} + +void sub_80A1B48(u8 taskId) +{ + if (++gTasks[taskId].data[8] > 7) + { + PlaySE(SE_PN_ON); + DisplayItemMessageInBag(taskId, 2, gStringVar4, sub_810A1F8); + } +} + +bool8 sub_80A1B8C(void) +{ + if (gMapHeader.escapeRope & 1) + return TRUE; + else + return FALSE; +} + +void ItemUseOutOfBattle_EscapeRope(u8 taskId) +{ + if (sub_80A1B8C() == TRUE) + { + ItemUse_SetQuestLogEvent(4, NULL, gSpecialVar_ItemId, gMapHeader.regionMapSectionId); + sItemUseOnFieldCB = sub_80A1C08; + sub_80A103C(taskId); + } + else + sub_80A1110(taskId, gTasks[taskId].data[3]); +} + +void sub_80A1C08(u8 taskId) +{ + sub_8054D70(); + sub_80A1A44(); + gTasks[taskId].data[0] = 0; + DisplayItemMessageOnField(taskId, 2, gStringVar4, sub_80A1C44); +} + +void sub_80A1C44(u8 taskId) +{ + ResetInitialPlayerAvatarState(); + sub_8085620(); + DestroyTask(taskId); +} + +void FieldUseFunc_TownMap(u8 taskId) +{ + if (gTasks[taskId].data[3] == 0) + { + ItemMenu_SetExitCallback(sub_80A1CAC); + ItemMenu_StartFadeToExitCallback(taskId); + } + else + { + sub_80CCB68(); + fade_screen(1, 0); + gTasks[taskId].func = sub_80A1CC0; + } +} + +void sub_80A1CAC(void) +{ + sub_80BFF50(0, ReturnToBagFromKeyItem); +} + +void sub_80A1CC0(u8 taskId) +{ + if (!gPaletteFade.active) + { + CleanupOverworldWindowsAndTilemaps(); + sub_80A1184(); + sub_80BFF50(0, CB2_ReturnToField); + DestroyTask(taskId); + } +} + +void FieldUseFunc_FameChecker(u8 taskId) +{ + ItemUse_SetQuestLogEvent(4, NULL, gSpecialVar_ItemId, 0xFFFF); + if (gTasks[taskId].data[3] == 0) + { + ItemMenu_SetExitCallback(sub_80A1D58); + ItemMenu_StartFadeToExitCallback(taskId); + } + else + { + sub_80CCB68(); + fade_screen(1, 0); + gTasks[taskId].func = sub_80A1D68; + } +} + +void sub_80A1D58(void) +{ + UseFameChecker(ReturnToBagFromKeyItem); +} + +void sub_80A1D68(u8 taskId) +{ + if (!gPaletteFade.active) + { + CleanupOverworldWindowsAndTilemaps(); + sub_80A1184(); + UseFameChecker(CB2_ReturnToField); + DestroyTask(taskId); + } +} + +void FieldUseFunc_VsSeeker(u8 taskId) +{ + if ((gMapHeader.mapType != MAP_TYPE_ROUTE + && gMapHeader.mapType != MAP_TYPE_TOWN + && gMapHeader.mapType != MAP_TYPE_CITY) + || (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(VIRIDIAN_FOREST) + && (gSaveBlock1Ptr->location.mapNum == MAP_NUM(VIRIDIAN_FOREST) + || gSaveBlock1Ptr->location.mapNum == MAP_NUM(MT_EMBER_EXTERIOR) + || gSaveBlock1Ptr->location.mapNum == MAP_NUM(THREE_ISLAND_BERRY_FOREST) + || gSaveBlock1Ptr->location.mapNum == MAP_NUM(SIX_ISLAND_PATTERN_BUSH)))) + { + sub_80A1110(taskId, gTasks[taskId].data[3]); + } + else + { + sItemUseOnFieldCB = Task_VsSeeker_0; + sub_80A103C(taskId); + } +} + +void sub_80A1E0C(u8 taskId) +{ + sub_80A112C(taskId); +} + +void BattleUseFunc_PokeBallEtc(u8 taskId) +{ + if (!IsPlayerPartyAndPokemonStorageFull()) + { + RemoveBagItem(gSpecialVar_ItemId, 1); + sub_8108CB4(); + ItemMenu_StartFadeToExitCallback(taskId); + } + else + { + DisplayItemMessageInBag(taskId, 2, gUnknown_8416631, sub_810A1F8); + } +} + +void BattleUseFunc_PokeFlute(u8 taskId) +{ + sub_8108CB4(); + ItemMenu_StartFadeToExitCallback(taskId); +} + +void BattleUseFunc_GuardSpec(u8 taskId) +{ + if (ExecuteTableBasedItemEffect(&gPlayerParty[gBattlerPartyIndexes[gBattlerInMenuId]], gSpecialVar_ItemId, gBattlerPartyIndexes[gBattlerInMenuId], 0)) + { + DisplayItemMessageInBag(taskId, 2, gUnknown_84169DC, sub_810A1F8); + } + else + { + gTasks[taskId].data[8] = 0; + gTasks[taskId].func = Task_BattleUse_StatBooster_DelayAndPrint; + } +} + +void Task_BattleUse_StatBooster_DelayAndPrint(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (++data[8] > 7) + { + u16 itemId = gSpecialVar_ItemId; + PlaySE(SE_KAIFUKU); + RemoveBagItem(itemId, 1); + DisplayItemMessageInBag(taskId, 2, Battle_PrintStatBoosterEffectMessage(itemId), Task_BattleUse_StatBooster_WaitButton_ReturnToBattle); + } +} + +void Task_BattleUse_StatBooster_WaitButton_ReturnToBattle(u8 taskId) +{ + if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) + { + sub_8108CB4(); + ItemMenu_StartFadeToExitCallback(taskId); + } +} + +void ItemUse_SwitchToPartyMenuInBattle(u8 taskId) +{ + if (GetPocketByItemId(gSpecialVar_ItemId) == POCKET_BERRY_POUCH) + { + BerryPouch_SetExitCallback(sub_81279E0); + BerryPouch_StartFadeToExitCallback(taskId); + } + else + { + ItemMenu_SetExitCallback(sub_81279E0); + ItemMenu_StartFadeToExitCallback(taskId); + } +} + +void BattleUseFunc_Medicine(u8 taskId) +{ + gUnknown_3005E98 = ItemUseCB_Medicine; + ItemUse_SwitchToPartyMenuInBattle(taskId); +} + +void sub_80A1FD8(u8 taskId) +{ + gUnknown_3005E98 = sub_8126894; + ItemUse_SwitchToPartyMenuInBattle(taskId); +} + +void BattleUseFunc_Ether(u8 taskId) +{ + gUnknown_3005E98 = ItemUseCB_PpRestore; + ItemUse_SwitchToPartyMenuInBattle(taskId); +} + +void BattleUseFunc_PokeDoll(u8 taskId) +{ + if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER)) + { + sub_80A1A44(); + ItemUse_SetQuestLogEvent(4, 0, gSpecialVar_ItemId, 0xFFFF); + DisplayItemMessageInBag(taskId, 2, gStringVar4, ItemMenu_StartFadeToExitCallback); + } + else + sub_80A1110(taskId, 0); +} + +void ItemUseOutOfBattle_EnigmaBerry(u8 taskId) +{ + switch (GetItemEffectType(gSpecialVar_ItemId) - 1) + { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + gTasks[taskId].data[4] = 1; + FieldUseFunc_Medicine(taskId); + break; + case 9: + gTasks[taskId].data[4] = 1; + FieldUseFunc_SacredAsh(taskId); + break; + case 0: + gTasks[taskId].data[4] = 1; + FieldUseFunc_RareCandy(taskId); + break; + case 18: + case 19: + gTasks[taskId].data[4] = 1; + FieldUseFunc_PpUp(taskId); + break; + case 20: + gTasks[taskId].data[4] = 1; + FieldUseFunc_Ether(taskId); + break; + default: + gTasks[taskId].data[4] = 4; + FieldUseFunc_OakStopsYou(taskId); + } +} + +void ItemUseInBattle_EnigmaBerry(u8 taskId) +{ + switch (GetItemEffectType(gSpecialVar_ItemId)) + { + case 0: + BattleUseFunc_GuardSpec(taskId); + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 11: + BattleUseFunc_Medicine(taskId); + break; + case 21: + BattleUseFunc_Ether(taskId); + break; + default: + FieldUseFunc_OakStopsYou(taskId); + } +} + +void FieldUseFunc_OakStopsYou(u8 taskId) +{ + if (GetPocketByItemId(gSpecialVar_ItemId) == POCKET_BERRY_POUCH) + { + StringExpandPlaceholders(gStringVar4, gUnknown_8416425); + DisplayItemMessageInBerryPouch(taskId, 4, gStringVar4, sub_813E2B8); + } + else + sub_80A1110(taskId, gTasks[taskId].data[3]); +} + +void ItemUse_SetQuestLogEvent(u8 eventId, struct Pokemon * pokemon, u16 itemId, u16 param) +{ + struct UnkStruct_ItemUseQuestLog + { + u16 itemId; + u16 unk2; + u16 species; + u16 param; + } * questLog = Alloc(sizeof(*questLog)); + + questLog->itemId = itemId; + questLog->param = param; + if (pokemon != NULL) + questLog->species = GetMonData(pokemon, MON_DATA_SPECIES2); + else + questLog->species = 0xFFFF; + sub_8113550(eventId, (void *)questLog); + Free(questLog); +} diff --git a/src/load_save.c b/src/load_save.c index da55869aa..8d09a86a8 100644 --- a/src/load_save.c +++ b/src/load_save.c @@ -7,7 +7,7 @@ #include "malloc.h" #include "item.h" -extern void sub_8099E44(void); +extern void SetBagPocketsPointers(void); extern void sub_8110840(void *oldSave); extern void sub_8055778(int); extern void sub_8054F38(u32 newKey); @@ -80,7 +80,7 @@ void SetSaveBlocksPointers(void) *sav1_LocalVar = (void*)(&gSaveBlock1) + offset; gPokemonStoragePtr = (void*)(&gPokemonStorage) + offset; - sub_8099E44(); + SetBagPocketsPointers(); sub_8110840(oldSave); } @@ -287,7 +287,7 @@ void ApplyNewEncryptionKeyToAllEncryptedData(u32 encryptionKey) int i; for(i = 0; i < 4; i++) - ApplyNewEncryptionKeyToWord(&gSaveBlock1Ptr->unkArray[i][1], encryptionKey); + ApplyNewEncryptionKeyToWord(&gSaveBlock1Ptr->unkArray[i].unk4, encryptionKey); sub_8054F38(encryptionKey); ApplyNewEncryptionKeyToBagItems_(encryptionKey); diff --git a/src/m4a.c b/src/m4a.c new file mode 100644 index 000000000..7b4441ca4 --- /dev/null +++ b/src/m4a.c @@ -0,0 +1,1779 @@ +#include "gba/m4a_internal.h" + +extern const u8 gCgb3Vol[]; + +#define BSS_CODE __attribute__((section(".bss.code"))) + +BSS_CODE ALIGNED(4) char SoundMainRAM_Buffer[0x800] = {0}; + +struct SoundInfo gSoundInfo; +struct PokemonCrySong gPokemonCrySongs[MAX_POKEMON_CRIES]; +struct MusicPlayerInfo gPokemonCryMusicPlayers[MAX_POKEMON_CRIES]; +void *gMPlayJumpTable[36]; +struct CgbChannel gCgbChans[4]; +struct MusicPlayerTrack gPokemonCryTracks[MAX_POKEMON_CRIES * 2]; +struct PokemonCrySong gPokemonCrySong; +struct MusicPlayerInfo gMPlayInfo_BGM; +struct MusicPlayerInfo gMPlayInfo_SE1; +struct MusicPlayerInfo gMPlayInfo_SE2; +struct MusicPlayerInfo gMPlayInfo_SE3; +u8 gMPlayMemAccArea[0x10]; + +u32 MidiKeyToFreq(struct WaveData *wav, u8 key, u8 fineAdjust) +{ + u32 val1; + u32 val2; + u32 fineAdjustShifted = fineAdjust << 24; + + if (key > 178) + { + key = 178; + fineAdjustShifted = 255 << 24; + } + + val1 = gScaleTable[key]; + val1 = gFreqTable[val1 & 0xF] >> (val1 >> 4); + + val2 = gScaleTable[key + 1]; + val2 = gFreqTable[val2 & 0xF] >> (val2 >> 4); + + return umul3232H32(wav->freq, val1 + umul3232H32(val2 - val1, fineAdjustShifted)); +} + +void UnusedDummyFunc(void) +{ +} + +void MPlayContinue(struct MusicPlayerInfo *mplayInfo) +{ + if (mplayInfo->ident == ID_NUMBER) + { + mplayInfo->ident++; + mplayInfo->status &= ~MUSICPLAYER_STATUS_PAUSE; + mplayInfo->ident = ID_NUMBER; + } +} + +void MPlayFadeOut(struct MusicPlayerInfo *mplayInfo, u16 speed) +{ + if (mplayInfo->ident == ID_NUMBER) + { + mplayInfo->ident++; + mplayInfo->fadeOC = speed; + mplayInfo->fadeOI = speed; + mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT); + mplayInfo->ident = ID_NUMBER; + } +} + +void m4aSoundInit(void) +{ + s32 i; + + CpuCopy32((void *)((s32)SoundMainRAM & ~1), SoundMainRAM_Buffer, sizeof(SoundMainRAM_Buffer)); + + SoundInit(&gSoundInfo); + MPlayExtender(gCgbChans); + m4aSoundMode(SOUND_MODE_DA_BIT_8 + | SOUND_MODE_FREQ_13379 + | (12 << SOUND_MODE_MASVOL_SHIFT) + | (5 << SOUND_MODE_MAXCHN_SHIFT)); + + for (i = 0; i < NUM_MUSIC_PLAYERS; i++) + { + struct MusicPlayerInfo *mplayInfo = gMPlayTable[i].info; + MPlayOpen(mplayInfo, gMPlayTable[i].track, gMPlayTable[i].unk_8); + mplayInfo->unk_B = gMPlayTable[i].unk_A; + mplayInfo->memAccArea = gMPlayMemAccArea; + } + + memcpy(&gPokemonCrySong, &gPokemonCrySongTemplate, sizeof(struct PokemonCrySong)); + + for (i = 0; i < MAX_POKEMON_CRIES; i++) + { + struct MusicPlayerInfo *mplayInfo = &gPokemonCryMusicPlayers[i]; + struct MusicPlayerTrack *track = &gPokemonCryTracks[i * 2]; + MPlayOpen(mplayInfo, track, 2); + track->chan = 0; + } +} + +void m4aSoundMain(void) +{ + SoundMain(); +} + +void m4aSongNumStart(u16 n) +{ + const struct MusicPlayer *mplayTable = gMPlayTable; + const struct Song *songTable = gSongTable; + const struct Song *song = &songTable[n]; + const struct MusicPlayer *mplay = &mplayTable[song->ms]; + + MPlayStart(mplay->info, song->header); +} + +void m4aSongNumStartOrChange(u16 n) +{ + const struct MusicPlayer *mplayTable = gMPlayTable; + const struct Song *songTable = gSongTable; + const struct Song *song = &songTable[n]; + const struct MusicPlayer *mplay = &mplayTable[song->ms]; + + if (mplay->info->songHeader != song->header) + { + MPlayStart(mplay->info, song->header); + } + else + { + if ((mplay->info->status & MUSICPLAYER_STATUS_TRACK) == 0 + || (mplay->info->status & MUSICPLAYER_STATUS_PAUSE)) + { + MPlayStart(mplay->info, song->header); + } + } +} + +void m4aSongNumStartOrContinue(u16 n) +{ + const struct MusicPlayer *mplayTable = gMPlayTable; + const struct Song *songTable = gSongTable; + const struct Song *song = &songTable[n]; + const struct MusicPlayer *mplay = &mplayTable[song->ms]; + + if (mplay->info->songHeader != song->header) + MPlayStart(mplay->info, song->header); + else if ((mplay->info->status & MUSICPLAYER_STATUS_TRACK) == 0) + MPlayStart(mplay->info, song->header); + else if (mplay->info->status & MUSICPLAYER_STATUS_PAUSE) + MPlayContinue(mplay->info); +} + +void m4aSongNumStop(u16 n) +{ + const struct MusicPlayer *mplayTable = gMPlayTable; + const struct Song *songTable = gSongTable; + const struct Song *song = &songTable[n]; + const struct MusicPlayer *mplay = &mplayTable[song->ms]; + + if (mplay->info->songHeader == song->header) + m4aMPlayStop(mplay->info); +} + +void m4aSongNumContinue(u16 n) +{ + const struct MusicPlayer *mplayTable = gMPlayTable; + const struct Song *songTable = gSongTable; + const struct Song *song = &songTable[n]; + const struct MusicPlayer *mplay = &mplayTable[song->ms]; + + if (mplay->info->songHeader == song->header) + MPlayContinue(mplay->info); +} + +void m4aMPlayAllStop(void) +{ + s32 i; + + for (i = 0; i < NUM_MUSIC_PLAYERS; i++) + m4aMPlayStop(gMPlayTable[i].info); + + for (i = 0; i < MAX_POKEMON_CRIES; i++) + m4aMPlayStop(&gPokemonCryMusicPlayers[i]); +} + +void m4aMPlayContinue(struct MusicPlayerInfo *mplayInfo) +{ + MPlayContinue(mplayInfo); +} + +void m4aMPlayAllContinue(void) +{ + s32 i; + + for (i = 0; i < NUM_MUSIC_PLAYERS; i++) + MPlayContinue(gMPlayTable[i].info); + + for (i = 0; i < MAX_POKEMON_CRIES; i++) + MPlayContinue(&gPokemonCryMusicPlayers[i]); +} + +void m4aMPlayFadeOut(struct MusicPlayerInfo *mplayInfo, u16 speed) +{ + MPlayFadeOut(mplayInfo, speed); +} + +void m4aMPlayFadeOutTemporarily(struct MusicPlayerInfo *mplayInfo, u16 speed) +{ + if (mplayInfo->ident == ID_NUMBER) + { + mplayInfo->ident++; + mplayInfo->fadeOC = speed; + mplayInfo->fadeOI = speed; + mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT) | TEMPORARY_FADE; + mplayInfo->ident = ID_NUMBER; + } +} + +void m4aMPlayFadeIn(struct MusicPlayerInfo *mplayInfo, u16 speed) +{ + if (mplayInfo->ident == ID_NUMBER) + { + mplayInfo->ident++; + mplayInfo->fadeOC = speed; + mplayInfo->fadeOI = speed; + mplayInfo->fadeOV = (0 << FADE_VOL_SHIFT) | FADE_IN; + mplayInfo->status &= ~MUSICPLAYER_STATUS_PAUSE; + mplayInfo->ident = ID_NUMBER; + } +} + +void m4aMPlayImmInit(struct MusicPlayerInfo *mplayInfo) +{ + s32 trackCount = mplayInfo->trackCount; + struct MusicPlayerTrack *track = mplayInfo->tracks; + + while (trackCount > 0) + { + if (track->flags & MPT_FLG_EXIST) + { + if (track->flags & MPT_FLG_START) + { + Clear64byte(track); + track->flags = MPT_FLG_EXIST; + track->bendRange = 2; + track->volX = 64; + track->lfoSpeed = 22; + track->tone.type = 1; + } + } + + trackCount--; + track++; + } +} + +void MPlayExtender(struct CgbChannel *cgbChans) +{ + struct SoundInfo *soundInfo; + u32 ident; + + REG_SOUNDCNT_X = SOUND_MASTER_ENABLE + | SOUND_4_ON + | SOUND_3_ON + | SOUND_2_ON + | SOUND_1_ON; + REG_SOUNDCNT_L = 0; // set master volume to zero + REG_NR12 = 0x8; + REG_NR22 = 0x8; + REG_NR42 = 0x8; + REG_NR14 = 0x80; + REG_NR24 = 0x80; + REG_NR44 = 0x80; + REG_NR30 = 0; + REG_NR50 = 0x77; + + soundInfo = SOUND_INFO_PTR; + + ident = soundInfo->ident; + + if (ident != ID_NUMBER) + return; + + soundInfo->ident++; + + gMPlayJumpTable[8] = ply_memacc; + gMPlayJumpTable[17] = ply_lfos; + gMPlayJumpTable[19] = ply_mod; + gMPlayJumpTable[28] = ply_xcmd; + gMPlayJumpTable[29] = ply_endtie; + gMPlayJumpTable[30] = SampleFreqSet; + gMPlayJumpTable[31] = TrackStop; + gMPlayJumpTable[32] = FadeOutBody; + gMPlayJumpTable[33] = TrkVolPitSet; + + soundInfo->cgbChans = (struct CgbChannel *)cgbChans; + soundInfo->CgbSound = CgbSound; + soundInfo->CgbOscOff = CgbOscOff; + soundInfo->MidiKeyToCgbFreq = MidiKeyToCgbFreq; + soundInfo->maxLines = MAX_LINES; + + CpuFill32(0, cgbChans, sizeof(struct CgbChannel) * 4); + + cgbChans[0].ty = 1; + cgbChans[0].panMask = 0x11; + cgbChans[1].ty = 2; + cgbChans[1].panMask = 0x22; + cgbChans[2].ty = 3; + cgbChans[2].panMask = 0x44; + cgbChans[3].ty = 4; + cgbChans[3].panMask = 0x88; + + soundInfo->ident = ident; +} + +void MusicPlayerJumpTableCopy(void) +{ + asm("swi 0x2A"); +} + +void ClearChain(void *x) +{ + void (*func)(void *) = *(&gMPlayJumpTable[34]); + func(x); +} + +void Clear64byte(void *x) +{ + void (*func)(void *) = *(&gMPlayJumpTable[35]); + func(x); +} + +void SoundInit(struct SoundInfo *soundInfo) +{ + soundInfo->ident = 0; + + if (REG_DMA1CNT & (DMA_REPEAT << 16)) + REG_DMA1CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4; + + if (REG_DMA2CNT & (DMA_REPEAT << 16)) + REG_DMA2CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4; + + REG_DMA1CNT_H = DMA_32BIT; + REG_DMA2CNT_H = DMA_32BIT; + REG_SOUNDCNT_X = SOUND_MASTER_ENABLE + | SOUND_4_ON + | SOUND_3_ON + | SOUND_2_ON + | SOUND_1_ON; + REG_SOUNDCNT_H = SOUND_B_FIFO_RESET | SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT + | SOUND_A_FIFO_RESET | SOUND_A_TIMER_0 | SOUND_A_RIGHT_OUTPUT + | SOUND_ALL_MIX_FULL; + REG_SOUNDBIAS_H = (REG_SOUNDBIAS_H & 0x3F) | 0x40; + + REG_DMA1SAD = (s32)soundInfo->pcmBuffer; + REG_DMA1DAD = (s32)®_FIFO_A; + REG_DMA2SAD = (s32)soundInfo->pcmBuffer + PCM_DMA_BUF_SIZE; + REG_DMA2DAD = (s32)®_FIFO_B; + + SOUND_INFO_PTR = soundInfo; + CpuFill32(0, soundInfo, sizeof(struct SoundInfo)); + + soundInfo->maxChans = 8; + soundInfo->masterVolume = 15; + soundInfo->plynote = (u32)ply_note; + soundInfo->CgbSound = DummyFunc; + soundInfo->CgbOscOff = (void (*)(u8))DummyFunc; + soundInfo->MidiKeyToCgbFreq = (u32 (*)(u8, u8, u8))DummyFunc; + soundInfo->ExtVolPit = (u32)DummyFunc; + + MPlayJumpTableCopy(gMPlayJumpTable); + + soundInfo->MPlayJumpTable = (u32)gMPlayJumpTable; + + SampleFreqSet(SOUND_MODE_FREQ_13379); + + soundInfo->ident = ID_NUMBER; +} + +void SampleFreqSet(u32 freq) +{ + struct SoundInfo *soundInfo = SOUND_INFO_PTR; + + freq = (freq & 0xF0000) >> 16; + soundInfo->freq = freq; + soundInfo->pcmSamplesPerVBlank = gPcmSamplesPerVBlankTable[freq - 1]; + soundInfo->pcmDmaPeriod = PCM_DMA_BUF_SIZE / soundInfo->pcmSamplesPerVBlank; + + // LCD refresh rate 59.7275Hz + soundInfo->pcmFreq = (597275 * soundInfo->pcmSamplesPerVBlank + 5000) / 10000; + + // CPU frequency 16.78Mhz + soundInfo->divFreq = (16777216 / soundInfo->pcmFreq + 1) >> 1; + + // Turn off timer 0. + REG_TM0CNT_H = 0; + + // cycles per LCD fresh 280896 + REG_TM0CNT_L = -(280896 / soundInfo->pcmSamplesPerVBlank); + + m4aSoundVSyncOn(); + + while (*(vu8 *)REG_ADDR_VCOUNT == 159) + ; + + while (*(vu8 *)REG_ADDR_VCOUNT != 159) + ; + + REG_TM0CNT_H = TIMER_ENABLE | TIMER_1CLK; +} + +void m4aSoundMode(u32 mode) +{ + struct SoundInfo *soundInfo = SOUND_INFO_PTR; + u32 temp; + + if (soundInfo->ident != ID_NUMBER) + return; + + soundInfo->ident++; + + temp = mode & (SOUND_MODE_REVERB_SET | SOUND_MODE_REVERB_VAL); + + if (temp) + soundInfo->reverb = temp & SOUND_MODE_REVERB_VAL; + + temp = mode & SOUND_MODE_MAXCHN; + + if (temp) + { + struct SoundChannel *chan; + + soundInfo->maxChans = temp >> SOUND_MODE_MAXCHN_SHIFT; + + temp = MAX_DIRECTSOUND_CHANNELS; + chan = &soundInfo->chans[0]; + + while (temp != 0) + { + chan->status = 0; + temp--; + chan++; + } + } + + temp = mode & SOUND_MODE_MASVOL; + + if (temp) + soundInfo->masterVolume = temp >> SOUND_MODE_MASVOL_SHIFT; + + temp = mode & SOUND_MODE_DA_BIT; + + if (temp) + { + temp = (temp & 0x300000) >> 14; + REG_SOUNDBIAS_H = (REG_SOUNDBIAS_H & 0x3F) | temp; + } + + temp = mode & SOUND_MODE_FREQ; + + if (temp) + { + m4aSoundVSyncOff(); + SampleFreqSet(temp); + } + + soundInfo->ident = ID_NUMBER; +} + +void SoundClear(void) +{ + struct SoundInfo *soundInfo = SOUND_INFO_PTR; + s32 i; + void *chan; + + if (soundInfo->ident != ID_NUMBER) + return; + + soundInfo->ident++; + + i = MAX_DIRECTSOUND_CHANNELS; + chan = &soundInfo->chans[0]; + + while (i > 0) + { + ((struct SoundChannel *)chan)->status = 0; + i--; + chan = (void *)((s32)chan + sizeof(struct SoundChannel)); + } + + chan = soundInfo->cgbChans; + + if (chan) + { + i = 1; + + while (i <= 4) + { + soundInfo->CgbOscOff(i); + ((struct CgbChannel *)chan)->sf = 0; + i++; + chan = (void *)((s32)chan + sizeof(struct CgbChannel)); + } + } + + soundInfo->ident = ID_NUMBER; +} + +void m4aSoundVSyncOff(void) +{ + struct SoundInfo *soundInfo = SOUND_INFO_PTR; + + if (soundInfo->ident >= ID_NUMBER && soundInfo->ident <= ID_NUMBER + 1) + { + soundInfo->ident += 10; + + if (REG_DMA1CNT & (DMA_REPEAT << 16)) + REG_DMA1CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4; + + if (REG_DMA2CNT & (DMA_REPEAT << 16)) + REG_DMA2CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4; + + REG_DMA1CNT_H = DMA_32BIT; + REG_DMA2CNT_H = DMA_32BIT; + + CpuFill32(0, soundInfo->pcmBuffer, sizeof(soundInfo->pcmBuffer)); + } +} + +void m4aSoundVSyncOn(void) +{ + struct SoundInfo *soundInfo = SOUND_INFO_PTR; + u32 ident = soundInfo->ident; + + if (ident == ID_NUMBER) + return; + + REG_DMA1CNT_H = DMA_ENABLE | DMA_START_SPECIAL | DMA_32BIT | DMA_REPEAT; + REG_DMA2CNT_H = DMA_ENABLE | DMA_START_SPECIAL | DMA_32BIT | DMA_REPEAT; + + soundInfo->pcmDmaCounter = 0; + soundInfo->ident = ident - 10; +} + +void MPlayOpen(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *tracks, u8 trackCount) +{ + struct SoundInfo *soundInfo; + + if (trackCount == 0) + return; + + if (trackCount > MAX_MUSICPLAYER_TRACKS) + trackCount = MAX_MUSICPLAYER_TRACKS; + + soundInfo = SOUND_INFO_PTR; + + if (soundInfo->ident != ID_NUMBER) + return; + + soundInfo->ident++; + + Clear64byte(mplayInfo); + + mplayInfo->tracks = tracks; + mplayInfo->trackCount = trackCount; + mplayInfo->status = MUSICPLAYER_STATUS_PAUSE; + + while (trackCount != 0) + { + tracks->flags = 0; + trackCount--; + tracks++; + } + + if (soundInfo->func != 0) + { + mplayInfo->func = soundInfo->func; + mplayInfo->intp = soundInfo->intp; + soundInfo->func = 0; + } + + soundInfo->intp = (u32)mplayInfo; + soundInfo->func = (u32)MPlayMain; + soundInfo->ident = ID_NUMBER; + mplayInfo->ident = ID_NUMBER; +} + +void MPlayStart(struct MusicPlayerInfo *mplayInfo, struct SongHeader *songHeader) +{ + s32 i; + u8 unk_B; + struct MusicPlayerTrack *track; + + if (mplayInfo->ident != ID_NUMBER) + return; + + unk_B = mplayInfo->unk_B; + + if (!unk_B + || ((!mplayInfo->songHeader || !(mplayInfo->tracks[0].flags & MPT_FLG_START)) + && ((mplayInfo->status & MUSICPLAYER_STATUS_TRACK) == 0 + || (mplayInfo->status & MUSICPLAYER_STATUS_PAUSE))) + || (mplayInfo->priority <= songHeader->priority)) + { + mplayInfo->ident++; + mplayInfo->status = 0; + mplayInfo->songHeader = songHeader; + mplayInfo->tone = songHeader->tone; + mplayInfo->priority = songHeader->priority; + mplayInfo->clock = 0; + mplayInfo->tempoD = 150; + mplayInfo->tempoI = 150; + mplayInfo->tempoU = 0x100; + mplayInfo->tempoC = 0; + mplayInfo->fadeOI = 0; + + i = 0; + track = mplayInfo->tracks; + + while (i < songHeader->trackCount && i < mplayInfo->trackCount) + { + TrackStop(mplayInfo, track); + track->flags = MPT_FLG_EXIST | MPT_FLG_START; + track->chan = 0; + track->cmdPtr = songHeader->part[i]; + i++; + track++; + } + + while (i < mplayInfo->trackCount) + { + TrackStop(mplayInfo, track); + track->flags = 0; + i++; + track++; + } + + if (songHeader->reverb & 0x80) + m4aSoundMode(songHeader->reverb); + + mplayInfo->ident = ID_NUMBER; + } +} + +void m4aMPlayStop(struct MusicPlayerInfo *mplayInfo) +{ + s32 i; + struct MusicPlayerTrack *track; + + if (mplayInfo->ident != ID_NUMBER) + return; + + mplayInfo->ident++; + mplayInfo->status |= MUSICPLAYER_STATUS_PAUSE; + + i = mplayInfo->trackCount; + track = mplayInfo->tracks; + + while (i > 0) + { + TrackStop(mplayInfo, track); + i--; + track++; + } + + mplayInfo->ident = ID_NUMBER; +} + +void FadeOutBody(struct MusicPlayerInfo *mplayInfo) +{ + s32 i; + struct MusicPlayerTrack *track; + u16 fadeOV; +#ifdef NONMATCHING + u16 mask; +#else + register u16 mask asm("r2"); +#endif // NONMATCHING + + if (mplayInfo->fadeOI == 0) + return; + + mplayInfo->fadeOC--; + mask = 0xFFFF; + + if (mplayInfo->fadeOC != 0) + return; + + mplayInfo->fadeOC = mplayInfo->fadeOI; + + if (mplayInfo->fadeOV & FADE_IN) + { + mplayInfo->fadeOV += (4 << FADE_VOL_SHIFT); + + if ((u16)(mplayInfo->fadeOV & mask) >= (64 << FADE_VOL_SHIFT)) + { + mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT); + mplayInfo->fadeOI = 0; + } + } + else + { + mplayInfo->fadeOV -= (4 << FADE_VOL_SHIFT); + + if ((s16)(mplayInfo->fadeOV & mask) <= 0) + { + i = mplayInfo->trackCount; + track = mplayInfo->tracks; + + while (i > 0) + { + u32 val; + + TrackStop(mplayInfo, track); + + val = TEMPORARY_FADE; + fadeOV = mplayInfo->fadeOV; + val &= fadeOV; + + if (!val) + track->flags = 0; + + i--; + track++; + } + + if (mplayInfo->fadeOV & TEMPORARY_FADE) + mplayInfo->status |= MUSICPLAYER_STATUS_PAUSE; + else + mplayInfo->status = MUSICPLAYER_STATUS_PAUSE; + + mplayInfo->fadeOI = 0; + return; + } + } + + i = mplayInfo->trackCount; + track = mplayInfo->tracks; + + while (i > 0) + { + if (track->flags & MPT_FLG_EXIST) + { + fadeOV = mplayInfo->fadeOV; + + track->volX = (fadeOV >> FADE_VOL_SHIFT); + track->flags |= MPT_FLG_VOLCHG; + } + + i--; + track++; + } +} + +void TrkVolPitSet(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + if (track->flags & MPT_FLG_VOLSET) + { + s32 x; + s32 y; + + x = (u32)(track->vol * track->volX) >> 5; + + if (track->modT == 1) + x = (u32)(x * (track->modM + 128)) >> 7; + + y = 2 * track->pan + track->panX; + + if (track->modT == 2) + y += track->modM; + + if (y < -128) + y = -128; + else if (y > 127) + y = 127; + + track->volMR = (u32)((y + 128) * x) >> 8; + track->volML = (u32)((127 - y) * x) >> 8; + } + + if (track->flags & MPT_FLG_PITSET) + { + s32 bend = track->bend * track->bendRange; + s32 x = (track->tune + bend) + * 4 + + (track->keyShift << 8) + + (track->keyShiftX << 8) + + track->pitX; + + if (track->modT == 0) + x += 16 * track->modM; + + track->keyM = x >> 8; + track->pitM = x; + } + + track->flags &= ~(MPT_FLG_PITSET | MPT_FLG_VOLSET); +} + +u32 MidiKeyToCgbFreq(u8 chanNum, u8 key, u8 fineAdjust) +{ + if (chanNum == 4) + { + if (key <= 20) + { + key = 0; + } + else + { + key -= 21; + if (key > 59) + key = 59; + } + + return gNoiseTable[key]; + } + else + { + s32 val1; + s32 val2; + + if (key <= 35) + { + fineAdjust = 0; + key = 0; + } + else + { + key -= 36; + if (key > 130) + { + key = 130; + fineAdjust = 255; + } + } + + val1 = gCgbScaleTable[key]; + val1 = gCgbFreqTable[val1 & 0xF] >> (val1 >> 4); + + val2 = gCgbScaleTable[key + 1]; + val2 = gCgbFreqTable[val2 & 0xF] >> (val2 >> 4); + + return val1 + ((fineAdjust * (val2 - val1)) >> 8) + 2048; + } +} + +void CgbOscOff(u8 chanNum) +{ + switch (chanNum) + { + case 1: + REG_NR12 = 8; + REG_NR14 = 0x80; + break; + case 2: + REG_NR22 = 8; + REG_NR24 = 0x80; + break; + case 3: + REG_NR30 = 0; + break; + default: + REG_NR42 = 8; + REG_NR44 = 0x80; + } +} + +static inline int CgbPan(struct CgbChannel *chan) +{ + u32 rightVolume = chan->rightVolume; + u32 leftVolume = chan->leftVolume; + + if ((rightVolume = (u8)rightVolume) >= (leftVolume = (u8)leftVolume)) + { + if (rightVolume / 2 >= leftVolume) + { + chan->pan = 0x0F; + return 1; + } + } + else + { + if (leftVolume / 2 >= rightVolume) + { + chan->pan = 0xF0; + return 1; + } + } + + return 0; +} + +void CgbModVol(struct CgbChannel *chan) +{ + struct SoundInfo *soundInfo = SOUND_INFO_PTR; + + if ((soundInfo->mode & 1) || !CgbPan(chan)) + { + chan->pan = 0xFF; + chan->eg = (u32)(chan->rightVolume + chan->leftVolume) >> 4; + } + else + { + // Force chan->rightVolume and chan->leftVolume to be read from memory again, + // even though there is no reason to do so. + // The command line option "-fno-gcse" achieves the same result as this. + asm("" : : : "memory"); + + chan->eg = (u32)(chan->rightVolume + chan->leftVolume) >> 4; + if (chan->eg > 15) + chan->eg = 15; + } + + chan->sg = (chan->eg * chan->su + 15) >> 4; + chan->pan &= chan->panMask; +} + +void CgbSound(void) +{ + s32 ch; + struct CgbChannel *channels; + s32 evAdd; + s32 prevC15; + struct SoundInfo *soundInfo = SOUND_INFO_PTR; + vu8 *nrx0ptr; + vu8 *nrx1ptr; + vu8 *nrx2ptr; + vu8 *nrx3ptr; + vu8 *nrx4ptr; + + // Most comparision operations that cast to s8 perform 'and' by 0xFF. + int mask = 0xff; + + if (soundInfo->c15) + soundInfo->c15--; + else + soundInfo->c15 = 14; + + for (ch = 1, channels = soundInfo->cgbChans; ch <= 4; ch++, channels++) + { + if (!(channels->sf & 0xc7)) + continue; + + switch (ch) + { + case 1: + nrx0ptr = (vu8 *)(REG_ADDR_NR10); + nrx1ptr = (vu8 *)(REG_ADDR_NR11); + nrx2ptr = (vu8 *)(REG_ADDR_NR12); + nrx3ptr = (vu8 *)(REG_ADDR_NR13); + nrx4ptr = (vu8 *)(REG_ADDR_NR14); + break; + case 2: + nrx0ptr = (vu8 *)(REG_ADDR_NR10+1); + nrx1ptr = (vu8 *)(REG_ADDR_NR21); + nrx2ptr = (vu8 *)(REG_ADDR_NR22); + nrx3ptr = (vu8 *)(REG_ADDR_NR23); + nrx4ptr = (vu8 *)(REG_ADDR_NR24); + break; + case 3: + nrx0ptr = (vu8 *)(REG_ADDR_NR30); + nrx1ptr = (vu8 *)(REG_ADDR_NR31); + nrx2ptr = (vu8 *)(REG_ADDR_NR32); + nrx3ptr = (vu8 *)(REG_ADDR_NR33); + nrx4ptr = (vu8 *)(REG_ADDR_NR34); + break; + default: + nrx0ptr = (vu8 *)(REG_ADDR_NR30+1); + nrx1ptr = (vu8 *)(REG_ADDR_NR41); + nrx2ptr = (vu8 *)(REG_ADDR_NR42); + nrx3ptr = (vu8 *)(REG_ADDR_NR43); + nrx4ptr = (vu8 *)(REG_ADDR_NR44); + break; + } + + prevC15 = soundInfo->c15; + evAdd = *nrx2ptr; + + if (channels->sf & 0x80) + { + if (!(channels->sf & 0x40)) + { + channels->sf = 3; + channels->mo = 3; + CgbModVol(channels); + switch (ch) + { + case 1: + *nrx0ptr = channels->sw; + // fallthrough + case 2: + *nrx1ptr = ((u32)channels->wp << 6) + channels->le; + goto loc_82E0E30; + case 3: + if ((u32)channels->wp != channels->cp) + { + *nrx0ptr = 0x40; + REG_WAVE_RAM0 = channels->wp[0]; + REG_WAVE_RAM1 = channels->wp[1]; + REG_WAVE_RAM2 = channels->wp[2]; + REG_WAVE_RAM3 = channels->wp[3]; + channels->cp = (u32)channels->wp; + } + *nrx0ptr = 0; + *nrx1ptr = channels->le; + if (channels->le) + channels->n4 = -64; + else + channels->n4 = -128; + break; + default: + *nrx1ptr = channels->le; + *nrx3ptr = (u32)channels->wp << 3; + loc_82E0E30: + evAdd = channels->at + 8; + if (channels->le) + channels->n4 = 64; + else + channels->n4 = 0; + break; + } + channels->ec = channels->at; + if ((s8)(channels->at & mask)) + { + channels->ev = 0; + goto EC_MINUS; + } + else + { + goto loc_82E0F96; + } + } + else + { + goto loc_82E0E82; + } + } + else if (channels->sf & 0x04) + { + channels->echoLength--; + if ((s8)(channels->echoLength & mask) <= 0) + { + loc_82E0E82: + CgbOscOff(ch); + channels->sf = 0; + goto LAST_LABEL; + } + goto loc_82E0FD6; + } + else if ((channels->sf & 0x40) && (channels->sf & 0x03)) + { + channels->sf &= 0xfc; + channels->ec = channels->re; + if ((s8)(channels->re & mask)) + { + channels->mo |= 1; + if (ch != 3) + { + evAdd = channels->re; + } + goto EC_MINUS; + } + else + { + goto loc_82E0F02; + } + } + else + { + loc_82E0ED0: + if (channels->ec == 0) + { + if (ch == 3) + { + channels->mo |= 1; + } + CgbModVol(channels); + if ((channels->sf & 0x3) == 0) + { + channels->ev--; + if ((s8)(channels->ev & mask) <= 0) + { + loc_82E0F02: + channels->ev = ((channels->eg * channels->echoVolume) + 0xFF) >> 8; + if (channels->ev) + { + channels->sf |= 0x4; + channels->mo |= 1; + if (ch != 3) + { + evAdd = 8; + } + goto loc_82E0FD6; + } + else + { + goto loc_82E0E82; + } + } + else + { + channels->ec = channels->re; + } + } + else if ((channels->sf & 0x3) == 1) + { + loc_82E0F3A: + channels->ev = channels->sg; + channels->ec = 7; + } + else if ((channels->sf & 0x3) == 2) + { + int ev, sg; + + channels->ev--; + ev = (s8)(channels->ev & mask); + sg = (s8)(channels->sg); + if (ev <= sg) + { + loc_82E0F5A: + if (channels->su == 0) + { + channels->sf &= 0xfc; + goto loc_82E0F02; + } + else + { + channels->sf--; + channels->mo |= 1; + if (ch != 3) + { + evAdd = 8; + } + goto loc_82E0F3A; + } + } + else + { + channels->ec = channels->de; + } + } + else + { + channels->ev++; + if ((u8)(channels->ev & mask) >= channels->eg) + { + loc_82E0F96: + channels->sf--; + channels->ec = channels->de; + if ((u8)(channels->ec & mask)) + { + channels->mo |= 1; + channels->ev = channels->eg; + if (ch != 3) + { + evAdd = channels->de; + } + } + else + { + goto loc_82E0F5A; + } + } + else + { + channels->ec = channels->at; + } + } + } + } + + EC_MINUS: + channels->ec--; + if (prevC15 == 0) + { + prevC15--; + goto loc_82E0ED0; + } + + loc_82E0FD6: + if (channels->mo & 0x2) + { + if (ch < 4 && (channels->ty & 0x08)) + { + int biasH = REG_SOUNDBIAS_H; + + if (biasH < 64) + { + channels->fr = (channels->fr + 2) & 0x7fc; + } + else if (biasH < 128) + { + channels->fr = (channels->fr + 1) & 0x7fe; + } + } + if (ch != 4) + { + *nrx3ptr = channels->fr; + } + else + { + *nrx3ptr = (*nrx3ptr & 0x08) | channels->fr; + } + channels->n4 = (channels->n4 & 0xC0) + (*((u8*)(&channels->fr) + 1)); + *nrx4ptr = (s8)(channels->n4 & mask); + } + + if (channels->mo & 1) + { + REG_NR51 = (REG_NR51 & ~channels->panMask) | channels->pan; + if (ch == 3) + { + *nrx2ptr = gCgb3Vol[channels->ev]; + if (channels->n4 & 0x80) + { + *nrx0ptr = 0x80; + *nrx4ptr = channels->n4; + channels->n4 &= 0x7f; + } + } + else + { + evAdd &= 0xf; + *nrx2ptr = (channels->ev << 4) + evAdd; + *nrx4ptr = channels->n4 | 0x80; + if (ch == 1 && !(*nrx0ptr & 0x08)) + { + *nrx4ptr = channels->n4 | 0x80; + } + } + } + + LAST_LABEL: + channels->mo = 0; + } +} + +void m4aMPlayTempoControl(struct MusicPlayerInfo *mplayInfo, u16 tempo) +{ + if (mplayInfo->ident == ID_NUMBER) + { + mplayInfo->ident++; + mplayInfo->tempoU = tempo; + mplayInfo->tempoI = (mplayInfo->tempoD * mplayInfo->tempoU) >> 8; + mplayInfo->ident = ID_NUMBER; + } +} + +void m4aMPlayVolumeControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u16 volume) +{ + s32 i; + u32 bit; + struct MusicPlayerTrack *track; + + if (mplayInfo->ident != ID_NUMBER) + return; + + mplayInfo->ident++; + + i = mplayInfo->trackCount; + track = mplayInfo->tracks; + bit = 1; + + while (i > 0) + { + if (trackBits & bit) + { + if (track->flags & MPT_FLG_EXIST) + { + track->volX = volume / 4; + track->flags |= MPT_FLG_VOLCHG; + } + } + + i--; + track++; + bit <<= 1; + } + + mplayInfo->ident = ID_NUMBER; +} + +void m4aMPlayPitchControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s16 pitch) +{ + s32 i; + u32 bit; + struct MusicPlayerTrack *track; + + if (mplayInfo->ident != ID_NUMBER) + return; + + mplayInfo->ident++; + + i = mplayInfo->trackCount; + track = mplayInfo->tracks; + bit = 1; + + while (i > 0) + { + if (trackBits & bit) + { + if (track->flags & MPT_FLG_EXIST) + { + track->keyShiftX = pitch >> 8; + track->pitX = pitch; + track->flags |= MPT_FLG_PITCHG; + } + } + + i--; + track++; + bit <<= 1; + } + + mplayInfo->ident = ID_NUMBER; +} + +void m4aMPlayPanpotControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s8 pan) +{ + s32 i; + u32 bit; + struct MusicPlayerTrack *track; + + if (mplayInfo->ident != ID_NUMBER) + return; + + mplayInfo->ident++; + + i = mplayInfo->trackCount; + track = mplayInfo->tracks; + bit = 1; + + while (i > 0) + { + if (trackBits & bit) + { + if (track->flags & MPT_FLG_EXIST) + { + track->panX = pan; + track->flags |= MPT_FLG_VOLCHG; + } + } + + i--; + track++; + bit <<= 1; + } + + mplayInfo->ident = ID_NUMBER; +} + +void ClearModM(struct MusicPlayerTrack *track) +{ + track->lfoSpeedC = 0; + track->modM = 0; + + if (track->modT == 0) + track->flags |= MPT_FLG_PITCHG; + else + track->flags |= MPT_FLG_VOLCHG; +} + +void m4aMPlayModDepthSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 modDepth) +{ + s32 i; + u32 bit; + struct MusicPlayerTrack *track; + + if (mplayInfo->ident != ID_NUMBER) + return; + + mplayInfo->ident++; + + i = mplayInfo->trackCount; + track = mplayInfo->tracks; + bit = 1; + + while (i > 0) + { + if (trackBits & bit) + { + if (track->flags & MPT_FLG_EXIST) + { + track->mod = modDepth; + + if (!track->mod) + ClearModM(track); + } + } + + i--; + track++; + bit <<= 1; + } + + mplayInfo->ident = ID_NUMBER; +} + +void m4aMPlayLFOSpeedSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 lfoSpeed) +{ + s32 i; + u32 bit; + struct MusicPlayerTrack *track; + + if (mplayInfo->ident != ID_NUMBER) + return; + + mplayInfo->ident++; + + i = mplayInfo->trackCount; + track = mplayInfo->tracks; + bit = 1; + + while (i > 0) + { + if (trackBits & bit) + { + if (track->flags & MPT_FLG_EXIST) + { + track->lfoSpeed = lfoSpeed; + + if (!track->lfoSpeed) + ClearModM(track); + } + } + + i--; + track++; + bit <<= 1; + } + + mplayInfo->ident = ID_NUMBER; +} + +#define MEMACC_COND_JUMP(cond) \ +if (cond) \ + goto cond_true; \ +else \ + goto cond_false; \ + +void ply_memacc(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + u32 op; + u8 *addr; + u8 data; + + op = *track->cmdPtr; + track->cmdPtr++; + + addr = mplayInfo->memAccArea + *track->cmdPtr; + track->cmdPtr++; + + data = *track->cmdPtr; + track->cmdPtr++; + + switch (op) + { + case 0: + *addr = data; + return; + case 1: + *addr += data; + return; + case 2: + *addr -= data; + return; + case 3: + *addr = mplayInfo->memAccArea[data]; + return; + case 4: + *addr += mplayInfo->memAccArea[data]; + return; + case 5: + *addr -= mplayInfo->memAccArea[data]; + return; + case 6: + MEMACC_COND_JUMP(*addr == data) + return; + case 7: + MEMACC_COND_JUMP(*addr != data) + return; + case 8: + MEMACC_COND_JUMP(*addr > data) + return; + case 9: + MEMACC_COND_JUMP(*addr >= data) + return; + case 10: + MEMACC_COND_JUMP(*addr <= data) + return; + case 11: + MEMACC_COND_JUMP(*addr < data) + return; + case 12: + MEMACC_COND_JUMP(*addr == mplayInfo->memAccArea[data]) + return; + case 13: + MEMACC_COND_JUMP(*addr != mplayInfo->memAccArea[data]) + return; + case 14: + MEMACC_COND_JUMP(*addr > mplayInfo->memAccArea[data]) + return; + case 15: + MEMACC_COND_JUMP(*addr >= mplayInfo->memAccArea[data]) + return; + case 16: + MEMACC_COND_JUMP(*addr <= mplayInfo->memAccArea[data]) + return; + case 17: + MEMACC_COND_JUMP(*addr < mplayInfo->memAccArea[data]) + return; + default: + return; + } + +cond_true: + { + void (*func)(struct MusicPlayerInfo *, struct MusicPlayerTrack *) = *(&gMPlayJumpTable[1]); + func(mplayInfo, track); + return; + } + +cond_false: + track->cmdPtr += 4; +} + +void ply_xcmd(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + u32 n = *track->cmdPtr; + track->cmdPtr++; + + gXcmdTable[n](mplayInfo, track); +} + +void ply_xxx(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + void (*func)(struct MusicPlayerInfo *, struct MusicPlayerTrack *) = *(&gMPlayJumpTable[0]); + func(mplayInfo, track); +} + +#define READ_XCMD_BYTE(var, n) \ +{ \ + u32 byte = track->cmdPtr[(n)]; \ + byte <<= n * 8; \ + (var) &= ~(0xFF << (n * 8)); \ + (var) |= byte; \ +} + +void ply_xwave(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + u32 wav; + + READ_XCMD_BYTE(wav, 0) // UB: uninitialized variable + READ_XCMD_BYTE(wav, 1) + READ_XCMD_BYTE(wav, 2) + READ_XCMD_BYTE(wav, 3) + + track->tone.wav = (struct WaveData *)wav; + track->cmdPtr += 4; +} + +void ply_xtype(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->tone.type = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xatta(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->tone.attack = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xdeca(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->tone.decay = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xsust(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->tone.sustain = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xrele(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->tone.release = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xiecv(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->echoVolume = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xiecl(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->echoLength = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xleng(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->tone.length = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xswee(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + track->tone.pan_sweep = *track->cmdPtr; + track->cmdPtr++; +} + +void ply_xcmd_0C(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + u32 unk; + + READ_XCMD_BYTE(unk, 0) // UB: uninitialized variable + READ_XCMD_BYTE(unk, 1) + + if (track->unk_3A < (u16)unk) + { + track->unk_3A++; + track->cmdPtr -= 2; + track->wait = 1; + } + else + { + track->unk_3A = 0; + track->cmdPtr += 2; + } +} + +void ply_xcmd_0D(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +{ + u32 unk; + + READ_XCMD_BYTE(unk, 0) // UB: uninitialized variable + READ_XCMD_BYTE(unk, 1) + READ_XCMD_BYTE(unk, 2) + READ_XCMD_BYTE(unk, 3) + + track->unk_3C = unk; + track->cmdPtr += 4; +} + +void DummyFunc(void) +{ +} + +struct MusicPlayerInfo *SetPokemonCryTone(struct ToneData *tone) +{ + u32 maxClock = 0; + s32 maxClockIndex = 0; + s32 i; + struct MusicPlayerInfo *mplayInfo; + + for (i = 0; i < MAX_POKEMON_CRIES; i++) + { + struct MusicPlayerTrack *track = &gPokemonCryTracks[i * 2]; + + if (!track->flags && (!track->chan || track->chan->track != track)) + goto start_song; + + if (maxClock < gPokemonCryMusicPlayers[i].clock) + { + maxClock = gPokemonCryMusicPlayers[i].clock; + maxClockIndex = i; + } + } + + i = maxClockIndex; + +start_song: + mplayInfo = &gPokemonCryMusicPlayers[i]; + mplayInfo->ident++; + +#define CRY ((s32)&gPokemonCrySongs + i * sizeof(struct PokemonCrySong)) +#define CRY_OFS(field) offsetof(struct PokemonCrySong, field) + + memcpy((void *)CRY, &gPokemonCrySong, sizeof(struct PokemonCrySong)); + + *(u32 *)(CRY + CRY_OFS(tone)) = (u32)tone; + *(u32 *)(CRY + CRY_OFS(part)) = CRY + CRY_OFS(part0); + *(u32 *)(CRY + CRY_OFS(part) + 4) = CRY + CRY_OFS(part1); + *(u32 *)(CRY + CRY_OFS(gotoTarget)) = CRY + CRY_OFS(cont); + +#undef CRY_OFS +#undef CRY + + mplayInfo->ident = ID_NUMBER; + + MPlayStart(mplayInfo, (struct SongHeader *)(&gPokemonCrySongs[i])); + + return mplayInfo; +} + +void SetPokemonCryVolume(u8 val) +{ + gPokemonCrySong.volumeValue = val & 0x7F; +} + +void SetPokemonCryPanpot(s8 val) +{ + gPokemonCrySong.panValue = (val + C_V) & 0x7F; +} + +void SetPokemonCryPitch(s16 val) +{ + s16 b = val + 0x80; + u8 a = gPokemonCrySong.tuneValue2 - gPokemonCrySong.tuneValue; + gPokemonCrySong.tieKeyValue = (b >> 8) & 0x7F; + gPokemonCrySong.tuneValue = (b >> 1) & 0x7F; + gPokemonCrySong.tuneValue2 = (a + ((b >> 1) & 0x7F)) & 0x7F; +} + +void SetPokemonCryLength(u16 val) +{ + gPokemonCrySong.unkCmd0CParam = val; +} + +void SetPokemonCryRelease(u8 val) +{ + gPokemonCrySong.releaseValue = val; +} + +void SetPokemonCryProgress(u32 val) +{ + gPokemonCrySong.unkCmd0DParam = val; +} + +int IsPokemonCryPlaying(struct MusicPlayerInfo *mplayInfo) +{ + struct MusicPlayerTrack *track = mplayInfo->tracks; + + if (track->chan && track->chan->track == track) + return 1; + else + return 0; +} + +void SetPokemonCryChorus(s8 val) +{ + if (val) + { + gPokemonCrySong.trackCount = 2; + gPokemonCrySong.tuneValue2 = (val + gPokemonCrySong.tuneValue) & 0x7F; + } + else + { + gPokemonCrySong.trackCount = 1; + } +} + +void SetPokemonCryStereo(u32 val) +{ + struct SoundInfo *soundInfo = SOUND_INFO_PTR; + + if (val) + { + REG_SOUNDCNT_H = SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT + | SOUND_A_TIMER_0 | SOUND_A_RIGHT_OUTPUT + | SOUND_ALL_MIX_FULL; + soundInfo->mode &= ~1; + } + else + { + REG_SOUNDCNT_H = SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT | SOUND_B_RIGHT_OUTPUT + | SOUND_A_TIMER_0 | SOUND_A_LEFT_OUTPUT | SOUND_A_RIGHT_OUTPUT + | SOUND_B_MIX_HALF | SOUND_A_MIX_HALF | SOUND_CGB_MIX_FULL; + soundInfo->mode |= 1; + } +} + +void SetPokemonCryPriority(u8 val) +{ + gPokemonCrySong.priority = val; +} diff --git a/src/m4a_2.c b/src/m4a_2.c deleted file mode 100644 index 0625f05d1..000000000 --- a/src/m4a_2.c +++ /dev/null @@ -1,912 +0,0 @@ -#include "gba/m4a_internal.h" - -#define BSS_CODE __attribute__((section(".bss.code"))) - -BSS_CODE ALIGNED(4) char SoundMainRAM_Buffer[0x800] = {0}; - -struct SoundInfo gSoundInfo; -struct PokemonCrySong gPokemonCrySongs[MAX_POKEMON_CRIES]; -struct MusicPlayerInfo gPokemonCryMusicPlayers[MAX_POKEMON_CRIES]; -void *gMPlayJumpTable[36]; -struct CgbChannel gCgbChans[4]; -struct MusicPlayerTrack gPokemonCryTracks[MAX_POKEMON_CRIES * 2]; -struct PokemonCrySong gPokemonCrySong; -struct MusicPlayerInfo gMPlayInfo_BGM; -struct MusicPlayerInfo gMPlayInfo_SE1; -struct MusicPlayerInfo gMPlayInfo_SE2; -struct MusicPlayerInfo gMPlayInfo_SE3; -u8 gMPlayMemAccArea[0x10]; - -u32 MidiKeyToFreq(struct WaveData *wav, u8 key, u8 fineAdjust) -{ - u32 val1; - u32 val2; - u32 fineAdjustShifted = fineAdjust << 24; - - if (key > 178) - { - key = 178; - fineAdjustShifted = 255 << 24; - } - - val1 = gScaleTable[key]; - val1 = gFreqTable[val1 & 0xF] >> (val1 >> 4); - - val2 = gScaleTable[key + 1]; - val2 = gFreqTable[val2 & 0xF] >> (val2 >> 4); - - return umul3232H32(wav->freq, val1 + umul3232H32(val2 - val1, fineAdjustShifted)); -} - -void UnusedDummyFunc() -{ -} - -void MPlayContinue(struct MusicPlayerInfo *mplayInfo) -{ - if (mplayInfo->ident == ID_NUMBER) - { - mplayInfo->ident++; - mplayInfo->status &= ~MUSICPLAYER_STATUS_PAUSE; - mplayInfo->ident = ID_NUMBER; - } -} - -void MPlayFadeOut(struct MusicPlayerInfo *mplayInfo, u16 speed) -{ - if (mplayInfo->ident == ID_NUMBER) - { - mplayInfo->ident++; - mplayInfo->fadeOC = speed; - mplayInfo->fadeOI = speed; - mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT); - mplayInfo->ident = ID_NUMBER; - } -} - -void m4aSoundInit(void) -{ - s32 i; - - CpuCopy32((void *)((s32)SoundMainRAM & ~1), SoundMainRAM_Buffer, sizeof(SoundMainRAM_Buffer)); - - SoundInit(&gSoundInfo); - MPlayExtender(gCgbChans); - m4aSoundMode(SOUND_MODE_DA_BIT_8 - | SOUND_MODE_FREQ_13379 - | (12 << SOUND_MODE_MASVOL_SHIFT) - | (5 << SOUND_MODE_MAXCHN_SHIFT)); - - for (i = 0; i < NUM_MUSIC_PLAYERS; i++) - { - struct MusicPlayerInfo *mplayInfo = gMPlayTable[i].info; - MPlayOpen(mplayInfo, gMPlayTable[i].track, gMPlayTable[i].unk_8); - mplayInfo->unk_B = gMPlayTable[i].unk_A; - mplayInfo->memAccArea = gMPlayMemAccArea; - } - - memcpy(&gPokemonCrySong, &gPokemonCrySongTemplate, sizeof(struct PokemonCrySong)); - - for (i = 0; i < MAX_POKEMON_CRIES; i++) - { - struct MusicPlayerInfo *mplayInfo = &gPokemonCryMusicPlayers[i]; - struct MusicPlayerTrack *track = &gPokemonCryTracks[i * 2]; - MPlayOpen(mplayInfo, track, 2); - track->chan = 0; - } -} - -void m4aSoundMain(void) -{ - SoundMain(); -} - -void m4aSongNumStart(u16 n) -{ - const struct MusicPlayer *mplayTable = gMPlayTable; - const struct Song *songTable = gSongTable; - const struct Song *song = &songTable[n]; - const struct MusicPlayer *mplay = &mplayTable[song->ms]; - - MPlayStart(mplay->info, song->header); -} - -void m4aSongNumStartOrChange(u16 n) -{ - const struct MusicPlayer *mplayTable = gMPlayTable; - const struct Song *songTable = gSongTable; - const struct Song *song = &songTable[n]; - const struct MusicPlayer *mplay = &mplayTable[song->ms]; - - if (mplay->info->songHeader != song->header) - { - MPlayStart(mplay->info, song->header); - } - else - { - if ((mplay->info->status & MUSICPLAYER_STATUS_TRACK) == 0 - || (mplay->info->status & MUSICPLAYER_STATUS_PAUSE)) - { - MPlayStart(mplay->info, song->header); - } - } -} - -void m4aSongNumStartOrContinue(u16 n) -{ - const struct MusicPlayer *mplayTable = gMPlayTable; - const struct Song *songTable = gSongTable; - const struct Song *song = &songTable[n]; - const struct MusicPlayer *mplay = &mplayTable[song->ms]; - - if (mplay->info->songHeader != song->header) - MPlayStart(mplay->info, song->header); - else if ((mplay->info->status & MUSICPLAYER_STATUS_TRACK) == 0) - MPlayStart(mplay->info, song->header); - else if (mplay->info->status & MUSICPLAYER_STATUS_PAUSE) - MPlayContinue(mplay->info); -} - -void m4aSongNumStop(u16 n) -{ - const struct MusicPlayer *mplayTable = gMPlayTable; - const struct Song *songTable = gSongTable; - const struct Song *song = &songTable[n]; - const struct MusicPlayer *mplay = &mplayTable[song->ms]; - - if (mplay->info->songHeader == song->header) - m4aMPlayStop(mplay->info); -} - -void m4aSongNumContinue(u16 n) -{ - const struct MusicPlayer *mplayTable = gMPlayTable; - const struct Song *songTable = gSongTable; - const struct Song *song = &songTable[n]; - const struct MusicPlayer *mplay = &mplayTable[song->ms]; - - if (mplay->info->songHeader == song->header) - MPlayContinue(mplay->info); -} - -void m4aMPlayAllStop(void) -{ - s32 i; - - for (i = 0; i < NUM_MUSIC_PLAYERS; i++) - m4aMPlayStop(gMPlayTable[i].info); - - for (i = 0; i < MAX_POKEMON_CRIES; i++) - m4aMPlayStop(&gPokemonCryMusicPlayers[i]); -} - -void m4aMPlayContinue(struct MusicPlayerInfo *mplayInfo) -{ - MPlayContinue(mplayInfo); -} - -void m4aMPlayAllContinue(void) -{ - s32 i; - - for (i = 0; i < NUM_MUSIC_PLAYERS; i++) - MPlayContinue(gMPlayTable[i].info); - - for (i = 0; i < MAX_POKEMON_CRIES; i++) - MPlayContinue(&gPokemonCryMusicPlayers[i]); -} - -void m4aMPlayFadeOut(struct MusicPlayerInfo *mplayInfo, u16 speed) -{ - MPlayFadeOut(mplayInfo, speed); -} - -void m4aMPlayFadeOutTemporarily(struct MusicPlayerInfo *mplayInfo, u16 speed) -{ - if (mplayInfo->ident == ID_NUMBER) - { - mplayInfo->ident++; - mplayInfo->fadeOC = speed; - mplayInfo->fadeOI = speed; - mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT) | TEMPORARY_FADE; - mplayInfo->ident = ID_NUMBER; - } -} - -void m4aMPlayFadeIn(struct MusicPlayerInfo *mplayInfo, u16 speed) -{ - if (mplayInfo->ident == ID_NUMBER) - { - mplayInfo->ident++; - mplayInfo->fadeOC = speed; - mplayInfo->fadeOI = speed; - mplayInfo->fadeOV = (0 << FADE_VOL_SHIFT) | FADE_IN; - mplayInfo->status &= ~MUSICPLAYER_STATUS_PAUSE; - mplayInfo->ident = ID_NUMBER; - } -} - -void m4aMPlayImmInit(struct MusicPlayerInfo *mplayInfo) -{ - s32 trackCount = mplayInfo->trackCount; - struct MusicPlayerTrack *track = mplayInfo->tracks; - - while (trackCount > 0) - { - if (track->flags & MPT_FLG_EXIST) - { - if (track->flags & MPT_FLG_START) - { - Clear64byte(track); - track->flags = MPT_FLG_EXIST; - track->bendRange = 2; - track->volX = 64; - track->lfoSpeed = 22; - track->tone.type = 1; - } - } - - trackCount--; - track++; - } -} - -void MPlayExtender(struct CgbChannel *cgbChans) -{ - struct SoundInfo *soundInfo; - u32 ident; - - REG_SOUNDCNT_X = SOUND_MASTER_ENABLE - | SOUND_4_ON - | SOUND_3_ON - | SOUND_2_ON - | SOUND_1_ON; - REG_SOUNDCNT_L = 0; // set master volume to zero - REG_NR12 = 0x8; - REG_NR22 = 0x8; - REG_NR42 = 0x8; - REG_NR14 = 0x80; - REG_NR24 = 0x80; - REG_NR44 = 0x80; - REG_NR30 = 0; - REG_NR50 = 0x77; - - soundInfo = SOUND_INFO_PTR; - - ident = soundInfo->ident; - - if (ident != ID_NUMBER) - return; - - soundInfo->ident++; - - gMPlayJumpTable[8] = ply_memacc; - gMPlayJumpTable[17] = ply_lfos; - gMPlayJumpTable[19] = ply_mod; - gMPlayJumpTable[28] = ply_xcmd; - gMPlayJumpTable[29] = ply_endtie; - gMPlayJumpTable[30] = SampleFreqSet; - gMPlayJumpTable[31] = TrackStop; - gMPlayJumpTable[32] = FadeOutBody; - gMPlayJumpTable[33] = TrkVolPitSet; - - soundInfo->cgbChans = (struct CgbChannel *)cgbChans; - soundInfo->CgbSound = CgbSound; - soundInfo->CgbOscOff = CgbOscOff; - soundInfo->MidiKeyToCgbFreq = MidiKeyToCgbFreq; - soundInfo->maxLines = MAX_LINES; - - CpuFill32(0, cgbChans, sizeof(struct CgbChannel) * 4); - - cgbChans[0].ty = 1; - cgbChans[0].panMask = 0x11; - cgbChans[1].ty = 2; - cgbChans[1].panMask = 0x22; - cgbChans[2].ty = 3; - cgbChans[2].panMask = 0x44; - cgbChans[3].ty = 4; - cgbChans[3].panMask = 0x88; - - soundInfo->ident = ident; -} - -void MusicPlayerJumpTableCopy(void) -{ - asm("swi 0x2A"); -} - -void ClearChain(void *x) -{ - void (*func)(void *) = *(&gMPlayJumpTable[34]); - func(x); -} - -void Clear64byte(void *x) -{ - void (*func)(void *) = *(&gMPlayJumpTable[35]); - func(x); -} - -void SoundInit(struct SoundInfo *soundInfo) -{ - soundInfo->ident = 0; - - if (REG_DMA1CNT & (DMA_REPEAT << 16)) - REG_DMA1CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4; - - if (REG_DMA2CNT & (DMA_REPEAT << 16)) - REG_DMA2CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4; - - REG_DMA1CNT_H = DMA_32BIT; - REG_DMA2CNT_H = DMA_32BIT; - REG_SOUNDCNT_X = SOUND_MASTER_ENABLE - | SOUND_4_ON - | SOUND_3_ON - | SOUND_2_ON - | SOUND_1_ON; - REG_SOUNDCNT_H = SOUND_B_FIFO_RESET | SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT - | SOUND_A_FIFO_RESET | SOUND_A_TIMER_0 | SOUND_A_RIGHT_OUTPUT - | SOUND_ALL_MIX_FULL; - REG_SOUNDBIAS_H = (REG_SOUNDBIAS_H & 0x3F) | 0x40; - - REG_DMA1SAD = (s32)soundInfo->pcmBuffer; - REG_DMA1DAD = (s32)®_FIFO_A; - REG_DMA2SAD = (s32)soundInfo->pcmBuffer + PCM_DMA_BUF_SIZE; - REG_DMA2DAD = (s32)®_FIFO_B; - - SOUND_INFO_PTR = soundInfo; - CpuFill32(0, soundInfo, sizeof(struct SoundInfo)); - - soundInfo->maxChans = 8; - soundInfo->masterVolume = 15; - soundInfo->plynote = (u32)ply_note; - soundInfo->CgbSound = DummyFunc; - soundInfo->CgbOscOff = (void (*)(u8))DummyFunc; - soundInfo->MidiKeyToCgbFreq = (u32 (*)(u8, u8, u8))DummyFunc; - soundInfo->ExtVolPit = (u32)DummyFunc; - - MPlayJumpTableCopy(gMPlayJumpTable); - - soundInfo->MPlayJumpTable = (u32)gMPlayJumpTable; - - SampleFreqSet(SOUND_MODE_FREQ_13379); - - soundInfo->ident = ID_NUMBER; -} - -void SampleFreqSet(u32 freq) -{ - struct SoundInfo *soundInfo = SOUND_INFO_PTR; - - freq = (freq & 0xF0000) >> 16; - soundInfo->freq = freq; - soundInfo->pcmSamplesPerVBlank = gPcmSamplesPerVBlankTable[freq - 1]; - soundInfo->pcmDmaPeriod = PCM_DMA_BUF_SIZE / soundInfo->pcmSamplesPerVBlank; - - // LCD refresh rate 59.7275Hz - soundInfo->pcmFreq = (597275 * soundInfo->pcmSamplesPerVBlank + 5000) / 10000; - - // CPU frequency 16.78Mhz - soundInfo->divFreq = (16777216 / soundInfo->pcmFreq + 1) >> 1; - - // Turn off timer 0. - REG_TM0CNT_H = 0; - - // cycles per LCD fresh 280896 - REG_TM0CNT_L = -(280896 / soundInfo->pcmSamplesPerVBlank); - - m4aSoundVSyncOn(); - - while (*(vu8 *)REG_ADDR_VCOUNT == 159) - ; - - while (*(vu8 *)REG_ADDR_VCOUNT != 159) - ; - - REG_TM0CNT_H = TIMER_ENABLE | TIMER_1CLK; -} - -void m4aSoundMode(u32 mode) -{ - struct SoundInfo *soundInfo = SOUND_INFO_PTR; - u32 temp; - - if (soundInfo->ident != ID_NUMBER) - return; - - soundInfo->ident++; - - temp = mode & (SOUND_MODE_REVERB_SET | SOUND_MODE_REVERB_VAL); - - if (temp) - soundInfo->reverb = temp & SOUND_MODE_REVERB_VAL; - - temp = mode & SOUND_MODE_MAXCHN; - - if (temp) - { - struct SoundChannel *chan; - - soundInfo->maxChans = temp >> SOUND_MODE_MAXCHN_SHIFT; - - temp = MAX_DIRECTSOUND_CHANNELS; - chan = &soundInfo->chans[0]; - - while (temp != 0) - { - chan->status = 0; - temp--; - chan++; - } - } - - temp = mode & SOUND_MODE_MASVOL; - - if (temp) - soundInfo->masterVolume = temp >> SOUND_MODE_MASVOL_SHIFT; - - temp = mode & SOUND_MODE_DA_BIT; - - if (temp) - { - temp = (temp & 0x300000) >> 14; - REG_SOUNDBIAS_H = (REG_SOUNDBIAS_H & 0x3F) | temp; - } - - temp = mode & SOUND_MODE_FREQ; - - if (temp) - { - m4aSoundVSyncOff(); - SampleFreqSet(temp); - } - - soundInfo->ident = ID_NUMBER; -} - -void SoundClear(void) -{ - struct SoundInfo *soundInfo = SOUND_INFO_PTR; - s32 i; - void *chan; - - if (soundInfo->ident != ID_NUMBER) - return; - - soundInfo->ident++; - - i = MAX_DIRECTSOUND_CHANNELS; - chan = &soundInfo->chans[0]; - - while (i > 0) - { - ((struct SoundChannel *)chan)->status = 0; - i--; - chan = (void *)((s32)chan + sizeof(struct SoundChannel)); - } - - chan = soundInfo->cgbChans; - - if (chan) - { - i = 1; - - while (i <= 4) - { - soundInfo->CgbOscOff(i); - ((struct CgbChannel *)chan)->sf = 0; - i++; - chan = (void *)((s32)chan + sizeof(struct CgbChannel)); - } - } - - soundInfo->ident = ID_NUMBER; -} - -void m4aSoundVSyncOff(void) -{ - struct SoundInfo *soundInfo = SOUND_INFO_PTR; - - if (soundInfo->ident >= ID_NUMBER && soundInfo->ident <= ID_NUMBER + 1) - { - soundInfo->ident += 10; - - if (REG_DMA1CNT & (DMA_REPEAT << 16)) - REG_DMA1CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4; - - if (REG_DMA2CNT & (DMA_REPEAT << 16)) - REG_DMA2CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4; - - REG_DMA1CNT_H = DMA_32BIT; - REG_DMA2CNT_H = DMA_32BIT; - - CpuFill32(0, soundInfo->pcmBuffer, sizeof(soundInfo->pcmBuffer)); - } -} - -void m4aSoundVSyncOn(void) -{ - struct SoundInfo *soundInfo = SOUND_INFO_PTR; - u32 ident = soundInfo->ident; - - if (ident == ID_NUMBER) - return; - - REG_DMA1CNT_H = DMA_ENABLE | DMA_START_SPECIAL | DMA_32BIT | DMA_REPEAT; - REG_DMA2CNT_H = DMA_ENABLE | DMA_START_SPECIAL | DMA_32BIT | DMA_REPEAT; - - soundInfo->pcmDmaCounter = 0; - soundInfo->ident = ident - 10; -} - -void MPlayOpen(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *tracks, u8 trackCount) -{ - struct SoundInfo *soundInfo; - - if (trackCount == 0) - return; - - if (trackCount > MAX_MUSICPLAYER_TRACKS) - trackCount = MAX_MUSICPLAYER_TRACKS; - - soundInfo = SOUND_INFO_PTR; - - if (soundInfo->ident != ID_NUMBER) - return; - - soundInfo->ident++; - - Clear64byte(mplayInfo); - - mplayInfo->tracks = tracks; - mplayInfo->trackCount = trackCount; - mplayInfo->status = MUSICPLAYER_STATUS_PAUSE; - - while (trackCount != 0) - { - tracks->flags = 0; - trackCount--; - tracks++; - } - - if (soundInfo->func != 0) - { - mplayInfo->func = soundInfo->func; - mplayInfo->intp = soundInfo->intp; - soundInfo->func = 0; - } - - soundInfo->intp = (u32)mplayInfo; - soundInfo->func = (u32)MPlayMain; - soundInfo->ident = ID_NUMBER; - mplayInfo->ident = ID_NUMBER; -} - -void MPlayStart(struct MusicPlayerInfo *mplayInfo, struct SongHeader *songHeader) -{ - s32 i; - u8 unk_B; - struct MusicPlayerTrack *track; - - if (mplayInfo->ident != ID_NUMBER) - return; - - unk_B = mplayInfo->unk_B; - - if (!unk_B - || ((!mplayInfo->songHeader || !(mplayInfo->tracks[0].flags & MPT_FLG_START)) - && ((mplayInfo->status & MUSICPLAYER_STATUS_TRACK) == 0 - || (mplayInfo->status & MUSICPLAYER_STATUS_PAUSE))) - || (mplayInfo->priority <= songHeader->priority)) - { - mplayInfo->ident++; - mplayInfo->status = 0; - mplayInfo->songHeader = songHeader; - mplayInfo->tone = songHeader->tone; - mplayInfo->priority = songHeader->priority; - mplayInfo->clock = 0; - mplayInfo->tempoD = 150; - mplayInfo->tempoI = 150; - mplayInfo->tempoU = 0x100; - mplayInfo->tempoC = 0; - mplayInfo->fadeOI = 0; - - i = 0; - track = mplayInfo->tracks; - - while (i < songHeader->trackCount && i < mplayInfo->trackCount) - { - TrackStop(mplayInfo, track); - track->flags = MPT_FLG_EXIST | MPT_FLG_START; - track->chan = 0; - track->cmdPtr = songHeader->part[i]; - i++; - track++; - } - - while (i < mplayInfo->trackCount) - { - TrackStop(mplayInfo, track); - track->flags = 0; - i++; - track++; - } - - if (songHeader->reverb & 0x80) - m4aSoundMode(songHeader->reverb); - - mplayInfo->ident = ID_NUMBER; - } -} - -void m4aMPlayStop(struct MusicPlayerInfo *mplayInfo) -{ - s32 i; - struct MusicPlayerTrack *track; - - if (mplayInfo->ident != ID_NUMBER) - return; - - mplayInfo->ident++; - mplayInfo->status |= MUSICPLAYER_STATUS_PAUSE; - - i = mplayInfo->trackCount; - track = mplayInfo->tracks; - - while (i > 0) - { - TrackStop(mplayInfo, track); - i--; - track++; - } - - mplayInfo->ident = ID_NUMBER; -} - -void FadeOutBody(struct MusicPlayerInfo *mplayInfo) -{ - s32 i; - struct MusicPlayerTrack *track; - u16 fadeOI = mplayInfo->fadeOI; - register u32 temp asm("r3"); - register u16 mask asm("r2"); - - if (fadeOI == 0) - return; - - mplayInfo->fadeOC--; - - temp = 0xFFFF; - mask = temp; - - if (mplayInfo->fadeOC != 0) - return; - - mplayInfo->fadeOC = fadeOI; - - if (mplayInfo->fadeOV & FADE_IN) - { - mplayInfo->fadeOV += (4 << FADE_VOL_SHIFT); - - if ((u16)(mplayInfo->fadeOV & mask) >= (64 << FADE_VOL_SHIFT)) - { - mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT); - mplayInfo->fadeOI = 0; - } - } - else - { - mplayInfo->fadeOV -= (4 << FADE_VOL_SHIFT); - - if ((s16)(mplayInfo->fadeOV & mask) <= 0) - { - i = mplayInfo->trackCount; - track = mplayInfo->tracks; - - while (i > 0) - { - register u32 fadeOV asm("r7"); - u32 val; - - TrackStop(mplayInfo, track); - - val = TEMPORARY_FADE; - fadeOV = mplayInfo->fadeOV; - val &= fadeOV; - - if (!val) - track->flags = 0; - - i--; - track++; - } - - if (mplayInfo->fadeOV & TEMPORARY_FADE) - mplayInfo->status |= MUSICPLAYER_STATUS_PAUSE; - else - mplayInfo->status = MUSICPLAYER_STATUS_PAUSE; - - mplayInfo->fadeOI = 0; - return; - } - } - - i = mplayInfo->trackCount; - track = mplayInfo->tracks; - - while (i > 0) - { - if (track->flags & MPT_FLG_EXIST) - { - track->volX = (mplayInfo->fadeOV >> FADE_VOL_SHIFT); - track->flags |= MPT_FLG_VOLCHG; - } - - i--; - track++; - } -} - -void TrkVolPitSet(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - if (track->flags & MPT_FLG_VOLSET) - { - s32 x; - s32 y; - - x = (u32)(track->vol * track->volX) >> 5; - - if (track->modT == 1) - x = (u32)(x * (track->modM + 128)) >> 7; - - y = 2 * track->pan + track->panX; - - if (track->modT == 2) - y += track->modM; - - if (y < -128) - y = -128; - else if (y > 127) - y = 127; - - track->volMR = (u32)((y + 128) * x) >> 8; - track->volML = (u32)((127 - y) * x) >> 8; - } - - if (track->flags & MPT_FLG_PITSET) - { - s32 bend = track->bend * track->bendRange; - register s32 x asm("r1") = track->tune; - x += bend; - x *= 4; - x += (track->keyShift << 8); - x += (track->keyShiftX << 8); - x += track->pitX; - - if (track->modT == 0) - x += 16 * track->modM; - - track->keyM = x >> 8; - track->pitM = x; - } - - track->flags &= ~(MPT_FLG_PITSET | MPT_FLG_VOLSET); -} - -u32 MidiKeyToCgbFreq(u8 chanNum, u8 key, u8 fineAdjust) -{ - if (chanNum == 4) - { - if (key <= 20) - { - key = 0; - } - else - { - key -= 21; - if (key > 59) - key = 59; - } - - return gNoiseTable[key]; - } - else - { - s32 val1; - s32 val2; - - if (key <= 35) - { - fineAdjust = 0; - key = 0; - } - else - { - key -= 36; - if (key > 130) - { - key = 130; - fineAdjust = 255; - } - } - - val1 = gCgbScaleTable[key]; - val1 = gCgbFreqTable[val1 & 0xF] >> (val1 >> 4); - - val2 = gCgbScaleTable[key + 1]; - val2 = gCgbFreqTable[val2 & 0xF] >> (val2 >> 4); - - return val1 + ((fineAdjust * (val2 - val1)) >> 8) + 2048; - } -} - -void CgbOscOff(u8 chanNum) -{ - switch (chanNum) - { - case 1: - REG_NR12 = 8; - REG_NR14 = 0x80; - break; - case 2: - REG_NR22 = 8; - REG_NR24 = 0x80; - break; - case 3: - REG_NR30 = 0; - break; - default: - REG_NR42 = 8; - REG_NR44 = 0x80; - } -} - -static inline int CgbPan(struct CgbChannel *chan) -{ - u32 rightVolume = chan->rightVolume; - u32 leftVolume = chan->leftVolume; - - if ((rightVolume = (u8)rightVolume) >= (leftVolume = (u8)leftVolume)) - { - if (rightVolume / 2 >= leftVolume) - { - chan->pan = 0x0F; - return 1; - } - } - else - { - if (leftVolume / 2 >= rightVolume) - { - chan->pan = 0xF0; - return 1; - } - } - - return 0; -} - -void CgbModVol(struct CgbChannel *chan) -{ - struct SoundInfo *soundInfo = SOUND_INFO_PTR; - - if ((soundInfo->mode & 1) || !CgbPan(chan)) - { - chan->pan = 0xFF; - chan->eg = (u32)(chan->rightVolume + chan->leftVolume) >> 4; - } - else - { - // Force chan->rightVolume and chan->leftVolume to be read from memory again, - // even though there is no reason to do so. - // The command line option "-fno-gcse" achieves the same result as this. - asm("" : : : "memory"); - - chan->eg = (u32)(chan->rightVolume + chan->leftVolume) >> 4; - if (chan->eg > 15) - chan->eg = 15; - } - - chan->sg = (chan->eg * chan->su + 15) >> 4; - chan->pan &= chan->panMask; -} diff --git a/src/m4a_4.c b/src/m4a_4.c deleted file mode 100644 index 2e1d140b4..000000000 --- a/src/m4a_4.c +++ /dev/null @@ -1,545 +0,0 @@ -#include "gba/m4a_internal.h" - -void m4aMPlayTempoControl(struct MusicPlayerInfo *mplayInfo, u16 tempo) -{ - if (mplayInfo->ident == ID_NUMBER) - { - mplayInfo->ident++; - mplayInfo->tempoU = tempo; - mplayInfo->tempoI = (mplayInfo->tempoD * mplayInfo->tempoU) >> 8; - mplayInfo->ident = ID_NUMBER; - } -} - -void m4aMPlayVolumeControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u16 volume) -{ - s32 i; - u32 bit; - struct MusicPlayerTrack *track; - - if (mplayInfo->ident != ID_NUMBER) - return; - - mplayInfo->ident++; - - i = mplayInfo->trackCount; - track = mplayInfo->tracks; - bit = 1; - - while (i > 0) - { - if (trackBits & bit) - { - if (track->flags & MPT_FLG_EXIST) - { - track->volX = volume / 4; - track->flags |= MPT_FLG_VOLCHG; - } - } - - i--; - track++; - bit <<= 1; - } - - mplayInfo->ident = ID_NUMBER; -} - -void m4aMPlayPitchControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s16 pitch) -{ - s32 i; - u32 bit; - struct MusicPlayerTrack *track; - - if (mplayInfo->ident != ID_NUMBER) - return; - - mplayInfo->ident++; - - i = mplayInfo->trackCount; - track = mplayInfo->tracks; - bit = 1; - - while (i > 0) - { - if (trackBits & bit) - { - if (track->flags & MPT_FLG_EXIST) - { - track->keyShiftX = (s16)pitch >> 8; - track->pitX = pitch; - track->flags |= MPT_FLG_PITCHG; - } - } - - i--; - track++; - bit <<= 1; - } - - mplayInfo->ident = ID_NUMBER; -} - -void m4aMPlayPanpotControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s8 pan) -{ - s32 i; - u32 bit; - struct MusicPlayerTrack *track; - - if (mplayInfo->ident != ID_NUMBER) - return; - - mplayInfo->ident++; - - i = mplayInfo->trackCount; - track = mplayInfo->tracks; - bit = 1; - - while (i > 0) - { - if (trackBits & bit) - { - if (track->flags & MPT_FLG_EXIST) - { - track->panX = pan; - track->flags |= MPT_FLG_VOLCHG; - } - } - - i--; - track++; - bit <<= 1; - } - - mplayInfo->ident = ID_NUMBER; -} - -void ClearModM(struct MusicPlayerTrack *track) -{ - track->lfoSpeedC = 0; - track->modM = 0; - - if (track->modT == 0) - track->flags |= MPT_FLG_PITCHG; - else - track->flags |= MPT_FLG_VOLCHG; -} - -void m4aMPlayModDepthSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 modDepth) -{ - s32 i; - u32 bit; - struct MusicPlayerTrack *track; - - if (mplayInfo->ident != ID_NUMBER) - return; - - mplayInfo->ident++; - - i = mplayInfo->trackCount; - track = mplayInfo->tracks; - bit = 1; - - while (i > 0) - { - if (trackBits & bit) - { - if (track->flags & MPT_FLG_EXIST) - { - track->mod = modDepth; - - if (!track->mod) - ClearModM(track); - } - } - - i--; - track++; - bit <<= 1; - } - - mplayInfo->ident = ID_NUMBER; -} - -void m4aMPlayLFOSpeedSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 lfoSpeed) -{ - s32 i; - u32 bit; - struct MusicPlayerTrack *track; - - if (mplayInfo->ident != ID_NUMBER) - return; - - mplayInfo->ident++; - - i = mplayInfo->trackCount; - track = mplayInfo->tracks; - bit = 1; - - while (i > 0) - { - if (trackBits & bit) - { - if (track->flags & MPT_FLG_EXIST) - { - track->lfoSpeed = lfoSpeed; - - if (!track->lfoSpeed) - ClearModM(track); - } - } - - i--; - track++; - bit <<= 1; - } - - mplayInfo->ident = ID_NUMBER; -} - -#define MEMACC_COND_JUMP(cond) \ -if (cond) \ - goto cond_true; \ -else \ - goto cond_false; \ - -void ply_memacc(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - u32 op; - u8 *addr; - u8 data; - - op = *track->cmdPtr; - track->cmdPtr++; - - addr = mplayInfo->memAccArea + *track->cmdPtr; - track->cmdPtr++; - - data = *track->cmdPtr; - track->cmdPtr++; - - switch (op) - { - case 0: - *addr = data; - return; - case 1: - *addr += data; - return; - case 2: - *addr -= data; - return; - case 3: - *addr = mplayInfo->memAccArea[data]; - return; - case 4: - *addr += mplayInfo->memAccArea[data]; - return; - case 5: - *addr -= mplayInfo->memAccArea[data]; - return; - case 6: - MEMACC_COND_JUMP(*addr == data) - return; - case 7: - MEMACC_COND_JUMP(*addr != data) - return; - case 8: - MEMACC_COND_JUMP(*addr > data) - return; - case 9: - MEMACC_COND_JUMP(*addr >= data) - return; - case 10: - MEMACC_COND_JUMP(*addr <= data) - return; - case 11: - MEMACC_COND_JUMP(*addr < data) - return; - case 12: - MEMACC_COND_JUMP(*addr == mplayInfo->memAccArea[data]) - return; - case 13: - MEMACC_COND_JUMP(*addr != mplayInfo->memAccArea[data]) - return; - case 14: - MEMACC_COND_JUMP(*addr > mplayInfo->memAccArea[data]) - return; - case 15: - MEMACC_COND_JUMP(*addr >= mplayInfo->memAccArea[data]) - return; - case 16: - MEMACC_COND_JUMP(*addr <= mplayInfo->memAccArea[data]) - return; - case 17: - MEMACC_COND_JUMP(*addr < mplayInfo->memAccArea[data]) - return; - default: - return; - } - -cond_true: - { - void (*func)(struct MusicPlayerInfo *, struct MusicPlayerTrack *) = *(&gMPlayJumpTable[1]); - func(mplayInfo, track); - return; - } - -cond_false: - track->cmdPtr += 4; -} - -void ply_xcmd(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - u32 n = *track->cmdPtr; - track->cmdPtr++; - - gXcmdTable[n](mplayInfo, track); -} - -void ply_xxx(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - void (*func)(struct MusicPlayerInfo *, struct MusicPlayerTrack *) = *(&gMPlayJumpTable[0]); - func(mplayInfo, track); -} - -#define READ_XCMD_BYTE(var, n) \ -{ \ - u32 byte = track->cmdPtr[(n)]; \ - byte <<= n * 8; \ - (var) &= ~(0xFF << (n * 8)); \ - (var) |= byte; \ -} - -void ply_xwave(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - u32 wav; - - READ_XCMD_BYTE(wav, 0) // UB: uninitialized variable - READ_XCMD_BYTE(wav, 1) - READ_XCMD_BYTE(wav, 2) - READ_XCMD_BYTE(wav, 3) - - track->tone.wav = (struct WaveData *)wav; - track->cmdPtr += 4; -} - -void ply_xtype(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->tone.type = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xatta(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->tone.attack = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xdeca(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->tone.decay = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xsust(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->tone.sustain = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xrele(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->tone.release = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xiecv(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->echoVolume = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xiecl(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->echoLength = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xleng(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->tone.length = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xswee(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - track->tone.pan_sweep = *track->cmdPtr; - track->cmdPtr++; -} - -void ply_xcmd_0C(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - u32 unk; - - READ_XCMD_BYTE(unk, 0) // UB: uninitialized variable - READ_XCMD_BYTE(unk, 1) - - if (track->unk_3A < (u16)unk) - { - track->unk_3A++; - track->cmdPtr -= 2; - track->wait = 1; - } - else - { - track->unk_3A = 0; - track->cmdPtr += 2; - } -} - -void ply_xcmd_0D(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) -{ - u32 unk; - - READ_XCMD_BYTE(unk, 0) // UB: uninitialized variable - READ_XCMD_BYTE(unk, 1) - READ_XCMD_BYTE(unk, 2) - READ_XCMD_BYTE(unk, 3) - - track->unk_3C = unk; - track->cmdPtr += 4; -} - -void DummyFunc(void) -{ -} - -struct MusicPlayerInfo *SetPokemonCryTone(struct ToneData *tone) -{ - u32 maxClock = 0; - s32 maxClockIndex = 0; - s32 i; - struct MusicPlayerInfo *mplayInfo; - - for (i = 0; i < MAX_POKEMON_CRIES; i++) - { - struct MusicPlayerTrack *track = &gPokemonCryTracks[i * 2]; - - if (!track->flags && (!track->chan || track->chan->track != track)) - goto start_song; - - if (maxClock < gPokemonCryMusicPlayers[i].clock) - { - maxClock = gPokemonCryMusicPlayers[i].clock; - maxClockIndex = i; - } - } - - i = maxClockIndex; - -start_song: - mplayInfo = &gPokemonCryMusicPlayers[i]; - mplayInfo->ident++; - -#define CRY ((s32)&gPokemonCrySongs + i * sizeof(struct PokemonCrySong)) -#define CRY_OFS(field) offsetof(struct PokemonCrySong, field) - - memcpy((void *)CRY, &gPokemonCrySong, sizeof(struct PokemonCrySong)); - - *(u32 *)(CRY + CRY_OFS(tone)) = (u32)tone; - *(u32 *)(CRY + CRY_OFS(part)) = CRY + CRY_OFS(part0); - *(u32 *)(CRY + CRY_OFS(part) + 4) = CRY + CRY_OFS(part1); - *(u32 *)(CRY + CRY_OFS(gotoTarget)) = CRY + CRY_OFS(cont); - -#undef CRY_OFS -#undef CRY - - mplayInfo->ident = ID_NUMBER; - - MPlayStart(mplayInfo, (struct SongHeader *)(&gPokemonCrySongs[i])); - - return mplayInfo; -} - -void SetPokemonCryVolume(u8 val) -{ - gPokemonCrySong.volumeValue = val & 0x7F; -} - -void SetPokemonCryPanpot(s8 val) -{ - gPokemonCrySong.panValue = (val + C_V) & 0x7F; -} - -void SetPokemonCryPitch(s16 val) -{ - s16 b = val + 0x80; - u8 a = gPokemonCrySong.tuneValue2 - gPokemonCrySong.tuneValue; - gPokemonCrySong.tieKeyValue = (b >> 8) & 0x7F; - gPokemonCrySong.tuneValue = (b >> 1) & 0x7F; - gPokemonCrySong.tuneValue2 = (a + ((b >> 1) & 0x7F)) & 0x7F; -} - -void SetPokemonCryLength(u16 val) -{ - gPokemonCrySong.unkCmd0CParam = val; -} - -void SetPokemonCryRelease(u8 val) -{ - gPokemonCrySong.releaseValue = val; -} - -void SetPokemonCryProgress(u32 val) -{ - gPokemonCrySong.unkCmd0DParam = val; -} - -int IsPokemonCryPlaying(struct MusicPlayerInfo *mplayInfo) -{ - struct MusicPlayerTrack *track = mplayInfo->tracks; - - if (track->chan && track->chan->track == track) - return 1; - else - return 0; -} - -void SetPokemonCryChorus(s8 val) -{ - if (val) - { - gPokemonCrySong.trackCount = 2; - gPokemonCrySong.tuneValue2 = (val + gPokemonCrySong.tuneValue) & 0x7F; - } - else - { - gPokemonCrySong.trackCount = 1; - } -} - -void SetPokemonCryStereo(u32 val) -{ - struct SoundInfo *soundInfo = SOUND_INFO_PTR; - - if (val) - { - REG_SOUNDCNT_H = SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT - | SOUND_A_TIMER_0 | SOUND_A_RIGHT_OUTPUT - | SOUND_ALL_MIX_FULL; - soundInfo->mode &= ~1; - } - else - { - REG_SOUNDCNT_H = SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT | SOUND_B_RIGHT_OUTPUT - | SOUND_A_TIMER_0 | SOUND_A_LEFT_OUTPUT | SOUND_A_RIGHT_OUTPUT - | SOUND_B_MIX_HALF | SOUND_A_MIX_HALF | SOUND_CGB_MIX_FULL; - soundInfo->mode |= 1; - } -} - -void SetPokemonCryPriority(u8 val) -{ - gPokemonCrySong.priority = val; -} diff --git a/src/main.c b/src/main.c index 068cc8578..ae9a33e81 100644 --- a/src/main.c +++ b/src/main.c @@ -5,6 +5,7 @@ #include "dma3.h" #include "gba/flash_internal.h" #include "battle.h" +#include "help_system.h" extern u16 GetGpuReg(u8); extern void SetGpuReg(u8, u16); @@ -29,10 +30,9 @@ extern void MapMusicMain(void); extern void EnableInterrupts(u16); extern void sub_800DD28(void); extern u16 SetFlashTimerIntr(u8 timerNum, void (**intrFunc)(void)); -extern void remove_some_task(void); +extern void ScanlineEffect_Stop(void); extern void sub_80F50F4(void); extern bool32 sub_80F5118(void); -extern bool8 sub_813B870(void); extern struct SoundInfo gSoundInfo; extern u32 gFlashMemoryPresent; @@ -96,13 +96,13 @@ u8 gUnknown_3003D84; static IntrFunc * const sTimerIntrFunc = gIntrTable + 0x7; -extern u16 gTrainerId; +EWRAM_DATA u8 gDecompressionBuffer[0x4000] = {0}; +EWRAM_DATA u16 gTrainerId = 0; + extern bool8 gUnknown_3005ECC; extern bool8 gWirelessCommType; extern bool8 gUnknown_3005E88; -EWRAM_DATA void (**gFlashTimerIntrFunc)(void) = NULL; - static void UpdateLinkAndCallCallbacks(void); static void InitMainCallbacks(void); static void CallCallbacks(void); @@ -116,7 +116,7 @@ void EnableVCountIntrAtLine150(void); void AgbMain() { RegisterRamReset(RESET_ALL); - *(vu16 *)BG_PLTT = 0x7FFF; + *(vu16 *)BG_PLTT = RGB_WHITE; InitGpuRegManager(); REG_WAITCNT = WAITCNT_PREFETCH_ENABLE | WAITCNT_WS0_S_1 | WAITCNT_WS0_N_3; InitKeys(); @@ -206,7 +206,7 @@ static void InitMainCallbacks(void) static void CallCallbacks(void) { - if (!sub_80F5118() && !sub_813B870()) + if (!sub_80F5118() && !RunHelpSystemCallback()) { if (gMain.callback1) gMain.callback1(); @@ -441,7 +441,7 @@ void DoSoftReset(void) { REG_IME = 0; m4aSoundVSyncOff(); - remove_some_task(); + ScanlineEffect_Stop(); DmaStop(1); DmaStop(2); DmaStop(3); diff --git a/src/map_obj_lock.c b/src/map_obj_lock.c new file mode 100644 index 000000000..cdd74a5b9 --- /dev/null +++ b/src/map_obj_lock.c @@ -0,0 +1,116 @@ +#include "global.h" +#include "task.h" +#include "field_player_avatar.h" +#include "field_map_obj.h" +#include "field_map_obj_helpers.h" +#include "script_movement.h" +#include "map_obj_80688E4.h" +#include "event_data.h" +#include "map_obj_lock.h" + +bool8 walkrun_is_standing_still(void) +{ + if (gPlayerAvatar.running1 == 1) + return FALSE; + else + return TRUE; +} + +void sub_8069570(u8 taskId) +{ + if (walkrun_is_standing_still()) + { + sub_805C270(); + DestroyTask(taskId); + } +} + +bool8 sub_8069590(void) +{ + if (FuncIsActiveTask(sub_8069570)) + return FALSE; + else + { + sub_805C780(); + return TRUE; + } +} + +void ScriptFreezeMapObjects(void) +{ + player_bitmagic(); + CreateTask(sub_8069570, 80); +} + +void sub_80695CC(u8 taskId) +{ + struct Task * task = &gTasks[taskId]; + + if (task->data[0] == 0 && walkrun_is_standing_still() == TRUE) + { + sub_805C270(); + task->data[0] = 1; + } + + if (task->data[1] == 0 && !gMapObjects[gSelectedEventObject].mapobj_bit_1) + { + FreezeMapObject(&gMapObjects[gSelectedEventObject]); + task->data[1] = 1; + } + + if (task->data[0] && task->data[1]) + DestroyTask(taskId); +} + +bool8 sub_8069648(void) +{ + if (FuncIsActiveTask(sub_80695CC)) + return FALSE; + else + { + sub_805C780(); + return TRUE; + } +} + +void LockSelectedMapObject(void) +{ + u8 taskId; + + FreezeMapObjectsExceptOne(gSelectedEventObject); + taskId = CreateTask(sub_80695CC, 80); + if (!gMapObjects[gSelectedEventObject].mapobj_bit_1) + { + FreezeMapObject(&gMapObjects[gSelectedEventObject]); + gTasks[taskId].data[1] = 1; + } +} + +void sub_80696C0(void) +{ + u8 fieldObjectId = GetFieldObjectIdByLocalIdAndMap(0xFF, 0, 0); + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[fieldObjectId]); + sub_80974D8(); + UnfreezeMapObjects(); +} + +void sub_80696F0(void) +{ + u8 fieldObjectId; + if (gMapObjects[gSelectedEventObject].active) + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[gSelectedEventObject]); + fieldObjectId = GetFieldObjectIdByLocalIdAndMap(0xFF, 0, 0); + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[fieldObjectId]); + sub_80974D8(); + UnfreezeMapObjects(); +} + +void sub_8069740(void) +{ + FieldObjectFaceOppositeDirection(&gMapObjects[gSelectedEventObject], gSpecialVar_Facing); +} + +void sub_8069768(void) +{ + FieldObjectClearAnimIfSpecialAnimActive(&gMapObjects[gSelectedEventObject]); +} diff --git a/src/menews_jisan.c b/src/menews_jisan.c index b4fe080bf..0d406e66a 100644 --- a/src/menews_jisan.c +++ b/src/menews_jisan.c @@ -10,76 +10,24 @@ static u32 sub_8146E0C(struct MysteryEventStruct *); static void sub_8146DA0(struct MysteryEventStruct *); static void sub_8146D94(struct MysteryEventStruct *); -#ifdef NONMATCHING -void sub_8146C30(u32 a0) +void GenerateRandomNews(u32 a0) { struct MysteryEventStruct *r5 = sub_8143D94(); r5->unk_0_0 = a0; - asm_comment("The switch logic does not match. Specifically, the \"bhi\" is replaced with a \"bls\" and the comparisons with 1 and 3 are swapped chronologically."); switch (a0) { - case 0: - r5->unk_1 = (Random() % 15) + 16; - break; - case 1: - break; - case 2: - break; - case 3: - r5->unk_1 = (Random() % 15) + 1; - break; + case 0: + break; + case 1: + case 2: + r5->unk_1 = (Random() % 15) + 16; + break; + case 3: + r5->unk_1 = (Random() % 15) + 1; + break; } } -#else -NAKED -void sub_8146C30(u32 a0) -{ - asm_unified("\tpush {r4,r5,lr}\n" - "\tadds r4, r0, 0\n" - "\tbl sub_8143D94\n" - "\tadds r5, r0, 0\n" - "\tmovs r0, 0x3\n" - "\tadds r1, r4, 0\n" - "\tands r1, r0\n" - "\tldrb r2, [r5]\n" - "\tmovs r0, 0x4\n" - "\tnegs r0, r0\n" - "\tands r0, r2\n" - "\torrs r0, r1\n" - "\tstrb r0, [r5]\n" - "\tcmp r4, 0x2\n" - "\tbhi _08146C56\n" - "\tcmp r4, 0x1\n" - "\tbcs _08146C5C\n" - "\tb _08146C80\n" - "_08146C56:\n" - "\tcmp r4, 0x3\n" - "\tbeq _08146C6E\n" - "\tb _08146C80\n" - "_08146C5C:\n" - "\tbl Random\n" - "\tlsls r0, 16\n" - "\tlsrs r0, 16\n" - "\tmovs r1, 0xF\n" - "\tbl __umodsi3\n" - "\tadds r0, 0x10\n" - "\tb _08146C7E\n" - "_08146C6E:\n" - "\tbl Random\n" - "\tlsls r0, 16\n" - "\tlsrs r0, 16\n" - "\tmovs r1, 0xF\n" - "\tbl __umodsi3\n" - "\tadds r0, 0x1\n" - "_08146C7E:\n" - "\tstrb r0, [r5, 0x1]\n" - "_08146C80:\n" - "\tpop {r4,r5}\n" - "\tpop {r0}\n" - "\tbx r0"); -} -#endif void sub_8146C88(void) { @@ -111,33 +59,33 @@ u16 sub_8146CE8(void) struct MysteryEventStruct *r4 = sub_8143D94(); u16 r5; - if (!sub_806E2BC() || !sub_8143E1C()) + if (!sub_806E2BC() || !ValidateReceivedWonderNews()) return 0; r5 = sub_8146E0C(r4); switch (r5) { - case 0: - break; - case 1: - *r6 = sub_8146D74(r4); - break; - case 2: - *r6 = sub_8146D74(r4); - break; - case 3: - break; - case 4: - *r6 = sub_8146D74(r4); - sub_8146DA0(r4); - break; - case 5: - *r6 = sub_8146D74(r4); - sub_8146D94(r4); - break; - case 6: - break; + case 0: + break; + case 1: + *r6 = sub_8146D74(r4); + break; + case 2: + *r6 = sub_8146D74(r4); + break; + case 3: + break; + case 4: + *r6 = sub_8146D74(r4); + sub_8146DA0(r4); + break; + case 5: + *r6 = sub_8146D74(r4); + sub_8146D94(r4); + break; + case 6: + break; } return r5; @@ -182,18 +130,18 @@ static u32 sub_8146E0C(struct MysteryEventStruct *a0) r0 = *a0; switch (r0.unk_0_0) { - case 0: - return 3; - case 1: - return 1; - case 2: - return 2; - case 3: - if ((u8)r0.unk_0_2 < 3) - return 4; - return 5; - default: - AGB_ASSERT_EX(0, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/menews_jisan.c", 383); - return 0; + case 0: + return 3; + case 1: + return 1; + case 2: + return 2; + case 3: + if ((u8)r0.unk_0_2 < 3) + return 4; + return 5; + default: + AGB_ASSERT_EX(0, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/menews_jisan.c", 383); + return 0; } } diff --git a/src/menu2.c b/src/menu2.c new file mode 100644 index 000000000..9a1846c7e --- /dev/null +++ b/src/menu2.c @@ -0,0 +1,851 @@ +#include "global.h" +#include "text.h" +#include "gpu_regs.h" +#include "task.h" +#include "wild_encounter.h" +#include "string_util.h" +#include "constants/species.h" + +static void Task_SmoothBlendLayers(u8 taskId); + +static const u8 gUnknown_845FD54[][5] = { + [SPECIES_BULBASAUR - 1] = {0x16, 0x1b, 0x30, 0x16, 0x29}, + [SPECIES_IVYSAUR - 1] = {0x14, 0x1b, 0x30, 0x15, 0x2a}, + [SPECIES_VENUSAUR - 1] = {0x1b, 0x20, 0x20, 0x1b, 0x33}, + [SPECIES_CHARMANDER - 1] = {0x14, 0x0f, 0x38, 0x13, 0x1e}, + [SPECIES_CHARMELEON - 1] = {0x0d, 0x11, 0x30, 0x0f, 0x22}, + [SPECIES_CHARIZARD - 1] = {0x1b, 0x07, 0x28, 0x1a, 0x19}, + [SPECIES_SQUIRTLE - 1] = {0x19, 0x13, 0x30, 0x1a, 0x22}, + [SPECIES_WARTORTLE - 1] = {0x16, 0x13, 0x30, 0x17, 0x21}, + [SPECIES_BLASTOISE - 1] = {0x12, 0x08, 0x28, 0x15, 0x19}, + [SPECIES_CATERPIE - 1] = {0x15, 0x14, 0x30, 0x13, 0x24}, + [SPECIES_METAPOD - 1] = {0x13, 0x1d, 0x30, 0x18, 0x2a}, + [SPECIES_BUTTERFREE - 1] = {0x12, 0x1b, 0x08, 0x12, 0x2a}, + [SPECIES_WEEDLE - 1] = {0x16, 0x1c, 0x30, 0x15, 0x2b}, + [SPECIES_KAKUNA - 1] = {0x19, 0x13, 0x30, 0x1a, 0x24}, + [SPECIES_BEEDRILL - 1] = {0x19, 0x16, 0x08, 0x19, 0x25}, + [SPECIES_PIDGEY - 1] = {0x15, 0x12, 0x30, 0x12, 0x1e}, + [SPECIES_PIDGEOTTO - 1] = {0x24, 0x0e, 0x30, 0x1f, 0x1e}, + [SPECIES_PIDGEOT - 1] = {0x0c, 0x13, 0x08, 0x0a, 0x23}, + [SPECIES_RATTATA - 1] = {0x17, 0x1e, 0x30, 0x18, 0x2d}, + [SPECIES_RATICATE - 1] = {0x12, 0x14, 0x30, 0x10, 0x26}, + [SPECIES_SPEAROW - 1] = {0x15, 0x14, 0x30, 0x15, 0x1f}, + [SPECIES_FEAROW - 1] = {0x0c, 0x27, 0x00, 0x0b, 0x3f}, + [SPECIES_EKANS - 1] = {0x11, 0x0f, 0x30, 0x14, 0x1d}, + [SPECIES_ARBOK - 1] = {0x1b, 0x01, 0x28, 0x1d, 0x10}, + [SPECIES_PIKACHU - 1] = {0x19, 0x13, 0x30, 0x1a, 0x1f}, + [SPECIES_RAICHU - 1] = {0x19, 0x14, 0x28, 0x1c, 0x22}, + [SPECIES_SANDSHREW - 1] = {0x17, 0x16, 0x30, 0x18, 0x25}, + [SPECIES_SANDSLASH - 1] = {0x11, 0x13, 0x28, 0x13, 0x22}, + [SPECIES_NIDORAN_F - 1] = {0x16, 0x15, 0x30, 0x18, 0x21}, + [SPECIES_NIDORINA - 1] = {0x1f, 0x17, 0x30, 0x1e, 0x28}, + [SPECIES_NIDOQUEEN - 1] = {0x10, 0x0b, 0x28, 0x13, 0x1c}, + [SPECIES_NIDORAN_M - 1] = {0x15, 0x22, 0x28, 0x15, 0x31}, + [SPECIES_NIDORINO - 1] = {0x13, 0x1e, 0x28, 0x1b, 0x2d}, + [SPECIES_NIDOKING - 1] = {0x12, 0x15, 0x28, 0x13, 0x27}, + [SPECIES_CLEFAIRY - 1] = {0x19, 0x14, 0x30, 0x1b, 0x24}, + [SPECIES_CLEFABLE - 1] = {0x1c, 0x12, 0x30, 0x1d, 0x21}, + [SPECIES_VULPIX - 1] = {0x10, 0x16, 0x30, 0x0e, 0x25}, + [SPECIES_NINETALES - 1] = {0x28, 0x10, 0x28, 0x27, 0x1e}, + [SPECIES_JIGGLYPUFF - 1] = {0x1d, 0x15, 0x30, 0x1e, 0x25}, + [SPECIES_WIGGLYTUFF - 1] = {0x1a, 0x12, 0x30, 0x1c, 0x22}, + [SPECIES_ZUBAT - 1] = {0x14, 0x1d, 0x08, 0x14, 0x29}, + [SPECIES_GOLBAT - 1] = {0x23, 0x1a, 0x00, 0x21, 0x2e}, + [SPECIES_ODDISH - 1] = {0x1d, 0x20, 0x28, 0x1d, 0x2b}, + [SPECIES_GLOOM - 1] = {0x1c, 0x18, 0x28, 0x1c, 0x27}, + [SPECIES_VILEPLUME - 1] = {0x1c, 0x1e, 0x28, 0x1d, 0x2a}, + [SPECIES_PARAS - 1] = {0x1d, 0x1a, 0x30, 0x1c, 0x27}, + [SPECIES_PARASECT - 1] = {0x1e, 0x1c, 0x28, 0x20, 0x2e}, + [SPECIES_VENONAT - 1] = {0x1b, 0x16, 0x10, 0x1a, 0x29}, + [SPECIES_VENOMOTH - 1] = {0x12, 0x19, 0x08, 0x16, 0x27}, + [SPECIES_DIGLETT - 1] = {0x1e, 0x16, 0x30, 0x1c, 0x23}, + [SPECIES_DUGTRIO - 1] = {0x1a, 0x11, 0x30, 0x1a, 0x1f}, + [SPECIES_MEOWTH - 1] = {0x1c, 0x16, 0x30, 0x1c, 0x23}, + [SPECIES_PERSIAN - 1] = {0x13, 0x13, 0x30, 0x13, 0x21}, + [SPECIES_PSYDUCK - 1] = {0x1c, 0x13, 0x30, 0x17, 0x29}, + [SPECIES_GOLDUCK - 1] = {0x17, 0x12, 0x28, 0x17, 0x22}, + [SPECIES_MANKEY - 1] = {0x1c, 0x15, 0x30, 0x1b, 0x23}, + [SPECIES_PRIMEAPE - 1] = {0x1e, 0x16, 0x30, 0x1a, 0x27}, + [SPECIES_GROWLITHE - 1] = {0x14, 0x17, 0x30, 0x14, 0x24}, + [SPECIES_ARCANINE - 1] = {0x0f, 0x09, 0x28, 0x0c, 0x19}, + [SPECIES_POLIWAG - 1] = {0x15, 0x14, 0x30, 0x13, 0x1f}, + [SPECIES_POLIWHIRL - 1] = {0x1f, 0x10, 0x30, 0x1e, 0x17}, + [SPECIES_POLIWRATH - 1] = {0x22, 0x0c, 0x30, 0x21, 0x18}, + [SPECIES_ABRA - 1] = {0x1f, 0x13, 0x30, 0x1f, 0x21}, + [SPECIES_KADABRA - 1] = {0x1b, 0x12, 0x30, 0x1c, 0x25}, + [SPECIES_ALAKAZAM - 1] = {0x1c, 0x11, 0x28, 0x1d, 0x26}, + [SPECIES_MACHOP - 1] = {0x1b, 0x11, 0x30, 0x1b, 0x1e}, + [SPECIES_MACHOKE - 1] = {0x1d, 0x11, 0x30, 0x1d, 0x1f}, + [SPECIES_MACHAMP - 1] = {0x1a, 0x0d, 0x28, 0x1c, 0x1b}, + [SPECIES_BELLSPROUT - 1] = {0x15, 0x0e, 0x30, 0x0e, 0x1c}, + [SPECIES_WEEPINBELL - 1] = {0x1a, 0x1c, 0x10, 0x15, 0x32}, + [SPECIES_VICTREEBEL - 1] = {0x1e, 0x0f, 0x30, 0x1c, 0x1b}, + [SPECIES_TENTACOOL - 1] = {0x1a, 0x15, 0x30, 0x1e, 0x26}, + [SPECIES_TENTACRUEL - 1] = {0x1b, 0x10, 0x28, 0x1c, 0x26}, + [SPECIES_GEODUDE - 1] = {0x1c, 0x20, 0x28, 0x1d, 0x2d}, + [SPECIES_GRAVELER - 1] = {0x1d, 0x19, 0x28, 0x1e, 0x26}, + [SPECIES_GOLEM - 1] = {0x19, 0x1b, 0x28, 0x1c, 0x27}, + [SPECIES_PONYTA - 1] = {0x0f, 0x11, 0x30, 0x0e, 0x23}, + [SPECIES_RAPIDASH - 1] = {0x2f, 0x0f, 0x28, 0x2b, 0x1e}, + [SPECIES_SLOWPOKE - 1] = {0x14, 0x1f, 0x28, 0x15, 0x2f}, + [SPECIES_SLOWBRO - 1] = {0x0e, 0x0d, 0x28, 0x0c, 0x1f}, + [SPECIES_MAGNEMITE - 1] = {0x20, 0x1b, 0x10, 0x1f, 0x29}, + [SPECIES_MAGNETON - 1] = {0x1f, 0x14, 0x08, 0x1f, 0x22}, + [SPECIES_FARFETCHD - 1] = {0x16, 0x14, 0x30, 0x16, 0x29}, + [SPECIES_DODUO - 1] = {0x11, 0x16, 0x30, 0x0d, 0x2c}, + [SPECIES_DODRIO - 1] = {0x1d, 0x04, 0x28, 0x0e, 0x07}, + [SPECIES_SEEL - 1] = {0x1b, 0x24, 0x20, 0x17, 0x35}, + [SPECIES_DEWGONG - 1] = {0x12, 0x0a, 0x30, 0x0e, 0x1a}, + [SPECIES_GRIMER - 1] = {0x1f, 0x10, 0x30, 0x1d, 0x25}, + [SPECIES_MUK - 1] = {0x17, 0x0f, 0x30, 0x19, 0x22}, + [SPECIES_SHELLDER - 1] = {0x1a, 0x18, 0x30, 0x17, 0x29}, + [SPECIES_CLOYSTER - 1] = {0x19, 0x1e, 0x28, 0x1d, 0x2c}, + [SPECIES_GASTLY - 1] = {0x1a, 0x1f, 0x08, 0x19, 0x30}, + [SPECIES_HAUNTER - 1] = {0x20, 0x14, 0x08, 0x1d, 0x26}, + [SPECIES_GENGAR - 1] = {0x1a, 0x16, 0x30, 0x19, 0x28}, + [SPECIES_ONIX - 1] = {0x1f, 0x24, 0x20, 0x28, 0x36}, + [SPECIES_DROWZEE - 1] = {0x1a, 0x0e, 0x30, 0x1a, 0x1e}, + [SPECIES_HYPNO - 1] = {0x1c, 0x12, 0x30, 0x19, 0x24}, + [SPECIES_KRABBY - 1] = {0x1d, 0x1d, 0x30, 0x1a, 0x2b}, + [SPECIES_KINGLER - 1] = {0x1e, 0x1f, 0x28, 0x1c, 0x30}, + [SPECIES_VOLTORB - 1] = {0x1c, 0x1b, 0x30, 0x1b, 0x2b}, + [SPECIES_ELECTRODE - 1] = {0x1c, 0x18, 0x30, 0x1d, 0x2e}, + [SPECIES_EXEGGCUTE - 1] = {0x21, 0x17, 0x30, 0x20, 0x24}, + [SPECIES_EXEGGUTOR - 1] = {0x1c, 0x17, 0x28, 0x1b, 0x25}, + [SPECIES_CUBONE - 1] = {0x1b, 0x12, 0x30, 0x1b, 0x22}, + [SPECIES_MAROWAK - 1] = {0x14, 0x0f, 0x30, 0x11, 0x23}, + [SPECIES_HITMONLEE - 1] = {0x2e, 0x11, 0x30, 0x28, 0x22}, + [SPECIES_HITMONCHAN - 1] = {0x22, 0x0e, 0x30, 0x1e, 0x1d}, + [SPECIES_LICKITUNG - 1] = {0x14, 0x11, 0x30, 0x14, 0x24}, + [SPECIES_KOFFING - 1] = {0x1e, 0x14, 0x10, 0x1d, 0x20}, + [SPECIES_WEEZING - 1] = {0x11, 0x0d, 0x10, 0x0f, 0x1c}, + [SPECIES_RHYHORN - 1] = {0x0e, 0x23, 0x20, 0x14, 0x33}, + [SPECIES_RHYDON - 1] = {0x0d, 0x12, 0x28, 0x17, 0x22}, + [SPECIES_CHANSEY - 1] = {0x1a, 0x0d, 0x30, 0x1a, 0x1a}, + [SPECIES_TANGELA - 1] = {0x1c, 0x18, 0x30, 0x1d, 0x29}, + [SPECIES_KANGASKHAN - 1] = {0x1b, 0x06, 0x28, 0x1c, 0x14}, + [SPECIES_HORSEA - 1] = {0x1c, 0x14, 0x30, 0x16, 0x23}, + [SPECIES_SEADRA - 1] = {0x10, 0x17, 0x30, 0x09, 0x2a}, + [SPECIES_GOLDEEN - 1] = {0x16, 0x23, 0x20, 0x15, 0x34}, + [SPECIES_SEAKING - 1] = {0x16, 0x0f, 0x30, 0x10, 0x18}, + [SPECIES_STARYU - 1] = {0x1c, 0x18, 0x30, 0x1a, 0x26}, + [SPECIES_STARMIE - 1] = {0x1d, 0x13, 0x30, 0x1b, 0x20}, + [SPECIES_MR_MIME - 1] = {0x24, 0x11, 0x30, 0x25, 0x1e}, + [SPECIES_SCYTHER - 1] = {0x10, 0x19, 0x28, 0x12, 0x27}, + [SPECIES_JYNX - 1] = {0x1b, 0x0f, 0x30, 0x19, 0x1c}, + [SPECIES_ELECTABUZZ - 1] = {0x14, 0x11, 0x30, 0x17, 0x20}, + [SPECIES_MAGMAR - 1] = {0x10, 0x0e, 0x30, 0x0b, 0x19}, + [SPECIES_PINSIR - 1] = {0x1d, 0x1c, 0x28, 0x20, 0x2b}, + [SPECIES_TAUROS - 1] = {0x11, 0x1d, 0x28, 0x13, 0x2e}, + [SPECIES_MAGIKARP - 1] = {0x16, 0x15, 0x30, 0x13, 0x23}, + [SPECIES_GYARADOS - 1] = {0x0b, 0x18, 0x28, 0x16, 0x29}, + [SPECIES_LAPRAS - 1] = {0x16, 0x08, 0x28, 0x15, 0x16}, + [SPECIES_DITTO - 1] = {0x24, 0x12, 0x30, 0x1f, 0x20}, + [SPECIES_EEVEE - 1] = {0x16, 0x16, 0x30, 0x16, 0x23}, + [SPECIES_VAPOREON - 1] = {0x18, 0x23, 0x28, 0x18, 0x30}, + [SPECIES_JOLTEON - 1] = {0x14, 0x1b, 0x30, 0x16, 0x28}, + [SPECIES_FLAREON - 1] = {0x16, 0x17, 0x30, 0x14, 0x25}, + [SPECIES_PORYGON - 1] = {0x18, 0x12, 0x30, 0x10, 0x23}, + [SPECIES_OMANYTE - 1] = {0x1d, 0x1d, 0x30, 0x1c, 0x2b}, + [SPECIES_OMASTAR - 1] = {0x16, 0x1a, 0x30, 0x19, 0x2d}, + [SPECIES_KABUTO - 1] = {0x1b, 0x16, 0x30, 0x1a, 0x27}, + [SPECIES_KABUTOPS - 1] = {0x15, 0x11, 0x30, 0x15, 0x1f}, + [SPECIES_AERODACTYL - 1] = {0x13, 0x1d, 0x00, 0x14, 0x30}, + [SPECIES_SNORLAX - 1] = {0x35, 0x09, 0x30, 0x2e, 0x14}, + [SPECIES_ARTICUNO - 1] = {0x18, 0x0b, 0x18, 0x17, 0x17}, + [SPECIES_ZAPDOS - 1] = {0x0e, 0x0e, 0x10, 0x04, 0x28}, + [SPECIES_MOLTRES - 1] = {0x0b, 0x2a, 0x08, 0x0b, 0x38}, + [SPECIES_DRATINI - 1] = {0x0d, 0x12, 0x30, 0x0b, 0x21}, + [SPECIES_DRAGONAIR - 1] = {0x18, 0x0e, 0x30, 0x13, 0x1c}, + [SPECIES_DRAGONITE - 1] = {0x1b, 0x07, 0x18, 0x19, 0x17}, + [SPECIES_MEWTWO - 1] = {0x2b, 0x09, 0x28, 0x2c, 0x18}, + [SPECIES_MEW - 1] = {0x19, 0x14, 0x10, 0x1f, 0x21}, + [SPECIES_CHIKORITA - 1] = {0x1b, 0x17, 0x30, 0x1b, 0x24}, + [SPECIES_BAYLEEF - 1] = {0x1d, 0x10, 0x30, 0x20, 0x1d}, + [SPECIES_MEGANIUM - 1] = {0x05, 0x0d, 0x28, 0x0d, 0x1b}, + [SPECIES_CYNDAQUIL - 1] = {0x11, 0x1b, 0x30, 0x14, 0x27}, + [SPECIES_QUILAVA - 1] = {0x25, 0x18, 0x30, 0x27, 0x26}, + [SPECIES_TYPHLOSION - 1] = {0x09, 0x10, 0x28, 0x10, 0x1c}, + [SPECIES_TOTODILE - 1] = {0x16, 0x10, 0x30, 0x19, 0x20}, + [SPECIES_CROCONAW - 1] = {0x16, 0x10, 0x30, 0x18, 0x21}, + [SPECIES_FERALIGATR - 1] = {0x0e, 0x0a, 0x28, 0x08, 0x1a}, + [SPECIES_SENTRET - 1] = {0x1e, 0x0a, 0x30, 0x1d, 0x15}, + [SPECIES_FURRET - 1] = {0x21, 0x0e, 0x30, 0x21, 0x19}, + [SPECIES_HOOTHOOT - 1] = {0x1d, 0x15, 0x30, 0x1c, 0x24}, + [SPECIES_NOCTOWL - 1] = {0x19, 0x0e, 0x30, 0x18, 0x1c}, + [SPECIES_LEDYBA - 1] = {0x1b, 0x15, 0x30, 0x1c, 0x24}, + [SPECIES_LEDIAN - 1] = {0x18, 0x12, 0x10, 0x1c, 0x21}, + [SPECIES_SPINARAK - 1] = {0x20, 0x20, 0x28, 0x20, 0x2d}, + [SPECIES_ARIADOS - 1] = {0x17, 0x23, 0x28, 0x15, 0x30}, + [SPECIES_CROBAT - 1] = {0x22, 0x1e, 0x08, 0x23, 0x2b}, + [SPECIES_CHINCHOU - 1] = {0x1f, 0x1d, 0x30, 0x1f, 0x29}, + [SPECIES_LANTURN - 1] = {0x10, 0x23, 0x28, 0x19, 0x33}, + [SPECIES_PICHU - 1] = {0x1e, 0x17, 0x30, 0x1e, 0x24}, + [SPECIES_CLEFFA - 1] = {0x1c, 0x18, 0x30, 0x1e, 0x26}, + [SPECIES_IGGLYBUFF - 1] = {0x1f, 0x19, 0x30, 0x1f, 0x24}, + [SPECIES_TOGEPI - 1] = {0x21, 0x15, 0x30, 0x1f, 0x20}, + [SPECIES_TOGETIC - 1] = {0x1b, 0x10, 0x30, 0x1c, 0x1c}, + [SPECIES_NATU - 1] = {0x1c, 0x17, 0x30, 0x15, 0x21}, + [SPECIES_XATU - 1] = {0x1b, 0x08, 0x30, 0x19, 0x14}, + [SPECIES_MAREEP - 1] = {0x16, 0x15, 0x30, 0x15, 0x24}, + [SPECIES_FLAAFFY - 1] = {0x19, 0x12, 0x30, 0x18, 0x21}, + [SPECIES_AMPHAROS - 1] = {0x0f, 0x0a, 0x30, 0x10, 0x1b}, + [SPECIES_BELLOSSOM - 1] = {0x1f, 0x13, 0x30, 0x1f, 0x20}, + [SPECIES_MARILL - 1] = {0x1d, 0x15, 0x30, 0x1d, 0x22}, + [SPECIES_AZUMARILL - 1] = {0x1a, 0x12, 0x30, 0x17, 0x1f}, + [SPECIES_SUDOWOODO - 1] = {0x20, 0x10, 0x30, 0x20, 0x1f}, + [SPECIES_POLITOED - 1] = {0x1d, 0x0f, 0x30, 0x1e, 0x20}, + [SPECIES_HOPPIP - 1] = {0x23, 0x25, 0x08, 0x25, 0x33}, + [SPECIES_SKIPLOOM - 1] = {0x1e, 0x18, 0x08, 0x1c, 0x27}, + [SPECIES_JUMPLUFF - 1] = {0x1d, 0x21, 0x08, 0x20, 0x2f}, + [SPECIES_AIPOM - 1] = {0x1e, 0x29, 0x18, 0x1e, 0x35}, + [SPECIES_SUNKERN - 1] = {0x1f, 0x20, 0x08, 0x24, 0x2e}, + [SPECIES_SUNFLORA - 1] = {0x1c, 0x0c, 0x30, 0x1b, 0x19}, + [SPECIES_YANMA - 1] = {0x1b, 0x28, 0x08, 0x16, 0x35}, + [SPECIES_WOOPER - 1] = {0x1d, 0x13, 0x30, 0x1f, 0x21}, + [SPECIES_QUAGSIRE - 1] = {0x15, 0x09, 0x30, 0x12, 0x18}, + [SPECIES_ESPEON - 1] = {0x11, 0x1b, 0x30, 0x11, 0x29}, + [SPECIES_UMBREON - 1] = {0x23, 0x15, 0x30, 0x23, 0x22}, + [SPECIES_MURKROW - 1] = {0x24, 0x13, 0x30, 0x20, 0x22}, + [SPECIES_SLOWKING - 1] = {0x1e, 0x13, 0x28, 0x1d, 0x25}, + [SPECIES_MISDREAVUS - 1] = {0x28, 0x21, 0x08, 0x26, 0x2e}, + [SPECIES_UNOWN - 1] = {0x20, 0x17, 0x08, 0x1f, 0x21}, + [SPECIES_WOBBUFFET - 1] = {0x1d, 0x09, 0x30, 0x1d, 0x1a}, + [SPECIES_GIRAFARIG - 1] = {0x0b, 0x0d, 0x28, 0x11, 0x1d}, + [SPECIES_PINECO - 1] = {0x1d, 0x12, 0x10, 0x19, 0x25}, + [SPECIES_FORRETRESS - 1] = {0x19, 0x17, 0x08, 0x1e, 0x26}, + [SPECIES_DUNSPARCE - 1] = {0x10, 0x1b, 0x30, 0x0c, 0x2d}, + [SPECIES_GLIGAR - 1] = {0x1e, 0x13, 0x08, 0x1d, 0x23}, + [SPECIES_STEELIX - 1] = {0x0c, 0x0d, 0x28, 0x0d, 0x1c}, + [SPECIES_SNUBBULL - 1] = {0x1b, 0x15, 0x30, 0x1a, 0x23}, + [SPECIES_GRANBULL - 1] = {0x1c, 0x09, 0x30, 0x19, 0x18}, + [SPECIES_QWILFISH - 1] = {0x1f, 0x26, 0x20, 0x1d, 0x33}, + [SPECIES_SCIZOR - 1] = {0x15, 0x0f, 0x10, 0x1a, 0x1a}, + [SPECIES_SHUCKLE - 1] = {0x25, 0x0a, 0x30, 0x24, 0x18}, + [SPECIES_HERACROSS - 1] = {0x18, 0x19, 0x28, 0x1a, 0x26}, + [SPECIES_SNEASEL - 1] = {0x1c, 0x13, 0x30, 0x1d, 0x24}, + [SPECIES_TEDDIURSA - 1] = {0x1e, 0x12, 0x30, 0x1b, 0x23}, + [SPECIES_URSARING - 1] = {0x1e, 0x04, 0x28, 0x1d, 0x14}, + [SPECIES_SLUGMA - 1] = {0x20, 0x18, 0x30, 0x20, 0x28}, + [SPECIES_MAGCARGO - 1] = {0x16, 0x11, 0x30, 0x17, 0x23}, + [SPECIES_SWINUB - 1] = {0x1c, 0x18, 0x30, 0x1b, 0x25}, + [SPECIES_PILOSWINE - 1] = {0x18, 0x23, 0x20, 0x18, 0x36}, + [SPECIES_CORSOLA - 1] = {0x19, 0x1d, 0x28, 0x19, 0x2b}, + [SPECIES_REMORAID - 1] = {0x15, 0x1f, 0x28, 0x13, 0x2b}, + [SPECIES_OCTILLERY - 1] = {0x1c, 0x11, 0x30, 0x1a, 0x20}, + [SPECIES_DELIBIRD - 1] = {0x1d, 0x11, 0x30, 0x1b, 0x1f}, + [SPECIES_MANTINE - 1] = {0x16, 0x1e, 0x28, 0x1f, 0x27}, + [SPECIES_SKARMORY - 1] = {0x1e, 0x00, 0x28, 0x13, 0x07}, + [SPECIES_HOUNDOUR - 1] = {0x25, 0x11, 0x30, 0x25, 0x1f}, + [SPECIES_HOUNDOOM - 1] = {0x0d, 0x13, 0x30, 0x0d, 0x24}, + [SPECIES_KINGDRA - 1] = {0x0e, 0x13, 0x28, 0x0a, 0x2c}, + [SPECIES_PHANPY - 1] = {0x1b, 0x11, 0x30, 0x19, 0x24}, + [SPECIES_DONPHAN - 1] = {0x11, 0x15, 0x30, 0x19, 0x2c}, + [SPECIES_PORYGON2 - 1] = {0x18, 0x11, 0x30, 0x11, 0x20}, + [SPECIES_STANTLER - 1] = {0x15, 0x15, 0x28, 0x17, 0x28}, + [SPECIES_SMEARGLE - 1] = {0x18, 0x10, 0x30, 0x1b, 0x25}, + [SPECIES_TYROGUE - 1] = {0x1e, 0x12, 0x30, 0x1f, 0x1f}, + [SPECIES_HITMONTOP - 1] = {0x1a, 0x39, 0x10, 0x1a, 0x2b}, + [SPECIES_SMOOCHUM - 1] = {0x20, 0x18, 0x30, 0x21, 0x26}, + [SPECIES_ELEKID - 1] = {0x1d, 0x14, 0x30, 0x1d, 0x23}, + [SPECIES_MAGBY - 1] = {0x1c, 0x15, 0x30, 0x1a, 0x24}, + [SPECIES_MILTANK - 1] = {0x18, 0x0e, 0x30, 0x18, 0x1e}, + [SPECIES_BLISSEY - 1] = {0x1d, 0x09, 0x30, 0x1d, 0x19}, + [SPECIES_RAIKOU - 1] = {0x29, 0x0c, 0x28, 0x27, 0x1e}, + [SPECIES_ENTEI - 1] = {0x08, 0x09, 0x28, 0x0b, 0x18}, + [SPECIES_SUICUNE - 1] = {0x23, 0x1d, 0x28, 0x26, 0x2c}, + [SPECIES_LARVITAR - 1] = {0x1c, 0x18, 0x30, 0x1a, 0x24}, + [SPECIES_PUPITAR - 1] = {0x1b, 0x19, 0x30, 0x1b, 0x28}, + [SPECIES_TYRANITAR - 1] = {0x06, 0x0b, 0x28, 0x0d, 0x19}, + [SPECIES_LUGIA - 1] = {0x08, 0x2a, 0x08, 0x14, 0x34}, + [SPECIES_HO_OH - 1] = {0x0d, 0x25, 0x08, 0x0e, 0x34}, + [SPECIES_CELEBI - 1] = {0x15, 0x21, 0x08, 0x1a, 0x2b}, + [SPECIES_OLD_UNOWN_B - 1] = {0x1f, 0x12, 0x08, 0x1e, 0x1c}, + [SPECIES_OLD_UNOWN_C - 1] = {0x20, 0x17, 0x08, 0x1f, 0x21}, + [SPECIES_OLD_UNOWN_D - 1] = {0x1c, 0x19, 0x08, 0x1b, 0x23}, + [SPECIES_OLD_UNOWN_E - 1] = {0x21, 0x19, 0x08, 0x20, 0x23}, + [SPECIES_OLD_UNOWN_F - 1] = {0x1b, 0x13, 0x08, 0x1a, 0x1d}, + [SPECIES_OLD_UNOWN_G - 1] = {0x20, 0x16, 0x08, 0x1f, 0x21}, + [SPECIES_OLD_UNOWN_H - 1] = {0x20, 0x19, 0x08, 0x1f, 0x23}, + [SPECIES_OLD_UNOWN_I - 1] = {0x20, 0x19, 0x08, 0x1f, 0x23}, + [SPECIES_OLD_UNOWN_J - 1] = {0x20, 0x16, 0x08, 0x1f, 0x20}, + [SPECIES_OLD_UNOWN_K - 1] = {0x1d, 0x1a, 0x08, 0x1c, 0x24}, + [SPECIES_OLD_UNOWN_L - 1] = {0x20, 0x16, 0x08, 0x1f, 0x1f}, + [SPECIES_OLD_UNOWN_M - 1] = {0x20, 0x1c, 0x08, 0x1f, 0x26}, + [SPECIES_OLD_UNOWN_N - 1] = {0x20, 0x1a, 0x08, 0x1f, 0x23}, + [SPECIES_OLD_UNOWN_O - 1] = {0x20, 0x1a, 0x08, 0x1f, 0x23}, + [SPECIES_OLD_UNOWN_P - 1] = {0x20, 0x16, 0x08, 0x1f, 0x20}, + [SPECIES_OLD_UNOWN_Q - 1] = {0x1d, 0x16, 0x08, 0x1c, 0x20}, + [SPECIES_OLD_UNOWN_R - 1] = {0x20, 0x15, 0x08, 0x1f, 0x1f}, + [SPECIES_OLD_UNOWN_S - 1] = {0x20, 0x19, 0x08, 0x1f, 0x23}, + [SPECIES_OLD_UNOWN_T - 1] = {0x20, 0x1e, 0x08, 0x1f, 0x28}, + [SPECIES_OLD_UNOWN_U - 1] = {0x20, 0x17, 0x08, 0x1f, 0x21}, + [SPECIES_OLD_UNOWN_V - 1] = {0x1e, 0x1e, 0x08, 0x1d, 0x28}, + [SPECIES_OLD_UNOWN_W - 1] = {0x20, 0x1d, 0x08, 0x1f, 0x27}, + [SPECIES_OLD_UNOWN_X - 1] = {0x20, 0x19, 0x08, 0x1f, 0x23}, + [SPECIES_OLD_UNOWN_Y - 1] = {0x20, 0x15, 0x08, 0x1f, 0x1f}, + [SPECIES_OLD_UNOWN_Z - 1] = {0x20, 0x19, 0x08, 0x1f, 0x23}, + [SPECIES_TREECKO - 1] = {0x1a, 0x0f, 0x30, 0x19, 0x20}, + [SPECIES_GROVYLE - 1] = {0x0d, 0x05, 0x10, 0x05, 0x13}, + [SPECIES_SCEPTILE - 1] = {0x10, 0x04, 0x28, 0x0c, 0x12}, + [SPECIES_TORCHIC - 1] = {0x17, 0x18, 0x30, 0x15, 0x25}, + [SPECIES_COMBUSKEN - 1] = {0x20, 0x12, 0x28, 0x1e, 0x20}, + [SPECIES_BLAZIKEN - 1] = {0x1a, 0x07, 0x28, 0x1d, 0x13}, + [SPECIES_MUDKIP - 1] = {0x1b, 0x1d, 0x28, 0x19, 0x2c}, + [SPECIES_MARSHTOMP - 1] = {0x1d, 0x11, 0x30, 0x1c, 0x20}, + [SPECIES_SWAMPERT - 1] = {0x1b, 0x11, 0x28, 0x1b, 0x23}, + [SPECIES_POOCHYENA - 1] = {0x14, 0x12, 0x30, 0x0f, 0x20}, + [SPECIES_MIGHTYENA - 1] = {0x09, 0x0d, 0x28, 0x09, 0x1c}, + [SPECIES_ZIGZAGOON - 1] = {0x0b, 0x1a, 0x30, 0x09, 0x2b}, + [SPECIES_LINOONE - 1] = {0x0d, 0x28, 0x18, 0x0b, 0x37}, + [SPECIES_WURMPLE - 1] = {0x21, 0x17, 0x30, 0x1f, 0x26}, + [SPECIES_SILCOON - 1] = {0x13, 0x1c, 0x30, 0x11, 0x2a}, + [SPECIES_BEAUTIFLY - 1] = {0x0f, 0x1b, 0x08, 0x0e, 0x28}, + [SPECIES_CASCOON - 1] = {0x14, 0x1d, 0x30, 0x11, 0x2c}, + [SPECIES_DUSTOX - 1] = {0x14, 0x19, 0x08, 0x16, 0x26}, + [SPECIES_LOTAD - 1] = {0x19, 0x25, 0x28, 0x17, 0x32}, + [SPECIES_LOMBRE - 1] = {0x22, 0x10, 0x30, 0x29, 0x1d}, + [SPECIES_LUDICOLO - 1] = {0x1c, 0x0f, 0x28, 0x1b, 0x24}, + [SPECIES_SEEDOT - 1] = {0x1b, 0x17, 0x30, 0x18, 0x28}, + [SPECIES_NUZLEAF - 1] = {0x20, 0x0d, 0x30, 0x1a, 0x1d}, + [SPECIES_SHIFTRY - 1] = {0x32, 0x11, 0x28, 0x2e, 0x23}, + [SPECIES_NINCADA - 1] = {0x18, 0x1a, 0x30, 0x17, 0x28}, + [SPECIES_NINJASK - 1] = {0x17, 0x21, 0x00, 0x17, 0x2f}, + [SPECIES_SHEDINJA - 1] = {0x16, 0x19, 0x08, 0x18, 0x2a}, + [SPECIES_TAILLOW - 1] = {0x17, 0x10, 0x30, 0x14, 0x1e}, + [SPECIES_SWELLOW - 1] = {0x0c, 0x0a, 0x28, 0x05, 0x16}, + [SPECIES_SHROOMISH - 1] = {0x1f, 0x16, 0x30, 0x1d, 0x23}, + [SPECIES_BRELOOM - 1] = {0x25, 0x0c, 0x30, 0x23, 0x19}, + [SPECIES_SPINDA - 1] = {0x21, 0x16, 0x30, 0x1f, 0x27}, + [SPECIES_WINGULL - 1] = {0x1a, 0x16, 0x10, 0x15, 0x26}, + [SPECIES_PELIPPER - 1] = {0x1d, 0x0a, 0x10, 0x09, 0x1b}, + [SPECIES_SURSKIT - 1] = {0x1d, 0x16, 0x30, 0x1c, 0x25}, + [SPECIES_MASQUERAIN - 1] = {0x1a, 0x21, 0x08, 0x14, 0x30}, + [SPECIES_WAILMER - 1] = {0x17, 0x17, 0x30, 0x16, 0x28}, + [SPECIES_WAILORD - 1] = {0x17, 0x03, 0x30, 0x09, 0x13}, + [SPECIES_SKITTY - 1] = {0x24, 0x1a, 0x30, 0x22, 0x2a}, + [SPECIES_DELCATTY - 1] = {0x1e, 0x12, 0x30, 0x1c, 0x21}, + [SPECIES_KECLEON - 1] = {0x19, 0x10, 0x30, 0x13, 0x1e}, + [SPECIES_BALTOY - 1] = {0x1d, 0x15, 0x30, 0x1b, 0x22}, + [SPECIES_CLAYDOL - 1] = {0x1e, 0x0d, 0x28, 0x1d, 0x24}, + [SPECIES_NOSEPASS - 1] = {0x1f, 0x10, 0x30, 0x15, 0x23}, + [SPECIES_TORKOAL - 1] = {0x0e, 0x19, 0x28, 0x0a, 0x27}, + [SPECIES_SABLEYE - 1] = {0x1e, 0x16, 0x30, 0x1d, 0x27}, + [SPECIES_BARBOACH - 1] = {0x17, 0x12, 0x30, 0x15, 0x1e}, + [SPECIES_WHISCASH - 1] = {0x18, 0x20, 0x28, 0x17, 0x31}, + [SPECIES_LUVDISC - 1] = {0x19, 0x0f, 0x30, 0x13, 0x1c}, + [SPECIES_CORPHISH - 1] = {0x1f, 0x14, 0x30, 0x1d, 0x23}, + [SPECIES_CRAWDAUNT - 1] = {0x14, 0x0c, 0x28, 0x18, 0x23}, + [SPECIES_FEEBAS - 1] = {0x18, 0x1e, 0x28, 0x16, 0x2f}, + [SPECIES_MILOTIC - 1] = {0x20, 0x0c, 0x28, 0x1f, 0x1d}, + [SPECIES_CARVANHA - 1] = {0x16, 0x19, 0x30, 0x13, 0x22}, + [SPECIES_SHARPEDO - 1] = {0x19, 0x0c, 0x28, 0x17, 0x27}, + [SPECIES_TRAPINCH - 1] = {0x29, 0x13, 0x30, 0x17, 0x18}, + [SPECIES_VIBRAVA - 1] = {0x10, 0x27, 0x20, 0x0e, 0x34}, + [SPECIES_FLYGON - 1] = {0x22, 0x07, 0x10, 0x21, 0x13}, + [SPECIES_MAKUHITA - 1] = {0x22, 0x13, 0x30, 0x1c, 0x23}, + [SPECIES_HARIYAMA - 1] = {0x24, 0x0f, 0x28, 0x26, 0x1c}, + [SPECIES_ELECTRIKE - 1] = {0x11, 0x18, 0x30, 0x14, 0x27}, + [SPECIES_MANECTRIC - 1] = {0x2f, 0x18, 0x28, 0x2e, 0x29}, + [SPECIES_NUMEL - 1] = {0x10, 0x1a, 0x30, 0x0d, 0x2a}, + [SPECIES_CAMERUPT - 1] = {0x0d, 0x22, 0x28, 0x0e, 0x36}, + [SPECIES_SPHEAL - 1] = {0x1e, 0x0f, 0x30, 0x18, 0x1f}, + [SPECIES_SEALEO - 1] = {0x1c, 0x09, 0x30, 0x1a, 0x18}, + [SPECIES_WALREIN - 1] = {0x19, 0x01, 0x28, 0x10, 0x16}, + [SPECIES_CACNEA - 1] = {0x1f, 0x17, 0x30, 0x1d, 0x29}, + [SPECIES_CACTURNE - 1] = {0x1d, 0x0e, 0x28, 0x1d, 0x1b}, + [SPECIES_SNORUNT - 1] = {0x1e, 0x16, 0x30, 0x1e, 0x26}, + [SPECIES_GLALIE - 1] = {0x1a, 0x1c, 0x08, 0x1a, 0x31}, + [SPECIES_LUNATONE - 1] = {0x1c, 0x16, 0x08, 0x19, 0x2c}, + [SPECIES_SOLROCK - 1] = {0x18, 0x18, 0x10, 0x17, 0x31}, + [SPECIES_AZURILL - 1] = {0x1b, 0x10, 0x30, 0x18, 0x1f}, + [SPECIES_SPOINK - 1] = {0x21, 0x14, 0x30, 0x1b, 0x28}, + [SPECIES_GRUMPIG - 1] = {0x14, 0x10, 0x30, 0x15, 0x20}, + [SPECIES_PLUSLE - 1] = {0x1c, 0x16, 0x08, 0x1d, 0x25}, + [SPECIES_MINUN - 1] = {0x21, 0x16, 0x08, 0x1f, 0x26}, + [SPECIES_MAWILE - 1] = {0x2d, 0x14, 0x30, 0x2f, 0x24}, + [SPECIES_MEDITITE - 1] = {0x1f, 0x17, 0x30, 0x1e, 0x25}, + [SPECIES_MEDICHAM - 1] = {0x21, 0x0f, 0x28, 0x1e, 0x1d}, + [SPECIES_SWABLU - 1] = {0x1b, 0x16, 0x10, 0x17, 0x23}, + [SPECIES_ALTARIA - 1] = {0x1d, 0x0b, 0x10, 0x1a, 0x1a}, + [SPECIES_WYNAUT - 1] = {0x1a, 0x15, 0x30, 0x1b, 0x26}, + [SPECIES_DUSKULL - 1] = {0x10, 0x18, 0x08, 0x14, 0x2e}, + [SPECIES_DUSCLOPS - 1] = {0x1c, 0x0f, 0x30, 0x1a, 0x28}, + [SPECIES_ROSELIA - 1] = {0x1e, 0x11, 0x30, 0x1d, 0x20}, + [SPECIES_SLAKOTH - 1] = {0x19, 0x1e, 0x30, 0x18, 0x2f}, + [SPECIES_VIGOROTH - 1] = {0x10, 0x12, 0x28, 0x14, 0x24}, + [SPECIES_SLAKING - 1] = {0x37, 0x0f, 0x30, 0x29, 0x21}, + [SPECIES_GULPIN - 1] = {0x1b, 0x18, 0x30, 0x17, 0x26}, + [SPECIES_SWALOT - 1] = {0x1f, 0x06, 0x30, 0x15, 0x13}, + [SPECIES_TROPIUS - 1] = {0x18, 0x0a, 0x28, 0x20, 0x18}, + [SPECIES_WHISMUR - 1] = {0x1f, 0x19, 0x30, 0x1d, 0x29}, + [SPECIES_LOUDRED - 1] = {0x1c, 0x12, 0x28, 0x22, 0x27}, + [SPECIES_EXPLOUD - 1] = {0x10, 0x10, 0x28, 0x1a, 0x2a}, + [SPECIES_CLAMPERL - 1] = {0x20, 0x1a, 0x30, 0x1e, 0x26}, + [SPECIES_HUNTAIL - 1] = {0x13, 0x1e, 0x28, 0x15, 0x33}, + [SPECIES_GOREBYSS - 1] = {0x0d, 0x1f, 0x28, 0x03, 0x32}, + [SPECIES_ABSOL - 1] = {0x2a, 0x11, 0x28, 0x2a, 0x22}, + [SPECIES_SHUPPET - 1] = {0x16, 0x19, 0x08, 0x17, 0x27}, + [SPECIES_BANETTE - 1] = {0x1c, 0x14, 0x08, 0x1b, 0x23}, + [SPECIES_SEVIPER - 1] = {0x0e, 0x0d, 0x30, 0x0b, 0x1e}, + [SPECIES_ZANGOOSE - 1] = {0x18, 0x0c, 0x28, 0x15, 0x1a}, + [SPECIES_RELICANTH - 1] = {0x0c, 0x1f, 0x30, 0x09, 0x2d}, + [SPECIES_ARON - 1] = {0x18, 0x1c, 0x30, 0x1a, 0x2c}, + [SPECIES_LAIRON - 1] = {0x0b, 0x21, 0x30, 0x12, 0x2f}, + [SPECIES_AGGRON - 1] = {0x10, 0x0b, 0x28, 0x16, 0x1b}, + [SPECIES_CASTFORM - 1] = {0x1d, 0x18, 0x08, 0x1b, 0x26}, + [SPECIES_VOLBEAT - 1] = {0x25, 0x15, 0x08, 0x21, 0x25}, + [SPECIES_ILLUMISE - 1] = {0x20, 0x12, 0x08, 0x1f, 0x20}, + [SPECIES_LILEEP - 1] = {0x1e, 0x11, 0x30, 0x1f, 0x1e}, + [SPECIES_CRADILY - 1] = {0x12, 0x16, 0x28, 0x15, 0x28}, + [SPECIES_ANORITH - 1] = {0x1c, 0x1e, 0x30, 0x1b, 0x2b}, + [SPECIES_ARMALDO - 1] = {0x15, 0x05, 0x28, 0x14, 0x13}, + [SPECIES_RALTS - 1] = {0x1f, 0x17, 0x30, 0x20, 0x23}, + [SPECIES_KIRLIA - 1] = {0x1c, 0x12, 0x30, 0x1f, 0x1e}, + [SPECIES_GARDEVOIR - 1] = {0x35, 0x07, 0x28, 0x32, 0x14}, + [SPECIES_BAGON - 1] = {0x17, 0x13, 0x30, 0x16, 0x26}, + [SPECIES_SHELGON - 1] = {0x19, 0x1b, 0x30, 0x19, 0x2c}, + [SPECIES_SALAMENCE - 1] = {0x09, 0x11, 0x30, 0x0a, 0x21}, + [SPECIES_BELDUM - 1] = {0x16, 0x19, 0x08, 0x18, 0x23}, + [SPECIES_METANG - 1] = {0x22, 0x0f, 0x10, 0x1f, 0x21}, + [SPECIES_METAGROSS - 1] = {0x24, 0x1b, 0x28, 0x22, 0x2b}, + [SPECIES_REGIROCK - 1] = {0x16, 0x07, 0x28, 0x14, 0x12}, + [SPECIES_REGICE - 1] = {0x19, 0x0c, 0x28, 0x17, 0x19}, + [SPECIES_REGISTEEL - 1] = {0x19, 0x0d, 0x28, 0x19, 0x19}, + [SPECIES_KYOGRE - 1] = {0x0e, 0x19, 0x28, 0x0b, 0x26}, + [SPECIES_GROUDON - 1] = {0x04, 0x0b, 0x28, 0x0a, 0x19}, + [SPECIES_RAYQUAZA - 1] = {0x0c, 0x0e, 0x10, 0x0e, 0x1f}, + [SPECIES_LATIAS - 1] = {0x1e, 0x0c, 0x10, 0x23, 0x19}, + [SPECIES_LATIOS - 1] = {0x05, 0x0e, 0x10, 0x05, 0x1d}, + [SPECIES_JIRACHI - 1] = {0x1c, 0x15, 0x08, 0x1e, 0x22}, + [SPECIES_DEOXYS - 1] = {0x1b, 0x08, 0x28, 0x1c, 0x16}, + [SPECIES_CHIMECHO - 1] = {0x1d, 0x0c, 0x08, 0x1c, 0x1a}, + [SPECIES_OLD_UNOWN_EMARK - 1] = {0x20, 0x21, 0x08, 0x20, 0x2b}, + [SPECIES_OLD_UNOWN_QMARK - 1] = {0x20, 0x23, 0x08, 0x20, 0x2d} +}; + +void AddTextPrinterParameterized3(u8 windowId, u8 fontId, u8 x, u8 y, const struct TextColor * color, s8 speed, const u8 * str) +{ + struct TextPrinterTemplate printer; + + printer.currentChar = str; + printer.windowId = windowId; + printer.fontId = fontId; + printer.x = x; + printer.y = y; + printer.currentX = printer.x; + printer.currentY = printer.y; + printer.letterSpacing = GetFontAttribute(fontId, 2); + printer.lineSpacing = GetFontAttribute(fontId, 3); + printer.unk = 0; + printer.fgColor = color->bgColor; + printer.bgColor = color->fgColor; + printer.shadowColor = color->shadowColor; + AddTextPrinter(&printer, speed, NULL); +} + +void AddTextPrinterParameterized4(u8 windowId, u8 fontId, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, const struct TextColor *color, s8 speed, const u8 *str) +{ + struct TextPrinterTemplate printer; + + printer.currentChar = str; + printer.windowId = windowId; + printer.fontId = fontId; + printer.x = x; + printer.y = y; + printer.currentX = printer.x; + printer.currentY = printer.y; + printer.letterSpacing = letterSpacing; + printer.lineSpacing = lineSpacing; + printer.unk = 0; + printer.fgColor = color->bgColor; + printer.bgColor = color->fgColor; + printer.shadowColor = color->shadowColor; + AddTextPrinter(&printer, speed, NULL); +} + +void AddTextPrinterParameterized5(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16), u8 letterSpacing, u8 lineSpacing) +{ + struct TextPrinterTemplate printer; + + printer.currentChar = str; + printer.windowId = windowId; + printer.fontId = fontId; + printer.x = x; + printer.y = y; + printer.currentX = x; + printer.currentY = y; + printer.letterSpacing = letterSpacing; + printer.lineSpacing = lineSpacing; + printer.unk = 0; + printer.fgColor = GetFontAttribute(fontId, 5); + printer.bgColor = GetFontAttribute(fontId, 6); + printer.shadowColor = GetFontAttribute(fontId, 7); + AddTextPrinter(&printer, speed, callback); +} + +void sub_812E6DC(u8 windowId, const u8 * src, u16 x, u16 y) +{ + s32 i; + + for (i = 0; gSaveBlock2Ptr->playerName[i] != EOS; i++) + ; + + StringExpandPlaceholders(gStringVar4, src); + if (i != 5) + { + AddTextPrinterParameterized(windowId, 2, gStringVar4, x, y, 0xFF, NULL); + } + else + { + AddTextPrinterParameterized5(windowId, 2, gStringVar4, x, y, 0xFF, NULL, 0, 0); + } +} + +// Yeah, no, I'm not bothering with this +NAKED +void sub_819A080(void * a0, void * a1, u16 a2, u16 a3, u16 a4, u16 a5, u16 a6, u16 a7) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tmov r7, r10\n" + "\tmov r6, r9\n" + "\tmov r5, r8\n" + "\tpush {r5-r7}\n" + "\tsub sp, 0x28\n" + "\tstr r0, [sp]\n" + "\tstr r1, [sp, 0x4]\n" + "\tldr r0, [sp, 0x48]\n" + "\tldr r4, [sp, 0x4C]\n" + "\tldr r1, [sp, 0x50]\n" + "\tldr r5, [sp, 0x54]\n" + "\tlsls r2, 16\n" + "\tlsrs r2, 16\n" + "\tstr r2, [sp, 0x8]\n" + "\tlsls r3, 16\n" + "\tlsrs r3, 16\n" + "\tlsls r0, 16\n" + "\tlsrs r0, 16\n" + "\tstr r0, [sp, 0xC]\n" + "\tlsls r4, 16\n" + "\tlsrs r4, 16\n" + "\tlsls r1, 16\n" + "\tlsrs r1, 16\n" + "\tlsls r5, 16\n" + "\tlsrs r5, 16\n" + "\tldr r2, [sp, 0x4]\n" + "\tldrh r0, [r2, 0x4]\n" + "\tldr r2, [sp, 0xC]\n" + "\tsubs r0, r2\n" + "\tldr r2, [sp, 0x8]\n" + "\tadds r2, r1, r2\n" + "\tstr r2, [sp, 0x10]\n" + "\tcmp r0, r1\n" + "\tbge _0812E7B4\n" + "\tldr r1, [sp, 0x8]\n" + "\tadds r0, r1\n" + "\tstr r0, [sp, 0x10]\n" + "_0812E7B4:\n" + "\tldr r2, [sp, 0x4]\n" + "\tldrh r1, [r2, 0x6]\n" + "\tsubs r0, r1, r4\n" + "\tcmp r0, r5\n" + "\tbge _0812E7C6\n" + "\tadds r0, r3, r1\n" + "\tsubs r0, r4\n" + "\tstr r0, [sp, 0x14]\n" + "\tb _0812E7CA\n" + "_0812E7C6:\n" + "\tadds r5, r3, r5\n" + "\tstr r5, [sp, 0x14]\n" + "_0812E7CA:\n" + "\tldr r0, [sp]\n" + "\tldrh r1, [r0, 0x4]\n" + "\tmovs r2, 0x7\n" + "\tadds r0, r1, 0\n" + "\tands r0, r2\n" + "\tadds r1, r0\n" + "\tasrs r1, 3\n" + "\tstr r1, [sp, 0x18]\n" + "\tldr r0, [sp, 0x4]\n" + "\tldrh r1, [r0, 0x4]\n" + "\tadds r0, r1, 0\n" + "\tands r0, r2\n" + "\tadds r1, r0\n" + "\tasrs r1, 3\n" + "\tstr r1, [sp, 0x1C]\n" + "\tmov r12, r3\n" + "\tmov r8, r4\n" + "\tldr r1, [sp, 0x14]\n" + "\tcmp r12, r1\n" + "\tblt _0812E7F4\n" + "\tb _0812E932\n" + "_0812E7F4:\n" + "\tldr r5, [sp, 0x8]\n" + "\tldr r6, [sp, 0xC]\n" + "\tmov r2, r12\n" + "\tadds r2, 0x1\n" + "\tstr r2, [sp, 0x20]\n" + "\tmov r0, r8\n" + "\tadds r0, 0x1\n" + "\tstr r0, [sp, 0x24]\n" + "\tldr r1, [sp, 0x10]\n" + "\tcmp r5, r1\n" + "\tblt _0812E80C\n" + "\tb _0812E922\n" + "_0812E80C:\n" + "\tmovs r7, 0x1\n" + "\tmovs r2, 0xF0\n" + "\tmov r10, r2\n" + "\tmovs r0, 0xF\n" + "\tmov r9, r0\n" + "_0812E816:\n" + "\tasrs r0, r5, 1\n" + "\tmovs r1, 0x3\n" + "\tands r0, r1\n" + "\tldr r2, [sp]\n" + "\tldr r1, [r2]\n" + "\tadds r1, r0\n" + "\tasrs r0, r5, 3\n" + "\tlsls r0, 5\n" + "\tadds r1, r0\n" + "\tmov r2, r12\n" + "\tasrs r0, r2, 3\n" + "\tldr r2, [sp, 0x18]\n" + "\tmuls r0, r2\n" + "\tlsls r0, 5\n" + "\tadds r1, r0\n" + "\tmov r2, r12\n" + "\tlsls r0, r2, 29\n" + "\tlsrs r0, 27\n" + "\tadds r3, r1, r0\n" + "\tasrs r0, r6, 1\n" + "\tmovs r1, 0x3\n" + "\tands r0, r1\n" + "\tldr r2, [sp, 0x4]\n" + "\tldr r1, [r2]\n" + "\tadds r1, r0\n" + "\tasrs r0, r6, 3\n" + "\tlsls r0, 5\n" + "\tadds r1, r0\n" + "\tmov r2, r8\n" + "\tasrs r0, r2, 3\n" + "\tldr r2, [sp, 0x1C]\n" + "\tmuls r0, r2\n" + "\tlsls r0, 5\n" + "\tadds r1, r0\n" + "\tmov r2, r8\n" + "\tlsls r0, r2, 29\n" + "\tlsrs r0, 27\n" + "\tadds r4, r1, r0\n" + "\tadds r0, r4, 0\n" + "\tands r0, r7\n" + "\tcmp r0, 0\n" + "\tbeq _0812E8C2\n" + "\tsubs r4, 0x1\n" + "\tadds r0, r6, 0\n" + "\tands r0, r7\n" + "\tcmp r0, 0\n" + "\tbeq _0812E89A\n" + "\tldrh r0, [r4]\n" + "\tldr r2, _0812E88C @ =0x00000fff\n" + "\tands r2, r0\n" + "\tadds r0, r5, 0\n" + "\tands r0, r7\n" + "\tcmp r0, 0\n" + "\tbeq _0812E890\n" + "\tldrb r1, [r3]\n" + "\tmov r0, r10\n" + "\tands r0, r1\n" + "\tlsls r0, 8\n" + "\tb _0812E912\n" + "\t.align 2, 0\n" + "_0812E88C: .4byte 0x00000fff\n" + "_0812E890:\n" + "\tldrb r1, [r3]\n" + "\tmov r0, r9\n" + "\tands r0, r1\n" + "\tlsls r0, 12\n" + "\tb _0812E912\n" + "_0812E89A:\n" + "\tldrh r0, [r4]\n" + "\tldr r2, _0812E8B4 @ =0x0000f0ff\n" + "\tands r2, r0\n" + "\tadds r0, r5, 0\n" + "\tands r0, r7\n" + "\tcmp r0, 0\n" + "\tbeq _0812E8B8\n" + "\tldrb r1, [r3]\n" + "\tmov r0, r10\n" + "\tands r0, r1\n" + "\tlsls r0, 4\n" + "\tb _0812E912\n" + "\t.align 2, 0\n" + "_0812E8B4: .4byte 0x0000f0ff\n" + "_0812E8B8:\n" + "\tldrb r1, [r3]\n" + "\tmov r0, r9\n" + "\tands r0, r1\n" + "\tlsls r0, 8\n" + "\tb _0812E912\n" + "_0812E8C2:\n" + "\tadds r0, r6, 0\n" + "\tands r0, r7\n" + "\tcmp r0, 0\n" + "\tbeq _0812E8EE\n" + "\tldrh r0, [r4]\n" + "\tldr r2, _0812E8E0 @ =0x0000ff0f\n" + "\tands r2, r0\n" + "\tadds r0, r5, 0\n" + "\tands r0, r7\n" + "\tcmp r0, 0\n" + "\tbeq _0812E8E4\n" + "\tldrb r1, [r3]\n" + "\tmov r0, r10\n" + "\tb _0812E910\n" + "\t.align 2, 0\n" + "_0812E8E0: .4byte 0x0000ff0f\n" + "_0812E8E4:\n" + "\tldrb r1, [r3]\n" + "\tmov r0, r9\n" + "\tands r0, r1\n" + "\tlsls r0, 4\n" + "\tb _0812E912\n" + "_0812E8EE:\n" + "\tldrh r0, [r4]\n" + "\tldr r2, _0812E908 @ =0x0000fff0\n" + "\tands r2, r0\n" + "\tadds r0, r5, 0\n" + "\tands r0, r7\n" + "\tcmp r0, 0\n" + "\tbeq _0812E90C\n" + "\tldrb r1, [r3]\n" + "\tmov r0, r10\n" + "\tands r0, r1\n" + "\tlsrs r0, 4\n" + "\tb _0812E912\n" + "\t.align 2, 0\n" + "_0812E908: .4byte 0x0000fff0\n" + "_0812E90C:\n" + "\tldrb r1, [r3]\n" + "\tmov r0, r9\n" + "_0812E910:\n" + "\tands r0, r1\n" + "_0812E912:\n" + "\torrs r2, r0\n" + "\tstrh r2, [r4]\n" + "\tadds r5, 0x1\n" + "\tadds r6, 0x1\n" + "\tldr r0, [sp, 0x10]\n" + "\tcmp r5, r0\n" + "\tbge _0812E922\n" + "\tb _0812E816\n" + "_0812E922:\n" + "\tldr r1, [sp, 0x20]\n" + "\tmov r12, r1\n" + "\tldr r2, [sp, 0x24]\n" + "\tmov r8, r2\n" + "\tldr r0, [sp, 0x14]\n" + "\tcmp r12, r0\n" + "\tbge _0812E932\n" + "\tb _0812E7F4\n" + "_0812E932:\n" + "\tadd sp, 0x28\n" + "\tpop {r3-r5}\n" + "\tmov r8, r3\n" + "\tmov r9, r4\n" + "\tmov r10, r5\n" + "\tpop {r4-r7}\n" + "\tpop {r0}\n" + "\tbx r0"); +} + +#define tEvA data[0] +#define tEvB data[1] +#define tEvAEnd data[2] +#define tEvBEnd data[3] +#define tEvADelta data[4] +#define tEvBDelta data[5] +#define tEvWhich data[6] +#define tEvStepCount data[8] + +void StartBlendTask(u8 eva_start, u8 evb_start, u8 eva_end, u8 evb_end, u8 ev_step, u8 priority) +{ + u8 taskId = CreateTask(Task_SmoothBlendLayers, priority); + gTasks[taskId].tEvA = eva_start << 8; + gTasks[taskId].tEvB = evb_start << 8; + gTasks[taskId].tEvAEnd = eva_end; + gTasks[taskId].tEvBEnd = evb_end; + gTasks[taskId].tEvADelta = (eva_end - eva_start) * 256 / ev_step; + gTasks[taskId].tEvBDelta = (evb_end - evb_start) * 256 / ev_step; + gTasks[taskId].tEvStepCount = ev_step; + SetGpuReg(REG_OFFSET_BLDALPHA, (evb_start << 8) | eva_start); +} + +bool8 IsBlendTaskActive(void) +{ + return FuncIsActiveTask(Task_SmoothBlendLayers); +} + +static void Task_SmoothBlendLayers(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (tEvStepCount != 0) + { + if (tEvWhich == 0) + { + tEvA += tEvADelta; + tEvWhich = 1; + } + else + { + if (--tEvStepCount != 0) + { + tEvB += tEvBDelta; + } + else + { + tEvA = tEvAEnd << 8; + tEvB = tEvBEnd << 8; + } + tEvWhich = 0; + } + SetGpuReg(REG_OFFSET_BLDALPHA, (tEvB & ~0xFF) | ((u16)tEvA >> 8)); + if (tEvStepCount == 0) + DestroyTask(taskId); + } +} + +u8 sub_812EA78(u16 species, u32 personality, u8 a2) +{ + if (species == SPECIES_UNOWN) + { + u8 unownLetter = GetUnownLetterByPersonality(personality); + switch (unownLetter) + { + case 0: + break; + case 26: + species = SPECIES_OLD_UNOWN_EMARK; + break; + case 27: + species = SPECIES_OLD_UNOWN_QMARK; + break; + default: + species = SPECIES_OLD_UNOWN_B + unownLetter - 1; + break; + } + } + if (species != SPECIES_NONE && a2 < 5) + { + species--; + if (gUnknown_845FD54[species][a2] != 0xFF) + return gUnknown_845FD54[species][a2]; + } + return 32; +} + +s8 sub_812EAE4(u16 species, u32 personality, u8 a2) +{ + return sub_812EA78(species, personality, a2) - 32; +} diff --git a/src/mevent.c b/src/mevent.c index a62286f21..fc0c1f2d4 100644 --- a/src/mevent.c +++ b/src/mevent.c @@ -28,7 +28,7 @@ struct MEventTaskData1 u16 t02; u16 t04; u16 t06; - u8 t08; + u8 state; u8 t09; u8 t0A; u8 t0B; @@ -91,46 +91,46 @@ struct MEvent_Str_1 gUnknown_3005ED0; static EWRAM_DATA bool32 gUnknown_203F3BC = FALSE; -void sub_81435DC(struct MEvent_Str_1 *a0, size_t a1, const void * a2) +void sub_81435DC(struct MEvent_Str_1 *mgr, size_t size, const void * data) { vu16 imeBak = REG_IME; REG_IME = 0; - gIntrTable[1] = sub_815C6D4; - gIntrTable[2] = sub_815C6C4; - sub_815C8C8(); - sub_815C960(); + gIntrTable[1] = EReaderHelper_SerialCallback; + gIntrTable[2] = EReaderHelper_Timer3Callback; + EReaderHelper_SaveRegsState(); + EReaderHelper_ClearsSendRecvMgr(); REG_IE |= INTR_FLAG_VCOUNT; REG_IME = imeBak; - a0->unk_000 = 0; - a0->unk_004 = a1; - a0->unk_008 = a2; + mgr->status = 0; + mgr->size = size; + mgr->data = data; } void sub_8143644(struct MEvent_Str_1 *unused) { vu16 imeBak = REG_IME; REG_IME = 0; - sub_815C960(); - sub_815C91C(); + EReaderHelper_ClearsSendRecvMgr(); + EReaderHelper_RestoreRegsState(); RestoreSerialTimer3IntrHandlers(); REG_IME = imeBak; } -u8 sub_8143674(struct MEvent_Str_1 *a0) +u8 sub_8143674(struct MEvent_Str_1 *mgr) { u8 resp = 0; - a0->unk_000 = sub_815C498(1, a0->unk_004, a0->unk_008, 0); - if ((a0->unk_000 & 0x13) == 0x10) + mgr->status = EReaderHandleTransfer(1, mgr->size, mgr->data, 0); + if ((mgr->status & 0x13) == 0x10) resp = 1; - if (a0->unk_000 & 8) + if (mgr->status & 8) resp = 2; - if (a0->unk_000 & 4) + if (mgr->status & 4) resp = 3; gUnknown_3003F84 = 0; return resp; } -void sub_81436BC(void) +static void ResetTTDataBuffer(void) { memset(gDecompressionBuffer, 0, 0x2000); gLinkType = 0x5502; @@ -143,7 +143,7 @@ bool32 sub_81436EC(void) vu16 imeBak = REG_IME; u16 data[4]; REG_IME = 0; - *(u64 *)data = gUnknown_3003FB4; + *(u64 *)data = gSioMlt_Recv; REG_IME = imeBak; if ( data[0] == 0xB9A0 && data[1] == 0xCCD0 @@ -154,7 +154,7 @@ bool32 sub_81436EC(void) return FALSE; } -bool32 sub_814374C(void) +static bool32 IsEReaderConnectionSane(void) { if (sub_800AA48() && GetLinkPlayerCount_2() == 2) return TRUE; @@ -240,11 +240,11 @@ u32 sub_8143770(u8 * r4, u16 * r5) return 0; } -void sub_81438A0(void) +void task_add_00_ereader(void) { u8 taskId = CreateTask(sub_8143910, 0); struct MEventTaskData1 *data = (struct MEventTaskData1 *)gTasks[taskId].data; - data->t08 = 0; + data->state = 0; data->t09 = 0; data->t0A = 0; data->t0B = 0; @@ -258,12 +258,12 @@ void sub_81438A0(void) data->t10 = AllocZeroed(sizeof(struct MEvent_Str_2)); } -void sub_81438E8(u16 *a0) +static void ResetDelayTimer(u16 *a0) { *a0 = 0; } -bool32 sub_81438F0(u16 * a0, u16 a1) +static bool32 AdvanceDelayTimerCheckTimeout(u16 * a0, u16 a1) { if (++(*a0) > a1) { @@ -276,114 +276,114 @@ bool32 sub_81438F0(u16 * a0, u16 a1) void sub_8143910(u8 taskId) { struct MEventTaskData1 *data = (struct MEventTaskData1 *)gTasks[taskId].data; - switch (data->t08) + switch (data->state) { case 0: - if (mevent_0814257C(&data->t09, gUnknown_841DE52)) - data->t08 = 1; + if (MG_PrintTextOnWindow1AndWaitButton(&data->t09, gUnknown_841DE52)) + data->state = 1; break; case 1: - sub_81436BC(); - sub_81438E8(&data->t00); - data->t08 = 2; + ResetTTDataBuffer(); + ResetDelayTimer(&data->t00); + data->state = 2; break; case 2: - if (sub_81438F0(&data->t00, 10)) - data->t08 = 3; + if (AdvanceDelayTimerCheckTimeout(&data->t00, 10)) + data->state = 3; break; case 3: - if (!sub_814374C()) + if (!IsEReaderConnectionSane()) { - sub_80098B8(); - data->t08 = 4; + CloseLink(); + data->state = 4; } else - data->t08 = 13; + data->state = 13; break; case 4: - if (mevent_0814257C(&data->t09, gUnknown_841DE53)) + if (MG_PrintTextOnWindow1AndWaitButton(&data->t09, gUnknown_841DE53)) { - sub_8142504(gUnknown_841DE54); - sub_81438E8(&data->t00); - data->t08 = 5; + AddTextPrinterToWindow1(gUnknown_841DE54); + ResetDelayTimer(&data->t00); + data->state = 5; } break; case 5: - if (sub_81438F0(&data->t00, 90)) + if (AdvanceDelayTimerCheckTimeout(&data->t00, 90)) { - sub_81436BC(); - data->t08 = 6; + ResetTTDataBuffer(); + data->state = 6; } else if (JOY_NEW(B_BUTTON)) { - sub_81438E8(&data->t00); + ResetDelayTimer(&data->t00); PlaySE(SE_SELECT); - data->t08 = 23; + data->state = 23; } break; case 6: if (JOY_NEW(B_BUTTON)) { PlaySE(SE_SELECT); - sub_80098B8(); - sub_81438E8(&data->t00); - data->t08 = 23; + CloseLink(); + ResetDelayTimer(&data->t00); + data->state = 23; } else if (GetLinkPlayerCount_2() > 1) { - sub_81438E8(&data->t00); - sub_80098B8(); - data->t08 = 7; + ResetDelayTimer(&data->t00); + CloseLink(); + data->state = 7; } else if (sub_81436EC()) { PlaySE(SE_SELECT); - sub_80098B8(); - sub_81438E8(&data->t00); - data->t08 = 8; + CloseLink(); + ResetDelayTimer(&data->t00); + data->state = 8; } - else if (sub_81438F0(&data->t00, 10)) + else if (AdvanceDelayTimerCheckTimeout(&data->t00, 10)) { - sub_80098B8(); - sub_81436BC(); - sub_81438E8(&data->t00); + CloseLink(); + ResetTTDataBuffer(); + ResetDelayTimer(&data->t00); } break; case 7: - if (mevent_0814257C(&data->t09, gUnknown_841DE7C)) - data->t08 = 4; + if (MG_PrintTextOnWindow1AndWaitButton(&data->t09, gUnknown_841DE7C)) + data->state = 4; break; case 8: - sub_8142504(gUnknown_841DE95); + AddTextPrinterToWindow1(gUnknown_841DE95); sub_81435DC(&gUnknown_3005ED0, gUnknownSerialData_End - gUnknownSerialData_Start, gUnknownSerialData_Start); - data->t08 = 9; + data->state = 9; break; case 9: data->t0E = sub_8143674(&gUnknown_3005ED0); if (data->t0E != 0) - data->t08 = 10; + data->state = 10; break; case 10: sub_8143644(&gUnknown_3005ED0); if (data->t0E == 3) - data->t08 = 20; + data->state = 20; else if (data->t0E == 1) { - sub_81438E8(&data->t00); - sub_8142504(gUnknown_841DE9B); - data->t08 = 11; + ResetDelayTimer(&data->t00); + AddTextPrinterToWindow1(gUnknown_841DE9B); + data->state = 11; } else - data->t08 = 0; + data->state = 0; break; case 11: - if (sub_81438F0(&data->t00, 840)) - data->t08 = 12; + if (AdvanceDelayTimerCheckTimeout(&data->t00, 840)) + data->state = 12; break; case 12: - sub_81436BC(); - sub_8142504(gUnknown_841DE98); - data->t08 = 13; + ResetTTDataBuffer(); + AddTextPrinterToWindow1(gUnknown_841DE98); + data->state = 13; break; case 13: switch (sub_8143770(&data->t09, &data->t00)) @@ -391,94 +391,94 @@ void sub_8143910(u8 taskId) case 0: break; case 2: - sub_8142504(gUnknown_841DE95); - data->t08 = 14; + AddTextPrinterToWindow1(gUnknown_841DE95); + data->state = 14; break; case 1: PlaySE(SE_SELECT); - sub_80098B8(); - data->t08 = 23; + CloseLink(); + data->state = 23; break; case 5: - sub_80098B8(); - data->t08 = 21; + CloseLink(); + data->state = 21; break; case 3: case 4: - sub_80098B8(); - data->t08 = 20; + CloseLink(); + data->state = 20; break; } break; case 14: if (HasLinkErrorOccurred()) { - sub_80098B8(); - data->t08 = 20; + CloseLink(); + data->state = 20; } else if (GetBlockReceivedStatus()) { ResetBlockReceivedFlags(); - data->t08 = 15; + data->state = 15; } break; case 15: - data->t0E = sub_815D6B4(gDecompressionBuffer); + data->t0E = ValidateTrainerTowerData((struct TrainerTowerData *)gDecompressionBuffer); sub_800AA80(data->t0E); - data->t08 = 16; + data->state = 16; break; case 16: if (!gReceivedRemoteLinkPlayers) { if (data->t0E == 1) - data->t08 = 17; + data->state = 17; else - data->t08 = 20; + data->state = 20; } break; case 17: - if (sub_815D794(gDecompressionBuffer)) + if (CEReaderTool_SaveTrainerTower((struct TrainerTowerData *)gDecompressionBuffer)) { - sub_8142504(gUnknown_841DE99); - sub_81438E8(&data->t00); - data->t08 = 18; + AddTextPrinterToWindow1(gUnknown_841DE99); + ResetDelayTimer(&data->t00); + data->state = 18; } else - data->t08 = 22; + data->state = 22; break; case 18: - if (sub_81438F0(&data->t00, 120)) + if (AdvanceDelayTimerCheckTimeout(&data->t00, 120)) { - sub_8142504(gUnknown_841DE9A); + AddTextPrinterToWindow1(gUnknown_841DE9A); PlayFanfare(258); - data->t08 = 19; + data->state = 19; } break; case 19: if (IsFanfareTaskInactive() &&JOY_NEW(A_BUTTON | B_BUTTON)) - data->t08 = 26; + data->state = 26; break; case 23: - if (mevent_0814257C(&data->t09, gUnknown_841DE7D)) - data->t08 = 26; + if (MG_PrintTextOnWindow1AndWaitButton(&data->t09, gUnknown_841DE7D)) + data->state = 26; break; case 20: - if (mevent_0814257C(&data->t09, gUnknown_841DE96)) - data->t08 = 0; + if (MG_PrintTextOnWindow1AndWaitButton(&data->t09, gUnknown_841DE96)) + data->state = 0; break; case 21: - if (mevent_0814257C(&data->t09, gUnknown_841DE97)) - data->t08 = 0; + if (MG_PrintTextOnWindow1AndWaitButton(&data->t09, gUnknown_841DE97)) + data->state = 0; break; case 22: - if (mevent_0814257C(&data->t09, gUnknown_841DE9C)) - data->t08 = 0; + if (MG_PrintTextOnWindow1AndWaitButton(&data->t09, gUnknown_841DE9C)) + data->state = 0; break; case 26: sub_812B484(); Free(data->t10); DestroyTask(taskId); - SetMainCallback2(sub_81422FC); + SetMainCallback2(MainCB_FreeAllBuffersAndReturnToInitTitleScreen); break; } } @@ -490,12 +490,12 @@ void sub_8143D24(void) sub_80BDE28(); } -struct MEventBuffer_3120_Sub * sub_8143D58(void) +struct MEventBuffer_3120_Sub * GetSavedWonderNews(void) { return &gSaveBlock1Ptr->unk_3120.buffer_000.data; } -struct MEventBuffer_32E0_Sub * sav1_get_mevent_buffer_1(void) +struct MEventBuffer_32E0_Sub * GetSavedWonderCard(void) { return &gSaveBlock1Ptr->unk_3120.buffer_1c0.data; } @@ -515,7 +515,7 @@ u16 * sub_8143DA8(void) return gSaveBlock1Ptr->unk_3120.unk_338; } -void sub_8143DBC(void) +void DestroyWonderNews(void) { sub_8143E9C(); } @@ -530,7 +530,7 @@ bool32 sub_8143DC8(const struct MEventBuffer_3120_Sub * src) return TRUE; } -bool32 sub_8143E1C(void) +bool32 ValidateReceivedWonderNews(void) { if (CalcCRC16WithTable((void *)&gSaveBlock1Ptr->unk_3120.buffer_000.data, sizeof(struct MEventBuffer_3120_Sub)) != gSaveBlock1Ptr->unk_3120.buffer_000.crc) return FALSE; @@ -546,7 +546,7 @@ bool32 sub_8143E64(const struct MEventBuffer_3120_Sub * data) return TRUE; } -bool32 sub_8143E78(void) +bool32 WonderNews_Test_Unk_02(void) { const struct MEventBuffer_3120_Sub * data = &gSaveBlock1Ptr->unk_3120.buffer_000.data; if (data->unk_02 == 0) @@ -556,7 +556,7 @@ bool32 sub_8143E78(void) void sub_8143E9C(void) { - CpuFill32(0, sub_8143D58(), sizeof(gSaveBlock1Ptr->unk_3120.buffer_000.data)); + CpuFill32(0, GetSavedWonderNews(), sizeof(gSaveBlock1Ptr->unk_3120.buffer_000.data)); gSaveBlock1Ptr->unk_3120.buffer_000.crc = 0; } @@ -570,7 +570,7 @@ bool32 sub_8143EF4(const u8 * src) { const u8 * r5 = (const u8 *)&gSaveBlock1Ptr->unk_3120.buffer_000.data; u32 i; - if (!sub_8143E1C()) + if (!ValidateReceivedWonderNews()) return FALSE; for (i = 0; i < sizeof(struct MEventBuffer_3120_Sub); i++) { @@ -580,7 +580,7 @@ bool32 sub_8143EF4(const u8 * src) return TRUE; } -void sub_8143F38(void) +void DestroyWonderCard(void) { sub_814407C(); sub_81440B4(); @@ -597,7 +597,7 @@ bool32 sub_8143F68(const struct MEventBuffer_32E0_Sub * data) struct MEventBuffer_32E0_Sub * r1; if (!sub_8144018(data)) return FALSE; - sub_8143F38(); + DestroyWonderCard(); memcpy(&gSaveBlock1Ptr->unk_3120.buffer_1c0.data, data, sizeof(struct MEventBuffer_32E0_Sub)); gSaveBlock1Ptr->unk_3120.buffer_1c0.crc = CalcCRC16WithTable((void *)&gSaveBlock1Ptr->unk_3120.buffer_1c0.data, sizeof(struct MEventBuffer_32E0_Sub)); r2 = &gSaveBlock1Ptr->unk_3120.buffer_310.data; @@ -606,7 +606,7 @@ bool32 sub_8143F68(const struct MEventBuffer_32E0_Sub * data) return TRUE; } -bool32 sub_8143FC8(void) +bool32 ValidateReceivedWonderCard(void) { if (gSaveBlock1Ptr->unk_3120.buffer_1c0.crc != CalcCRC16WithTable((void *)&gSaveBlock1Ptr->unk_3120.buffer_1c0.data, sizeof(struct MEventBuffer_32E0_Sub))) return FALSE; @@ -632,7 +632,7 @@ bool32 sub_8144018(const struct MEventBuffer_32E0_Sub * data) return TRUE; } -bool32 sub_8144054(void) +bool32 WonderCard_Test_Unk_08_6(void) { const struct MEventBuffer_32E0_Sub * data = &gSaveBlock1Ptr->unk_3120.buffer_1c0.data; if (data->unk_08_6 == 0) @@ -654,7 +654,7 @@ void sub_81440B4(void) u16 sub_81440E8(void) { - if (sub_8143FC8()) + if (ValidateReceivedWonderCard()) return gSaveBlock1Ptr->unk_3120.buffer_1c0.data.unk_00; return 0; } @@ -672,7 +672,7 @@ bool32 sub_8144124(u16 a0) return FALSE; } -bool32 sub_8144144(void) +bool32 CheckReceivedGiftFromWonderCard(void) { u16 value = sub_81440E8(); if (!sub_8144124(value)) @@ -721,7 +721,7 @@ bool32 sub_81441F0(const u16 * data) s32 sub_8144218(void) { struct MEventBuffer_32E0_Sub * data; - if (!sub_8143FC8()) + if (!ValidateReceivedWonderCard()) return 0; data = &gSaveBlock1Ptr->unk_3120.buffer_1c0.data; if (data->unk_08_0 != 1) @@ -759,11 +759,11 @@ void sub_81442CC(struct MEventStruct_Unk1442CC * data) data->unk_08 = 1; data->unk_0C = 1; data->unk_10 = 1; - if (sub_8143FC8()) + if (ValidateReceivedWonderCard()) { - data->unk_14 = sav1_get_mevent_buffer_1()->unk_00; + data->unk_14 = GetSavedWonderCard()->unk_00; data->unk_20 = *sav1_get_mevent_buffer_2(); - data->unk_44 = sav1_get_mevent_buffer_1()->unk_09; + data->unk_44 = GetSavedWonderCard()->unk_09; } else data->unk_14 = 0; @@ -945,7 +945,7 @@ bool32 sub_81446D0(u16 a0) gUnknown_203F3BC = FALSE; if (a0 == 0) return FALSE; - if (!sub_8143FC8()) + if (!ValidateReceivedWonderCard()) return FALSE; if (gSaveBlock1Ptr->unk_3120.buffer_1c0.data.unk_00 != a0) return FALSE; diff --git a/src/mevent_8145654.c b/src/mevent_8145654.c index c39d76f25..034a07679 100644 --- a/src/mevent_8145654.c +++ b/src/mevent_8145654.c @@ -58,7 +58,7 @@ void sub_8145D18(u8 whichWindow); void sub_8146060(void); void sub_81461D8(void); -extern const struct OamData gUnknown_83AC9F8; +extern const struct OamData gOamData_83AC9F8; const struct TextColor gUnknown_8467068[] = { {0, 2, 3}, @@ -113,7 +113,7 @@ const struct SpritePalette gUnknown_8467F60[] = { {gUnknown_8467ED4, 0x8000} }; const struct SpriteTemplate gUnknown_8467FA0 = { - 0x8000, 0x8000, &gUnknown_83AC9F8, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy + 0x8000, 0x8000, &gOamData_83AC9F8, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy }; const struct UnkStruct_8467FB8 gUnknown_8467FB8[8] = { {1, 0, 0, 0, gUnknown_846718C, gUnknown_8467288, gUnknown_846708C}, @@ -126,7 +126,7 @@ const struct UnkStruct_8467FB8 gUnknown_8467FB8[8] = { {1, 0, 0, 7, gUnknown_8467A7C, gUnknown_8467CAC, gUnknown_846716C} }; -bool32 sub_8145654(struct MEventBuffer_32E0_Sub * r5, struct MEventBuffer_3430_Sub * r6) +bool32 InitWonderCardResources(struct MEventBuffer_32E0_Sub * r5, struct MEventBuffer_3430_Sub * r6) { if (r5 == NULL || r6 == NULL) return FALSE; @@ -145,7 +145,7 @@ bool32 sub_8145654(struct MEventBuffer_32E0_Sub * r5, struct MEventBuffer_3430_S return TRUE; } -void sub_81456F0(void) +void DestroyWonderCardResources(void) { if (gUnknown_203F3C8 != NULL) { @@ -155,7 +155,7 @@ void sub_81456F0(void) } } -s32 sub_814571C(void) +s32 FadeToWonderCardMenu(void) { if (gUnknown_203F3C8 == NULL) return -1; @@ -219,7 +219,7 @@ s32 sub_814571C(void) return 0; } -s32 sub_814593C(bool32 flag) +s32 FadeOutFromWonderCard(bool32 flag) { if (gUnknown_203F3C8 == NULL) return -1; @@ -252,7 +252,7 @@ s32 sub_814593C(bool32 flag) FreeMonIconPalettes(); break; case 5: - sub_8142344(gUnknown_203F3B8, flag); + PrintMysteryGiftOrEReaderTopMenu(gGiftIsFromEReader, flag); break; case 6: CopyBgTilemapBufferToVram(0); @@ -347,28 +347,28 @@ void sub_8145D18(u8 whichWindow) case 0: { s32 x; - box_print(windowId, 3, 0, 1, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal1], 0, gUnknown_203F3C8->unk_018B); + AddTextPrinterParameterized3(windowId, 3, 0, 1, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal1], 0, gUnknown_203F3C8->unk_018B); x = 160 - GetStringWidth(3, gUnknown_203F3C8->unk_01B4, GetFontAttribute(3, 2)); if (x < 0) x = 0; - box_print(windowId, 3, x, 17, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal1], 0, gUnknown_203F3C8->unk_01B4); + AddTextPrinterParameterized3(windowId, 3, x, 17, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal1], 0, gUnknown_203F3C8->unk_01B4); if (gUnknown_203F3C8->unk_0000.unk_04 != 0) { - box_print(windowId, 2, 166, 17, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal1], 0, gUnknown_203F3C8->unk_01DD); + AddTextPrinterParameterized3(windowId, 2, 166, 17, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal1], 0, gUnknown_203F3C8->unk_01DD); } break; } case 1: for (; sp0C < 4; sp0C++) { - box_print(windowId, 3, 0, 16 * sp0C + 2, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal2], 0, gUnknown_203F3C8->unk_01E4[sp0C]); + AddTextPrinterParameterized3(windowId, 3, 0, 16 * sp0C + 2, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal2], 0, gUnknown_203F3C8->unk_01E4[sp0C]); } break; case 2: - box_print(windowId, 3, 0, gUnknown_8467070[gUnknown_203F3C8->unk_0000.unk_08_0], &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal3], 0, gUnknown_203F3C8->unk_0288); + AddTextPrinterParameterized3(windowId, 3, 0, gUnknown_8467070[gUnknown_203F3C8->unk_0000.unk_08_0], &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal3], 0, gUnknown_203F3C8->unk_0288); if (gUnknown_203F3C8->unk_0000.unk_08_0 != 2) { - box_print(windowId, 3, 0, 16 + gUnknown_8467070[gUnknown_203F3C8->unk_0000.unk_08_0], &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal3], 0, gUnknown_203F3C8->unk_02B1); + AddTextPrinterParameterized3(windowId, 3, 0, 16 + gUnknown_8467070[gUnknown_203F3C8->unk_0000.unk_08_0], &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal3], 0, gUnknown_203F3C8->unk_02B1); } else { @@ -377,11 +377,11 @@ void sub_8145D18(u8 whichWindow) s32 spacing = GetFontAttribute(3, 2); for (; sp0C < gUnknown_203F3C8->unk_0175; sp0C++) { - box_print(windowId, 3, x, y, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal3], 0, gUnknown_203F3C8->unk_02DC[sp0C].unk_01); + AddTextPrinterParameterized3(windowId, 3, x, y, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal3], 0, gUnknown_203F3C8->unk_02DC[sp0C].unk_01); if (gUnknown_203F3C8->unk_02DC[sp0C].unk_42[0] != EOS) { x += GetStringWidth(3, gUnknown_203F3C8->unk_02DC[sp0C].unk_01, spacing); - box_print(windowId, 2, x, y, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal3], 0, gUnknown_203F3C8->unk_02DC[sp0C].unk_42); + AddTextPrinterParameterized3(windowId, 2, x, y, &gUnknown_8467068[gUnknown_203F3C8->unk_0170->textPal3], 0, gUnknown_203F3C8->unk_02DC[sp0C].unk_42); x += GetStringWidth(3, gUnknown_203F3C8->unk_02DC[sp0C].unk_42, spacing) + gUnknown_203F3C8->unk_02DC[sp0C].unk_00; } } @@ -460,7 +460,7 @@ struct UnkStruct_203F3CC /*01cc*/ u8 filler_01CC[2]; /*01ce*/ u8 unk_01CE[41]; /*01f7*/ u8 unk_01F7[10][41]; - /*0394*/ struct ScrollIndicatorArrowPairTemplate unk_0394; + /*0394*/ struct ScrollArrowsTemplate unk_0394; /*03a4*/ u8 buffer_03A4[0x1000]; }; @@ -478,9 +478,9 @@ const struct WindowTemplate gUnknown_8468040[] = { {0, 1, 0, 28, 3, 15, 0x000}, {2, 1, 3, 28, 20, 15, 0x000} }; -const struct ScrollIndicatorArrowPairTemplate gUnknown_8468050 = { +const struct ScrollArrowsTemplate gUnknown_8468050 = { 0x02, 0xe8, 0x18, 0x03, 0xe8, 0x98, - 0x0000, 0x0002, 0x1000, 0x1000, 0x0, 0x000 + 0x0000, 0x0002, 0x1000, 0x1000, 0x0, }; const u16 gUnknown_8468060[] = INCBIN_U16("data/graphics/mevent/pal_468060.gbapal"); @@ -508,7 +508,7 @@ const struct UnkStruct_8467FB8 gUnknown_8468720[] = { {1, 0, 0, 0, gUnknown_84685B4, gUnknown_8468644, gUnknown_84680A0} }; -bool32 sub_8146288(const struct MEventBuffer_3120_Sub * a0) +bool32 InitWonderNewsResources(const struct MEventBuffer_3120_Sub * a0) { if (a0 == NULL) return FALSE; @@ -523,7 +523,7 @@ bool32 sub_8146288(const struct MEventBuffer_3120_Sub * a0) return TRUE; } -void sub_81462EC(void) +void DestroyWonderNewsResources(void) { if (gUnknown_203F3CC != NULL) { @@ -533,7 +533,7 @@ void sub_81462EC(void) } } -s32 sub_8146318(void) +s32 FadeToWonderNewsMenu(void) { if (gUnknown_203F3CC == NULL) return -1; @@ -608,7 +608,7 @@ s32 sub_8146318(void) return 0; } -s32 sub_8146604(bool32 flag) +s32 FadeOutFromWonderNews(bool32 flag) { if (gUnknown_203F3CC == NULL) return -1; @@ -653,10 +653,10 @@ s32 sub_8146604(bool32 flag) } break; case 5: - sub_8142344(gUnknown_203F3B8, flag); + PrintMysteryGiftOrEReaderTopMenu(gGiftIsFromEReader, flag); break; case 6: - sub_8142420(); + MG_DrawCheckerboardPattern(); CopyBgTilemapBufferToVram(0); CopyBgTilemapBufferToVram(3); BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, 0); @@ -671,7 +671,7 @@ s32 sub_8146604(bool32 flag) return 0; } -void sub_81467EC(void) +void MENews_RemoveScrollIndicatorArrowPair(void) { if (!gUnknown_203F3CC->unk_01C0_0 && gUnknown_203F3CC->unk_01C1 != 0xFF) { @@ -682,7 +682,7 @@ void sub_81467EC(void) } -void sub_8146834(void) +void MENews_AddScrollIndicatorArrowPair(void) { if (gUnknown_203F3CC->unk_01C0_0) { @@ -691,7 +691,7 @@ void sub_8146834(void) } } -u8 sub_8146884(u16 input) +u32 MENews_GetInput(u16 input) { if (gUnknown_203F3CC->unk_01C2_0) { @@ -743,7 +743,7 @@ void sub_8146980(void) ++gUnknown_203F3CC->unk_01C4; } gUnknown_203F3CC->unk_0394 = gUnknown_8468050; - gUnknown_203F3CC->unk_0394.unk_08 = gUnknown_203F3CC->unk_01C4; + gUnknown_203F3CC->unk_0394.fullyDownThreshold = gUnknown_203F3CC->unk_01C4; } void sub_8146A30(void) @@ -757,10 +757,10 @@ void sub_8146A30(void) x = (0xe0 - GetStringWidth(3, gUnknown_203F3CC->unk_01CE, GetFontAttribute(3, 2))) / 2; if (x < 0) x = 0; - box_print(gUnknown_203F3CC->unk_01C8[0], 3, x, 6, &gUnknown_8468038[gUnknown_203F3CC->unk_01BC->textPal1], 0, gUnknown_203F3CC->unk_01CE); + AddTextPrinterParameterized3(gUnknown_203F3CC->unk_01C8[0], 3, x, 6, &gUnknown_8468038[gUnknown_203F3CC->unk_01BC->textPal1], 0, gUnknown_203F3CC->unk_01CE); for (; i < 10; ++i) { - box_print(gUnknown_203F3CC->unk_01C8[1], 3, 0, 16 * i + 2, &gUnknown_8468038[gUnknown_203F3CC->unk_01BC->textPal2], 0, gUnknown_203F3CC->unk_01F7[i]); + AddTextPrinterParameterized3(gUnknown_203F3CC->unk_01C8[1], 3, 0, 16 * i + 2, &gUnknown_8468038[gUnknown_203F3CC->unk_01BC->textPal2], 0, gUnknown_203F3CC->unk_01F7[i]); } CopyWindowToVram(gUnknown_203F3CC->unk_01C8[0], 3); CopyWindowToVram(gUnknown_203F3CC->unk_01C8[1], 3); diff --git a/src/mevent_server.c b/src/mevent_server.c index 5e384ae0b..1c2dc4ced 100644 --- a/src/mevent_server.c +++ b/src/mevent_server.c @@ -11,12 +11,12 @@ #include "mevent.h" #include "mevent_server.h" -EWRAM_DATA struct mevent_srv_ish * s_mevent_srv_ish_ptr = NULL; +EWRAM_DATA struct mevent_client * s_mevent_client_ptr = NULL; EWRAM_DATA struct mevent_srv_common * s_mevent_srv_common_ptr = NULL; -static void mevent_srv_ish_init(struct mevent_srv_ish *, u32, u32); -static u32 mevent_srv_ish_exec(struct mevent_srv_ish *); -static void mevent_srv_ish_free_resources(struct mevent_srv_ish *); +static void mevent_client_init(struct mevent_client *, u32, u32); +static u32 mevent_client_exec(struct mevent_client *); +static void mevent_client_free_resources(struct mevent_client *); static void mevent_srv_init_common(struct mevent_srv_common *, const void *, u32, u32); static void mevent_srv_free_resources(struct mevent_srv_common *); static u32 mevent_srv_exec_common(struct mevent_srv_common *); @@ -25,44 +25,44 @@ extern const u8 gUnknown_84687E0[]; extern const struct mevent_cmd gUnknown_8468B6C[]; extern const struct mevent_cmd gUnknown_8468BCC[]; -void mevent_srv_ish_do_init(void) +void mevent_client_do_init(void) { - s_mevent_srv_ish_ptr = AllocZeroed(sizeof(struct mevent_srv_ish)); - mevent_srv_ish_init(s_mevent_srv_ish_ptr, 1, 0); + s_mevent_client_ptr = AllocZeroed(sizeof(struct mevent_client)); + mevent_client_init(s_mevent_client_ptr, 1, 0); } -u32 mevent_srv_ish_do_exec(u16 * a0) +u32 mevent_client_do_exec(u16 * a0) { u32 result; - if (s_mevent_srv_ish_ptr == NULL) + if (s_mevent_client_ptr == NULL) return 6; - result = mevent_srv_ish_exec(s_mevent_srv_ish_ptr); + result = mevent_client_exec(s_mevent_client_ptr); if (result == 6) { - *a0 = s_mevent_srv_ish_ptr->param; - mevent_srv_ish_free_resources(s_mevent_srv_ish_ptr); - Free(s_mevent_srv_ish_ptr); - s_mevent_srv_ish_ptr = NULL; + *a0 = s_mevent_client_ptr->param; + mevent_client_free_resources(s_mevent_client_ptr); + Free(s_mevent_client_ptr); + s_mevent_client_ptr = NULL; } return result; } -void mevent_srv_ish_inc_flag(void) +void mevent_client_inc_flag(void) { - s_mevent_srv_ish_ptr->flag++; + s_mevent_client_ptr->flag++; } -void * mevent_srv_ish_get_buffer(void) +void * mevent_client_get_buffer(void) { - return s_mevent_srv_ish_ptr->buffer; + return s_mevent_client_ptr->buffer; } -void mevent_srv_ish_set_param(u32 a0) +void mevent_client_set_param(u32 a0) { - s_mevent_srv_ish_ptr->param = a0; + s_mevent_client_ptr->param = a0; } -static void mevent_srv_ish_init(struct mevent_srv_ish * svr, u32 sendPlayerNo, u32 recvPlayerNo) +static void mevent_client_init(struct mevent_client * svr, u32 sendPlayerNo, u32 recvPlayerNo) { svr->unk_00 = 0; svr->mainseqno = 0; @@ -74,7 +74,7 @@ static void mevent_srv_ish_init(struct mevent_srv_ish * svr, u32 sendPlayerNo, u mevent_srv_sub_init(&svr->manager, sendPlayerNo, recvPlayerNo); } -static void mevent_srv_ish_free_resources(struct mevent_srv_ish * svr) +static void mevent_client_free_resources(struct mevent_client * svr) { Free(svr->sendBuffer); Free(svr->recvBuffer); @@ -82,20 +82,20 @@ static void mevent_srv_ish_free_resources(struct mevent_srv_ish * svr) Free(svr->buffer); } -static void mevent_srv_ish_jmp_buffer(struct mevent_srv_ish * svr) +static void mevent_client_jmp_buffer(struct mevent_client * svr) { memcpy(svr->cmdBuffer, svr->recvBuffer, ME_SEND_BUF_SIZE); svr->cmdidx = 0; } -static void mevent_srv_ish_send_word(struct mevent_srv_ish * svr, u32 ident, u32 word) +static void mevent_client_send_word(struct mevent_client * svr, u32 ident, u32 word) { CpuFill32(0, svr->sendBuffer, ME_SEND_BUF_SIZE); *(u32 *)svr->sendBuffer = word; mevent_srv_sub_init_send(&svr->manager, ident, svr->sendBuffer, sizeof(u32)); } -static u32 ish_mainseq_0(struct mevent_srv_ish * svr) +static u32 ish_mainseq_0(struct mevent_client * svr) { // init memcpy(svr->cmdBuffer, gUnknown_84687E0, ME_SEND_BUF_SIZE); @@ -105,13 +105,13 @@ static u32 ish_mainseq_0(struct mevent_srv_ish * svr) return 0; } -static u32 ish_mainseq_1(struct mevent_srv_ish * svr) +static u32 ish_mainseq_1(struct mevent_client * svr) { // done return 6; } -static u32 ish_mainseq_2(struct mevent_srv_ish * svr) +static u32 ish_mainseq_2(struct mevent_client * svr) { // do recv if (mevent_srv_sub_recv(&svr->manager)) @@ -122,7 +122,7 @@ static u32 ish_mainseq_2(struct mevent_srv_ish * svr) return 1; } -static u32 ish_mainseq_3(struct mevent_srv_ish * svr) +static u32 ish_mainseq_3(struct mevent_client * svr) { // do send if (mevent_srv_sub_send(&svr->manager)) @@ -133,7 +133,7 @@ static u32 ish_mainseq_3(struct mevent_srv_ish * svr) return 1; } -static u32 ish_mainseq_4(struct mevent_srv_ish * svr) +static u32 ish_mainseq_4(struct mevent_client * svr) { // process command struct mevent_cmd_ish * cmd = &svr->cmdBuffer[svr->cmdidx]; @@ -162,20 +162,20 @@ static u32 ish_mainseq_4(struct mevent_srv_ish * svr) svr->flag = 0; break; case 19: - mevent_srv_ish_send_word(svr, 0x12, GetGameStat(cmd->parameter)); + mevent_client_send_word(svr, 0x12, GetGameStat(cmd->parameter)); svr->mainseqno = 3; svr->flag = 0; break; case 6: if (svr->param == 0) - mevent_srv_ish_jmp_buffer(svr); + mevent_client_jmp_buffer(svr); break; case 7: if (svr->param == 1) - mevent_srv_ish_jmp_buffer(svr); + mevent_client_jmp_buffer(svr); break; case 4: - mevent_srv_ish_jmp_buffer(svr); + mevent_client_jmp_buffer(svr); break; case 5: memcpy(svr->buffer, svr->recvBuffer, 0x40); @@ -201,7 +201,7 @@ static u32 ish_mainseq_4(struct mevent_srv_ish * svr) mevent_srv_sub_init_send(&svr->manager, 0x11, svr->sendBuffer, sizeof(struct MEventStruct_Unk1442CC)); break; case 14: - mevent_srv_ish_send_word(svr, 0x13, svr->param); + mevent_client_send_word(svr, 0x13, svr->param); break; case 10: sub_8143F68(svr->recvBuffer); @@ -210,10 +210,10 @@ static u32 ish_mainseq_4(struct mevent_srv_ish * svr) if (!sub_8143EF4(svr->recvBuffer)) { sub_8143DC8(svr->recvBuffer); - mevent_srv_ish_send_word(svr, 0x13, 0); + mevent_client_send_word(svr, 0x13, 0); } else - mevent_srv_ish_send_word(svr, 0x13, 1); + mevent_client_send_word(svr, 0x13, 1); break; case 15: svr->mainseqno = 6; @@ -239,7 +239,7 @@ static u32 ish_mainseq_4(struct mevent_srv_ish * svr) return 1; } -static u32 ish_mainseq_5(struct mevent_srv_ish * svr) +static u32 ish_mainseq_5(struct mevent_client * svr) { // wait flag if (svr->flag) @@ -250,7 +250,7 @@ static u32 ish_mainseq_5(struct mevent_srv_ish * svr) return 1; } -static u32 ish_mainseq_6(struct mevent_srv_ish * svr) +static u32 ish_mainseq_6(struct mevent_client * svr) { // ??? switch (svr->flag) @@ -270,7 +270,7 @@ static u32 ish_mainseq_6(struct mevent_srv_ish * svr) return 1; } -static u32 ish_mainseq_7(struct mevent_srv_ish * svr) +static u32 ish_mainseq_7(struct mevent_client * svr) { // exec arbitrary code u32 (*func)(u32 *, struct SaveBlock2 *, struct SaveBlock1 *) = (void *)gDecompressionBuffer; @@ -282,9 +282,9 @@ static u32 ish_mainseq_7(struct mevent_srv_ish * svr) return 1; } -static u32 mevent_srv_ish_exec(struct mevent_srv_ish * svr) +static u32 mevent_client_exec(struct mevent_client * svr) { - u32 (*funcs[])(struct mevent_srv_ish *) = { + u32 (*funcs[])(struct mevent_client *) = { ish_mainseq_0, ish_mainseq_1, ish_mainseq_2, @@ -297,19 +297,19 @@ static u32 mevent_srv_ish_exec(struct mevent_srv_ish * svr) return funcs[svr->mainseqno](svr); } -void mevent_srv_common_do_init_1(void) +void mevent_srv_init_wnews(void) { s_mevent_srv_common_ptr = AllocZeroed(sizeof(struct mevent_srv_common)); mevent_srv_init_common(s_mevent_srv_common_ptr, gUnknown_8468B6C, 0, 1); } -void mevent_srv_common_do_init_2(void) +void mevent_srv_new_wcard(void) { s_mevent_srv_common_ptr = AllocZeroed(sizeof(struct mevent_srv_common)); mevent_srv_init_common(s_mevent_srv_common_ptr, gUnknown_8468BCC, 0, 1); } -u32 mevent_srv_init_do_exec(u16 * a0) +u32 mevent_srv_common_do_exec(u16 * a0) { u32 result; if (s_mevent_srv_common_ptr == NULL) @@ -526,12 +526,12 @@ static u32 common_mainseq_4(struct mevent_srv_common * svr) break; case 26: AGB_ASSERT_EX(cmd->flag == FALSE && cmd->parameter == NULL, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/mevent_server.c", 506); - memcpy(svr->mevent_32e0, sav1_get_mevent_buffer_1(), 332); + memcpy(svr->mevent_32e0, GetSavedWonderCard(), 332); sub_814410C(svr->mevent_32e0); break; case 27: AGB_ASSERT_EX(cmd->flag == FALSE && cmd->parameter == NULL, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/mevent_server.c", 512); - memcpy(svr->mevent_3120, sub_8143D58(), 444); + memcpy(svr->mevent_3120, GetSavedWonderNews(), 444); break; case 28: AGB_ASSERT_EX(cmd->flag == FALSE && cmd->parameter == NULL, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/mevent_server.c", 517); diff --git a/src/money.c b/src/money.c index 6d9a0fce9..ffaba2e29 100644 --- a/src/money.c +++ b/src/money.c @@ -128,13 +128,13 @@ void DrawMoneyBox(int amount, u8 x, u8 y) sMoneyBoxWindowId = AddWindow(&template2); FillWindowPixelBuffer(sMoneyBoxWindowId, 0); PutWindowTilemap(sMoneyBoxWindowId); - sub_814FF2C(sMoneyBoxWindowId, 0x21D, 0xD0); + TextWindow_SetStdFrame0_WithPal(sMoneyBoxWindowId, 0x21D, 0xD0); PrintMoneyAmountInMoneyBoxWithBorder(sMoneyBoxWindowId, 0x21D, 13, amount); } void HideMoneyBox(void) { - sub_810F4D8(sMoneyBoxWindowId, FALSE); + ClearMenuWindow(sMoneyBoxWindowId, FALSE); CopyWindowToVram(sMoneyBoxWindowId, 2); RemoveWindow(sMoneyBoxWindowId); } diff --git a/src/mystery_event_msg.c b/src/mystery_event_msg.c index a21750b7a..7cde2d9f2 100644 --- a/src/mystery_event_msg.c +++ b/src/mystery_event_msg.c @@ -10,4 +10,4 @@ const u8 gText_MysteryGiftSentOver[] = _("{STR_VAR_1} was sent over!"); const u8 gText_MysteryGiftFullParty[] = _("Your party is full.\n{STR_VAR_1} could not be sent over."); const u8 gText_MysteryGiftNewTrainer[] = _("A new TRAINER has arrived in\nHOENN."); const u8 gText_MysteryGiftNewAdversaryInBattleTower[] = _("バトルタワーに あらたな\nたいせんしゃが あらわれた!"); -const u8 gText_MysteryGiftCantBeUsed[] = _("This data can’t be used in\nthis version."); +const u8 gText_MysteryGiftCantBeUsed[] = _("This data can't be used in\nthis version."); diff --git a/src/mystery_gift_menu.c b/src/mystery_gift_menu.c new file mode 100644 index 000000000..9ff96eb23 --- /dev/null +++ b/src/mystery_gift_menu.c @@ -0,0 +1,1756 @@ +#include "global.h" +#include "palette.h" +#include "dma3.h" +#include "gpu_regs.h" +#include "bg.h" +#include "task.h" +#include "scanline_effect.h" +#include "malloc.h" +#include "text.h" +#include "window.h" +#include "text_window.h" +#include "menu.h" +#include "new_menu_helpers.h" +#include "sound.h" +#include "mystery_gift_menu.h" +#include "title_screen.h" +#include "list_menu.h" +#include "link_rfu.h" +#include "string_util.h" +#include "mevent.h" +#include "save.h" +#include "link.h" +#include "event_data.h" +#include "mevent_server.h" +#include "menews_jisan.h" +#include "help_system.h" +#include "constants/songs.h" + +EWRAM_DATA u8 sDownArrowCounterAndYCoordIdx[8] = {}; +EWRAM_DATA bool8 gGiftIsFromEReader = FALSE; + +void task_add_00_mystery_gift(void); +void task00_mystery_gift(u8 taskId); +void task_add_00_ereader(void); + +extern const u8 gText_PickOKExit[]; +extern const u8 gText_PickOKCancel[]; +extern const u8 gText_MysteryGift[]; +extern const u8 gJPText_MysteryGift[]; +extern const u8 gJPText_DecideStop[]; +extern const u8 gText_WhatToDoWithCards[]; +extern const u8 gText_WhatToDoWithNews[]; +extern const u8 gText_OkayToDiscardNews[]; +extern const u8 gText_IfThrowAwayCardEventWontHappen[]; +extern const u8 gText_WonderCardThrownAway[]; +extern const u8 gText_WonderNewsThrownAway[]; +extern const u8 gText_DataWillBeSaved[]; +extern const u8 gText_SaveCompletedPressA[]; +extern const u8 gText_WonderCards[]; +extern const u8 gText_WonderNews[]; +extern const u8 gText_Exit3[]; +extern const u8 gText_WirelessCommunication[]; +extern const u8 gText_Friend2[]; +extern const u8 gFameCheckerText_Cancel[]; +extern const u8 gText_Receive[]; +extern const u8 gText_Send[]; +extern const u8 gText_Toss[]; +extern const u8 gText_VarietyOfEventsImportedWireless[]; +extern const u8 gText_WonderCardsInPossession[]; +extern const u8 gText_ReadNewsThatArrived[]; +extern const u8 gText_ReturnToTitle[]; +extern const u8 gText_NothingSentOver[]; +extern const u8 gText_RecordUploadedViaWireless[]; +extern const u8 gText_WonderCardReceived[]; +extern const u8 gText_WonderCardReceivedFrom[]; +extern const u8 gText_WonderNewsReceived[]; +extern const u8 gText_WonderNewsReceivedFrom[]; +extern const u8 gText_NewStampReceived[]; +extern const u8 gText_AlreadyHadCard[]; +extern const u8 gText_AlreadyHadStamp[]; +extern const u8 gText_AlreadyHadNews[]; +extern const u8 gText_NoMoreRoomForStamps[]; +extern const u8 gText_CommunicationCanceled[]; +extern const u8 gText_CantAcceptCardFromTrainer[]; +extern const u8 gText_CantAcceptNewsFromTrainer[]; +extern const u8 gText_CommunicationError[]; +extern const u8 gText_NewTrainerReceived[]; +extern const u8 gText_WonderCardSentTo[]; +extern const u8 gText_WonderNewsSentTo[]; +extern const u8 gText_StampSentTo[]; +extern const u8 gText_OtherTrainerHasCard[]; +extern const u8 gText_OtherTrainerHasStamp[]; +extern const u8 gText_OtherTrainerHasNews[]; +extern const u8 gText_OtherTrainerCanceled[]; +extern const u8 gText_GiftSentTo[]; +extern const u8 gText_CantSendGiftToTrainer[]; +extern const u8 gText_DontHaveCardNewOneInput[]; +extern const u8 gText_DontHaveNewsNewOneInput[]; +extern const u8 gText_WhereShouldCardBeAccessed[]; +extern const u8 gText_WhereShouldNewsBeAccessed[]; +extern const u8 gText_Communicating[]; +extern const u8 gText_ThrowAwayWonderCard[]; +extern const u8 gText_HaventReceivedCardsGift[]; +extern const u8 gText_CommunicationCompleted[]; +extern const u8 gText_HaventReceivedGiftOkayToDiscard[]; +extern const u8 gText_SendingWonderCard[]; +extern const u8 gText_SendingWonderNews[]; + +const u16 gUnkTextboxBorderPal[] = INCBIN_U16("graphics/interface/unk_textbox_border.gbapal"); +const u32 gUnkTextboxBorderGfx[] = INCBIN_U32("graphics/interface/unk_textbox_border.4bpp.lz"); + +struct MysteryGiftTaskData +{ + u16 curPromptWindowId; + u16 unk2; + u16 unk4; + u16 unk6; + u8 state; + u8 textState; + u8 unkA; + u8 unkB; + u8 IsCardOrNews; + u8 source; + u8 prevPromptWindowId; + u8 * buffer; +}; + +const struct BgTemplate sBGTemplates[] = { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 15, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0x000 + }, { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 14, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0x000 + }, { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 13, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0x000 + }, { + .bg = 3, + .charBaseIndex = 0, + .mapBaseIndex = 12, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0x000 + } +}; + +const struct WindowTemplate sMainWindows[] = { + { + .bg = 0x00, + .tilemapLeft = 0x00, + .tilemapTop = 0x00, + .width = 0x1e, + .height = 0x02, + .paletteNum = 0x0f, + .baseBlock = 0x0013 + }, { + .bg = 0x00, + .tilemapLeft = 0x01, + .tilemapTop = 0x0f, + .width = 0x1c, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x004f + }, { + .bg = 0x00, + .tilemapLeft = 0x00, + .tilemapTop = 0x0f, + .width = 0x1e, + .height = 0x05, + .paletteNum = 0x0d, + .baseBlock = 0x004f + }, { + 0xFF + } +}; + +const struct WindowTemplate sWindowTemplate_PromptYesOrNo_Width28 = { + .bg = 0x00, + .tilemapLeft = 0x01, + .tilemapTop = 0x0f, + .width = 0x1c, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x00e5 +}; + +const struct WindowTemplate sWindowTemplate_PromptYesOrNo_Width20 = { + .bg = 0x00, + .tilemapLeft = 0x01, + .tilemapTop = 0x0f, + .width = 0x14, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x00e5 +}; + +const struct WindowTemplate sMysteryGiftMenuWindowTemplate = { + .bg = 0x00, + .tilemapLeft = 0x01, + .tilemapTop = 0x0f, + .width = 0x13, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x00e5 +}; + +const struct WindowTemplate sWindowTemplate_ThreeOptions = { + .bg = 0x00, + .tilemapLeft = 0x08, + .tilemapTop = 0x05, + .width = 0x0e, + .height = 0x05, + .paletteNum = 0x0e, + .baseBlock = 0x0155 +}; + +const struct WindowTemplate sWindowTemplate_YesNoBox = { + .bg = 0x00, + .tilemapLeft = 0x17, + .tilemapTop = 0x0f, + .width = 0x06, + .height = 0x04, + .paletteNum = 0x0e, + .baseBlock = 0x0155 +}; + +const struct WindowTemplate sWindowTemplate_7by8 = { + .bg = 0x00, + .tilemapLeft = 0x16, + .tilemapTop = 0x0c, + .width = 0x07, + .height = 0x07, + .paletteNum = 0x0e, + .baseBlock = 0x0155 +}; + +const struct WindowTemplate sWindowTemplate_7by6 = { + .bg = 0x00, + .tilemapLeft = 0x16, + .tilemapTop = 0x0e, + .width = 0x07, + .height = 0x05, + .paletteNum = 0x0e, + .baseBlock = 0x0155 +}; + +const struct WindowTemplate sWindowTemplate_7by4 = { + .bg = 0x00, + .tilemapLeft = 0x16, + .tilemapTop = 0x0f, + .width = 0x07, + .height = 0x04, + .paletteNum = 0x0e, + .baseBlock = 0x0155 +}; + +const struct ListMenuItem sListMenuItems_CardsOrNews[] = { + { gText_WonderCards, 0 }, + { gText_WonderNews, 1 }, + { gText_Exit3, -2 } +}; + +const struct ListMenuItem sListMenuItems_WirelessOrFriend[] = { + { gText_WirelessCommunication, 0 }, + { gText_Friend2, 1 }, + { gFameCheckerText_Cancel, -2 } +}; + +const struct ListMenuTemplate sListMenuTemplate_ThreeOptions = { + .items = NULL, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 3, + .maxShowed = 3, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 0, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 2, + .cursorKind = 0 +}; + +const struct ListMenuItem sListMenuItems_ReceiveSendToss[] = { + { gText_Receive, 0 }, + { gText_Send, 1 }, + { gText_Toss, 2 }, + { gFameCheckerText_Cancel, -2 } +}; + +const struct ListMenuItem sListMenuItems_ReceiveToss[] = { + { gText_Receive, 0 }, + { gText_Toss, 2 }, + { gFameCheckerText_Cancel, -2 } +}; + +const struct ListMenuItem sListMenuItems_ReceiveSend[] = { + { gText_Receive, 0 }, + { gText_Send, 1 }, + { gFameCheckerText_Cancel, -2 } +}; + +const struct ListMenuItem sListMenuItems_Receive[] = { + { gText_Receive, 0 }, + { gFameCheckerText_Cancel, -2 } +}; + +const struct ListMenuTemplate sListMenu_ReceiveSendToss = { + .items = sListMenuItems_ReceiveSendToss, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 4, + .maxShowed = 4, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 2, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 2, + .cursorKind = 0 +}; + +const struct ListMenuTemplate sListMenu_ReceiveToss = { + .items = sListMenuItems_ReceiveToss, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 3, + .maxShowed = 3, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 0, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 2, + .cursorKind = 0 +}; + +const struct ListMenuTemplate sListMenu_ReceiveSend = { + .items = sListMenuItems_ReceiveSend, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 3, + .maxShowed = 3, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 0, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = 0, + .fontId = 2, + .cursorKind = 0 +}; + +const struct ListMenuTemplate sListMenu_Receive = { + .items = sListMenuItems_Receive, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = NULL, + .totalItems = 2, + .maxShowed = 2, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 0, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 2, + .scrollMultiple = 0, + .fontId = 2, + .cursorKind = 0 +}; + +const u8 *const Unref_08366ED8[] = { + gText_VarietyOfEventsImportedWireless, + gText_WonderCardsInPossession, + gText_ReadNewsThatArrived, + gText_ReturnToTitle +}; + +ALIGNED(4) const struct TextColor sMG_Ereader_TextColor_1 = { 0, 1, 2 }; +ALIGNED(4) const struct TextColor sMG_Ereader_TextColor_1_Copy = { 0, 1, 2 }; +ALIGNED(4) const struct TextColor sMG_Ereader_TextColor_2 = { 1, 2, 3 }; + +const u8 gUnknown_8466EF3[] = _("テスト"); +const u8 gUnknown_8466EF7[] = _("むげんのチケット"); + +void vblankcb_mystery_gift_e_reader_run(void) +{ + ProcessSpriteCopyRequests(); + LoadOam(); + TransferPlttBuffer(); +} + +void c2_mystery_gift_e_reader_run(void) +{ + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); +} + +bool32 HandleMysteryGiftOrEReaderSetup(s32 mg_or_ereader) +{ + switch (gMain.state) + { + case 0: + SetVBlankCallback(NULL); + ResetPaletteFade(); + ResetSpriteData(); + FreeAllSpritePalettes(); + ResetTasks(); + ScanlineEffect_Stop(); + ResetBgsAndClearDma3BusyFlags(1); + + InitBgsFromTemplates(0, sBGTemplates, ARRAY_COUNT(sBGTemplates)); + ChangeBgX(0, 0, 0); + ChangeBgY(0, 0, 0); + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(2, 0, 0); + ChangeBgY(2, 0, 0); + ChangeBgX(3, 0, 0); + ChangeBgY(3, 0, 0); + + SetBgTilemapBuffer(3, Alloc(0x800)); + SetBgTilemapBuffer(2, Alloc(0x800)); + SetBgTilemapBuffer(1, Alloc(0x800)); + SetBgTilemapBuffer(0, Alloc(0x800)); + + LoadUserWindowBorderGfx(0, 10, 0xE0); + sub_814FDA0(0, 1, 0xF0); + DecompressAndLoadBgGfxUsingHeap(3, gUnkTextboxBorderGfx, 0x100, 0, 0); + InitWindows(sMainWindows); + DeactivateAllTextPrinters(); + ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON | DISPCNT_WIN1_ON); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); + gMain.state++; + break; + case 1: + LoadPalette(gUnkTextboxBorderPal, 0, 0x20); + LoadPalette(stdpal_get(2), 0xd0, 0x20); + FillBgTilemapBufferRect(0, 0x000, 0, 0, 32, 32, 0x11); + FillBgTilemapBufferRect(1, 0x000, 0, 0, 32, 32, 0x11); + FillBgTilemapBufferRect(2, 0x000, 0, 0, 32, 32, 0x11); + MG_DrawCheckerboardPattern(); + PrintMysteryGiftOrEReaderTopMenu(mg_or_ereader, 0); + gMain.state++; + break; + case 2: + CopyBgTilemapBufferToVram(3); + CopyBgTilemapBufferToVram(2); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(0); + gMain.state++; + break; + case 3: + ShowBg(0); + ShowBg(3); + PlayBGM(BGM_FRLG_MYSTERY_GIFT); + SetVBlankCallback(vblankcb_mystery_gift_e_reader_run); + EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_VCOUNT | INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); + return TRUE; + } + + return FALSE; +} + +void c2_mystery_gift(void) +{ + if (HandleMysteryGiftOrEReaderSetup(0)) + { + SetMainCallback2(c2_mystery_gift_e_reader_run); + gGiftIsFromEReader = FALSE; + task_add_00_mystery_gift(); + } +} + +void c2_ereader(void) +{ + if (HandleMysteryGiftOrEReaderSetup(1)) + { + SetMainCallback2(c2_mystery_gift_e_reader_run); + gGiftIsFromEReader = TRUE; + task_add_00_ereader(); + } +} + +void MainCB_FreeAllBuffersAndReturnToInitTitleScreen(void) +{ + gGiftIsFromEReader = FALSE; + FreeAllWindowBuffers(); + Free(GetBgTilemapBuffer(0)); + Free(GetBgTilemapBuffer(1)); + Free(GetBgTilemapBuffer(2)); + Free(GetBgTilemapBuffer(3)); + SetMainCallback2(CB2_InitTitleScreen); +} + +void PrintMysteryGiftOrEReaderTopMenu(bool8 mg_or_ereader, bool32 usePickOkCancel) +{ + const u8 * src; + s32 width; + FillWindowPixelBuffer(0, 0x00); + if (!mg_or_ereader) + { + src = usePickOkCancel == TRUE ? gText_PickOKExit : gText_PickOKCancel; + AddTextPrinterParameterized4(0, 2, 2, 2, 0, 0, &sMG_Ereader_TextColor_1, 0, gText_MysteryGift); + width = 222 - GetStringWidth(0, src, 0); + AddTextPrinterParameterized4(0, 0, width, 2, 0, 0, &sMG_Ereader_TextColor_1, 0, src); + } + else + { + AddTextPrinterParameterized4(0, 2, 2, 2, 0, 0, &sMG_Ereader_TextColor_1, 0, gJPText_MysteryGift); + AddTextPrinterParameterized4(0, 0, 0x78, 2, 0, 0, &sMG_Ereader_TextColor_1, 0, gJPText_DecideStop); + } + CopyWindowToVram(0, 2); + PutWindowTilemap(0); +} + +void MG_DrawTextBorder(u8 windowId) +{ + DrawTextBorderOuter(windowId, 0x01, 0xF); +} + +void MG_DrawCheckerboardPattern(void) +{ + s32 i = 0, j; + + FillBgTilemapBufferRect(3, 0x003, 0, 0, 32, 2, 0x11); + + for (i = 0; i < 18; i++) + { + for (j = 0; j < 32; j++) + { + if ((i & 1) != (j & 1)) + { + FillBgTilemapBufferRect(3, 1, j, i + 2, 1, 1, 0x11); + } + else + { + FillBgTilemapBufferRect(3, 2, j, i + 2, 1, 1, 0x11); + } + } + } +} + +void ClearScreenInBg0(bool32 ignoreTopTwoRows) +{ + switch (ignoreTopTwoRows) + { + case 0: + FillBgTilemapBufferRect(0, 0, 0, 0, 32, 32, 0x11); + break; + case 1: + FillBgTilemapBufferRect(0, 0, 0, 2, 32, 30, 0x11); + break; + } + CopyBgTilemapBufferToVram(0); +} + +void AddTextPrinterToWindow1(const u8 *str) +{ + StringExpandPlaceholders(gStringVar4, str); + FillWindowPixelBuffer(1, 0x11); + AddTextPrinterParameterized4(1, 2, 0, 2, 0, 2, &sMG_Ereader_TextColor_2, 0, gStringVar4); + DrawTextBorderOuter(1, 0x001, 0xF); + PutWindowTilemap(1); + CopyWindowToVram(1, 3); +} + +void ClearTextWindow(void) +{ + rbox_fill_rectangle(1); + ClearWindowTilemap(1); + CopyWindowToVram(1, 1); +} + +bool32 MG_PrintTextOnWindow1AndWaitButton(u8 *textState, const u8 *str) +{ + switch (*textState) + { + case 0: + AddTextPrinterToWindow1(str); + goto inc; + case 1: + DrawDownArrow(1, 0xD0, 0x14, 1, FALSE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + inc: + (*textState)++; + } + break; + case 2: + DrawDownArrow(1, 0xD0, 0x14, 1, TRUE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); + *textState = 0; + ClearTextWindow(); + return TRUE; + case 0xFF: + *textState = 2; + break; + } + return FALSE; +} + +void HideDownArrow(void) +{ + DrawDownArrow(1, 0xD0, 0x14, 1, FALSE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); +} + +void ShowDownArrow(void) +{ + DrawDownArrow(1, 0xD0, 0x14, 1, TRUE, &sDownArrowCounterAndYCoordIdx[0], &sDownArrowCounterAndYCoordIdx[1]); +} + +bool32 unref_HideDownArrowAndWaitButton(u8 * textState) +{ + switch (*textState) + { + case 0: + HideDownArrow(); + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + (*textState)++; + } + break; + case 1: + ShowDownArrow(); + *textState = 0; + return TRUE; + } + return FALSE; +} + +bool32 PrintStringAndWait2Seconds(u8 * counter, const u8 * str) +{ + if (*counter == 0) + { + AddTextPrinterToWindow1(str); + } + if (++(*counter) > 120) + { + *counter = 0; + ClearTextWindow(); + return TRUE; + } + else + { + return FALSE; + } +} + +u32 MysteryGift_HandleThreeOptionMenu(u8 * unused0, u16 * unused1, u8 whichMenu) +{ + struct ListMenuTemplate listMenuTemplate = sListMenuTemplate_ThreeOptions; + struct WindowTemplate windowTemplate = sWindowTemplate_ThreeOptions; + u32 width; + s32 finalWidth; + s32 response; + u32 i; + + if (whichMenu == 0) + { + listMenuTemplate.items = sListMenuItems_CardsOrNews; + } + else + { + listMenuTemplate.items = sListMenuItems_WirelessOrFriend; + } + width = 0; + for (i = 0; i < listMenuTemplate.totalItems; i++) + { + u32 curWidth = GetStringWidth(2, listMenuTemplate.items[i].label, listMenuTemplate.lettersSpacing); + if (curWidth > width) + width = curWidth; + } + finalWidth = (((width + 9) / 8) + 2) & ~1; + windowTemplate.width = finalWidth; + windowTemplate.tilemapLeft = (30 - finalWidth) / 2; + response = DoMysteryGiftListMenu(&windowTemplate, &listMenuTemplate, 1, 0x00A, 0xE0); + if (response != -1) + { + ClearWindowTilemap(2); + CopyWindowToVram(2, 1); + } + return response; +} + +s8 mevent_message_print_and_prompt_yes_no(u8 * textState, u16 * windowId, bool8 yesNoBoxPlacement, const u8 * str) +{ + struct WindowTemplate windowTemplate; + s8 input; + + switch (*textState) + { + case 0: + StringExpandPlaceholders(gStringVar4, str); + if (yesNoBoxPlacement == 0) + { + *windowId = AddWindow(&sWindowTemplate_PromptYesOrNo_Width28); + } + else + { + *windowId = AddWindow(&sWindowTemplate_PromptYesOrNo_Width20); + } + FillWindowPixelBuffer(*windowId, 0x11); + AddTextPrinterParameterized4(*windowId, 2, 0, 2, 0, 2, &sMG_Ereader_TextColor_2, 0, gStringVar4); + DrawTextBorderOuter(*windowId, 0x001, 0x0F); + CopyWindowToVram(*windowId, 2); + PutWindowTilemap(*windowId); + (*textState)++; + break; + case 1: + windowTemplate = sWindowTemplate_YesNoBox; + if (yesNoBoxPlacement == 0) + { + windowTemplate.tilemapTop = 9; + } + else + { + windowTemplate.tilemapTop = 15; + } + CreateYesNoMenu(&windowTemplate, 2, 0, 2, 10, 14, 0); + (*textState)++; + break; + case 2: + input = Menu_ProcessInputNoWrapClearOnChoose(); + if (input == -1 || input == 0 || input == 1) + { + *textState = 0; + rbox_fill_rectangle(*windowId); + ClearWindowTilemap(*windowId); + CopyWindowToVram(*windowId, 1); + RemoveWindow(*windowId); + return input; + } + break; + case 0xFF: + *textState = 0; + rbox_fill_rectangle(*windowId); + ClearWindowTilemap(*windowId); + CopyWindowToVram(*windowId, 1); + RemoveWindow(*windowId); + return -1; + } + + return -2; +} + +s32 HandleMysteryGiftListMenu(u8 * textState, u16 * windowId, bool32 cannotToss, bool32 cannotSend) +{ + struct WindowTemplate windowTemplate; + s32 input; + + switch (*textState) + { + case 0: + if (cannotToss == 0) + { + StringExpandPlaceholders(gStringVar4, gText_WhatToDoWithCards); + } + else + { + StringExpandPlaceholders(gStringVar4, gText_WhatToDoWithNews); + } + *windowId = AddWindow(&sMysteryGiftMenuWindowTemplate); + FillWindowPixelBuffer(*windowId, 0x11); + AddTextPrinterParameterized4(*windowId, 2, 0, 2, 0, 2, &sMG_Ereader_TextColor_2, 0, gStringVar4); + DrawTextBorderOuter(*windowId, 0x001, 0x0F); + CopyWindowToVram(*windowId, 2); + PutWindowTilemap(*windowId); + (*textState)++; + break; + case 1: + windowTemplate = sWindowTemplate_YesNoBox; + if (cannotSend) + { + if (cannotToss == 0) + { + input = DoMysteryGiftListMenu(&sWindowTemplate_7by6, &sListMenu_ReceiveToss, 1, 0x00A, 0xE0); + } + else + { + input = DoMysteryGiftListMenu(&sWindowTemplate_7by4, &sListMenu_Receive, 1, 0x00A, 0xE0); + } + } + else + { + if (cannotToss == 0) + { + input = DoMysteryGiftListMenu(&sWindowTemplate_7by8, &sListMenu_ReceiveSendToss, 1, 0x00A, 0xE0); + } + else + { + input = DoMysteryGiftListMenu(&sWindowTemplate_7by6, &sListMenu_ReceiveSend, 1, 0x00A, 0xE0); + } + } + if (input != -1) + { + *textState = 0; + rbox_fill_rectangle(*windowId); + ClearWindowTilemap(*windowId); + CopyWindowToVram(*windowId, 1); + RemoveWindow(*windowId); + return input; + } + break; + case 0xFF: + *textState = 0; + rbox_fill_rectangle(*windowId); + ClearWindowTilemap(*windowId); + CopyWindowToVram(*windowId, 1); + RemoveWindow(*windowId); + return -2; + } + + return -1; +} + +bool32 ValidateCardOrNews(bool32 cardOrNews) +{ + if (cardOrNews == 0) + { + return ValidateReceivedWonderCard(); + } + else + { + return ValidateReceivedWonderNews(); + } +} + +bool32 HandleLoadWonderCardOrNews(u8 * state, bool32 cardOrNews) +{ + s32 v0; + + switch (*state) + { + case 0: + if (cardOrNews == 0) + { + InitWonderCardResources(GetSavedWonderCard(), sav1_get_mevent_buffer_2()); + } + else + { + InitWonderNewsResources(GetSavedWonderNews()); + } + (*state)++; + break; + case 1: + if (cardOrNews == 0) + { + v0 = FadeToWonderCardMenu(); + check: + if (v0 != 0) + { + goto done; + } + break; + } + else + { + v0 = FadeToWonderNewsMenu(); + goto check; + } + done: + *state = 0; + return TRUE; + } + + return FALSE; +} + +bool32 DestroyNewsOrCard(bool32 cardOrNews) +{ + if (cardOrNews == 0) + { + DestroyWonderCard(); + } + else + { + DestroyWonderNews(); + } + return TRUE; +} + +bool32 TearDownCardOrNews_ReturnToTopMenu(bool32 cardOrNews, bool32 arg1) +{ + if (cardOrNews == 0) + { + if (FadeOutFromWonderCard(arg1) != 0) + { + DestroyWonderCardResources(); + return TRUE; + } + else + { + return FALSE; + } + } + else + { + if (FadeOutFromWonderNews(arg1) != 0) + { + DestroyWonderNewsResources(); + return TRUE; + } + else + { + return FALSE; + } + } +} + +s32 mevent_message_prompt_discard(u8 * textState, u16 * windowId, bool32 cardOrNews) +{ + if (cardOrNews == 0) + { + return mevent_message_print_and_prompt_yes_no(textState, windowId, TRUE, gText_IfThrowAwayCardEventWontHappen); + } + else + { + return mevent_message_print_and_prompt_yes_no(textState, windowId, TRUE, gText_OkayToDiscardNews); + } +} + +bool32 mevent_message_was_thrown_away(u8 * textState, bool32 cardOrNews) +{ + if (cardOrNews == 0) + { + return MG_PrintTextOnWindow1AndWaitButton(textState, gText_WonderCardThrownAway); + } + else + { + return MG_PrintTextOnWindow1AndWaitButton(textState, gText_WonderNewsThrownAway); + } +} + +bool32 mevent_save_game(u8 * state) +{ + switch (*state) + { + case 0: + AddTextPrinterToWindow1(gText_DataWillBeSaved); + (*state)++; + break; + case 1: + TrySavingData(0); + (*state)++; + break; + case 2: + AddTextPrinterToWindow1(gText_SaveCompletedPressA); + (*state)++; + break; + case 3: + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + (*state)++; + } + break; + case 4: + *state = 0; + ClearTextWindow(); + return TRUE; + } + + return FALSE; +} + +const u8 * mevent_message(u32 * flag_p, u8 cardOrNews, u8 cardOrNewsSource, u32 msgId) +{ + const u8 * msg = NULL; + *flag_p = 0; + + switch (msgId) + { + case 0: + *flag_p = 0; + msg = gText_NothingSentOver; + break; + case 1: + *flag_p = 0; + msg = gText_RecordUploadedViaWireless; + break; + case 2: + *flag_p = 1; + msg = cardOrNewsSource == 0 ? gText_WonderCardReceived : gText_WonderCardReceivedFrom; + break; + case 3: + *flag_p = 1; + msg = cardOrNewsSource == 0 ? gText_WonderNewsReceived : gText_WonderNewsReceivedFrom; + break; + case 4: + *flag_p = 1; + msg = gText_NewStampReceived; + break; + case 5: + *flag_p = 0; + msg = gText_AlreadyHadCard; + break; + case 6: + *flag_p = 0; + msg = gText_AlreadyHadStamp; + break; + case 7: + *flag_p = 0; + msg = gText_AlreadyHadNews; + break; + case 8: + *flag_p = 0; + msg = gText_NoMoreRoomForStamps; + break; + case 9: + *flag_p = 0; + msg = gText_CommunicationCanceled; + break; + case 10: + *flag_p = 0; + msg = cardOrNews == 0 ? gText_CantAcceptCardFromTrainer : gText_CantAcceptNewsFromTrainer; + break; + case 11: + *flag_p = 0; + msg = gText_CommunicationError; + break; + case 12: + *flag_p = 1; + msg = gText_NewTrainerReceived; + break; + case 13: + *flag_p = 1; + break; + case 14: + *flag_p = 0; + break; + } + + return msg; +} + +bool32 PrintMGSuccessMessage(u8 * state, const u8 * arg1, u16 * arg2) +{ + switch (*state) + { + case 0: + if (arg1 != NULL) + { + AddTextPrinterToWindow1(arg1); + } + PlayFanfare(MUS_FANFA4); + *arg2 = 0; + (*state)++; + break; + case 1: + if (++(*arg2) > 0xF0) + { + (*state)++; + } + break; + case 2: + if (IsFanfareTaskInactive()) + { + *state = 0; + ClearTextWindow(); + return TRUE; + } + break; + } + return FALSE; +} + +const u8 * mevent_message_stamp_card_etc_send_status(u32 * a0, u8 unused, u32 msgId) +{ + const u8 * result = gText_CommunicationError; + *a0 = 0; + switch (msgId) + { + case 0: + result = gText_NothingSentOver; + break; + case 1: + result = gText_RecordUploadedViaWireless; + break; + case 2: + result = gText_WonderCardSentTo; + *a0 = 1; + break; + case 3: + result = gText_WonderNewsSentTo; + *a0 = 1; + break; + case 4: + result = gText_StampSentTo; + break; + case 5: + result = gText_OtherTrainerHasCard; + break; + case 6: + result = gText_OtherTrainerHasStamp; + break; + case 7: + result = gText_OtherTrainerHasNews; + break; + case 8: + result = gText_NoMoreRoomForStamps; + break; + case 9: + result = gText_OtherTrainerCanceled; + break; + case 10: + result = gText_CantSendGiftToTrainer; + break; + case 11: + result = gText_CommunicationError; + break; + case 12: + result = gText_GiftSentTo; + break; + case 13: + result = gText_GiftSentTo; + break; + case 14: + result = gText_CantSendGiftToTrainer; + break; + } + return result; +} + +bool32 PrintMGSendStatus(u8 * state, u16 * arg1, u8 arg2, u32 msgId) +{ + u32 flag; + const u8 * str = mevent_message_stamp_card_etc_send_status(&flag, arg2, msgId); + if (flag) + { + return PrintMGSuccessMessage(state, str, arg1); + } + else + { + return MG_PrintTextOnWindow1AndWaitButton(state, str); + } +} + +void task_add_00_mystery_gift(void) +{ + u8 taskId = CreateTask(task00_mystery_gift, 0); + struct MysteryGiftTaskData * data = (void *)gTasks[taskId].data; + data->state = 0; + data->textState = 0; + data->unkA = 0; + data->unkB = 0; + data->IsCardOrNews = 0; + data->source = 0; + data->curPromptWindowId = 0; + data->unk2 = 0; + data->unk4 = 0; + data->unk6 = 0; + data->prevPromptWindowId = 0; + data->buffer = AllocZeroed(0x40); +} + +void task00_mystery_gift(u8 taskId) +{ + struct MysteryGiftTaskData * data = (void *)gTasks[taskId].data; + u32 sp0; + const u8 * r1; + + switch (data->state) + { + case 0: + data->state = 1; + break; + case 1: + switch (MysteryGift_HandleThreeOptionMenu(&data->textState, &data->curPromptWindowId, FALSE)) + { + case 0: + data->IsCardOrNews = 0; + if (ValidateReceivedWonderCard() == TRUE) + { + data->state = 18; + } + else + { + data->state = 2; + } + break; + case 1: + data->IsCardOrNews = 1; + if (ValidateReceivedWonderNews() == TRUE) + { + data->state = 18; + } + else + { + data->state = 2; + } + break; + case -2u: + data->state = 37; + break; + } + break; + case 2: + { + if (data->IsCardOrNews == 0) + { + if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, gText_DontHaveCardNewOneInput)) + { + data->state = 3; + PrintMysteryGiftOrEReaderTopMenu(0, 1); + } + } + else + { + if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, gText_DontHaveNewsNewOneInput)) + { + data->state = 3; + PrintMysteryGiftOrEReaderTopMenu(0, 1); + } + } + break; + } + case 3: + if (data->IsCardOrNews == 0) + { + AddTextPrinterToWindow1(gText_WhereShouldCardBeAccessed); + } + else + { + AddTextPrinterToWindow1(gText_WhereShouldNewsBeAccessed); + } + data->state = 4; + break; + case 4: + switch (MysteryGift_HandleThreeOptionMenu(&data->textState, &data->curPromptWindowId, TRUE)) + { + case 0: + ClearTextWindow(); + data->state = 5; + data->source = 0; + break; + case 1: + ClearTextWindow(); + data->state = 5; + data->source = 1; + break; + case -2u: + ClearTextWindow(); + if (ValidateCardOrNews(data->IsCardOrNews)) + { + data->state = 18; + } + else + { + data->state = 0; + PrintMysteryGiftOrEReaderTopMenu(0, 0); + } + break; + } + break; + case 5: + { + register u8 eos asm("r1"); + gStringVar1[0] = (eos = EOS); + gStringVar2[0] = eos; + gStringVar3[0] = eos; + } + switch (data->IsCardOrNews) + { + case 0: + if (data->source == 1) + { + MEvent_CreateTask_CardOrNewsWithFriend(0x15); + } + else if (data->source == 0) + { + MEvent_CreateTask_CardOrNewsOverWireless(0x15); + } + break; + case 1: + if (data->source == 1) + { + MEvent_CreateTask_CardOrNewsWithFriend(0x16); + } + else if (data->source == 0) + { + MEvent_CreateTask_CardOrNewsOverWireless(0x16); + } + break; + } + data->state = 6; + break; + case 6: + if (gReceivedRemoteLinkPlayers != 0) + { + ClearScreenInBg0(TRUE); + data->state = 7; + mevent_client_do_init(); + } + else if (gSpecialVar_Result == 5) + { + ClearScreenInBg0(TRUE); + data->state = 3; + } + break; + case 7: + AddTextPrinterToWindow1(gText_Communicating); + data->state = 8; + break; + case 8: + switch (mevent_client_do_exec(&data->curPromptWindowId)) + { + case 6: + task_add_05_task_del_08FA224_when_no_RfuFunc(); + data->prevPromptWindowId = data->curPromptWindowId; + data->state = 13; + break; + case 5: + memcpy(data->buffer, mevent_client_get_buffer(), 0x40); + mevent_client_inc_flag(); + break; + case 3: + data->state = 10; + break; + case 2: + data->state = 9; + break; + case 4: + data->state = 11; + StringCopy(gStringVar1, gLinkPlayers[0].name); + break; + } + break; + case 9: + switch ((u32)mevent_message_print_and_prompt_yes_no(&data->textState, &data->curPromptWindowId, FALSE, mevent_client_get_buffer())) + { + case 0: + mevent_client_set_param(0); + mevent_client_inc_flag(); + data->state = 7; + break; + case 1: + mevent_client_set_param(1); + mevent_client_inc_flag(); + data->state = 7; + break; + case -1u: + mevent_client_set_param(1); + mevent_client_inc_flag(); + data->state = 7; + break; + } + break; + case 10: + if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, mevent_client_get_buffer())) + { + mevent_client_inc_flag(); + data->state = 7; + } + break; + case 11: + switch ((u32)mevent_message_print_and_prompt_yes_no(&data->textState, &data->curPromptWindowId, FALSE, gText_ThrowAwayWonderCard)) + { + case 0: + if (CheckReceivedGiftFromWonderCard() == TRUE) + { + data->state = 12; + } + else + { + mevent_client_set_param(0); + mevent_client_inc_flag(); + data->state = 7; + } + break; + case 1: + mevent_client_set_param(1); + mevent_client_inc_flag(); + data->state = 7; + break; + case -1u: + mevent_client_set_param(1); + mevent_client_inc_flag(); + data->state = 7; + break; + } + break; + case 12: + switch ((u32)mevent_message_print_and_prompt_yes_no(&data->textState, &data->curPromptWindowId, FALSE, gText_HaventReceivedCardsGift)) + { + case 0: + mevent_client_set_param(0); + mevent_client_inc_flag(); + data->state = 7; + break; + case 1: + mevent_client_set_param(1); + mevent_client_inc_flag(); + data->state = 7; + break; + case -1u: + mevent_client_set_param(1); + mevent_client_inc_flag(); + data->state = 7; + break; + } + break; + case 13: + if (IsNoOneConnected()) + { + DestroyWirelessStatusIndicatorSprite(); + data->state = 14; + } + break; + case 14: + if (PrintStringAndWait2Seconds(&data->textState, gText_CommunicationCompleted)) + { + if (data->source == 1) + { + StringCopy(gStringVar1, gLinkPlayers[0].name); + } + data->state = 15; + } + break; + case 15: + { + register bool32 flag asm("r1"); + r1 = mevent_message(&sp0, data->IsCardOrNews, data->source, data->prevPromptWindowId); + if (r1 == NULL) + { + r1 = data->buffer; + } + if (sp0) + { + flag = PrintMGSuccessMessage(&data->textState, r1, &data->curPromptWindowId); + } + else + { + flag = MG_PrintTextOnWindow1AndWaitButton(&data->textState, r1); + } + if (flag) + { + if (data->prevPromptWindowId == 3) + { + if (data->source == 1) + { + GenerateRandomNews(1); + } + else + { + GenerateRandomNews(2); + } + } + if (sp0 == 0) + { + data->state = 0; + PrintMysteryGiftOrEReaderTopMenu(0, 0); + } + else + { + data->state = 17; + } + } + break; + } + case 16: + if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, gText_CommunicationError)) + { + data->state = 0; + PrintMysteryGiftOrEReaderTopMenu(0, 0); + } + break; + case 17: + if (mevent_save_game(&data->textState)) + { + data->state = 0; + PrintMysteryGiftOrEReaderTopMenu(0, 0); + } + break; + case 18: + if (HandleLoadWonderCardOrNews(&data->textState, data->IsCardOrNews)) + { + data->state = 20; + } + break; + case 20: + if (data->IsCardOrNews == 0) + { + if (JOY_NEW(A_BUTTON)) + { + data->state = 21; + } + if (JOY_NEW(B_BUTTON)) + { + data->state = 27; + } + } + else + { + switch (MENews_GetInput(gMain.newKeys)) + { + case 0: + MENews_RemoveScrollIndicatorArrowPair(); + data->state = 21; + break; + case 1: + data->state = 27; + break; + } + } + break; + case 21: + { + u32 result; + if (data->IsCardOrNews == 0) + { + if (WonderCard_Test_Unk_08_6()) + { + result = HandleMysteryGiftListMenu(&data->textState, &data->curPromptWindowId, data->IsCardOrNews, FALSE); + } + else + { + result = HandleMysteryGiftListMenu(&data->textState, &data->curPromptWindowId, data->IsCardOrNews, TRUE); + } + } + else + { + if (WonderNews_Test_Unk_02()) + { + result = HandleMysteryGiftListMenu(&data->textState, &data->curPromptWindowId, data->IsCardOrNews, FALSE); + } + else + { + result = HandleMysteryGiftListMenu(&data->textState, &data->curPromptWindowId, data->IsCardOrNews, TRUE); + } + } + switch (result) + { + case 0: + data->state = 28; + break; + case 1: + data->state = 29; + break; + case 2: + data->state = 22; + break; + case -2u: + if (data->IsCardOrNews == 1) + { + MENews_AddScrollIndicatorArrowPair(); + } + data->state = 20; + break; + } + break; + } + case 22: + switch (mevent_message_prompt_discard(&data->textState, &data->curPromptWindowId, data->IsCardOrNews)) + { + case 0: + if (data->IsCardOrNews == 0 && CheckReceivedGiftFromWonderCard() == TRUE) + { + data->state = 23; + } + else + { + data->state = 24; + } + break; + case 1: + data->state = 21; + break; + case -1: + data->state = 21; + break; + } + break; + case 23: + switch ((u32)mevent_message_print_and_prompt_yes_no(&data->textState, &data->curPromptWindowId, TRUE, gText_HaventReceivedGiftOkayToDiscard)) + { + case 0: + data->state = 24; + break; + case 1: + data->state = 21; + break; + case -1u: + data->state = 21; + break; + } + break; + case 24: + if (TearDownCardOrNews_ReturnToTopMenu(data->IsCardOrNews, 1)) + { + DestroyNewsOrCard(data->IsCardOrNews); + data->state = 25; + } + break; + case 25: + if (mevent_save_game(&data->textState)) + { + data->state = 26; + } + break; + case 26: + if (mevent_message_was_thrown_away(&data->textState, data->IsCardOrNews)) + { + data->state = 0; + PrintMysteryGiftOrEReaderTopMenu(0, 0); + } + break; + case 27: + if (TearDownCardOrNews_ReturnToTopMenu(data->IsCardOrNews, 0)) + { + data->state = 0; + } + break; + case 28: + if (TearDownCardOrNews_ReturnToTopMenu(data->IsCardOrNews, 1)) + { + data->state = 3; + } + break; + case 29: + if (TearDownCardOrNews_ReturnToTopMenu(data->IsCardOrNews, 1)) + { + switch (data->IsCardOrNews) + { + case 0: + MEvent_CreateTask_Leader(21); + break; + case 1: + MEvent_CreateTask_Leader(22); + break; + } + data->source = 1; + data->state = 30; + } + break; + case 30: + if (gReceivedRemoteLinkPlayers != 0) + { + ClearScreenInBg0(1); + data->state = 31; + } + else if (gSpecialVar_Result == 5) + { + ClearScreenInBg0(1); + data->state = 18; + } + break; + case 31: + { + register u8 eos asm("r1"); + gStringVar1[0] = (eos = EOS); + gStringVar2[0] = eos; + gStringVar3[0] = eos; + } + if (data->IsCardOrNews == 0) + { + AddTextPrinterToWindow1(gText_SendingWonderCard); + mevent_srv_new_wcard(); + } + else + { + AddTextPrinterToWindow1(gText_SendingWonderNews); + mevent_srv_init_wnews(); + } + data->state = 32; + break; + case 32: + if (mevent_srv_common_do_exec(&data->curPromptWindowId) == 3) + { + data->prevPromptWindowId = data->curPromptWindowId; + data->state = 33; + } + break; + case 33: + task_add_05_task_del_08FA224_when_no_RfuFunc(); + StringCopy(gStringVar1, gLinkPlayers[1].name); + data->state = 34; + break; + case 34: + if (IsNoOneConnected()) + { + DestroyWirelessStatusIndicatorSprite(); + data->state = 35; + } + break; + case 35: + if (PrintMGSendStatus(&data->textState, &data->curPromptWindowId, data->source, data->prevPromptWindowId)) + { + if (data->source == 1 && data->prevPromptWindowId == 3) + { + GenerateRandomNews(3); + data->state = 17; + } + else + { + data->state = 0; + PrintMysteryGiftOrEReaderTopMenu(0, 0); + } + } + break; + case 36: + if (MG_PrintTextOnWindow1AndWaitButton(&data->textState, gText_CommunicationError)) + { + data->state = 0; + PrintMysteryGiftOrEReaderTopMenu(0, 0); + } + break; + case 37: + CloseLink(); + sub_812B484(); + Free(data->buffer); + DestroyTask(taskId); + SetMainCallback2(MainCB_FreeAllBuffersAndReturnToInitTitleScreen); + break; + } +} + +u16 GetMysteryGiftBaseBlock(void) +{ + return 0x19B; +} diff --git a/src/oak_speech.c b/src/oak_speech.c new file mode 100644 index 000000000..3bf174778 --- /dev/null +++ b/src/oak_speech.c @@ -0,0 +1,1891 @@ +#include "global.h" +#include "main.h" +#include "decompress.h" +#include "task.h" +#include "malloc.h" +#include "gpu_regs.h" +#include "wild_encounter.h" +#include "palette.h" +#include "blend_palette.h" +#include "text.h" +#include "window.h" +#include "text_window.h" +#include "bg.h" +#include "menu.h" +#include "help_system.h" +#include "new_menu_helpers.h" +#include "pokemon_3.h" +#include "sound.h" +#include "event_scripts.h" +#include "scanline_effect.h" +#include "string_util.h" +#include "pokeball.h" +#include "naming_screen.h" +#include "math_util.h" +#include "overworld.h" +#include "random.h" +#include "oak_speech.h" +#include "constants/species.h" +#include "constants/songs.h" + +struct OakSpeechResources +{ + void * solidColorsGfx; + void * trainerPicTilemapBuffer; + void * unk_0008; + u8 filler_000C[4]; + u16 unk_0010; + u16 unk_0012; + u16 unk_0014[4]; + u8 unk_001C[3]; + u8 textSpeed; + u8 filler_0020[0x1800]; + u8 bg2TilemapBuffer[0x400]; + u8 bg1TilemapBuffer[0x800]; +}; //size=0x2420 + +EWRAM_DATA struct OakSpeechResources * sOakSpeechResources = NULL; + +static void Task_OaksSpeech1(u8 taskId); +static void CreateHelpDocsPage1(void); +static void Task_OaksSpeech2(u8 taskId); +static void Task_OakSpeech3(u8 taskId); +static void Task_OakSpeech5(u8 taskId); +static void Task_OakSpeech6(u8 taskId); +static void Task_OakSpeech7(u8 taskId); +static void Task_OakSpeech8(u8 taskId); +static void Task_OakSpeech9(u8 taskId); +static void Task_OakSpeech10(u8 taskId); +static void Task_OakSpeech10(u8 taskId); +static void Task_OakSpeech11(u8 taskId); +static void Task_OakSpeech12(u8 taskId); +static void Task_OakSpeech13(u8 taskId); +static void Task_OakSpeech14(u8 taskId); +static void Task_OakSpeech15(u8 taskId); +static void Task_OakSpeech16(u8 taskId); +static void Task_OakSpeech17(u8 taskId); +static void Task_OakSpeech18(u8 taskId); +static void Task_OakSpeech19(u8 taskId); +static void Task_OakSpeech20(u8 taskId); +static void Task_OakSpeech21(u8 taskId); +static void Task_OakSpeech22(u8 taskId); +static void Task_OakSpeech23(u8 taskId); +static void Task_OakSpeech24(u8 taskId); +static void Task_OakSpeech29(u8 taskId); +static void Task_OakSpeech25(u8 taskId); +static void Task_OakSpeech26(u8 taskId); +static void Task_OakSpeech27(u8 taskId); +static void Task_OakSpeech30(u8 taskId); +static void Task_OakSpeech31(u8 taskId); +static void Task_OakSpeech32(u8 taskId); +static void Task_OakSpeech34(u8 taskId); +static void Task_OakSpeech33(u8 taskId); +static void Task_OakSpeech36(u8 taskId); +static void Task_OakSpeech37(u8 taskId); +static void Task_OakSpeech38(u8 taskId); +static void Task_OakSpeech38_3(u8 taskId); +static void Task_OakSpeech39(u8 taskId); +static void Task_OakSpeech38_1(u8 taskId); +static void Task_OakSpeech38_sub1(u8 taskId); +static void Task_OakSpeech38_2(u8 taskId); +static void Task_OakSpeech38_sub2(u8 taskId); +static void Task_OakSpeech40(u8 taskId); +static void Task_OakSpeech41(u8 taskId); +static void Task_OakSpeech42(u8 taskId); + +static void CB2_ReturnFromNamingScreen(void); +static void CreateNidoranFSprite(u8 taskId); +static void CreatePikaOrGrassPlatformSpriteAndLinkToCurrentTask(u8 taskId, u8 state); +static void DestroyLinkedPikaOrGrassPlatformSprites(u8 taskId, u8 state); +static void LoadOaksSpeechTrainerPic(u16 whichPic, u16 tileOffset); +static void DestroyOaksSpeechTrainerPic(void); +static void CreateFadeInTask(u8 taskId, u8 state); +static void CreateFadeOutTask(u8 taskId, u8 state); +static void PrintNameChoiceOptions(u8 taskId, u8 state); +static void GetDefaultName(u8 arg0, u8 namePick); + +extern const u8 gText_Controls[]; +extern const u8 gText_ABUTTONNext[]; +extern const u8 gText_ABUTTONNext_BBUTTONBack[]; +extern const u8 gText_Boy[]; +extern const u8 gText_Girl[]; + +extern const struct CompressedSpriteSheet gUnknown_8235194[]; +extern const struct CompressedSpritePalette gUnknown_82373F4; + +ALIGNED(4) static const u16 sHelpDocsPalette[] = INCBIN_U16("data/oak_speech/help_docs_palette.gbapal"); +static const u32 sOakSpeechGfx_GameStartHelpUI[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_game_start_help_u_i.4bpp.lz"); +static const u32 sNewGameAdventureIntroTilemap[] = INCBIN_U32("data/oak_speech/new_game_adventure_intro_tilemap.bin.lz"); +static const u32 sOakSpeechGfx_SolidColors[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_solid_colors.4bpp.lz"); +static const u32 sOakSpeech_BackgroundTilemap[] = INCBIN_U32("data/oak_speech/oak_speech_background_tilemap.bin.lz"); +static const u16 sHelpDocsPage2Tilemap[] = INCBIN_U16("data/oak_speech/help_docs_page2_tilemap.bin"); +static const u16 sHelpDocsPage3Tilemap[] = INCBIN_U16("data/oak_speech/help_docs_page3_tilemap.bin"); +static const u16 sOakSpeechGfx_LeafPal[] = INCBIN_U16("data/oak_speech/oak_speech_gfx_leaf_pal.gbapal"); +static const u32 sOakSpeechGfx_LeafPic[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_leaf_pic.8bpp.lz"); +static const u16 sOakSpeechGfx_RedPal[] = INCBIN_U16("data/oak_speech/oak_speech_gfx_red_pal.gbapal"); +static const u32 sOakSpeechGfx_RedPic[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_red_pic.8bpp.lz"); +static const u16 sOakSpeechGfx_OakPal[] = INCBIN_U16("data/oak_speech/oak_speech_gfx_oak_pal.gbapal"); +static const u32 sOakSpeechGfx_OakPic[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_oak_pic.8bpp.lz"); +static const u16 sOakSpeechGfx_RivalPal[] = INCBIN_U16("data/oak_speech/oak_speech_gfx_rival_pal.gbapal"); +static const u32 sOakSpeechGfx_RivalPic[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_rival_pic.8bpp.lz"); +static const u16 sOakSpeech_GrassPlatformPalette[] = INCBIN_U16("data/oak_speech/oak_speech_grass_platform_palette.gbapal"); +static const u16 sOakSpeech_PikaPalette[] = INCBIN_U16("data/oak_speech/oak_speech_pika_palette.gbapal"); +static const u32 sOakSpeechGfx_GrassPlatform[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_grass_platform.4bpp.lz"); +static const u32 sOakSpeechGfx_Pika1[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_pika1.4bpp.lz"); +static const u32 sOakSpeechGfx_Pika2[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_pika2.4bpp.lz"); +static const u32 sOakSpeechGfx_PikaEyes[] = INCBIN_U32("data/oak_speech/oak_speech_gfx_pika_eyes.4bpp.lz"); + +static const struct BgTemplate sBgTemplates[3] = { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0x000 + }, { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0x000 + }, { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 28, + .screenSize = 1, + .paletteMode = 1, + .priority = 1, + .baseTile = 0x000 + } +}; + +static const struct WindowTemplate sHelpDocsWindowTemplates1[] = { + { + .bg = 0x00, + .tilemapLeft = 0x00, + .tilemapTop = 0x07, + .width = 0x1e, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x0001 + }, DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate sHelpDocsWindowTemplates2[] = { + { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x03, + .width = 0x18, + .height = 0x06, + .paletteNum = 0x0f, + .baseBlock = 0x0001 + }, { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x0a, + .width = 0x18, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x0092 + }, { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x0f, + .width = 0x18, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x00f3 + }, DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate sHelpDocsWindowTemplates3[] = { + { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x03, + .width = 0x18, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x0001 + }, { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x08, + .width = 0x18, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x0062 + }, { + .bg = 0x00, + .tilemapLeft = 0x06, + .tilemapTop = 0x0d, + .width = 0x18, + .height = 0x06, + .paletteNum = 0x0f, + .baseBlock = 0x00c3 + }, DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate *const sHelpDocsWindowTemplatePtrs[3] = { + sHelpDocsWindowTemplates1, + sHelpDocsWindowTemplates2, + sHelpDocsWindowTemplates3 +}; + +static const struct WindowTemplate sNewGameAdventureIntroWindowTemplates[] = { + { + .bg = 0x00, + .tilemapLeft = 0x01, + .tilemapTop = 0x04, + .width = 0x1c, + .height = 0x0f, + .paletteNum = 0x0f, + .baseBlock = 0x0001 + }, { + .bg = 0x00, + .tilemapLeft = 0x12, + .tilemapTop = 0x09, + .width = 0x09, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x0174 + }, { + .bg = 0x00, + .tilemapLeft = 0x02, + .tilemapTop = 0x02, + .width = 0x06, + .height = 0x04, + .paletteNum = 0x0f, + .baseBlock = 0x0180 + }, { + .bg = 0x00, + .tilemapLeft = 0x02, + .tilemapTop = 0x02, + .width = 0x0c, + .height = 0x0a, + .paletteNum = 0x0f, + .baseBlock = 0x0001 + }, DUMMY_WIN_TEMPLATE +}; + +ALIGNED(4) const struct TextColor sTextColor_HelpSystem = { + 0x00, 0x01, 0x02 +}; + +ALIGNED(4) const struct TextColor sTextColor_OakSpeech = { + 0x00, 0x02, 0x03 +}; + +static const u8 *const sNewGameAdventureIntroTextPointers[] = { + gNewGameAdventureIntro1, + gNewGameAdventureIntro2, + gNewGameAdventureIntro3 +}; + +static const struct CompressedSpriteSheet sOakSpeech_PikaSpriteSheets[3] = { + { (const void *)sOakSpeechGfx_Pika1, 0x0400, 0x1001 }, + { (const void *)sOakSpeechGfx_Pika2, 0x0200, 0x1002 }, + { (const void *)sOakSpeechGfx_PikaEyes, 0x0080, 0x1003 }, +}; + +static const struct CompressedSpriteSheet sOakSpeech_GrassPlatformSpriteSheet = { + (const void *)sOakSpeechGfx_GrassPlatform, 0x0600, 0x1000 +}; + +static const struct SpritePalette sOakSpeech_PikaSpritePal = { + (const void *)sOakSpeech_PikaPalette, 0x1001 +}; + +static const struct SpritePalette sOakSpeech_GrassPlatformSpritePal = { + (const void *)sOakSpeech_GrassPlatformPalette, 0x1000 +}; + +static const union AnimCmd sGrassPlatformAnim1[] = { + ANIMCMD_FRAME( 0, 0), + ANIMCMD_END +}; + +static const union AnimCmd sGrassPlatformAnim2[] = { + ANIMCMD_FRAME(16, 0), + ANIMCMD_END +}; + +static const union AnimCmd sGrassPlatformAnim3[] = { + ANIMCMD_FRAME(32, 0), + ANIMCMD_END +}; + +static const union AnimCmd *const sGrassPlatformAnims1[] = { + sGrassPlatformAnim1 +}; +static const union AnimCmd *const sGrassPlatformAnims2[] = { + sGrassPlatformAnim2 +}; +static const union AnimCmd *const sGrassPlatformAnims3[] = { + sGrassPlatformAnim3 +}; + +extern const struct OamData gOamData_83ACAF8; + +static const struct SpriteTemplate sOakSpeech_GrassPlatformSpriteTemplates[3] = { + { 0x1000, 0x1000, &gOamData_83ACAF8, sGrassPlatformAnims1, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy }, + { 0x1000, 0x1000, &gOamData_83ACAF8, sGrassPlatformAnims2, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy }, + { 0x1000, 0x1000, &gOamData_83ACAF8, sGrassPlatformAnims3, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy }, +}; + +static const union AnimCmd sPikaAnim1[] = { + ANIMCMD_FRAME( 0, 30), + ANIMCMD_FRAME(16, 30), + ANIMCMD_JUMP(0) +}; + +static const union AnimCmd sPikaAnim2[] = { + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(8, 12), + ANIMCMD_FRAME(0, 12), + ANIMCMD_FRAME(8, 12), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(8, 12), + ANIMCMD_FRAME(0, 12), + ANIMCMD_FRAME(8, 12), + ANIMCMD_JUMP(0) +}; + +static const union AnimCmd sPikaAnim3[] = { + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(2, 8), + ANIMCMD_FRAME(0, 8), + ANIMCMD_FRAME(2, 8), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(0, 60), + ANIMCMD_FRAME(2, 8), + ANIMCMD_FRAME(0, 8), + ANIMCMD_FRAME(2, 8), + ANIMCMD_JUMP(0) +}; + +static const union AnimCmd *const sPikaAnims1[] = { + sPikaAnim1 +}; +static const union AnimCmd *const sPikaAnims2[] = { + sPikaAnim2 +}; +static const union AnimCmd *const sPikaAnims3[] = { + sPikaAnim3 +}; + +extern const struct OamData gOamData_83AC9D8; +extern const struct OamData gOamData_83AC9F8; +extern const struct OamData gOamData_83AC9E8; + +static const struct SpriteTemplate sOakSpeech_PikaSpriteTemplates[3] = { + { 0x1001, 0x1001, &gOamData_83AC9D8, sPikaAnims1, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy }, + { 0x1002, 0x1001, &gOamData_83AC9F8, sPikaAnims2, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy }, + { 0x1003, 0x1001, &gOamData_83AC9E8, sPikaAnims3, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy } +}; + +static const u8 *const sHelpDocsPtrs[] = { + gNewGame_HelpDocs2, gNewGame_HelpDocs3, gNewGame_HelpDocs4, + gNewGame_HelpDocs5, gNewGame_HelpDocs6, gNewGame_HelpDocs7 +}; + +static const u8 *const sMaleNameChoices[] = { + gNameChoice_Red, + gNameChoice_Fire, + gNameChoice_Ash, + gNameChoice_Kene, + gNameChoice_Geki, + gNameChoice_Jak, + gNameChoice_Janne, + gNameChoice_Jonn, + gNameChoice_Kamon, + gNameChoice_Karl, + gNameChoice_Taylor, + gNameChoice_Oscar, + gNameChoice_Hiro, + gNameChoice_Max, + gNameChoice_Jon, + gNameChoice_Ralph, + gNameChoice_Kay, + gNameChoice_Tosh, + gNameChoice_Roak +}; + +static const u8 *const sFemaleNameChoices[] = { + gNameChoice_Red, + gNameChoice_Fire, + gNameChoice_Omi, + gNameChoice_Jodi, + gNameChoice_Amanda, + gNameChoice_Hillary, + gNameChoice_Makey, + gNameChoice_Michi, + gNameChoice_Paula, + gNameChoice_June, + gNameChoice_Cassie, + gNameChoice_Rey, + gNameChoice_Seda, + gNameChoice_Kiko, + gNameChoice_Mina, + gNameChoice_Norie, + gNameChoice_Sai, + gNameChoice_Momo, + gNameChoice_Suzi +}; + +static const u8 *const sRivalNameChoices[] = { + gNameChoice_Green, + gNameChoice_Gary, + gNameChoice_Kaz, + gNameChoice_Toru +}; + +static void VBlankCB_NewGameOaksSpeech(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void CB2_NewGameOaksSpeech(void) +{ + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +void StartNewGameScene(void) +{ + gPlttBufferUnfaded[0] = RGB_BLACK; + gPlttBufferFaded[0] = RGB_BLACK; + CreateTask(Task_OaksSpeech1, 0); + SetMainCallback2(CB2_NewGameOaksSpeech); +} + +static void Task_OaksSpeech1(u8 taskId) +{ + switch (gMain.state) + { + case 0: + SetVBlankCallback(NULL); + SetHBlankCallback(NULL); + DmaFill16(3, 0, VRAM, VRAM_SIZE); + DmaFill32(3, 0, OAM, OAM_SIZE); + DmaFill16(3, 0, PLTT + sizeof(u16), PLTT_SIZE - 2); + ResetPaletteFade(); + ScanlineEffect_Stop(); + ResetSpriteData(); + FreeAllSpritePalettes(); + reset_temp_tile_data_buffers(); + HelpSystem_SetSomeVariable2(2); + break; + case 1: + sOakSpeechResources = AllocZeroed(sizeof(*sOakSpeechResources)); + SetUpMonSpriteManagerMaybe(1, 1); + break; + case 2: + SetGpuReg(REG_OFFSET_WIN0H, 0); + SetGpuReg(REG_OFFSET_WIN0V, 0); + SetGpuReg(REG_OFFSET_WIN1H, 0); + SetGpuReg(REG_OFFSET_WIN1V, 0); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); + break; + case 3: + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(1, sBgTemplates, NELEMS(sBgTemplates)); + SetBgTilemapBuffer(1, sOakSpeechResources->bg1TilemapBuffer); + SetBgTilemapBuffer(2, sOakSpeechResources->bg2TilemapBuffer); + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(2, 0, 0); + ChangeBgY(2, 0, 0); + gSpriteCoordOffsetX = 0; + gSpriteCoordOffsetY = 0; + break; + case 4: + gPaletteFade.bufferTransferDisabled = TRUE; + InitStandardTextBoxWindows(); + ResetBg0(); + Menu_LoadStdPalAt(0xD0); + LoadPalette(sHelpDocsPalette, 0x000, 0x080); + LoadPalette(stdpal_get(2) + 15, 0x000, 0x002); + break; + case 5: + sOakSpeechResources->textSpeed = GetTextSpeedSetting(); + gTextFlags.canABSpeedUpPrint = TRUE; + decompress_and_copy_tile_data_to_vram(1, sOakSpeechGfx_GameStartHelpUI, 0, 0, 0); + break; + case 6: + if (free_temp_tile_data_buffers_if_possible()) + return; + ClearDialogWindowAndFrame(0, 1); + FillBgTilemapBufferRect_Palette0(1, 0x0000, 0, 0, 32, 32); + CopyBgTilemapBufferToVram(1); + break; + case 7: + CreateWindow_SnapRight_StdPal(0, 30, 0, 13, 0x1C4); + FillBgTilemapBufferRect_Palette0(1, 0xD00F, 0, 0, 30, 2); + FillBgTilemapBufferRect_Palette0(1, 0xD002, 0, 2, 30, 1); + FillBgTilemapBufferRect_Palette0(1, 0xD00E, 0, 19, 30, 1); + CreateHelpDocsPage1(); + gPaletteFade.bufferTransferDisabled = FALSE; + gTasks[taskId].data[5] = CreateTextCursorSpriteForOakSpeech(0, 0xE6, 0x95, 0, 0); + BlendPalettes(0xFFFFFFFF, 0x10, 0x00); + break; + case 10: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB_BLACK); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); + ShowBg(0); + ShowBg(1); + SetVBlankCallback(VBlankCB_NewGameOaksSpeech); + PlayBGM(BGM_FRLG_GAME_EXPLANATION_START); + gTasks[taskId].func = Task_OaksSpeech2; + gMain.state = 0; + return; + } + + gMain.state++; +} + +static void CreateHelpDocsPage1(void) +{ + Menu_PrintHelpSystemUIHeader(gText_Controls, gText_ABUTTONNext, 0, 0, 1); + sOakSpeechResources->unk_0014[0] = AddWindow(sHelpDocsWindowTemplatePtrs[sOakSpeechResources->unk_0012]); + PutWindowTilemap(sOakSpeechResources->unk_0014[0]); + FillWindowPixelBuffer(sOakSpeechResources->unk_0014[0], 0x00); + AddTextPrinterParameterized4(sOakSpeechResources->unk_0014[0], 2, 2, 0, 1, 1, &sTextColor_HelpSystem, 0, gNewGame_HelpDocs1); + CopyWindowToVram(sOakSpeechResources->unk_0014[0], 3); + FillBgTilemapBufferRect_Palette0(1, 0x3000, 1, 3, 5, 16); + CopyBgTilemapBufferToVram(1); +} + +static void Task_OakSpeech4(u8 taskId) +{ + u8 i = 0; + u8 r7 = sOakSpeechResources->unk_0012 - 1; + if (sOakSpeechResources->unk_0012 == 0) + { + CreateHelpDocsPage1(); + } + else + { + PrintTextOnRightSnappedWindow(gText_ABUTTONNext_BBUTTONBack, 0, 1); + for (i = 0; i < 3; i++) + { + sOakSpeechResources->unk_0014[i] = AddWindow(&sHelpDocsWindowTemplatePtrs[sOakSpeechResources->unk_0012][i]); + PutWindowTilemap(sOakSpeechResources->unk_0014[i]); + FillWindowPixelBuffer(sOakSpeechResources->unk_0014[i], 0x00); + AddTextPrinterParameterized4(sOakSpeechResources->unk_0014[i], 2, 6, 0, 1, 1, &sTextColor_HelpSystem, 0, sHelpDocsPtrs[i + r7 * 3]); + CopyWindowToVram(sOakSpeechResources->unk_0014[i], 3); + } + + if (sOakSpeechResources->unk_0012 == 1) + { + CopyToBgTilemapBufferRect(1, sHelpDocsPage2Tilemap, 1, 3, 5, 16); + } + else + { + CopyToBgTilemapBufferRect(1, sHelpDocsPage3Tilemap, 1, 3, 5, 16); + } + CopyBgTilemapBufferToVram(1); + } + BeginNormalPaletteFade(0xFFFFDFFF, -1, 16, 0, stdpal_get(2)[15]); + gTasks[taskId].func = Task_OaksSpeech2; +} + +static void Task_OaksSpeech2(u8 taskId) +{ + if (!gPaletteFade.active && JOY_NEW((A_BUTTON | B_BUTTON))) + { + if (JOY_NEW(A_BUTTON)) + { + gTasks[taskId].data[15] = 1; + if (sOakSpeechResources->unk_0012 < 2) + { + BeginNormalPaletteFade(0xFFFFDFFF, -1, 0, 16, stdpal_get(2)[15]); + } + } + else + { + if (sOakSpeechResources->unk_0012 != 0) + { + gTasks[taskId].data[15] = -1; + BeginNormalPaletteFade(0xFFFFDFFF, -1, 0, 16, stdpal_get(2)[15]); + } + else + return; + } + } + else + return; + PlaySE(SE_SELECT); + gTasks[taskId].func = Task_OakSpeech3; +} + +static void Task_OakSpeech3(u8 taskId) +{ + u8 r8 = 0; + u8 i; + + if (!gPaletteFade.active) + { + switch (sOakSpeechResources->unk_0012) { + case 0: + r8 = 1; + break; + case 1: + case 2: + r8 = 3; + break; + } + sOakSpeechResources->unk_0012 += gTasks[taskId].data[15]; + if (sOakSpeechResources->unk_0012 < 3) + { + for (i = 0; i < r8; i++) + { + FillWindowPixelBuffer(sOakSpeechResources->unk_0014[i], 0x00); + ClearWindowTilemap(sOakSpeechResources->unk_0014[i]); + CopyWindowToVram(sOakSpeechResources->unk_0014[i], 3); + RemoveWindow(sOakSpeechResources->unk_0014[i]); + sOakSpeechResources->unk_0014[i] = 0; + } + gTasks[taskId].func = Task_OakSpeech4; + } + else + { + BeginNormalPaletteFade(0xFFFFFFFF, 2, 0, 16, 0); + gTasks[taskId].func = Task_OakSpeech5; + } + } +} + +static void Task_OakSpeech5(u8 taskId) +{ + u8 i = 0; + + if (!gPaletteFade.active) + { + for (i = 0; i < 3; i++) + { + FillWindowPixelBuffer(sOakSpeechResources->unk_0014[i], 0x00); + ClearWindowTilemap(sOakSpeechResources->unk_0014[i]); + CopyWindowToVram(sOakSpeechResources->unk_0014[i], 3); + RemoveWindow(sOakSpeechResources->unk_0014[i]); + sOakSpeechResources->unk_0014[i] = 0; + } + FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 2, 30, 18); + CopyBgTilemapBufferToVram(1); + sub_8006398(gTasks[taskId].data[5]); + sOakSpeechResources->unk_0014[0] = RGB_BLACK; + LoadPalette(sOakSpeechResources->unk_0014, 0, 2); + gTasks[taskId].data[3] = 32; + gTasks[taskId].func = Task_OakSpeech6; + } +} + +static void Task_OakSpeech6(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u32 sp14 = 0; + + if (data[3] != 0) + data[3]--; + else + { + PlayBGM(BGM_FRLG_GAME_EXPLANATION_MIDDLE); + sub_810F71C(); + PrintTextOnRightSnappedWindow(gText_ABUTTONNext, 0, 1); + sOakSpeechResources->unk_0008 = malloc_and_decompress(sNewGameAdventureIntroTilemap, &sp14); + CopyToBgTilemapBufferRect(1, sOakSpeechResources->unk_0008, 0, 2, 30, 19); + CopyBgTilemapBufferToVram(1); + Free(sOakSpeechResources->unk_0008); + sOakSpeechResources->unk_0008 = NULL; + data[14] = AddWindow(&sNewGameAdventureIntroWindowTemplates[0]); + PutWindowTilemap(data[14]); + FillWindowPixelBuffer(data[14], 0x00); + CopyWindowToVram(data[14], 3); + sOakSpeechResources->unk_0012 = 0; + gMain.state = 0; + data[15] = 16; + AddTextPrinterParameterized4(data[14], 2, 3, 5, 1, 0, &sTextColor_OakSpeech, 0, sNewGameAdventureIntroTextPointers[0]); + data[5] = CreateTextCursorSpriteForOakSpeech(0, 0xe2, 0x91, 0, 0); + gSprites[data[5]].oam.objMode = ST_OAM_OBJ_BLEND; + gSprites[data[5]].oam.priority = 0; + CreatePikaOrGrassPlatformSpriteAndLinkToCurrentTask(taskId, 0); + BeginNormalPaletteFade(0xFFFFFFFF, 2, 16, 0, 0); + gTasks[taskId].func = Task_OakSpeech7; + } +} + +static void Task_OakSpeech7(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + switch (gMain.state) + { + case 0: + if (!gPaletteFade.active) + { + SetGpuReg(REG_OFFSET_WIN0H, 0x00F0); + SetGpuReg(REG_OFFSET_WIN0V, 0x10A0); + SetGpuReg(REG_OFFSET_WININ, 0x003F); + SetGpuReg(REG_OFFSET_WINOUT, 0x001F); + SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); + gMain.state = 1; + } + break; + case 1: + if (JOY_NEW((A_BUTTON | B_BUTTON))) + { + if (JOY_NEW(A_BUTTON)) + { + sOakSpeechResources->unk_0012++; + } + else if (sOakSpeechResources->unk_0012 != 0) + { + sOakSpeechResources->unk_0012--; + } + else + { + break; + } + PlaySE(SE_SELECT); + if (sOakSpeechResources->unk_0012 == 3) + { + gMain.state = 4; + } + else + { + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG0 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1); + SetGpuReg(REG_OFFSET_BLDALPHA, (16 - data[15]) | data[15]); + gMain.state++; + } + } + break; + case 2: + data[15] -= 2; + SetGpuReg(REG_OFFSET_BLDALPHA, ((16 - data[15]) << 8) | data[15]); + if (data[15] <= 0) + { + FillWindowPixelBuffer(data[14], 0x00); + AddTextPrinterParameterized4(data[14], 2, 3, 5, 1, 0, &sTextColor_OakSpeech, 0, sNewGameAdventureIntroTextPointers[sOakSpeechResources->unk_0012]); + if (sOakSpeechResources->unk_0012 == 0) + { + sub_810F71C(); + PrintTextOnRightSnappedWindow(gText_ABUTTONNext, 0, 1); + } + else + { + sub_810F71C(); + PrintTextOnRightSnappedWindow(gText_ABUTTONNext_BBUTTONBack, 0, 1); + } + gMain.state++; + } + break; + case 3: + data[15] += 2; + SetGpuReg(REG_OFFSET_BLDALPHA, ((16 - data[15]) << 8) | data[15]); + if (data[15] >= 16) + { + data[15] = 16; + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + gMain.state = 1; + } + break; + case 4: + sub_8006398(gTasks[taskId].data[5]); + PlayBGM(BGM_FRLG_GAME_EXPLANATION_END); + data[15] = 24; + gMain.state++; + break; + default: + if (data[15] != 0) + data[15]--; + else + { + gMain.state = 0; + sOakSpeechResources->unk_0012 = 0; + SetGpuReg(REG_OFFSET_WIN0H, 0); + SetGpuReg(REG_OFFSET_WIN0V, 0); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); + BeginNormalPaletteFade(0xFFFFFFFF, 2, 0, 16, RGB_BLACK); + gTasks[taskId].func = Task_OakSpeech8; + } + break; + } +} + +static void Task_OakSpeech8(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!gPaletteFade.active) + { + sub_810F740(); + FillWindowPixelBuffer(data[14], 0x00); + ClearWindowTilemap(data[14]); + CopyWindowToVram(data[14], 3); + RemoveWindow(data[14]); + data[14] = 0; + FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); + CopyBgTilemapBufferToVram(1); + DestroyLinkedPikaOrGrassPlatformSprites(taskId, 0); + data[3] = 80; + gTasks[taskId].func = Task_OakSpeech9; + } +} + +static void Task_OakSpeech9(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u32 size = 0; + + if (data[3] != 0) + data[3]--; + else + { + sOakSpeechResources->solidColorsGfx = malloc_and_decompress(sOakSpeechGfx_SolidColors, &size); + LoadBgTiles(1, sOakSpeechResources->solidColorsGfx, size, 0); + CopyToBgTilemapBuffer(1, sOakSpeech_BackgroundTilemap, 0, 0); + CopyBgTilemapBufferToVram(1); + CreateNidoranFSprite(taskId); + LoadOaksSpeechTrainerPic(3, 0); + CreatePikaOrGrassPlatformSpriteAndLinkToCurrentTask(taskId, 1); + PlayBGM(BGM_FRLG_ROUTE_24); + BeginNormalPaletteFade(0xFFFFFFFF, 5, 16, 0, RGB_BLACK); + data[3] = 80; + ShowBg(2); + gTasks[taskId].func = Task_OakSpeech10; + } +} + +#define OaksSpeechPrintMessage(str, speed) ({ \ + DrawDialogueFrame(0, FALSE);\ + if (str != gStringVar4) \ + { \ + StringExpandPlaceholders(gStringVar4, str); \ + AddTextPrinterParameterized2(0, 4, gStringVar4, speed, NULL, 2, 1, 3); \ + } \ + else \ + { \ + AddTextPrinterParameterized2(0, 4, str, speed, NULL, 2, 1, 3); \ + } \ + CopyWindowToVram(0, 3); \ +}) + +static void Task_OakSpeech10(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!gPaletteFade.active) + { + if (data[3] != 0) + data[3]--; + else + { + OaksSpeechPrintMessage(gOakText_WelcomeToTheWorld, sOakSpeechResources->textSpeed); + gTasks[taskId].func = Task_OakSpeech11; + } + } +} + +static void Task_OakSpeech11(u8 taskId) +{ + if (!IsTextPrinterActive(0)) + { + OaksSpeechPrintMessage(gOakText_WorldInhabited1, sOakSpeechResources->textSpeed); + gTasks[taskId].data[3] = 30; + gTasks[taskId].func = Task_OakSpeech12; + } +} + +static void Task_OakSpeech12(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u8 spriteId; + + if (!IsTextPrinterActive(0)) + { + if (data[3] != 0) + data[3]--; + // else { + spriteId = gTasks[taskId].data[4]; + gSprites[spriteId].invisible = FALSE; + gSprites[spriteId].data[0] = 0; + CreatePokeballSpriteToReleaseMon(spriteId, gSprites[spriteId].oam.paletteNum, 0x64, 0x42, 0, 0, 32, 0xFFFF1FFF); + gTasks[taskId].func = Task_OakSpeech13; + gTasks[taskId].data[3] = 0; + // } + } +} + +static void Task_OakSpeech13(u8 taskId) +{ + if (IsCryFinished()) + { + if (gTasks[taskId].data[3] >= 96) + gTasks[taskId].func = Task_OakSpeech14; + } + if (gTasks[taskId].data[3] < 0x4000) + { + gTasks[taskId].data[3]++; + if (gTasks[taskId].data[3] == 32) + { + OaksSpeechPrintMessage(gOakText_WorldInhabited2, sOakSpeechResources->textSpeed); + PlayCry1(SPECIES_NIDORAN_F, 0); + } + } +} + +static void Task_OakSpeech14(u8 taskId) +{ + if (!IsTextPrinterActive(0)) + { + OaksSpeechPrintMessage(gOakText_PetsBattlingStudy, sOakSpeechResources->textSpeed); + gTasks[taskId].func = Task_OakSpeech15; + } +} + +static void Task_OakSpeech15(u8 taskId) +{ + u8 spriteId; + + if (!IsTextPrinterActive(0)) + { + ClearDialogWindowAndFrame(0, 1); + spriteId = gTasks[taskId].data[4]; + gTasks[taskId].data[6] = sub_804BB98(spriteId, gSprites[spriteId].oam.paletteNum, 0x64, 0x42, 0, 0, 32, 0xFFFF1F3F); + gTasks[taskId].data[3] = 48; + gTasks[taskId].data[0] = 64; + gTasks[taskId].func = Task_OakSpeech16; + } +} + +static void Task_OakSpeech16(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (data[0] != 0) + { + if (data[0] < 24) + { + gSprites[data[4]].pos1.y--; + } + data[0]--; + } + else + { + if (data[3] == 48) + { + DestroySprite(&gSprites[data[4]]); + DestroySprite(&gSprites[data[6]]); + } + if (data[3] != 0) + { + data[3]--; + } + else + { + OaksSpeechPrintMessage(gOakText_TellMeALittleAboutYourself, sOakSpeechResources->textSpeed); + gTasks[taskId].func = Task_OakSpeech17; + } + } +} + +static void Task_OakSpeech17(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!IsTextPrinterActive(0)) + { + ClearDialogWindowAndFrame(0, 1); + CreateFadeInTask(taskId, 2); + data[3] = 48; + gTasks[taskId].func = Task_OakSpeech18; + } +} + +static void Task_OakSpeech18(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (data[2] != 0) + { + if (data[3] != 0) + data[3]--; + else + { + data[1] = -60; + DestroyOaksSpeechTrainerPic(); + OaksSpeechPrintMessage(gOakText_AskPlayerGender, sOakSpeechResources->textSpeed); + gTasks[taskId].func = Task_OakSpeech19; + } + } +} + +static void Task_OakSpeech19(u8 taskId) +{ + if (!IsTextPrinterActive(0)) + { + gTasks[taskId].data[13] = AddWindow(&sNewGameAdventureIntroWindowTemplates[1]); + PutWindowTilemap(gTasks[taskId].data[13]); + SetWindowBorderStyle(gTasks[taskId].data[13], 1, sub_80F796C(), 14); + FillWindowPixelBuffer(gTasks[taskId].data[13], 0x11); + sOakSpeechResources->unk_001C[0] = 1; + sOakSpeechResources->unk_001C[1] = 2; + sOakSpeechResources->unk_001C[2] = 3; + AddTextPrinterParameterized3(gTasks[taskId].data[13], 2, 8, 1, sOakSpeechResources->unk_001C, 0, gText_Boy); + sOakSpeechResources->unk_001C[0] = 1; + sOakSpeechResources->unk_001C[1] = 2; + sOakSpeechResources->unk_001C[2] = 3; + AddTextPrinterParameterized3(gTasks[taskId].data[13], 2, 8, 17, sOakSpeechResources->unk_001C, 0, gText_Girl); + ProgramAndPlaceMenuCursorOnWindow(gTasks[taskId].data[13], 2, 0, 1, GetFontAttribute(2, 1) + 2, 2, 0); + CopyWindowToVram(gTasks[taskId].data[13], 3); + gTasks[taskId].func = Task_OakSpeech20; + } +} + +static void Task_OakSpeech20(u8 taskId) +{ + s8 input = ProcessMenuInputNoWrapAround(); + switch (input) + { + case 0: + gSaveBlock2Ptr->playerGender = MALE; + break; + case 1: + gSaveBlock2Ptr->playerGender = FEMALE; + break; + case -1: + case -2: + return; + } + gTasks[taskId].func = Task_OakSpeech21; + +} + +static void Task_OakSpeech21(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + ClearMenuWindow(data[13], 1); + RemoveWindow(data[13]); + data[13] = 0; + ClearDialogWindowAndFrame(0, 1); + FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 30, 20); + CopyBgTilemapBufferToVram(0); + gTasks[taskId].func = Task_OakSpeech22; +} + +static void Task_OakSpeech22(u8 taskId) +{ + if (gSaveBlock2Ptr->playerGender == MALE) + LoadOaksSpeechTrainerPic(MALE, 0); + else + LoadOaksSpeechTrainerPic(FEMALE, 0); + CreateFadeOutTask(taskId, 2); + gTasks[taskId].data[3] = 32; + gTasks[taskId].func = Task_OakSpeech23; +} + +static void Task_OakSpeech23(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (data[2] != 0) + { + if (data[3] != 0) + data[3]--; + else + { + data[1] = 0; + OaksSpeechPrintMessage(gOakText_AskPlayerName, sOakSpeechResources->textSpeed); + gTasks[taskId].func = Task_OakSpeech24; + } + } +} + +static void Task_OakSpeech24(u8 taskId) +{ + if (!IsTextPrinterActive(0)) + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); + sOakSpeechResources->unk_0010 = 0; + gTasks[taskId].func = Task_OakSpeech25; + } +} +static void Task_OakSpeech35(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!IsTextPrinterActive(0)) + { + if (data[1] > -60) + { + data[1] -= 2; + gSpriteCoordOffsetX += 2; + ChangeBgX(2, 0x200, 2); + } + else + { + data[1] = -60; + PrintNameChoiceOptions(taskId, sOakSpeechResources->unk_0010); + gTasks[taskId].func = Task_OakSpeech29; + } + } +} + +static void Task_OakSpeech28(u8 taskId) +{ + PrintNameChoiceOptions(taskId, sOakSpeechResources->unk_0010); + if (sOakSpeechResources->unk_0010 == 0) + { + OaksSpeechPrintMessage(gOakText_AskPlayerName, 0); + } + else + { + OaksSpeechPrintMessage(gOakText_AskRivalName, 0); + } + gTasks[taskId].func = Task_OakSpeech29; +} + +static void Task_OakSpeech29(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + s8 input = ProcessMenuInput(); + switch (input) + { + case 1: + case 2: + case 3: + case 4: + PlaySE(SE_SELECT); + ClearMenuWindow(data[13], TRUE); + RemoveWindow(data[13]); + GetDefaultName(sOakSpeechResources->unk_0010, input - 1); + data[15] = 1; + gTasks[taskId].func = Task_OakSpeech26; + break; + case 0: + PlaySE(SE_SELECT); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, 0); + gTasks[taskId].func = Task_OakSpeech25; + break; + case -1: + break; + } +} + +static void Task_OakSpeech25(u8 taskId) +{ + if (!gPaletteFade.active) + { + GetDefaultName(sOakSpeechResources->unk_0010, 0); + if (sOakSpeechResources->unk_0010 == 0) + { + DoNamingScreen(0, gSaveBlock2Ptr->playerName, gSaveBlock2Ptr->playerGender, 0, 0, CB2_ReturnFromNamingScreen); + } + else + { + ClearMenuWindow(gTasks[taskId].data[13], 1); + RemoveWindow(gTasks[taskId].data[13]); + DoNamingScreen(4, gSaveBlock1Ptr->rivalName, 0, 0, 0, CB2_ReturnFromNamingScreen); + } + DestroyLinkedPikaOrGrassPlatformSprites(taskId, 1); + FreeAllWindowBuffers(); + } +} + +static void Task_OakSpeech26(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!gPaletteFade.active) + { + if (data[15] == 1) + { + if (sOakSpeechResources->unk_0010 == 0) + { + StringExpandPlaceholders(gStringVar4, gOakText_FinalizePlayerName); + } + else + { + StringExpandPlaceholders(gStringVar4, gOakText_ConfirmRivalName); + } + OaksSpeechPrintMessage(gStringVar4, sOakSpeechResources->textSpeed); + data[15] = 0; + data[3] = 25; + } + else if (!IsTextPrinterActive(0)) + { + if (data[3] != 0) + data[3]--; + else + { + CreateYesNoMenu(&sNewGameAdventureIntroWindowTemplates[2], 2, 0, 2, sub_80F796C(), 14, 0); + gTasks[taskId].func = Task_OakSpeech27; + } + } + } +} + +static void Task_OakSpeech27(u8 taskId) +{ + s8 input = Menu_ProcessInputNoWrapClearOnChoose(); + switch (input) + { + case 0: + PlaySE(SE_SELECT); + gTasks[taskId].data[3] = 40; + if (sOakSpeechResources->unk_0010 == 0) + { + ClearDialogWindowAndFrame(0, 1); + CreateFadeInTask(taskId, 2); + gTasks[taskId].func = Task_OakSpeech30; + } + else + { + StringExpandPlaceholders(gStringVar4, gOakText_RememberRivalName); + OaksSpeechPrintMessage(gStringVar4, sOakSpeechResources->textSpeed); + gTasks[taskId].func = Task_OakSpeech31; + } + break; + case 1: + case -1: + PlaySE(SE_SELECT); + if (sOakSpeechResources->unk_0010 == 0) + gTasks[taskId].func = Task_OakSpeech24; + else + gTasks[taskId].func = Task_OakSpeech28; + break; + } +} + +static void Task_OakSpeech30(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (data[2] != 0) + { + DestroyOaksSpeechTrainerPic(); + if (data[3] != 0) + data[3]--; + else + gTasks[taskId].func = Task_OakSpeech32; + } +} + +static void Task_OakSpeech31(u8 taskId) +{ + if (!IsTextPrinterActive(0)) + { + ClearDialogWindowAndFrame(0, 1); + CreateFadeInTask(taskId, 2); + gTasks[taskId].func = Task_OakSpeech33; + } +} + +static void Task_OakSpeech32(u8 taskId) +{ + ChangeBgX(2, 0, 0); + gTasks[taskId].data[1] = 0; + gSpriteCoordOffsetX = 0; + LoadOaksSpeechTrainerPic(2, 0); + CreateFadeOutTask(taskId, 2); + gTasks[taskId].func = Task_OakSpeech34; +} + +static void Task_OakSpeech34(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (data[2] != 0) + { + OaksSpeechPrintMessage(gOakText_IntroduceRival, sOakSpeechResources->textSpeed); + sOakSpeechResources->unk_0010 = 1; + gTasks[taskId].func = Task_OakSpeech35; + } +} + +static void Task_OakSpeech33(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (data[2] != 0) + { + DestroyOaksSpeechTrainerPic(); + if (data[3] != 0) + data[3]--; + else + { + if (gSaveBlock2Ptr->playerGender == MALE) + LoadOaksSpeechTrainerPic(MALE, 0); + else + LoadOaksSpeechTrainerPic(FEMALE, 0); + gTasks[taskId].data[1] = 0; + gSpriteCoordOffsetX = 0; + ChangeBgX(2, 0, 0); + CreateFadeOutTask(taskId, 2); + gTasks[taskId].func = Task_OakSpeech36; + } + } +} + +static void Task_OakSpeech36(u8 taskId) +{ + if (gTasks[taskId].data[2] != 0) + { + StringExpandPlaceholders(gStringVar4, gOakText_LegendAboutToUnfold); + OaksSpeechPrintMessage(gStringVar4, sOakSpeechResources->textSpeed); + gTasks[taskId].data[3] = 30; + gTasks[taskId].func = Task_OakSpeech37; + } +} + +static void Task_OakSpeech37(u8 taskId) +{ + if (!IsTextPrinterActive(0)) + { + if (gTasks[taskId].data[3] != 0) + gTasks[taskId].data[3]--; + else + { + FadeOutBGM(4); + gTasks[taskId].func = Task_OakSpeech38; + } + } +} + +static void Task_OakSpeech38(u8 taskId) +{ + sOakSpeechResources->unk_0012 = 0; + Task_OakSpeech38_1(taskId); + Task_OakSpeech38_2(taskId); + Task_OakSpeech38_3(taskId); +} + +static void Task_OakSpeech38_3(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + SetBgAttribute(2, 6, 1); + data[0] = 0; + data[1] = 0; + data[2] = 256; + data[15] = 0; + gTasks[taskId].func = Task_OakSpeech39; +} + +static void Task_OakSpeech39(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + s16 x, y; + u16 r0; + + sOakSpeechResources->unk_0012++; + if (sOakSpeechResources->unk_0012 % 20 == 0) + { + if (sOakSpeechResources->unk_0012 == 40) + PlaySE(SE_FU_ZUZUZU); + r0 = data[2]; + data[2] -= 32; + x = sub_80D8B90(r0 - 8); + y = sub_80D8B90(data[2] - 16); + SetBgAffine(2, 0x7800, 0x5400, 0x78, 0x54, x, y, 0); + if (data[2] <= 96) + { + data[15] = 1; + data[0] = 36; + gTasks[taskId].func = Task_OakSpeech40; + } + } +} + +static void Task_OakSpeech38_1(u8 taskId) +{ + u8 taskId2 = CreateTask(Task_OakSpeech38_sub1, 1); + s16 * data = gTasks[taskId2].data; + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[15] = 0; + BeginNormalPaletteFade(0xFFFF0FCF, 4, 0, 16, RGB_BLACK); +} + +static void Task_OakSpeech38_sub1(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + if (!gPaletteFade.active) + { + if (data[1] != 0) + { + DestroyTask(taskId); + DestroyLinkedPikaOrGrassPlatformSprites(taskId, 1); + } + else + { + data[1]++; + BeginNormalPaletteFade(0x0000F000, 0, 0, 16, RGB_BLACK); + } + } +} + +static void Task_OakSpeech38_2(u8 taskId) +{ + u8 taskId2 = CreateTask(Task_OakSpeech38_sub2, 2); + s16 * data = gTasks[taskId2].data; + data[0] = 8; + data[1] = 0; + data[2] = 8; + data[14] = 0; + data[15] = 0; +} + +static void Task_OakSpeech38_sub2(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u8 i; + + if (data[0] != 0) + data[0]--; + else + { + if (data[1] <= 0 && data[2] != 0) + data[2]--; + BlendPalette(0x40, 0x20, data[14], RGB_WHITE); + data[14]++; + data[1]--; + data[0] = data[2]; + if (data[14] > 14) + { + for (i = 0; i < 32; i++) + { + gPlttBufferFaded[i + 0x40] = RGB_WHITE; + gPlttBufferUnfaded[i + 0x40] = RGB_WHITE; + } + DestroyTask(taskId); + } + } +} + +static void Task_OakSpeech40(u8 taskId) +{ + if (gTasks[taskId].data[0] != 0) + gTasks[taskId].data[0]--; + else + { + BeginNormalPaletteFade(0x00000030, 2, 0, 16, RGB_BLACK); + gTasks[taskId].func = Task_OakSpeech41; + } +} + +static void Task_OakSpeech41(u8 taskId) +{ + if (!gPaletteFade.active) + { + gTasks[taskId].func = Task_OakSpeech42; + } +} + +static void Task_OakSpeech42(u8 taskId) +{ + FreeAllWindowBuffers(); + sub_8044D80(); + Free(sOakSpeechResources); + sOakSpeechResources = NULL; + gTextFlags.canABSpeedUpPrint = FALSE; + SetMainCallback2(CB2_NewGame); + DestroyTask(taskId); +} + +static void CB2_ReturnFromNamingScreen(void) +{ + u8 taskId; + + switch (gMain.state) + { + case 0: + SetVBlankCallback(NULL); + DmaFill16(3, 0, VRAM, VRAM_SIZE); + DmaFill32(3, 0, OAM, OAM_SIZE); + DmaFill16(3, RGB_BLACK, PLTT + sizeof(u16), PLTT_SIZE - sizeof(u16)); + ResetPaletteFade(); + ScanlineEffect_Stop(); + ResetSpriteData(); + FreeAllSpritePalettes(); + reset_temp_tile_data_buffers(); + break; + case 1: + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(1, sBgTemplates, NELEMS(sBgTemplates)); + SetBgTilemapBuffer(1, sOakSpeechResources->bg1TilemapBuffer); + SetBgTilemapBuffer(2, sOakSpeechResources->bg2TilemapBuffer); + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(2, 0, 0); + ChangeBgY(2, 0, 0); + break; + case 2: + SetGpuReg(REG_OFFSET_WIN0H, 0); + SetGpuReg(REG_OFFSET_WIN0V, 0); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); + break; + case 3: + FreeAllWindowBuffers(); + InitStandardTextBoxWindows(); + ResetBg0(); + LoadPalette(sHelpDocsPalette, 0, 0xe0); + break; + case 4: + decompress_and_copy_tile_data_to_vram(1, sOakSpeechGfx_SolidColors, 0, 0, 0); + break; + case 5: + if (free_temp_tile_data_buffers_if_possible()) + return; + FillBgTilemapBufferRect_Palette0(1, 0x000, 0, 0, 30, 20); + CopyToBgTilemapBuffer(1, sOakSpeech_BackgroundTilemap, 0, 0); + FillBgTilemapBufferRect_Palette0(2, 0x000, 0, 0, 30, 20); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(2); + break; + case 6: + taskId = CreateTask(Task_OakSpeech26, 0); + if (sOakSpeechResources->unk_0010 == 0) + { + if (gSaveBlock2Ptr->playerGender == MALE) + LoadOaksSpeechTrainerPic(MALE, 0); + else + LoadOaksSpeechTrainerPic(FEMALE, 0); + } + else + LoadOaksSpeechTrainerPic(2, 0); + gTasks[taskId].data[1] = -60; + gSpriteCoordOffsetX += 60; + ChangeBgX(2, -0x3C00, 0); + CreatePikaOrGrassPlatformSpriteAndLinkToCurrentTask(taskId, 1); + gTasks[taskId].data[15] = 1; + break; + case 7: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB_BLACK); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); + ShowBg(0); + ShowBg(1); + ShowBg(2); + EnableInterrupts(INTR_FLAG_VBLANK); + SetVBlankCallback(VBlankCB_NewGameOaksSpeech); + gTextFlags.canABSpeedUpPrint = TRUE; + SetMainCallback2(CB2_NewGameOaksSpeech); + return; + } + + gMain.state++; +} + +static void CreateNidoranFSprite(u8 taskId) +{ + u8 spriteId; + + DecompressPicFromTable(gUnknown_8235194, sub_8044E00(0), SPECIES_NIDORAN_F); + sub_800F078(&gUnknown_82373F4); + SetMultiuseSpriteTemplateToPokemon(SPECIES_NIDORAN_F, 0); + spriteId = CreateSprite(&gMultiuseSpriteTemplate, 0x60, 0x60, 1); + gSprites[spriteId].callback = SpriteCallbackDummy; + gSprites[spriteId].oam.priority = 1; + gSprites[spriteId].invisible = TRUE; + gTasks[taskId].data[4] = spriteId; +} + +static void SpriteCB_PikaSync(struct Sprite * sprite) +{ + sprite->pos2.y = gSprites[sprite->data[0]].animCmdIndex; +} + +static void CreatePikaOrGrassPlatformSpriteAndLinkToCurrentTask(u8 taskId, u8 state) +{ + u8 spriteId; + u8 i = 0; + + switch (state) + { + case 0: + LoadCompressedObjectPic(&sOakSpeech_PikaSpriteSheets[0]); + LoadCompressedObjectPic(&sOakSpeech_PikaSpriteSheets[1]); + LoadCompressedObjectPic(&sOakSpeech_PikaSpriteSheets[2]); + LoadSpritePalette(&sOakSpeech_PikaSpritePal); + spriteId = CreateSprite(&sOakSpeech_PikaSpriteTemplates[0], 0x10, 0x11, 2); + gSprites[spriteId].oam.priority = 0; + gTasks[taskId].data[7] = spriteId; + spriteId = CreateSprite(&sOakSpeech_PikaSpriteTemplates[1], 0x10, 0x09, 3); + gSprites[spriteId].oam.priority = 0; + gSprites[spriteId].data[0] = gTasks[taskId].data[7]; + gSprites[spriteId].callback = SpriteCB_PikaSync; + gTasks[taskId].data[8] = spriteId; + spriteId = CreateSprite(&sOakSpeech_PikaSpriteTemplates[2], 0x18, 0x0D, 1); + gSprites[spriteId].oam.priority = 0; + gSprites[spriteId].data[0] = gTasks[taskId].data[7]; + gSprites[spriteId].callback = SpriteCB_PikaSync; + gTasks[taskId].data[9] = spriteId; + break; + case 1: + LoadCompressedObjectPic(&sOakSpeech_GrassPlatformSpriteSheet); + LoadSpritePalette(&sOakSpeech_GrassPlatformSpritePal); + for (i = 0; i < 3; i++) + { + spriteId = CreateSprite(&sOakSpeech_GrassPlatformSpriteTemplates[i], i * 32 + 88, 0x70, 1); + gSprites[spriteId].oam.priority = 2; + gSprites[spriteId].animPaused = TRUE; + gSprites[spriteId].coordOffsetEnabled = TRUE; + gTasks[taskId].data[7 + i] = spriteId; + } + break; + } +} + +static void DestroyLinkedPikaOrGrassPlatformSprites(u8 taskId, u8 state) +{ + u8 i; + + for (i = 0; i < 3; i++) + { + DestroySprite(&gSprites[gTasks[taskId].data[7 + i]]); + } + + switch (state) + { + case 0: + FreeSpriteTilesByTag(0x1003); + FreeSpriteTilesByTag(0x1002); + FreeSpriteTilesByTag(0x1001); + FreeSpritePaletteByTag(0x1001); + break; + case 1: + FreeSpriteTilesByTag(0x1000); + FreeSpritePaletteByTag(0x1000); + break; + } +} + +static void LoadOaksSpeechTrainerPic(u16 whichPic, u16 tileOffset) +{ + u32 i; + + switch (whichPic) + { + case 0: // FIRE + LoadPalette(sOakSpeechGfx_RedPal, 0x40, 0x40); + LZ77UnCompVram(sOakSpeechGfx_RedPic, (void *)0x06000600 + tileOffset); + break; + case 1: // LEAF + LoadPalette(sOakSpeechGfx_LeafPal, 0x40, 0x40); + LZ77UnCompVram(sOakSpeechGfx_LeafPic, (void *)0x06000600 + tileOffset); + break; + case 2: // BLUE + LoadPalette(sOakSpeechGfx_RivalPal, 0x60, 0x40); + LZ77UnCompVram(sOakSpeechGfx_RivalPic, (void *)0x06000600 + tileOffset); + break; + case 3: // OAK + LoadPalette(sOakSpeechGfx_OakPal, 0x60, 0x40); + LZ77UnCompVram(sOakSpeechGfx_OakPic, (void *)0x06000600 + tileOffset); + break; + default: + return; + } + + sOakSpeechResources->trainerPicTilemapBuffer = AllocZeroed(0x60); + for (i = 0; i < 0x60; i++) + ((u8 *)sOakSpeechResources->trainerPicTilemapBuffer)[i] = i; + FillBgTilemapBufferRect(2, 0x000, 0, 0, 32, 32, 0x10); + CopyRectToBgTilemapBufferRect(2, sOakSpeechResources->trainerPicTilemapBuffer, 0, 0, 8, 12, 11, 2, 8, 12, 0x10, (tileOffset / 64) + 0x18, 0x00); + CopyBgTilemapBufferToVram(2); + Free(sOakSpeechResources->trainerPicTilemapBuffer); + sOakSpeechResources->trainerPicTilemapBuffer = 0; +} + +static void DestroyOaksSpeechTrainerPic(void) +{ + FillBgTilemapBufferRect(2, 0x000, 11, 1, 8, 12, 0x10); + CopyBgTilemapBufferToVram(2); +} + +static void Task_SlowFadeIn(u8 taskId) +{ + u8 i = 0; + if (gTasks[taskId].data[1] == 0) + { + gTasks[gTasks[taskId].data[0]].data[2] = 1; + DestroyTask(taskId); + for (i = 0; i < 3; i++) + { + gSprites[gTasks[taskId].data[7 + i]].invisible = TRUE; + } + } + else + { + if (gTasks[taskId].data[4] != 0) + gTasks[taskId].data[4]--; + else + { + gTasks[taskId].data[4] = gTasks[taskId].data[3]; + gTasks[taskId].data[1]--; + gTasks[taskId].data[2]++; + if (gTasks[taskId].data[1] == 8) + { + for (i = 0; i < 3; i++) + { + gSprites[gTasks[taskId].data[7 + i]].invisible ^= TRUE; + } + } + SetGpuReg(REG_OFFSET_BLDALPHA, (gTasks[taskId].data[2] * 256) + gTasks[taskId].data[1]); + } + } +} + +static void CreateFadeInTask(u8 taskId, u8 state) +{ + u8 taskId2; + u8 i = 0; + + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG2 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_OBJ); + SetGpuReg(REG_OFFSET_BLDALPHA, 0x10); + SetGpuReg(REG_OFFSET_BLDY, 0); + gTasks[taskId].data[2] = 0; + taskId2 = CreateTask(Task_SlowFadeIn, 0); + gTasks[taskId2].data[0] = taskId; + gTasks[taskId2].data[1] = 16; + gTasks[taskId2].data[2] = 0; + gTasks[taskId2].data[3] = state; + gTasks[taskId2].data[4] = state; + for (i = 0; i < 3; i++) + { + gTasks[taskId2].data[7 + i] = gTasks[taskId].data[7 + i]; + } +} + +static void Task_SlowFadeOut(u8 taskId) +{ + u8 i = 0; + + if (gTasks[taskId].data[1] == 16) + { + if (!gPaletteFade.active) + { + gTasks[gTasks[taskId].data[0]].data[2] = 1; + DestroyTask(taskId); + } + } + else + { + if (gTasks[taskId].data[4] != 0) + gTasks[taskId].data[4]--; + else + { + gTasks[taskId].data[4] = gTasks[taskId].data[3]; + gTasks[taskId].data[1] += 2; + gTasks[taskId].data[2] -= 2; + if (gTasks[taskId].data[1] == 8) + { + for (i = 0; i < 3; i++) + { + gSprites[gTasks[taskId].data[7 + i]].invisible ^= TRUE; + } + } + SetGpuReg(REG_OFFSET_BLDALPHA, (gTasks[taskId].data[2] * 256) + gTasks[taskId].data[1]); + } + } +} + +static void CreateFadeOutTask(u8 taskId, u8 state) +{ + u8 taskId2; + u8 i = 0; + + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG2 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_OBJ); + SetGpuReg(REG_OFFSET_BLDALPHA, 0x1000); + SetGpuReg(REG_OFFSET_BLDY, 0); + gTasks[taskId].data[2] = 0; + taskId2 = CreateTask(Task_SlowFadeOut, 0); + gTasks[taskId2].data[0] = taskId; + gTasks[taskId2].data[1] = 0; + gTasks[taskId2].data[2] = 16; + gTasks[taskId2].data[3] = state; + gTasks[taskId2].data[4] = state; + for (i = 0; i < 3; i++) + { + gTasks[taskId2].data[7 + i] = gTasks[taskId].data[7 + i]; + } +} + +static void PrintNameChoiceOptions(u8 taskId, u8 state) +{ + s16 * data = gTasks[taskId].data; + const u8 *const * textPtrs; + u8 i; + + data[13] = AddWindow(&sNewGameAdventureIntroWindowTemplates[3]); + PutWindowTilemap(data[13]); + SetWindowBorderStyle(data[13], 1, sub_80F796C(), 14); + FillWindowPixelBuffer(gTasks[taskId].data[13], 0x11); + AddTextPrinterParameterized(data[13], 2, gOtherText_NewName, 8, 1, 0, NULL); + if (state == 0) + textPtrs = gSaveBlock2Ptr->playerGender == MALE ? sMaleNameChoices : sFemaleNameChoices; + else + textPtrs = sRivalNameChoices; + for (i = 0; i < 4; i++) + { + AddTextPrinterParameterized(data[13], 2, textPtrs[i], 8, 16 * (i + 1) + 1, 0, NULL); + } + ProgramAndPlaceMenuCursorOnWindow(data[13], 2, 0, 1, 16, 5, 0); + CopyWindowToVram(data[13], 3); +} + +static void GetDefaultName(u8 arg0, u8 namePick) +{ + const u8 * src; + u8 * dest; + u8 i; + + if (arg0 == 0) + { + if (gSaveBlock2Ptr->playerGender == MALE) + src = sMaleNameChoices[Random() % 19]; + else + src = sFemaleNameChoices[Random() % 19]; + dest = gSaveBlock2Ptr->playerName; + } + else + { + src = sRivalNameChoices[namePick]; + dest = gSaveBlock1Ptr->rivalName; + } + for (i = 0; i < PLAYER_NAME_LENGTH - 1 && src[i] != EOS; i++) + dest[i] = src[i]; + for (; i < PLAYER_NAME_LENGTH; i++) + dest[i] = EOS; +} diff --git a/src/pokemon.c b/src/pokemon.c index 5cd2cd2d7..906b97cae 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -80,7 +80,7 @@ extern const u16 sHMMoves[]; extern s8 gPokeblockFlavorCompatibilityTable[]; // External functions -extern u8 sav1_map_get_name(void); // overworld +extern u8 GetCurrentRegionMapSectionId(void); // overworld extern const struct BattleMove gBattleMoves[]; extern u8 sBattler_AI; // battle_ai extern void set_unknown_box_id(u8); // field_specials @@ -194,7 +194,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, SetBoxMonData(boxMon, MON_DATA_SPECIES, &species); SetBoxMonData(boxMon, MON_DATA_EXP, &gExperienceTables[gBaseStats[species].growthRate][level]); SetBoxMonData(boxMon, MON_DATA_FRIENDSHIP, &gBaseStats[species].friendship); - value = sav1_map_get_name(); + value = GetCurrentRegionMapSectionId(); SetBoxMonData(boxMon, MON_DATA_MET_LOCATION, &value); SetBoxMonData(boxMon, MON_DATA_MET_LEVEL, &level); SetBoxMonData(boxMon, MON_DATA_MET_GAME, &gGameVersion); @@ -351,7 +351,7 @@ void CreateMonWithEVSpread(struct Pokemon *mon, u16 species, u8 level, u8 fixedI CalculateMonStats(mon); } -void sub_803E0A4(struct Pokemon *mon, struct UnknownPokemonStruct *src) +void sub_803E0A4(struct Pokemon *mon, struct BattleTowerPokemon *src) { s32 i; u8 value; @@ -410,7 +410,7 @@ void CreateObedientMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u SetMonData(mon, MON_DATA_OBEDIENCE, &obedient); } -void sub_803E23C(struct Pokemon *mon, struct UnknownPokemonStruct *dest) +void sub_803E23C(struct Pokemon *mon, struct BattleTowerPokemon *dest) { s32 i; u16 heldItem; @@ -1001,7 +1001,7 @@ s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *de damage /= 2; // sunny - if (gBattleWeather & WEATHER_SUN_ANY) + if (gBattleWeather & WEATHER_SUNNY_ANY) { switch (type) { @@ -1122,7 +1122,7 @@ u8 GetGenderFromSpeciesAndPersonality(u16 species, u32 personality) return MON_MALE; } -void sub_803F7D4(u16 trainerSpriteId, u8 battlerPosition) +void SetMultiuseSpriteTemplateToPokemon(u16 trainerSpriteId, u8 battlerPosition) { if(gMonSpritesGfxPtr != NULL) { @@ -1415,13 +1415,13 @@ u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data) case MON_DATA_LANGUAGE: retVal = boxMon->language; break; - case MON_DATA_SANITY_BIT1: + case MON_DATA_SANITY_IS_BAD_EGG: retVal = boxMon->isBadEgg; break; - case MON_DATA_SANITY_BIT2: + case MON_DATA_SANITY_HAS_SPECIES: retVal = boxMon->hasSpecies; break; - case MON_DATA_SANITY_BIT3: + case MON_DATA_SANITY_IS_EGG: retVal = boxMon->isEgg; break; case MON_DATA_OT_NAME: @@ -1809,13 +1809,13 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) case MON_DATA_LANGUAGE: SET8(boxMon->language); break; - case MON_DATA_SANITY_BIT1: + case MON_DATA_SANITY_IS_BAD_EGG: SET8(boxMon->isBadEgg); break; - case MON_DATA_SANITY_BIT2: + case MON_DATA_SANITY_HAS_SPECIES: SET8(boxMon->hasSpecies); break; - case MON_DATA_SANITY_BIT3: + case MON_DATA_SANITY_IS_EGG: SET8(boxMon->isEgg); break; case MON_DATA_OT_NAME: @@ -2769,7 +2769,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 mo { if (GetMonData(pkmn, MON_DATA_POKEBALL, NULL) == 11) friendship++; - if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) + if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) friendship++; } if (friendship < 0) @@ -2794,7 +2794,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 mo { if (GetMonData(pkmn, MON_DATA_POKEBALL, NULL) == 11) friendship++; - if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) + if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) friendship++; } if (friendship < 0) @@ -2818,7 +2818,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 mo { if (GetMonData(pkmn, MON_DATA_POKEBALL, NULL) == 11) friendship++; - if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) + if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) friendship++; } if (friendship < 0) @@ -3320,7 +3320,7 @@ bool8 PokemonUseItemEffects2(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 m { if (GetMonData(pkmn, MON_DATA_POKEBALL, NULL) == 11) friendship++; - if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) + if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) friendship++; } if (friendship < 0) @@ -3347,7 +3347,7 @@ bool8 PokemonUseItemEffects2(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 m { if (GetMonData(pkmn, MON_DATA_POKEBALL, NULL) == 11) friendship++; - if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) + if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) friendship++; } if (friendship < 0) @@ -3373,7 +3373,7 @@ bool8 PokemonUseItemEffects2(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 m { if (GetMonData(pkmn, MON_DATA_POKEBALL, NULL) == 11) friendship++; - if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) + if (GetMonData(pkmn, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) friendship++; } if (friendship < 0) @@ -4526,7 +4526,7 @@ void sub_8042D50(int stat) BattleStringExpandPlaceholdersToDisplayedString(BattleText_UnknownString3); } -u8 *sub_8042DA4(u16 itemId) +const u8 *Battle_PrintStatBoosterEffectMessage(u16 itemId) { int i; const u8 *itemEffect; @@ -5033,7 +5033,7 @@ void AdjustFriendship(struct Pokemon *mon, u8 event) { if (GetMonData(mon, MON_DATA_POKEBALL, 0) == ITEM_LUXURY_BALL) friendship++; - if (GetMonData(mon, MON_DATA_MET_LOCATION, 0) == sav1_map_get_name()) + if (GetMonData(mon, MON_DATA_MET_LOCATION, 0) == GetCurrentRegionMapSectionId()) friendship++; } @@ -5223,7 +5223,7 @@ void sub_8043B48(struct Pokemon *mon, int species, u8 unused, u32 data) } } -bool32 sub_8043B90(struct Pokemon *mon) +bool8 TryIncrementMonLevel(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u8 level = GetMonData(mon, MON_DATA_LEVEL, NULL); diff --git a/src/prof_pc.c b/src/prof_pc.c new file mode 100644 index 000000000..cfccbd6e3 --- /dev/null +++ b/src/prof_pc.c @@ -0,0 +1,108 @@ +#include "global.h" +#include "event_data.h" +#include "pokedex.h" +#include "field_message_box.h" +#include "constants/species.h" + +extern const u8 gUnknown_81A6D17[]; +extern const u8 gUnknown_81A6D6D[]; +extern const u8 gUnknown_81A6DDF[]; +extern const u8 gUnknown_81A6E36[]; +extern const u8 gUnknown_81A6EA4[]; +extern const u8 gUnknown_81A6F0B[]; +extern const u8 gUnknown_81A6F71[]; +extern const u8 gUnknown_81A6FAB[]; +extern const u8 gUnknown_81A6FF1[]; +extern const u8 gUnknown_81A7031[]; +extern const u8 gUnknown_81A7063[]; +extern const u8 gUnknown_81A70A5[]; +extern const u8 gUnknown_81A70D8[]; +extern const u8 gUnknown_81A7108[]; +extern const u8 gUnknown_81A7137[]; +extern const u8 gUnknown_81A7175[]; + +u16 Special_GetPokedexCount(void) +{ + if (gSpecialVar_0x8004 == 0) + { + gSpecialVar_0x8005 = sub_8088EDC(0); + gSpecialVar_0x8006 = sub_8088EDC(1); + } + else + { + gSpecialVar_0x8005 = pokedex_count(0); + gSpecialVar_0x8006 = pokedex_count(1); + } + return sub_806E25C(); +} + +const u8 * sub_80CA424(u16 count) +{ + gSpecialVar_Result = FALSE; + + if (count < 10) + return gUnknown_81A6D17; + + if (count < 20) + return gUnknown_81A6D6D; + + if (count < 30) + return gUnknown_81A6DDF; + + if (count < 40) + return gUnknown_81A6E36; + + if (count < 50) + return gUnknown_81A6EA4; + + if (count < 60) + return gUnknown_81A6F0B; + + if (count < 70) + return gUnknown_81A6F71; + + if (count < 80) + return gUnknown_81A6FAB; + + if (count < 90) + return gUnknown_81A6FF1; + + if (count < 100) + return gUnknown_81A7031; + + if (count < 110) + return gUnknown_81A7063; + + if (count < 120) + return gUnknown_81A70A5; + + if (count < 130) + return gUnknown_81A70D8; + + if (count < 140) + return gUnknown_81A7108; + + if (count < 150) + return gUnknown_81A7137; + + if (count == 150) + { + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(SPECIES_MEW), 1)) + return gUnknown_81A7137; + gSpecialVar_Result = TRUE; + return gUnknown_81A7175; + } + + if (count == 151) + { + gSpecialVar_Result = TRUE; + return gUnknown_81A7175; + } + + return gUnknown_81A6D17; +} + +void sub_80CA524(void) +{ + ShowFieldMessage(sub_80CA424(gSpecialVar_0x8004)); +} diff --git a/src/quest_log.c b/src/quest_log.c index 4f462505a..0021ee927 100644 --- a/src/quest_log.c +++ b/src/quest_log.c @@ -922,7 +922,7 @@ void sub_8111070(u8 a0) StringAppend(gStringVar4, gStringVar1); } - AddTextPrinterParametrized2(gUnknown_203ADFE[0], 2, 2, 2, 1, 2, &gUnknown_8456634, 0, gStringVar4); + AddTextPrinterParameterized4(gUnknown_203ADFE[0], 2, 2, 2, 1, 2, &gUnknown_8456634, 0, gStringVar4); PutWindowTilemap(gUnknown_203ADFE[0]); PutWindowTilemap(gUnknown_203ADFE[1]); CopyWindowToVram(gUnknown_203ADFE[0], 2); @@ -985,19 +985,19 @@ void sub_8111368(void) { gUnknown_203ADFA = 2; sub_806E6FC(); - sub_809A2DC(); - sub_809A2A4(); + ClearItemSlotsInAllBagPockets(); + ClearPCItemSlots(); if (sub_8110AC8() == 1) { sub_8111274(gUnknown_203ADF8, 0); - gUnknown_3005024 = sub_8111038; + gFieldCallback2 = sub_8111038; SetMainCallback2(sub_80572A8); } else { sub_8111274(gUnknown_203ADF8, 1); warp_in(); - gUnknown_3005024 = sub_8111000; + gFieldCallback2 = sub_8111000; SetMainCallback2(sub_805726C); } } @@ -1055,7 +1055,7 @@ void sub_8111438(void) { for (r6 = 0; r6 < 30; r6++) { - if (GetBoxMonDataFromAnyBox(r3, r6, MON_DATA_SANITY_BIT2)) + if (GetBoxMonDataFromAnyBox(r3, r6, MON_DATA_SANITY_HAS_SPECIES)) { sub_808BCB4(r3, r6); r5--; @@ -1074,7 +1074,7 @@ void sub_8111438(void) for (r6 = 0; r6 < IN_BOX_COUNT; r6++) { struct BoxPokemon * boxMon = GetBoxedMonPtr(r3, r6); - if (!GetBoxMonData(boxMon, MON_DATA_SANITY_BIT2)) + if (!GetBoxMonData(boxMon, MON_DATA_SANITY_HAS_SPECIES)) { CopyMon(boxMon, &r9->mon.box, sizeof(struct BoxPokemon)); r5++; @@ -1104,7 +1104,7 @@ u16 sub_8111618(void) for (i = 0; i < PARTY_SIZE; i++) { - if (GetMonData(&gPlayerParty[i], MON_DATA_SANITY_BIT2)) + if (GetMonData(&gPlayerParty[i], MON_DATA_SANITY_HAS_SPECIES)) count++; } @@ -1120,7 +1120,7 @@ u16 sub_811164C(void) { for (j = 0; j < IN_BOX_COUNT; j++) { - if (GetBoxMonDataFromAnyBox(i, j, MON_DATA_SANITY_BIT2)) + if (GetBoxMonDataFromAnyBox(i, j, MON_DATA_SANITY_HAS_SPECIES)) count++; } } @@ -1237,7 +1237,7 @@ void sub_8111984(void) Save_ResetSaveCounters(); Save_LoadGameData(0); SetMainCallback2(sub_8057430); - gUnknown_3005024 = sub_8111F60; + gFieldCallback2 = sub_8111F60; FreeAllWindowBuffers(); gUnknown_203ADFA = 3; gUnknown_203AE8C = NULL; @@ -1417,7 +1417,7 @@ void sub_8111D10(void) PutWindowTilemap(gUnknown_203ADFE[2]); sub_8111D90(gUnknown_203ADFE[2]); - AddTextPrinterParametrized2(gUnknown_203ADFE[2], 2, 2, gUnknown_8456698[count], 1, 0, &gUnknown_8456634, 0, gStringVar4); + AddTextPrinterParameterized4(gUnknown_203ADFE[2], 2, 2, gUnknown_8456698[count], 1, 0, &gUnknown_8456634, 0, gStringVar4); schedule_bg_copy_tilemap_to_vram(0); } @@ -1599,7 +1599,7 @@ void sub_81120AC(u8 taskId) gUnknown_203AE94 = (struct UnkStruct_203AE94){}; sub_80696C0(); ScriptContext2_Disable(); - gTextFlags.flag_2 = FALSE; + gTextFlags.autoScroll = FALSE; gUnknown_2036E28 = 0; sub_8082740(0); gUnknown_3005ECC = 1; @@ -1691,7 +1691,7 @@ void sub_81123BC(void) void sub_8112450(void) { - if (sub_80BF708() != 1) + if (MenuHelpers_LinkSomething() != 1) { sub_8112364(); sub_81123BC(); @@ -2291,7 +2291,7 @@ void sub_8112E3C(u8 a0, struct UnkStruct_300201C * a1, u16 a2) } } -const u16 gUnknown_84566A8[][16] = INCBIN_U16("data/graphics/unknown_84566a8.bin"); +const u16 gUnknown_84566A8[] = INCBIN_U16("data/graphics/unknown_84566a8.bin"); const struct WindowTemplate gUnknown_8456928 = { 0x00, 0, 15, 30, 5, 15, 0x008F @@ -2349,7 +2349,7 @@ void sub_8112F18(u8 a0) else k = 5; CpuCopy32( - gUnknown_84566A8[k], // operand swap on "add" instruction + (void *)gUnknown_84566A8 + 32 * k, // operand swap on "add" instruction buffer + 32 * (i * width + j), 32 ); @@ -2468,7 +2468,7 @@ const struct TextColor gUnknown_8456930 = { void sub_8112FE4(const u8 * a0) { - AddTextPrinterParametrized2(gUnknown_203B020, 0x02, 2, 5, 1, 1, &gUnknown_8456930, -1, a0); + AddTextPrinterParameterized4(gUnknown_203B020, 0x02, 2, 5, 1, 1, &gUnknown_8456930, -1, a0); } void sub_8113018(const u8 * a0, u8 a1) @@ -2515,7 +2515,7 @@ void sub_81130BC(struct Var4038Struct * varPtr) FlagClear(FLAG_0x06D); FlagClear(FLAG_0x06E); FlagClear(FLAG_0x06F); - VarSet(VAR_0x4073, 1); + VarSet(VAR_MAP_SCENE_SAFFRON_CITY_POKEMON_TRAINER_FAN_CLUB, 1); } } @@ -2523,7 +2523,7 @@ ALIGNED(4) const u8 gUnknown_8456934[] = {2, 1, 2, 1}; u8 sub_8113114(struct Var4038Struct * a0, u8 a1) { - if (VarGet(VAR_0x4073) == 2) + if (VarGet(VAR_MAP_SCENE_SAFFRON_CITY_POKEMON_TRAINER_FAN_CLUB) == 2) { if (a0->unk_0_0 + gUnknown_8456934[a1] >= 20) { @@ -2743,10 +2743,10 @@ void sub_81134B8(void) void sub_81134CC(struct Var4038Struct * a0) { - if (VarGet(VAR_0x4073) == 2) + if (VarGet(VAR_MAP_SCENE_SAFFRON_CITY_POKEMON_TRAINER_FAN_CLUB) == 2) { sub_8113078(a0); - if (gUnknown_2023E8A == 1) + if (gBattleOutcome == B_OUTCOME_WON) sub_8113194(a0); else sub_81131FC(a0); @@ -2842,7 +2842,7 @@ void sub_8113550(u16 a0, const u16 * a1) if (sub_81138A0(a0, a1) == TRUE) return; - if (sub_80BF708() == TRUE) + if (MenuHelpers_LinkSomething() == TRUE) return; // NONMATCHING: branch logic here @@ -2954,7 +2954,7 @@ void sub_8113550(u16 a0, const u16 * a1) "\tbne _081135AA\n" "\tb ._return\n" "_081135AA:\n" - "\tbl sub_80BF708\n" + "\tbl MenuHelpers_LinkSomething\n" "\tlsls r0, 24\n" "\tlsrs r0, 24\n" "\tcmp r0, 0x1\n" @@ -3708,7 +3708,7 @@ const u16 * sub_8113FBC(const u16 * a0) case POCKET_ITEMS: case POCKET_POKE_BALLS: case POCKET_BERRY_POUCH: - StringCopy(gStringVar1, ItemId_GetItem(r5[0])->name); + StringCopy(gStringVar1, ItemId_GetName(r5[0])); if (r5[0] == ITEM_ESCAPE_ROPE) { sub_80C4DF8(gStringVar2, r5[2]); @@ -3725,7 +3725,7 @@ const u16 * sub_8113FBC(const u16 * a0) } break; case POCKET_KEY_ITEMS: - StringCopy(gStringVar1, ItemId_GetItem(r5[0])->name); + StringCopy(gStringVar1, ItemId_GetName(r5[0])); StringExpandPlaceholders(gStringVar4, gUnknown_841A220); break; case POCKET_TM_CASE: @@ -3771,7 +3771,7 @@ const u16 * sub_8114188(const u16 * a0) { const u16 * r4 = sub_8113E88(5, a0); QuestLog_AutoGetSpeciesName(r4[1], gStringVar1, 0); - StringCopy(gStringVar2, ItemId_GetItem(r4[0])->name); + StringCopy(gStringVar2, ItemId_GetName(r4[0])); StringExpandPlaceholders(gStringVar4, gUnknown_841AB74); r4 += 2; return r4; @@ -3787,7 +3787,7 @@ const u16 * sub_81141E4(const u16 * a0) const u16 * r4 = sub_8113E88(6, a0); QuestLog_AutoGetSpeciesName(r4[1], gStringVar1, 0); - StringCopy(gStringVar2, ItemId_GetItem(r4[0])->name); + StringCopy(gStringVar2, ItemId_GetName(r4[0])); StringExpandPlaceholders(gStringVar4, gUnknown_841AB8E); r4 += 2; return r4; @@ -3803,7 +3803,7 @@ const u16 * sub_8114240(const u16 * a0) const u16 * r4 = sub_8113E88(7, a0); QuestLog_AutoGetSpeciesName(r4[1], gStringVar2, 0); - StringCopy(gStringVar1, ItemId_GetItem(r4[0])->name); + StringCopy(gStringVar1, ItemId_GetName(r4[0])); StringExpandPlaceholders(gStringVar4, gUnknown_841A6A5); r4 += 2; return r4; @@ -3819,7 +3819,7 @@ const u16 * sub_811429C(const u16 * a0) const u16 * r4 = sub_8113E88(8, a0); QuestLog_AutoGetSpeciesName(r4[1], gStringVar1, 0); - StringCopy(gStringVar2, ItemId_GetItem(r4[0])->name); + StringCopy(gStringVar2, ItemId_GetName(r4[0])); StringExpandPlaceholders(gStringVar4, gUnknown_841A1CD); r4 += 2; return r4; @@ -3846,8 +3846,8 @@ const u16 * sub_8114324(const u16 * a0) { const u16 * r4 = sub_8113E88(9, a0); QuestLog_AutoGetSpeciesName(r4[2], gStringVar1, 0); - StringCopy(gStringVar2, ItemId_GetItem(r4[0])->name); - StringCopy(gStringVar3, ItemId_GetItem(r4[1])->name); + StringCopy(gStringVar2, ItemId_GetName(r4[0])); + StringCopy(gStringVar3, ItemId_GetName(r4[1])); StringExpandPlaceholders(gStringVar4, gUnknown_841A193); r4 += 3; return r4; @@ -3862,8 +3862,8 @@ const u16 * sub_8114394(const u16 * a0) { const u16 * r4 = sub_8113E88(10, a0); QuestLog_AutoGetSpeciesName(r4[2], gStringVar2, 0); - StringCopy(gStringVar3, ItemId_GetItem(r4[0])->name); - StringCopy(gStringVar1, ItemId_GetItem(r4[1])->name); + StringCopy(gStringVar3, ItemId_GetName(r4[0])); + StringCopy(gStringVar1, ItemId_GetName(r4[1])); StringExpandPlaceholders(gStringVar4, gUnknown_841A6E1); r4 += 3; return r4; @@ -4312,7 +4312,7 @@ u16 * sub_8114C68(u16 * a0, const u16 * a1) const u16 * sub_8114C8C(const u16 * a0) { const u16 *r4 = sub_8113E88(28, a0); - sub_8099E90(r4[0], gStringVar1); + CopyItemName(r4[0], gStringVar1); StringExpandPlaceholders(gStringVar4, gUnknown_841A391); return r4 + 1; } @@ -4329,7 +4329,7 @@ u16 * sub_8114CC0(u16 * a0, const u16 * a1) const u16 * sub_8114CE4(const u16 * a0) { const u16 *r4 = sub_8113E88(29, a0); - sub_8099E90(r4[0], gStringVar1); + CopyItemName(r4[0], gStringVar1); StringExpandPlaceholders(gStringVar4, gUnknown_841A3DA); return r4 + 1; } @@ -4817,7 +4817,7 @@ const u16 * sub_8115518(const u16 * a0) UnkTextUtil_Reset(); sub_80C4DF8(gStringVar1, r7[0]); UnkTextUtil_SetPtrI(0, gStringVar1); - UnkTextUtil_SetPtrI(1, ItemId_GetItem(r4[0])->name); + UnkTextUtil_SetPtrI(1, ItemId_GetName(r4[0])); if (r4[1] < 2) UnkTextUtil_StringExpandPlaceholders(gStringVar4, gUnknown_841A7DD); else @@ -4852,7 +4852,7 @@ const u16 * sub_81155E0(const u16 * a0) { if (r7[1] == 0) { UnkTextUtil_SetPtrI(0, gSaveBlock2Ptr->playerName); UnkTextUtil_SetPtrI(1, gStringVar1); - UnkTextUtil_SetPtrI(2, ItemId_GetItem(r5[0])->name); + UnkTextUtil_SetPtrI(2, ItemId_GetName(r5[0])); if (r5[1] == 1) UnkTextUtil_SetPtrI(3, gUnknown_841A8D4); else @@ -4867,7 +4867,7 @@ const u16 * sub_81155E0(const u16 * a0) { else { UnkTextUtil_SetPtrI(0, gStringVar1); - UnkTextUtil_SetPtrI(1, ItemId_GetItem(r5[0])->name); + UnkTextUtil_SetPtrI(1, ItemId_GetName(r5[0])); ConvertIntToDecimalStringN(gStringVar2, r6, STR_CONV_MODE_LEFT_ALIGN, 6); UnkTextUtil_SetPtrI(2, gStringVar2); UnkTextUtil_StringExpandPlaceholders(gStringVar4, gUnknown_841A896); @@ -4890,7 +4890,7 @@ const u16 * sub_8115700(const u16 * a0) const u16 * r4 = sub_8113E88(40, a0); const u8 * r5 = (const u8 *)r4 + 2; sub_80C4DF8(gStringVar1, r5[0]); - StringCopy(gStringVar2, ItemId_GetItem(r4[0])->name); + StringCopy(gStringVar2, ItemId_GetName(r4[0])); StringExpandPlaceholders(gStringVar4, gUnknown_841B03F); return (const u16 *)(r5 + 2); } diff --git a/src/quest_log_battle.c b/src/quest_log_battle.c index c702b6a5c..4a63042bf 100644 --- a/src/quest_log_battle.c +++ b/src/quest_log_battle.c @@ -26,7 +26,7 @@ void sub_812C334(s32 *, s32 *); void sub_812BFDC(void) { - if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_DOME)) && (gUnknown_2023E8A == 1 || gUnknown_2023E8A == 7)) + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_DOME)) && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) { struct QuestLogStruct_TrainerBattleRecord * questLogTrainerBattleRecord = Alloc(sizeof(struct QuestLogStruct_TrainerBattleRecord)); struct QuestLogStruct_WildBattleRecord * questLogWildBattleRecord = Alloc(sizeof(struct QuestLogStruct_WildBattleRecord)); @@ -71,7 +71,7 @@ void sub_812BFDC(void) playerEndingHP = gBattleMons[GetBattlerAtPosition(0)].hp; playerMaxHP = gBattleMons[GetBattlerAtPosition(0)].maxHP; } - questLogTrainerBattleRecord->v7 = sav1_map_get_name(); + questLogTrainerBattleRecord->v7 = GetCurrentRegionMapSectionId(); questLogTrainerBattleRecord->v6 = 0; if (playerEndingHP < playerMaxHP / 3 * 2) questLogTrainerBattleRecord->v6 = 1; @@ -81,7 +81,7 @@ void sub_812BFDC(void) } else { - if (gUnknown_2023E8A == 1) + if (gBattleOutcome == B_OUTCOME_WON) { questLogWildBattleRecord->v0 = GetMonData(gEnemyParty + 0, MON_DATA_SPECIES); questLogWildBattleRecord->v2 = SPECIES_NONE; @@ -91,7 +91,7 @@ void sub_812BFDC(void) questLogWildBattleRecord->v0 = SPECIES_NONE; questLogWildBattleRecord->v2 = GetMonData(gEnemyParty + 0, MON_DATA_SPECIES); } - questLogWildBattleRecord->v4 = sav1_map_get_name(); + questLogWildBattleRecord->v4 = GetCurrentRegionMapSectionId(); sub_8113550(31, (const u16 *)questLogWildBattleRecord); } Free(questLogTrainerBattleRecord); @@ -116,7 +116,7 @@ void sub_812C224(void) if (gBattleTypeFlags & BATTLE_TYPE_LINK) { struct QuestLogStruct_LinkBattleRecord * r5 = Alloc(sizeof(struct QuestLogStruct_LinkBattleRecord)); - r5->v0 = gUnknown_2023E8A - 1; + r5->v0 = gBattleOutcome - 1; // 0 = won, 1 = lost, 2 = drew if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { r8 = 15; diff --git a/src/roamer.c b/src/roamer.c new file mode 100644 index 000000000..b42855644 --- /dev/null +++ b/src/roamer.c @@ -0,0 +1,240 @@ +#include "global.h" +#include "roamer.h" +#include "random.h" +#include "overworld.h" +#include "field_specials.h" +#include "constants/species.h" +#include "constants/maps.h" +#include "constants/region_map.h" + +EWRAM_DATA u8 sLocationHistory[3][2] = {}; +EWRAM_DATA u8 sRoamerLocation[2] = {}; + +#define saveRoamer (*(&gSaveBlock1Ptr->roamer)) + +enum +{ + MAP_GRP = 0, // map group + MAP_NUM = 1, // map number +}; + +const u8 sRoamerLocations[][7] = { + {MAP_NUM(ROUTE1), MAP_NUM(ROUTE2), MAP_NUM(ROUTE21_NORTH), MAP_NUM(ROUTE22), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE2), MAP_NUM(ROUTE1), MAP_NUM(ROUTE3), MAP_NUM(ROUTE22), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE3), MAP_NUM(ROUTE2), MAP_NUM(ROUTE4), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE4), MAP_NUM(ROUTE3), MAP_NUM(ROUTE5), MAP_NUM(ROUTE9), MAP_NUM(ROUTE24), 0xff, 0xff}, + {MAP_NUM(ROUTE5), MAP_NUM(ROUTE4), MAP_NUM(ROUTE6), MAP_NUM(ROUTE7), MAP_NUM(ROUTE8), MAP_NUM(ROUTE9), MAP_NUM(ROUTE24)}, + {MAP_NUM(ROUTE6), MAP_NUM(ROUTE5), MAP_NUM(ROUTE7), MAP_NUM(ROUTE8), MAP_NUM(ROUTE11), 0xff, 0xff}, + {MAP_NUM(ROUTE7), MAP_NUM(ROUTE5), MAP_NUM(ROUTE6), MAP_NUM(ROUTE8), MAP_NUM(ROUTE16), 0xff, 0xff}, + {MAP_NUM(ROUTE8), MAP_NUM(ROUTE5), MAP_NUM(ROUTE6), MAP_NUM(ROUTE7), MAP_NUM(ROUTE10), MAP_NUM(ROUTE12), 0xff}, + {MAP_NUM(ROUTE9), MAP_NUM(ROUTE4), MAP_NUM(ROUTE5), MAP_NUM(ROUTE10), MAP_NUM(ROUTE24), 0xff, 0xff}, + {MAP_NUM(ROUTE10), MAP_NUM(ROUTE8), MAP_NUM(ROUTE9), MAP_NUM(ROUTE12), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE11), MAP_NUM(ROUTE6), MAP_NUM(ROUTE12), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE12), MAP_NUM(ROUTE10), MAP_NUM(ROUTE11), MAP_NUM(ROUTE13), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE13), MAP_NUM(ROUTE12), MAP_NUM(ROUTE14), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE14), MAP_NUM(ROUTE13), MAP_NUM(ROUTE15), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE15), MAP_NUM(ROUTE14), MAP_NUM(ROUTE18), MAP_NUM(ROUTE19), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE16), MAP_NUM(ROUTE7), MAP_NUM(ROUTE17), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE17), MAP_NUM(ROUTE16), MAP_NUM(ROUTE18), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE18), MAP_NUM(ROUTE15), MAP_NUM(ROUTE17), MAP_NUM(ROUTE19), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE19), MAP_NUM(ROUTE15), MAP_NUM(ROUTE18), MAP_NUM(ROUTE20), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE20), MAP_NUM(ROUTE19), MAP_NUM(ROUTE21_NORTH), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE21_NORTH), MAP_NUM(ROUTE1), MAP_NUM(ROUTE20), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE22), MAP_NUM(ROUTE1), MAP_NUM(ROUTE2), MAP_NUM(ROUTE23), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE23), MAP_NUM(ROUTE22), MAP_NUM(ROUTE2), 0xff, 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE24), MAP_NUM(ROUTE4), MAP_NUM(ROUTE5), MAP_NUM(ROUTE9), 0xff, 0xff, 0xff}, + {MAP_NUM(ROUTE25), MAP_NUM(ROUTE24), MAP_NUM(ROUTE9), 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} +}; + +void ClearRoamerData(void) +{ + u32 i; + gSaveBlock1Ptr->roamer = (struct Roamer){}; + sRoamerLocation[MAP_GRP] = 0; + sRoamerLocation[MAP_NUM] = 0; + for (i = 0; i < 3; i++) + { + sLocationHistory[i][MAP_GRP] = 0; + sLocationHistory[i][MAP_NUM] = 0; + } +} + +#define GetRoamerSpecies() ({\ + u16 a;\ + switch (ScrSpecial_GetStarter())\ + {\ + default:\ + a = SPECIES_RAIKOU;\ + break;\ + case SPECIES_BULBASAUR:\ + a = SPECIES_ENTEI;\ + break;\ + case SPECIES_CHARMANDER:\ + a = SPECIES_SUICUNE;\ + break;\ + }\ + a;\ +}) + +void CreateInitialRoamerMon(void) +{ + struct Pokemon * tmpMon = &gEnemyParty[0]; + u16 roamerMon; + + CreateMon(tmpMon, (roamerMon = GetRoamerSpecies()), 50, 0x20, 0, 0, 0, 0); + saveRoamer.species = roamerMon; + saveRoamer.level = 50; + saveRoamer.status = 0; + saveRoamer.active = TRUE; + saveRoamer.ivs = GetMonData(tmpMon, MON_DATA_IVS); + saveRoamer.personality = GetMonData(tmpMon, MON_DATA_PERSONALITY); + saveRoamer.hp = GetMonData(tmpMon, MON_DATA_MAX_HP); + saveRoamer.cool = GetMonData(tmpMon, MON_DATA_COOL); + saveRoamer.beauty = GetMonData(tmpMon, MON_DATA_BEAUTY); + saveRoamer.cute = GetMonData(tmpMon, MON_DATA_CUTE); + saveRoamer.smart = GetMonData(tmpMon, MON_DATA_SMART); + saveRoamer.tough = GetMonData(tmpMon, MON_DATA_TOUGH); + sRoamerLocation[MAP_GRP] = 3; + sRoamerLocation[MAP_NUM] = sRoamerLocations[Random() % (ARRAY_COUNT(sRoamerLocations) - 1)][0]; +} + +void InitRoamer(void) +{ + ClearRoamerData(); + CreateInitialRoamerMon(); +} + +void UpdateLocationHistoryForRoamer(void) +{ + sLocationHistory[2][MAP_GRP] = sLocationHistory[1][MAP_GRP]; + sLocationHistory[2][MAP_NUM] = sLocationHistory[1][MAP_NUM]; + sLocationHistory[1][MAP_GRP] = sLocationHistory[0][MAP_GRP]; + sLocationHistory[1][MAP_NUM] = sLocationHistory[0][MAP_NUM]; + sLocationHistory[0][MAP_GRP] = gSaveBlock1Ptr->location.mapGroup; + sLocationHistory[0][MAP_NUM] = gSaveBlock1Ptr->location.mapNum; +} + +void RoamerMoveToOtherLocationSet(void) +{ + u8 mapNum = 0; + struct Roamer *roamer = &saveRoamer; + + if (!roamer->active) + return; + + sRoamerLocation[MAP_GRP] = 3; + + while (1) + { + mapNum = sRoamerLocations[Random() % (ARRAY_COUNT(sRoamerLocations) - 1)][0]; + if (sRoamerLocation[MAP_NUM] != mapNum) + { + sRoamerLocation[MAP_NUM] = mapNum; + return; + } + } +} + + +void RoamerMove(void) +{ + u8 locSet = 0; + + if ((Random() % 16) == 0) + { + RoamerMoveToOtherLocationSet(); + } + else + { + struct Roamer *roamer = &saveRoamer; + + if (!roamer->active) + return; + + while (locSet < (ARRAY_COUNT(sRoamerLocations) - 1)) + { + if (sRoamerLocation[MAP_NUM] == sRoamerLocations[locSet][0]) + { + u8 mapNum; + while (1) + { + mapNum = sRoamerLocations[locSet][(Random() % 6) + 1]; + if (!(sLocationHistory[2][MAP_GRP] == 3 && sLocationHistory[2][MAP_NUM] == mapNum) && mapNum != 0xFF) + break; + } + sRoamerLocation[MAP_NUM] = mapNum; + return; + } + locSet++; + } + } +} + +bool8 IsRoamerAt(u8 mapGroup, u8 mapNum) +{ + struct Roamer *roamer = &saveRoamer; + + if (roamer->active && mapGroup == sRoamerLocation[MAP_GRP] && mapNum == sRoamerLocation[MAP_NUM]) + return TRUE; + else + return FALSE; +} + +void CreateRoamerMonInstance(void) +{ + struct Pokemon *mon; + struct Roamer *roamer; + + mon = &gEnemyParty[0]; + ZeroEnemyPartyMons(); + roamer = &saveRoamer; + CreateMonWithIVsPersonality(mon, roamer->species, roamer->level, roamer->ivs, roamer->personality); + SetMonData(mon, MON_DATA_STATUS, &gSaveBlock1Ptr->roamer.status); + SetMonData(mon, MON_DATA_HP, &gSaveBlock1Ptr->roamer.hp); + SetMonData(mon, MON_DATA_COOL, &gSaveBlock1Ptr->roamer.cool); + SetMonData(mon, MON_DATA_BEAUTY, &gSaveBlock1Ptr->roamer.beauty); + SetMonData(mon, MON_DATA_CUTE, &gSaveBlock1Ptr->roamer.cute); + SetMonData(mon, MON_DATA_SMART, &gSaveBlock1Ptr->roamer.smart); + SetMonData(mon, MON_DATA_TOUGH, &gSaveBlock1Ptr->roamer.tough); +} + +bool8 TryStartRoamerEncounter(void) +{ + if (IsRoamerAt(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum) == TRUE && (Random() % 4) == 0) + { + CreateRoamerMonInstance(); + return TRUE; + } + else + { + return FALSE; + } +} +void UpdateRoamerHPStatus(struct Pokemon *mon) +{ + saveRoamer.hp = GetMonData(mon, MON_DATA_HP); + saveRoamer.status = GetMonData(mon, MON_DATA_STATUS); + + RoamerMoveToOtherLocationSet(); +} + +void SetRoamerInactive(void) +{ + struct Roamer *roamer = &saveRoamer; + roamer->active = FALSE; +} + +void GetRoamerLocation(u8 *mapGroup, u8 *mapNum) +{ + *mapGroup = sRoamerLocation[MAP_GRP]; + *mapNum = sRoamerLocation[MAP_NUM]; +} + +u16 GetRoamerLocationMapSectionId(void) +{ + struct Roamer *roamer = &saveRoamer; + if (!saveRoamer.active) + return MAPSEC_NONE; + return get_mapheader_by_bank_and_number(sRoamerLocation[MAP_GRP], sRoamerLocation[MAP_NUM])->regionMapSectionId; +} diff --git a/src/roulette_util.c b/src/roulette_util.c new file mode 100644 index 000000000..3c5a3c825 --- /dev/null +++ b/src/roulette_util.c @@ -0,0 +1,463 @@ +#include "global.h" +#include "palette.h" +#include "roulette_util.h" +#include "util.h" + +void sub_80D8BE4(struct UnkStruct0 *r0) +{ + r0->var00 = 0; + r0->var02 = 0; + memset(&r0->var04, 0, sizeof(r0->var04)); +} + +u8 sub_80D8BF8(struct UnkStruct0 *r0, u8 r1, const struct UnkStruct1 *r2) +{ + if (!(r1 < 16) || (r0->var04[r1].var00_7)) + return 0xFF; + + r0->var04[r1].var04.var00 = r2->var00; + r0->var04[r1].var04.var02 = r2->var02; + r0->var04[r1].var04.var04 = r2->var04; + r0->var04[r1].var04.var05 = r2->var05; + r0->var04[r1].var04.var06 = r2->var06; + r0->var04[r1].var04.var07_0 = r2->var07_0; + r0->var04[r1].var04.var07_5 = r2->var07_5; + r0->var04[r1].var04.var07_7 = r2->var07_7; + r0->var04[r1].var00_0 = 0; + r0->var04[r1].var00_7 = 1; + r0->var04[r1].var02 = 0; + r0->var04[r1].var01 = 0; + if (r0->var04[r1].var04.var07_7 < 0) + r0->var04[r1].var03 = 0xFF; + else + r0->var04[r1].var03 = 1; + + return r1; +} + +u8 sub_80D8C7C(struct UnkStruct0 *r0, u8 r1) +{ + if (r1 >= 16) + return 0xFF; + if (!r0->var04[r1].var00_7) + return 0xFF; + + memset(&r0->var04[r1], 0, sizeof(r0->var04[r1])); + return r1; +} + +u8 sub_80D8CB0(struct UnkStruct3 *r0) +{ + u8 i; + u8 returnval; + + for (i = 0; i < r0->var04.var04; i++) + { + struct PlttData *faded = (struct PlttData *)&gPlttBufferFaded[r0->var04.var02 + i]; + struct PlttData *unfaded = (struct PlttData *)&gPlttBufferUnfaded[r0->var04.var02 + i]; + + switch (r0->var00_0) + { + case 1: + if (faded->r + r0->var03 >= 0 && faded->r + r0->var03 < 32) + faded->r += r0->var03; + if (faded->g + r0->var03 >= 0 && faded->g + r0->var03 < 32) + faded->g += r0->var03; + if (faded->b + r0->var03 >= 0 && faded->b + r0->var03 < 32) + faded->b += r0->var03; + break; + case 2: + if (r0->var03 < 0) + { + if (faded->r + r0->var03 >= unfaded->r) + faded->r += r0->var03; + if (faded->g + r0->var03 >= unfaded->g) + faded->g += r0->var03; + if (faded->b + r0->var03 >= unfaded->b) + faded->b += r0->var03; + } + else + { + if (faded->r + r0->var03 <= unfaded->r) + faded->r += r0->var03; + if (faded->g + r0->var03 <= unfaded->g) + faded->g += r0->var03; + if (faded->b + r0->var03 <= unfaded->b) + faded->b += r0->var03; + } + break; + } + } + if ((u32)r0->var02++ != r0->var04.var07_0) + { + returnval = 0; + } + else + { + r0->var02 = 0; + r0->var03 *= -1; + if (r0->var00_0 == 1) + r0->var00_0++; + else + r0->var00_0--; + returnval = 1; + } + return returnval; +} + +u8 sub_80D8EB8(struct UnkStruct3 *r0) +{ + u8 rg2 = 0; + + switch (r0->var00_0) + { + case 1: + for (rg2 = 0; rg2 < r0->var04.var04; rg2++) + gPlttBufferFaded[r0->var04.var02 + rg2] = r0->var04.var00; + r0->var00_0++; + break; + case 2: + for (rg2 = 0; rg2 < r0->var04.var04; rg2++) + gPlttBufferFaded[r0->var04.var02 + rg2] = gPlttBufferUnfaded[r0->var04.var02 + rg2]; + r0->var00_0--; + break; + } + return 1; +} + +void task_tutorial_controls_fadein(struct UnkStruct0 *r0) +{ + u8 i = 0; + + if (r0->var00) + { + for (i = 0; i < 16; i++) + { + if ((r0->var02 >> i) & 1) + { + if (--r0->var04[i].var01 == 0xFF) // if underflow ? + { + if (r0->var04[i].var04.var00 & 0x8000) // PlttData->unused_15 ? + sub_80D8CB0(&r0->var04[i]); + else + sub_80D8EB8(&r0->var04[i]); + + r0->var04[i].var01 = r0->var04[i].var04.var05; + } + } + } + } +} + +void sub_80D8FB4(struct UnkStruct0 *r0, u16 r1) +{ + u8 i = 0; + + r0->var00++; + for (i = 0; i < 16; i++) + { + if ((r1 >> i) & 1) + { + if (r0->var04[i].var00_7) + { + r0->var02 |= 1 << i; + r0->var04[i].var00_0 = 1; + } + } + } +} + +void sub_80D9008(struct UnkStruct0 *r0, u16 r1) +{ + u8 i; + + for (i = 0; i < 16; i++) + { + if ((r0->var02 >> i) & 1) + { + if (r0->var04[i].var00_7) + { + if ((r1 >> i) & 1) + { + u32 offset = r0->var04[i].var04.var02; + u16 *faded = &gPlttBufferFaded[offset]; + u16 *unfaded = &gPlttBufferUnfaded[offset]; + memcpy(faded, unfaded, r0->var04[i].var04.var04 * 2); + r0->var04[i].var00_0 = 0; + r0->var04[i].var02 = 0; + r0->var04[i].var01 = 0; + if (r0->var04[i].var04.var07_7 < 0) + r0->var04[i].var03 = 0xFF; + else + r0->var04[i].var03 = 0x1; + } + } + } + } + if (r1 == 0xFFFF) + { + r0->var00 = 0; + r0->var02 = 0; + } + else + { + r0->var02 = r0->var02 & ~r1; + } +} + +void InitPulseBlend(struct PulseBlend *pulseBlend) +{ + u8 i = 0; + pulseBlend->usedPulseBlendPalettes = 0; + memset(&pulseBlend->pulseBlendPalettes, 0, sizeof(pulseBlend->pulseBlendPalettes)); + for (; i < 16; i++) + pulseBlend->pulseBlendPalettes[i].paletteSelector = i; +} + +int InitPulseBlendPaletteSettings(struct PulseBlend *pulseBlend, const struct PulseBlendSettings *settings) +{ + u8 i = 0; + struct PulseBlendPalette *pulseBlendPalette = NULL; + + if (!pulseBlend->pulseBlendPalettes[0].inUse) + { + pulseBlendPalette = &pulseBlend->pulseBlendPalettes[0]; + } + else + { + while (++i < 16) + { + if (!pulseBlend->pulseBlendPalettes[i].inUse) + { + pulseBlendPalette = &pulseBlend->pulseBlendPalettes[i]; + break; + } + } + } + + if (pulseBlendPalette == NULL) + return 0xFF; + + pulseBlendPalette->blendCoeff = 0; + pulseBlendPalette->fadeDirection = 0; + pulseBlendPalette->available = 1; + pulseBlendPalette->inUse = 1; + pulseBlendPalette->delayCounter = 0; + pulseBlendPalette->fadeCycleCounter = 0; + memcpy(&pulseBlendPalette->pulseBlendSettings, settings, sizeof(*settings)); + return i; +} + +static void ClearPulseBlendPalettesSettings(struct PulseBlendPalette *pulseBlendPalette) +{ + u16 i; + + if (!pulseBlendPalette->available && pulseBlendPalette->pulseBlendSettings.restorePaletteOnUnload) + { + for (i = pulseBlendPalette->pulseBlendSettings.paletteOffset; i < pulseBlendPalette->pulseBlendSettings.paletteOffset + pulseBlendPalette->pulseBlendSettings.numColors; i++) + gPlttBufferFaded[i] = gPlttBufferUnfaded[i]; + } + + memset(&pulseBlendPalette->pulseBlendSettings, 0, sizeof(pulseBlendPalette->pulseBlendSettings)); + pulseBlendPalette->blendCoeff = 0; + pulseBlendPalette->fadeDirection = 0; + pulseBlendPalette->unk1_5 = 0; + pulseBlendPalette->available = 1; + pulseBlendPalette->inUse = 0; + pulseBlendPalette->fadeCycleCounter = 0; + pulseBlendPalette->delayCounter = 0; +} + +void UnloadUsedPulseBlendPalettes(struct PulseBlend *pulseBlend, u16 pulseBlendPaletteSelector, u8 multiSelection) +{ + u16 i = 0; + + if (!multiSelection) + { + ClearPulseBlendPalettesSettings(&pulseBlend->pulseBlendPalettes[pulseBlendPaletteSelector & 0xF]); + } + else + { + for (i = 0; i < 16; i++) + { + if ((pulseBlendPaletteSelector & 1) && pulseBlend->pulseBlendPalettes[i].inUse) + ClearPulseBlendPalettesSettings(&pulseBlend->pulseBlendPalettes[i]); + + pulseBlendPaletteSelector >>= 1; + } + } +} + +void MarkUsedPulseBlendPalettes(struct PulseBlend *pulseBlend, u16 pulseBlendPaletteSelector, u8 multiSelection) +{ + u8 i = 0; + + if (!multiSelection) + { + i = pulseBlendPaletteSelector & 0xF; + pulseBlend->pulseBlendPalettes[i].available = 0; + pulseBlend->usedPulseBlendPalettes |= 1 << i; + } + else + { + for (i = 0; i < 16; i++) + { + if (!(pulseBlendPaletteSelector & 1) || !pulseBlend->pulseBlendPalettes[i].inUse || !pulseBlend->pulseBlendPalettes[i].available) + { + pulseBlendPaletteSelector <<= 1; + } + else + { + pulseBlend->pulseBlendPalettes[i].available = 0; + pulseBlend->usedPulseBlendPalettes |= 1 << i; + } + } + } +} + +void UnmarkUsedPulseBlendPalettes(struct PulseBlend *pulseBlend, u16 pulseBlendPaletteSelector, u8 multiSelection) +{ + u16 i; + struct PulseBlendPalette *pulseBlendPalette; + u8 j = 0; + + if (!multiSelection) + { + pulseBlendPalette = &pulseBlend->pulseBlendPalettes[pulseBlendPaletteSelector & 0xF]; + if (!pulseBlendPalette->available && pulseBlendPalette->inUse) + { + if (pulseBlendPalette->pulseBlendSettings.restorePaletteOnUnload) + { + for (i = pulseBlendPalette->pulseBlendSettings.paletteOffset; i < pulseBlendPalette->pulseBlendSettings.paletteOffset + pulseBlendPalette->pulseBlendSettings.numColors; i++) + gPlttBufferFaded[i] = gPlttBufferUnfaded[i]; + } + + pulseBlendPalette->available = 1; + pulseBlend->usedPulseBlendPalettes &= ~(1 << j); + } + } + else + { + for (j = 0; j < 16; j++) + { + pulseBlendPalette = &pulseBlend->pulseBlendPalettes[j]; + if (!(pulseBlendPaletteSelector & 1) || pulseBlendPalette->available || !pulseBlendPalette->inUse) + { + pulseBlendPaletteSelector <<= 1; + } + else + { + if (pulseBlendPalette->pulseBlendSettings.restorePaletteOnUnload) + { + for (i = pulseBlendPalette->pulseBlendSettings.paletteOffset; i < pulseBlendPalette->pulseBlendSettings.paletteOffset + pulseBlendPalette->pulseBlendSettings.numColors; i++) + gPlttBufferFaded[i] = gPlttBufferUnfaded[i]; + } + + pulseBlendPalette->available = 1; + pulseBlend->usedPulseBlendPalettes &= ~(1 << j); + } + } + } +} + +void UpdatePulseBlend(struct PulseBlend *pulseBlend) +{ + struct PulseBlendPalette *pulseBlendPalette; + u8 i = 0; + + if (pulseBlend->usedPulseBlendPalettes) + { + for (i = 0; i < 16; i++) + { + pulseBlendPalette = &pulseBlend->pulseBlendPalettes[i]; + if ((!pulseBlendPalette->available && pulseBlendPalette->inUse) && (!gPaletteFade.active || !pulseBlendPalette->pulseBlendSettings.unk7_7)) + { + if (--pulseBlendPalette->delayCounter == 0xFF) + { + pulseBlendPalette->delayCounter = pulseBlendPalette->pulseBlendSettings.delay; + BlendPalette(pulseBlendPalette->pulseBlendSettings.paletteOffset, pulseBlendPalette->pulseBlendSettings.numColors, pulseBlendPalette->blendCoeff, pulseBlendPalette->pulseBlendSettings.blendColor); + switch (pulseBlendPalette->pulseBlendSettings.fadeType) + { + case 0: // Fade all the way to the max blend amount, then wrap around + // BUG: This comparison will never be true for maxBlendCoeff values that are >= 8. This is because + // maxBlendCoeff is a signed 4-bit field, but blendCoeff is an unsigned 4-bit field. This code is never + // reached, anyway, so the bug is not observable in vanilla gameplay. + if (pulseBlendPalette->blendCoeff++ == pulseBlendPalette->pulseBlendSettings.maxBlendCoeff) + { + pulseBlendPalette->fadeCycleCounter++; + pulseBlendPalette->blendCoeff = 0; + } + break; + case 1: // Fade in and out + if (pulseBlendPalette->fadeDirection) + { + if (--pulseBlendPalette->blendCoeff == 0) + { + pulseBlendPalette->fadeCycleCounter++; + pulseBlendPalette->fadeDirection ^= 1; + } + } + else + { + u8 max = (pulseBlendPalette->pulseBlendSettings.maxBlendCoeff - 1) & 0xF; + if (pulseBlendPalette->blendCoeff++ == max) + { + pulseBlendPalette->fadeCycleCounter++; + pulseBlendPalette->fadeDirection ^= 1; + } + } + break; + case 2: // Flip back and forth + if (pulseBlendPalette->fadeDirection) + pulseBlendPalette->blendCoeff = 0; + else + pulseBlendPalette->blendCoeff = pulseBlendPalette->pulseBlendSettings.maxBlendCoeff & 0xF; + + pulseBlendPalette->fadeDirection ^= 1; + pulseBlendPalette->fadeCycleCounter++; + break; + } + + if (pulseBlendPalette->pulseBlendSettings.numFadeCycles != 0xFF + && pulseBlendPalette->fadeCycleCounter == pulseBlendPalette->pulseBlendSettings.numFadeCycles) + UnmarkUsedPulseBlendPalettes(pulseBlend, pulseBlendPalette->paletteSelector, FALSE); + } + } + } + } +} + +void sub_80D9574(u16 *dest, u16 src, u8 left, u8 top, u8 width, u8 height) +{ + u16 *_dest; + u8 i; + u8 j; + i = 0; + dest = &dest[top * 32 + left]; + for (; i < height; i++) + { + _dest = dest + i * 32; + for (j = 0; j < width; j++) + { + *_dest++ = src; + } + } +} + +void sub_80D95C4(u16 *dest, u16 *src, u8 left, u8 top, u8 width, u8 height) +{ + u16 *_dest; + u16 *_src = src; + u8 i; + u8 j; + i = 0; + dest = &dest[top * 32 + left]; + for (; i < height; i++) + { + _dest = dest + i * 32; + for (j = 0; j < width; j++) + { + *_dest++ = *_src++; + } + } +} diff --git a/src/save.c b/src/save.c index ef38d8b17..d3d31a22e 100644 --- a/src/save.c +++ b/src/save.c @@ -69,7 +69,7 @@ const struct SaveSectionOffsets gSaveSectionOffsets[] = extern void DoSaveFailedScreen(u8 saveType); // save_failed_screen extern void sub_800AB9C(void); // link extern bool8 sub_800A4BC(void); // link -extern void sub_80590D8(void); // fieldmap +extern void save_serialize_map(void); // fieldmap extern void sub_804C1C0(void); // load_save extern void sav2_gender2_inplace_and_xFE(void); // load_save @@ -828,7 +828,7 @@ u32 TryCopySpecialSaveSection(u8 sector, u8* dst) return 1; } -u32 sub_80DA5E0(u8 sector, u8* src) +u32 TryWriteSpecialSaveSection(u8 sector, u8* src) { s32 i; s32 size; @@ -867,7 +867,7 @@ void sub_80DA634(u8 taskId) case 2: if (sub_800A4BC()) { - sub_80590D8(); + save_serialize_map(); gTasks[taskId].data[0] = 3; } break; diff --git a/src/scanline_effect.c b/src/scanline_effect.c new file mode 100644 index 000000000..22699b96d --- /dev/null +++ b/src/scanline_effect.c @@ -0,0 +1,262 @@ +#include "global.h" +#include "battle.h" +#include "task.h" +#include "trig.h" +#include "scanline_effect.h" + +extern u16 gBattle_BG0_X; +extern u16 gBattle_BG0_Y; +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; +extern u16 gBattle_BG3_X; +extern u16 gBattle_BG3_Y; + +static void CopyValue16Bit(void); +static void CopyValue32Bit(void); + +// EWRAM vars + +// Per-scanline register values. +// This is double buffered so that it can be safely written to at any time +// without overwriting the buffer that the DMA is currently reading +EWRAM_DATA u16 gScanlineEffectRegBuffers[2][0x3C0] = {0}; + +EWRAM_DATA struct ScanlineEffect gScanlineEffect = {0}; +EWRAM_DATA static bool8 sShouldStopWaveTask = FALSE; + +void ScanlineEffect_Stop(void) +{ + gScanlineEffect.state = 0; + DmaStop(0); + if (gScanlineEffect.waveTaskId != 0xFF) + { + DestroyTask(gScanlineEffect.waveTaskId); + gScanlineEffect.waveTaskId = 0xFF; + } +} + +void ScanlineEffect_Clear(void) +{ + CpuFill16(0, gScanlineEffectRegBuffers, sizeof(gScanlineEffectRegBuffers)); + gScanlineEffect.dmaSrcBuffers[0] = NULL; + gScanlineEffect.dmaSrcBuffers[1] = NULL; + gScanlineEffect.dmaDest = NULL; + gScanlineEffect.dmaControl = 0; + gScanlineEffect.srcBuffer = 0; + gScanlineEffect.state = 0; + gScanlineEffect.unused16 = 0; + gScanlineEffect.unused17 = 0; + gScanlineEffect.waveTaskId = 0xFF; +} + +void ScanlineEffect_SetParams(struct ScanlineEffectParams params) +{ + if (params.dmaControl == SCANLINE_EFFECT_DMACNT_16BIT) // 16-bit + { + // Set the DMA src to the value for the second scanline because the + // first DMA transfer occurs in HBlank *after* the first scanline is drawn + gScanlineEffect.dmaSrcBuffers[0] = (u16 *)gScanlineEffectRegBuffers[0] + 1; + gScanlineEffect.dmaSrcBuffers[1] = (u16 *)gScanlineEffectRegBuffers[1] + 1; + gScanlineEffect.setFirstScanlineReg = CopyValue16Bit; + } + else // assume 32-bit + { + // Set the DMA src to the value for the second scanline because the + // first DMA transfer occurs in HBlank *after* the first scanline is drawn + gScanlineEffect.dmaSrcBuffers[0] = (u32 *)gScanlineEffectRegBuffers[0] + 1; + gScanlineEffect.dmaSrcBuffers[1] = (u32 *)gScanlineEffectRegBuffers[1] + 1; + gScanlineEffect.setFirstScanlineReg = CopyValue32Bit; + } + + gScanlineEffect.dmaControl = params.dmaControl; + gScanlineEffect.dmaDest = params.dmaDest; + gScanlineEffect.state = params.initState; + gScanlineEffect.unused16 = params.unused9; + gScanlineEffect.unused17 = params.unused9; +} + +void ScanlineEffect_InitHBlankDmaTransfer(void) +{ + if (gScanlineEffect.state == 0) + { + return; + } + else if (gScanlineEffect.state == 3) + { + gScanlineEffect.state = 0; + DmaStop(0); + sShouldStopWaveTask = TRUE; + } + else + { + DmaStop(0); + // Set DMA to copy to dest register on each HBlank for the next frame. + // The HBlank DMA transfers do not occurr during VBlank, so the transfer + // will begin on the HBlank after the first scanline + DmaSet(0, gScanlineEffect.dmaSrcBuffers[gScanlineEffect.srcBuffer], gScanlineEffect.dmaDest, gScanlineEffect.dmaControl); + // Manually set the reg for the first scanline + gScanlineEffect.setFirstScanlineReg(); + // Swap current buffer + gScanlineEffect.srcBuffer ^= 1; + } +} + +// These two functions are used to copy the register for the first scanline, +// depending whether it is a 16-bit register or a 32-bit register. + +static void CopyValue16Bit(void) +{ + u16 *dest = (u16 *)gScanlineEffect.dmaDest; + u16 *src = (u16 *)&gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer]; + + *dest = *src; +} + +static void CopyValue32Bit(void) +{ + u32 *dest = (u32 *)gScanlineEffect.dmaDest; + u32 *src = (u32 *)&gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer]; + + *dest = *src; +} + +#define tStartLine data[0] +#define tEndLine data[1] +#define tWaveLength data[2] +#define tSrcBufferOffset data[3] +#define tFramesUntilMove data[4] +#define tDelayInterval data[5] +#define tRegOffset data[6] +#define tApplyBattleBgOffsets data[7] + +static void TaskFunc_UpdateWavePerFrame(u8 taskId) +{ + int value = 0; + int i; + int offset; + + if (sShouldStopWaveTask) + { + DestroyTask(taskId); + gScanlineEffect.waveTaskId = 0xFF; + } + else + { + if (gTasks[taskId].tApplyBattleBgOffsets) + { + switch (gTasks[taskId].tRegOffset) + { + case SCANLINE_EFFECT_REG_BG0HOFS: + value = gBattle_BG0_X; + break; + case SCANLINE_EFFECT_REG_BG0VOFS: + value = gBattle_BG0_Y; + break; + case SCANLINE_EFFECT_REG_BG1HOFS: + value = gBattle_BG1_X; + break; + case SCANLINE_EFFECT_REG_BG1VOFS: + value = gBattle_BG1_Y; + break; + case SCANLINE_EFFECT_REG_BG2HOFS: + value = gBattle_BG2_X; + break; + case SCANLINE_EFFECT_REG_BG2VOFS: + value = gBattle_BG2_Y; + break; + case SCANLINE_EFFECT_REG_BG3HOFS: + value = gBattle_BG3_X; + break; + case SCANLINE_EFFECT_REG_BG3VOFS: + value = gBattle_BG3_Y; + break; + } + } + if (gTasks[taskId].tFramesUntilMove != 0) + { + gTasks[taskId].tFramesUntilMove--; + offset = gTasks[taskId].tSrcBufferOffset + 320; + for (i = gTasks[taskId].tStartLine; i < gTasks[taskId].tEndLine; i++) + { + gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = gScanlineEffectRegBuffers[0][offset] + value; + offset++; + } + } + else + { + gTasks[taskId].tFramesUntilMove = gTasks[taskId].tDelayInterval; + offset = gTasks[taskId].tSrcBufferOffset + 320; + for (i = gTasks[taskId].tStartLine; i < gTasks[taskId].tEndLine; i++) + { + gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = gScanlineEffectRegBuffers[0][offset] + value; + offset++; + } + + // increment src buffer offset + gTasks[taskId].tSrcBufferOffset++; + if (gTasks[taskId].tSrcBufferOffset == gTasks[taskId].tWaveLength) + gTasks[taskId].tSrcBufferOffset = 0; + } + } +} + +static void GenerateWave(u16 *buffer, u8 frequency, u8 amplitude, u8 unused) +{ + u16 i = 0; + u8 theta = 0; + + while (i < 256) + { + buffer[i] = (gSineTable[theta] * amplitude) / 256; + theta += frequency; + i++; + } +} + +// Initializes a background "wave" effect that affects scanlines startLine (inclusive) to endLine (exclusive). +// 'frequency' and 'amplitude' control the frequency and amplitude of the wave. +// 'delayInterval' controls how fast the wave travels up the screen. The wave will shift upwards one scanline every 'delayInterval'+1 frames. +// 'regOffset' is the offset of the video register to modify. +u8 ScanlineEffect_InitWave(u8 startLine, u8 endLine, u8 frequency, u8 amplitude, u8 delayInterval, u8 regOffset, bool8 applyBattleBgOffsets) +{ + int i; + int offset; + struct ScanlineEffectParams params; + u8 taskId; + + ScanlineEffect_Clear(); + + params.dmaDest = (void *)(REG_ADDR_BG0HOFS + regOffset); + params.dmaControl = SCANLINE_EFFECT_DMACNT_16BIT; + params.initState = 1; + params.unused9 = 0; + ScanlineEffect_SetParams(params); + + taskId = CreateTask(TaskFunc_UpdateWavePerFrame, 0); + + gTasks[taskId].tStartLine = startLine; + gTasks[taskId].tEndLine = endLine; + gTasks[taskId].tWaveLength = 256 / frequency; + gTasks[taskId].tSrcBufferOffset = 0; + gTasks[taskId].tFramesUntilMove = delayInterval; + gTasks[taskId].tDelayInterval = delayInterval; + gTasks[taskId].tRegOffset = regOffset; + gTasks[taskId].tApplyBattleBgOffsets = applyBattleBgOffsets; + + gScanlineEffect.waveTaskId = taskId; + sShouldStopWaveTask = FALSE; + + GenerateWave(&gScanlineEffectRegBuffers[0][320], frequency, amplitude, endLine - startLine); + + offset = 320; + for (i = startLine; i < endLine; i++) + { + gScanlineEffectRegBuffers[0][i] = gScanlineEffectRegBuffers[0][offset]; + gScanlineEffectRegBuffers[1][i] = gScanlineEffectRegBuffers[0][offset]; + offset++; + } + + return taskId; +} diff --git a/src/scrcmd.c b/src/scrcmd.c new file mode 100644 index 000000000..7c27293a7 --- /dev/null +++ b/src/scrcmd.c @@ -0,0 +1,2267 @@ +#include "global.h" +#include "gba/isagbprint.h" +#include "palette.h" +#include "script.h" +#include "mystery_event_script.h" +#include "event_data.h" +#include "random.h" +#include "item.h" +#include "overworld.h" +#include "field_screen_effect.h" +#include "quest_log.h" +#include "map_preview_screen.h" +#include "field_weather.h" +#include "field_tasks.h" +#include "field_fadetransition.h" +#include "field_player_avatar.h" +#include "sound.h" +#include "script_movement.h" +#include "field_map_obj.h" +#include "field_map_obj_helpers.h" +#include "map_obj_lock.h" +#include "field_message_box.h" +#include "new_menu_helpers.h" +#include "window.h" +#include "start_menu.h" +#include "script_menu.h" +#include "string_util.h" +#include "data2.h" +#include "field_specials.h" +#include "constants/items.h" +#include "script_pokemon_util_80A0058.h" +#include "pokemon_storage_system.h" +#include "party_menu.h" +#include "money.h" +#include "coins.h" +#include "battle_setup.h" +#include "shop.h" +#include "script_pokemon_80F8.h" +#include "slot_machine.h" +#include "field_effect.h" +#include "fieldmap.h" +#include "field_door.h" +#include "scrcmd.h" + +extern u16 (*const gSpecials[])(void); +extern u16 (*const gSpecialsEnd[])(void); +extern const u8 *const gStdScripts[]; +extern const u8 *const gStdScriptsEnd[]; + +static bool8 sub_806B93C(struct ScriptContext * ctx); +static u8 sub_806B96C(struct ScriptContext * ctx); + +EWRAM_DATA ptrdiff_t gVScriptOffset = 0; +EWRAM_DATA u8 gUnknown_20370AC = 0; +EWRAM_DATA u16 sPauseCounter = 0; +EWRAM_DATA u16 sMovingNpcId = 0; +EWRAM_DATA u16 sMovingNpcMapBank = 0; +EWRAM_DATA u16 sMovingNpcMapId = 0; +EWRAM_DATA u16 sFieldEffectScriptId = 0; + +IWRAM_DATA struct ScriptContext * gUnknown_3005070; + +extern u8 gSelectedEventObject; + +// This is defined in here so the optimizer can't see its value when compiling +// script.c. +void * const gNullScriptPtr = NULL; + +static const u8 sScriptConditionTable[6][3] = +{ +// < = > + 1, 0, 0, // < + 0, 1, 0, // = + 0, 0, 1, // > + 1, 1, 0, // <= + 0, 1, 1, // >= + 1, 0, 1, // != +}; + +bool8 ScrCmd_nop(struct ScriptContext *ctx) +{ + return FALSE; +} + +bool8 ScrCmd_nop1(struct ScriptContext *ctx) +{ + return FALSE; +} + +bool8 ScrCmd_end(struct ScriptContext *ctx) +{ + StopScript(ctx); + return FALSE; +} + +bool8 ScrCmd_gotonative(struct ScriptContext *ctx) +{ + bool8 (*func)(void) = (bool8 (*)(void))ScriptReadWord(ctx); + SetupNativeScript(ctx, func); + return TRUE; +} + +bool8 ScrCmd_special(struct ScriptContext *ctx) +{ + u16 (*const *specialPtr)(void) = gSpecials + ScriptReadHalfword(ctx); + if (specialPtr < gSpecialsEnd) + (*specialPtr)(); + else + AGB_ASSERT_EX(0, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/scrcmd.c", 241); + return FALSE; +} + +bool8 ScrCmd_specialvar(struct ScriptContext *ctx) +{ + u16 * varPtr = GetVarPointer(ScriptReadHalfword(ctx)); + u16 (*const *specialPtr)(void) = gSpecials + ScriptReadHalfword(ctx); + if (specialPtr < gSpecialsEnd) + *varPtr = (*specialPtr)(); + else + AGB_ASSERT_EX(0, "C:/WORK/POKeFRLG/src/pm_lgfr_ose/source/scrcmd.c", 263); + return FALSE; +} + +bool8 ScrCmd_callnative(struct ScriptContext *ctx) +{ + void (*func )(void) = ((void (*)(void))ScriptReadWord(ctx)); + func(); + return FALSE; +} + +bool8 ScrCmd_waitstate(struct ScriptContext *ctx) +{ + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_goto(struct ScriptContext *ctx) +{ + const u8 * scrptr = (const u8 *)ScriptReadWord(ctx); + ScriptJump(ctx, scrptr); + return FALSE; +} + +bool8 ScrCmd_return(struct ScriptContext *ctx) +{ + ScriptReturn(ctx); + return FALSE; +} + +bool8 ScrCmd_call(struct ScriptContext *ctx) +{ + const u8 * scrptr = (const u8 *)ScriptReadWord(ctx); + ScriptCall(ctx, scrptr); + return FALSE; +} + +bool8 ScrCmd_goto_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + const u8 * scrptr = (const u8 *)ScriptReadWord(ctx); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + ScriptJump(ctx, scrptr); + return FALSE; +} + +bool8 ScrCmd_call_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + const u8 * scrptr = (const u8 *)ScriptReadWord(ctx); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + ScriptCall(ctx, scrptr); + return FALSE; +} + +bool8 ScrCmd_setvaddress(struct ScriptContext *ctx) +{ + u32 addr1 = (u32)ctx->scriptPtr - 1; + u32 addr2 = ScriptReadWord(ctx); + + gVScriptOffset = addr2 - addr1; + return FALSE; +} + +bool8 ScrCmd_vgoto(struct ScriptContext *ctx) +{ + const u8 * scrptr = (const u8 *)ScriptReadWord(ctx); + ScriptJump(ctx, scrptr - gVScriptOffset); + return FALSE; +} + +bool8 ScrCmd_vcall(struct ScriptContext *ctx) +{ + const u8 * scrptr = (const u8 *)ScriptReadWord(ctx); + ScriptCall(ctx, scrptr - gVScriptOffset); + return FALSE; +} + +bool8 ScrCmd_vgoto_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + const u8 * scrptr = (const u8 *)ScriptReadWord(ctx) - gVScriptOffset; + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + ScriptJump(ctx, scrptr); + return FALSE; +} + +bool8 ScrCmd_vcall_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + const u8 * scrptr = (const u8 *)ScriptReadWord(ctx) - gVScriptOffset; + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + ScriptCall(ctx, scrptr); + return FALSE; +} + +bool8 ScrCmd_gotostd(struct ScriptContext *ctx) +{ + u8 stdIdx = ScriptReadByte(ctx); + const u8 *const * script = gStdScripts + stdIdx; + if (script < gStdScriptsEnd) + ScriptJump(ctx, *script); + return FALSE; +} + +bool8 ScrCmd_callstd(struct ScriptContext *ctx) +{ + u8 stdIdx = ScriptReadByte(ctx); + const u8 *const * script = gStdScripts + stdIdx; + if (script < gStdScriptsEnd) + ScriptCall(ctx, *script); + return FALSE; +} + +bool8 ScrCmd_gotostd_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + u8 stdIdx = ScriptReadByte(ctx); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + { + const u8 *const * script = gStdScripts + stdIdx; + if (script < gStdScriptsEnd) + ScriptJump(ctx, *script); + } + return FALSE; +} + +bool8 ScrCmd_callstd_if(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + u8 stdIdx = ScriptReadByte(ctx); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) + { + const u8 *const * script = gStdScripts + stdIdx; + if (script < gStdScriptsEnd) + ScriptCall(ctx, *script); + } + return FALSE; +} + +bool8 ScrCmd_gotoram(struct ScriptContext *ctx) +{ + ScriptJump(ctx, gRAMScriptPtr); + return FALSE; +} + +bool8 ScrCmd_killscript(struct ScriptContext *ctx) +{ + ClearRamScript(); + StopScript(ctx); + return TRUE; +} + +bool8 ScrCmd_setmysteryeventstatus(struct ScriptContext *ctx) +{ + SetMysteryEventScriptStatus(ScriptReadByte(ctx)); + return FALSE; +} + +bool8 ScrCmd_execram(struct ScriptContext *ctx) +{ + const u8 * script = sub_8069E48(); + if (script != NULL) + { + gRAMScriptPtr = ctx->scriptPtr; + ScriptJump(ctx, script); + } + return FALSE; +} + +bool8 ScrCmd_loadword(struct ScriptContext *ctx) +{ + u8 which = ScriptReadByte(ctx); + ctx->data[which] = ScriptReadWord(ctx); + return FALSE; +} + +bool8 ScrCmd_loadbytefromaddr(struct ScriptContext *ctx) +{ + u8 which = ScriptReadByte(ctx); + ctx->data[which] = *(const u8 *)ScriptReadWord(ctx); + return FALSE; +} + +bool8 ScrCmd_writebytetoaddr(struct ScriptContext *ctx) +{ + u8 value = ScriptReadByte(ctx); + *(u8 *)ScriptReadWord(ctx) = value; + return FALSE; +} + +bool8 ScrCmd_loadbyte(struct ScriptContext *ctx) +{ + u8 which = ScriptReadByte(ctx); + ctx->data[which] = ScriptReadByte(ctx); + return FALSE; +} + +bool8 ScrCmd_setptrbyte(struct ScriptContext *ctx) +{ + u8 which = ScriptReadByte(ctx); + *(u8 *)ScriptReadWord(ctx) = ctx->data[which]; + return FALSE; +} + +bool8 ScrCmd_copylocal(struct ScriptContext *ctx) +{ + u8 whichDst = ScriptReadByte(ctx); + u8 whichSrc = ScriptReadByte(ctx); + ctx->data[whichDst] = ctx->data[whichSrc]; + return FALSE; +} + +bool8 ScrCmd_copybyte(struct ScriptContext *ctx) +{ + u8 * dest = (u8 *)ScriptReadWord(ctx); + *dest = *(const u8 *)ScriptReadWord(ctx); + return FALSE; +} + +bool8 ScrCmd_setvar(struct ScriptContext *ctx) +{ + u16 * varPtr = GetVarPointer(ScriptReadHalfword(ctx)); + *varPtr = ScriptReadHalfword(ctx); + return FALSE; +} + +bool8 ScrCmd_copyvar(struct ScriptContext *ctx) +{ + u16 * destPtr = GetVarPointer(ScriptReadHalfword(ctx)); + u16 * srcPtr = GetVarPointer(ScriptReadHalfword(ctx)); + *destPtr = *srcPtr; + return FALSE; +} + +bool8 ScrCmd_setorcopyvar(struct ScriptContext *ctx) +{ + u16 * destPtr = GetVarPointer(ScriptReadHalfword(ctx)); + *destPtr = VarGet(ScriptReadHalfword(ctx)); + return FALSE; +} + +u8 compare_012(u16 left, u16 right) +{ + if (left < right) + return 0; + else if (left == right) + return 1; + else + return 2; +} + +// comparelocaltolocal +bool8 ScrCmd_compare_local_to_local(struct ScriptContext *ctx) +{ + const u8 value1 = ctx->data[ScriptReadByte(ctx)]; + const u8 value2 = ctx->data[ScriptReadByte(ctx)]; + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +// comparelocaltoimm +bool8 ScrCmd_compare_local_to_value(struct ScriptContext *ctx) +{ + const u8 value1 = ctx->data[ScriptReadByte(ctx)]; + const u8 value2 = ScriptReadByte(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_local_to_addr(struct ScriptContext *ctx) +{ + const u8 value1 = ctx->data[ScriptReadByte(ctx)]; + const u8 value2 = *(const u8 *)ScriptReadWord(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_addr_to_local(struct ScriptContext *ctx) +{ + const u8 value1 = *(const u8 *)ScriptReadWord(ctx); + const u8 value2 = ctx->data[ScriptReadByte(ctx)]; + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_addr_to_value(struct ScriptContext *ctx) +{ + const u8 value1 = *(const u8 *)ScriptReadWord(ctx); + const u8 value2 = ScriptReadByte(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_addr_to_addr(struct ScriptContext *ctx) +{ + const u8 value1 = *(const u8 *)ScriptReadWord(ctx); + const u8 value2 = *(const u8 *)ScriptReadWord(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_var_to_value(struct ScriptContext *ctx) +{ + const u16 value1 = *GetVarPointer(ScriptReadHalfword(ctx)); + const u16 value2 = ScriptReadHalfword(ctx); + + ctx->comparisonResult = compare_012(value1, value2); + return FALSE; +} + +bool8 ScrCmd_compare_var_to_var(struct ScriptContext *ctx) +{ + const u16 *ptr1 = GetVarPointer(ScriptReadHalfword(ctx)); + const u16 *ptr2 = GetVarPointer(ScriptReadHalfword(ctx)); + + ctx->comparisonResult = compare_012(*ptr1, *ptr2); + return FALSE; +} + +bool8 ScrCmd_addvar(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr += ScriptReadHalfword(ctx); + return FALSE; +} + +bool8 ScrCmd_subvar(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr -= VarGet(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_random(struct ScriptContext *ctx) +{ + u16 max = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = Random() % max; + return FALSE; +} + +bool8 ScrCmd_giveitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u32 quantity = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = AddBagItem(itemId, (u8)quantity); + sub_809A824(itemId); + return FALSE; +} + +bool8 ScrCmd_takeitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u32 quantity = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = RemoveBagItem(itemId, (u8)quantity); + return FALSE; +} + +bool8 ScrCmd_checkitemspace(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u32 quantity = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = CheckBagHasSpace(itemId, (u8)quantity); + return FALSE; +} + +bool8 ScrCmd_checkitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u32 quantity = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = CheckBagHasItem(itemId, (u8)quantity); + return FALSE; +} + +bool8 ScrCmd_checkitemtype(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = GetPocketByItemId(itemId); + return FALSE; +} + +bool8 ScrCmd_givepcitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u16 quantity = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = AddPCItem(itemId, quantity); + return FALSE; +} + +bool8 ScrCmd_checkpcitem(struct ScriptContext *ctx) +{ + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u16 quantity = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = CheckPCHasItem(itemId, quantity); + return FALSE; +} + +bool8 ScrCmd_givedecoration(struct ScriptContext *ctx) +{ + u32 decorId = VarGet(ScriptReadHalfword(ctx)); + +// gSpecialVar_Result = DecorationAdd(decorId); + return FALSE; +} + +bool8 ScrCmd_takedecoration(struct ScriptContext *ctx) +{ + u32 decorId = VarGet(ScriptReadHalfword(ctx)); + +// gSpecialVar_Result = DecorationRemove(decorId); + return FALSE; +} + +bool8 ScrCmd_checkdecorspace(struct ScriptContext *ctx) +{ + u32 decorId = VarGet(ScriptReadHalfword(ctx)); + +// gSpecialVar_Result = DecorationCheckSpace(decorId); + return FALSE; +} + +bool8 ScrCmd_checkdecor(struct ScriptContext *ctx) +{ + u32 decorId = VarGet(ScriptReadHalfword(ctx)); + +// gSpecialVar_Result = CheckHasDecoration(decorId); + return FALSE; +} + +bool8 ScrCmd_setflag(struct ScriptContext *ctx) +{ + FlagSet(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_clearflag(struct ScriptContext *ctx) +{ + FlagClear(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_checkflag(struct ScriptContext *ctx) +{ + ctx->comparisonResult = FlagGet(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_incrementgamestat(struct ScriptContext *ctx) +{ + IncrementGameStat(ScriptReadByte(ctx)); + return FALSE; +} + +bool8 ScrCmd_comparestattoword(struct ScriptContext *ctx) +{ + u8 statIdx = ScriptReadByte(ctx); + u32 value = ScriptReadWord(ctx); + u32 statValue = GetGameStat(statIdx); + + if (statValue < value) + ctx ->comparisonResult = 0; + else if (statValue == value) + ctx->comparisonResult = 1; + else + ctx->comparisonResult = 2; + return FALSE; +} + +bool8 ScrCmd_setworldmapflag(struct ScriptContext *ctx) +{ + u16 value = ScriptReadHalfword(ctx); + sub_8115748(value); + sub_80F85BC(value); + return FALSE; +} + +bool8 ScrCmd_animateflash(struct ScriptContext *ctx) +{ + sub_807F028(ScriptReadByte(ctx)); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_setflashradius(struct ScriptContext *ctx) +{ + u16 flashLevel = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetFlashLevel(flashLevel); + return FALSE; +} + +static bool8 IsPaletteNotActive(void) +{ + if (!gPaletteFade.active) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_fadescreen(struct ScriptContext *ctx) +{ + fade_screen(ScriptReadByte(ctx), 0); + SetupNativeScript(ctx, IsPaletteNotActive); + return TRUE; +} + +bool8 ScrCmd_fadescreenspeed(struct ScriptContext *ctx) +{ + u8 mode = ScriptReadByte(ctx); + u8 speed = ScriptReadByte(ctx); + + fade_screen(mode, speed); + SetupNativeScript(ctx, IsPaletteNotActive); + return TRUE; +} + +static bool8 RunPauseTimer(void) +{ + sPauseCounter--; + + if (sPauseCounter == 0) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_delay(struct ScriptContext *ctx) +{ + sPauseCounter = ScriptReadHalfword(ctx); + SetupNativeScript(ctx, RunPauseTimer); + return TRUE; +} + +bool8 ScrCmd_initclock(struct ScriptContext *ctx) +{ +// u8 hour = VarGet(ScriptReadHalfword(ctx)); +// u8 minute = VarGet(ScriptReadHalfword(ctx)); +// +// RtcInitLocalTimeOffset(hour, minute); + return FALSE; +} + +bool8 ScrCmd_dodailyevents(struct ScriptContext *ctx) +{ +// DoTimeBasedEvents(); + return FALSE; +} + +bool8 ScrCmd_gettime(struct ScriptContext *ctx) +{ +// RtcCalcLocalTime(); +// gSpecialVar_0x8000 = gLocalTime.hours; +// gSpecialVar_0x8001 = gLocalTime.minutes; +// gSpecialVar_0x8002 = gLocalTime.seconds; + gSpecialVar_0x8000 = 0; + gSpecialVar_0x8001 = 0; + gSpecialVar_0x8002 = 0; + return FALSE; +} + +bool8 ScrCmd_setweather(struct ScriptContext *ctx) +{ + u16 weather = VarGet(ScriptReadHalfword(ctx)); + + SetSav1Weather(weather); + return FALSE; +} + +bool8 ScrCmd_resetweather(struct ScriptContext *ctx) +{ + SetSav1WeatherFromCurrMapHeader(); + return FALSE; +} + +bool8 ScrCmd_doweather(struct ScriptContext *ctx) +{ + DoCurrentWeather(); + return FALSE; +} + +bool8 ScrCmd_setstepcallback(struct ScriptContext *ctx) +{ + ActivatePerStepCallback(ScriptReadByte(ctx)); + return FALSE; +} + +bool8 ScrCmd_setmaplayoutindex(struct ScriptContext *ctx) +{ + u16 value = VarGet(ScriptReadHalfword(ctx)); + + SetCurrentMapLayout(value); + return FALSE; +} + +bool8 ScrCmd_warp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + DoWarp(); + ResetInitialPlayerAvatarState(); + return TRUE; +} + +bool8 ScrCmd_warpsilent(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + DoDiveWarp(); + ResetInitialPlayerAvatarState(); + return TRUE; +} + +bool8 ScrCmd_warpdoor(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + DoDoorWarp(); + ResetInitialPlayerAvatarState(); + return TRUE; +} + +bool8 ScrCmd_warphole(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u16 x; + u16 y; + + PlayerGetDestCoords(&x, &y); + if (mapGroup == 0xFF && mapNum == 0xFF) + SetWarpDestinationToFixedHoleWarp(x - 7, y - 7); + else + Overworld_SetWarpDestination(mapGroup, mapNum, -1, x - 7, y - 7); + DoFallWarp(); + ResetInitialPlayerAvatarState(); + return TRUE; +} + +bool8 ScrCmd_warpteleport(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sub_807E59C(); + ResetInitialPlayerAvatarState(); + return TRUE; +} + +bool8 ScrCmd_warpteleport2(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + sub_805DAE4(player_get_direction_lower_nybble()); + sub_807E500(); + ResetInitialPlayerAvatarState(); + return TRUE; +} + +bool8 ScrCmd_setwarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetWarpDestination(mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_setdynamicwarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + SetDynamicWarpWithCoords(0, mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_setdivewarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + SetFixedDiveWarp(mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_setholewarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + SetFixedHoleWarp(mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_setescapewarp(struct ScriptContext *ctx) +{ + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 warpId = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + SetEscapeWarp(mapGroup, mapNum, warpId, x, y); + return FALSE; +} + +bool8 ScrCmd_getplayerxy(struct ScriptContext *ctx) +{ + u16 *pX = GetVarPointer(ScriptReadHalfword(ctx)); + u16 *pY = GetVarPointer(ScriptReadHalfword(ctx)); + + *pX = gSaveBlock1Ptr->pos.x; + *pY = gSaveBlock1Ptr->pos.y; + return FALSE; +} + +bool8 ScrCmd_getpartysize(struct ScriptContext *ctx) +{ + gSpecialVar_Result = CalculatePlayerPartyCount(); + return FALSE; +} + +bool8 ScrCmd_playse(struct ScriptContext *ctx) +{ + PlaySE(ScriptReadHalfword(ctx)); + return FALSE; +} + +static bool8 WaitForSoundEffectFinish(void) +{ + if (!IsSEPlaying()) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_waitse(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, WaitForSoundEffectFinish); + return TRUE; +} + +bool8 ScrCmd_playfanfare(struct ScriptContext *ctx) +{ + PlayFanfare(ScriptReadHalfword(ctx)); + return FALSE; +} + +static bool8 WaitForFanfareFinish(void) +{ + return IsFanfareTaskInactive(); +} + +bool8 ScrCmd_waitfanfare(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, WaitForFanfareFinish); + return TRUE; +} + +bool8 ScrCmd_playbgm(struct ScriptContext *ctx) +{ + u16 songId = ScriptReadHalfword(ctx); + bool8 val = ScriptReadByte(ctx); + + if (gUnknown_203ADFA == 2 || gUnknown_203ADFA == 3) + return FALSE; + if (val == TRUE) + Overworld_SetSavedMusic(songId); + PlayNewMapMusic(songId); + return FALSE; +} + +bool8 ScrCmd_savebgm(struct ScriptContext *ctx) +{ + Overworld_SetSavedMusic(ScriptReadHalfword(ctx)); + return FALSE; +} + +bool8 ScrCmd_fadedefaultbgm(struct ScriptContext *ctx) +{ + if (gUnknown_203ADFA == 2 || gUnknown_203ADFA == 3) + return FALSE; + Overworld_ChangeMusicToDefault(); + return FALSE; +} + +bool8 ScrCmd_fadenewbgm(struct ScriptContext *ctx) +{ + u16 music = ScriptReadHalfword(ctx); + if (gUnknown_203ADFA == 2 || gUnknown_203ADFA == 3) + return FALSE; + Overworld_ChangeMusicTo(music); + return FALSE; +} + +bool8 ScrCmd_fadeoutbgm(struct ScriptContext *ctx) +{ + u8 speed = ScriptReadByte(ctx); + + if (gUnknown_203ADFA == 2 || gUnknown_203ADFA == 3) + return FALSE; + if (speed != 0) + FadeOutBGMTemporarily(4 * speed); + else + FadeOutBGMTemporarily(4); + SetupNativeScript(ctx, IsBGMPausedOrStopped); + return TRUE; +} + +bool8 ScrCmd_fadeinbgm(struct ScriptContext *ctx) +{ + u8 speed = ScriptReadByte(ctx); + + if (gUnknown_203ADFA == 2 || gUnknown_203ADFA == 3) + return FALSE; + if (speed != 0) + FadeInBGM(4 * speed); + else + FadeInBGM(4); + return FALSE; +} + +bool8 ScrCmd_applymovement(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + const void *movementScript = (const void *)ScriptReadWord(ctx); + + ScriptMovement_StartObjectMovementScript(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, movementScript); + sMovingNpcId = localId; + return FALSE; +} + +bool8 ScrCmd_applymovement_at(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + const void *movementScript = (const void *)ScriptReadWord(ctx); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + ScriptMovement_StartObjectMovementScript(localId, mapNum, mapGroup, movementScript); + sMovingNpcId = localId; + return FALSE; +} + +static bool8 WaitForMovementFinish(void) +{ + return ScriptMovement_IsObjectMovementFinished(sMovingNpcId, sMovingNpcMapId, sMovingNpcMapBank); +} + +bool8 ScrCmd_waitmovement(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + + if (localId != 0) + sMovingNpcId = localId; + sMovingNpcMapBank = gSaveBlock1Ptr->location.mapGroup; + sMovingNpcMapId = gSaveBlock1Ptr->location.mapNum; + SetupNativeScript(ctx, WaitForMovementFinish); + return TRUE; +} + +bool8 ScrCmd_waitmovement_at(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapBank; + u8 mapId; + + if (localId != 0) + sMovingNpcId = localId; + mapBank = ScriptReadByte(ctx); + mapId = ScriptReadByte(ctx); + sMovingNpcMapBank = mapBank; + sMovingNpcMapId = mapId; + SetupNativeScript(ctx, WaitForMovementFinish); + return TRUE; +} + +bool8 ScrCmd_removeobject(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + + RemoveFieldObjectByLocalIdAndMap(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + return FALSE; +} + +bool8 ScrCmd_removeobject_at(struct ScriptContext *ctx) +{ + u16 objectId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + RemoveFieldObjectByLocalIdAndMap(objectId, mapNum, mapGroup); + return FALSE; +} + +bool8 ScrCmd_addobject(struct ScriptContext *ctx) +{ + u16 objectId = VarGet(ScriptReadHalfword(ctx)); + + show_sprite(objectId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + return FALSE; +} + +bool8 ScrCmd_addobject_at(struct ScriptContext *ctx) +{ + u16 objectId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + show_sprite(objectId, mapNum, mapGroup); + return FALSE; +} + +bool8 ScrCmd_setobjectxy(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + sub_805F7C4(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, x, y); + return FALSE; +} + +bool8 ScrCmd_setobjectxyperm(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + Overworld_SetMapObjTemplateCoords(localId, x, y); + return FALSE; +} + +bool8 ScrCmd_moveobjectoffscreen(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + + sub_805FE94(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + return FALSE; +} + +bool8 ScrCmd_showobject_at(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + npc_by_local_id_and_map_set_field_1_bit_x20(localId, mapNum, mapGroup, 0); + return FALSE; +} + +bool8 ScrCmd_hideobject_at(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + npc_by_local_id_and_map_set_field_1_bit_x20(localId, mapNum, mapGroup, 1); + return FALSE; +} + +bool8 ScrCmd_setobjectpriority(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + u8 priority = ScriptReadByte(ctx); + + sub_805F3A8(localId, mapNum, mapGroup, priority + 83); + return FALSE; +} + +bool8 ScrCmd_resetobjectpriority(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 mapGroup = ScriptReadByte(ctx); + u8 mapNum = ScriptReadByte(ctx); + + sub_805F400(localId, mapNum, mapGroup); + return FALSE; +} + +bool8 ScrCmd_faceplayer(struct ScriptContext *ctx) +{ + if (gMapObjects[gSelectedEventObject].active) + { + FieldObjectFaceOppositeDirection(&gMapObjects[gSelectedEventObject], + player_get_direction_lower_nybble()); + } + return FALSE; +} + +bool8 ScrCmd_turnobject(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 direction = ScriptReadByte(ctx); + + FieldObjectTurnByLocalIdAndMap(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, direction); + return FALSE; +} + +bool8 ScrCmd_setobjectmovementtype(struct ScriptContext *ctx) +{ + u16 localId = VarGet(ScriptReadHalfword(ctx)); + u8 movementType = ScriptReadByte(ctx); + + Overworld_SetMapObjTemplateMovementType(localId, movementType); + return FALSE; +} + +bool8 ScrCmd_createvobject(struct ScriptContext *ctx) +{ + u8 graphicsId = ScriptReadByte(ctx); + u8 v2 = ScriptReadByte(ctx); + u16 x = VarGet(ScriptReadHalfword(ctx)); + u32 y = VarGet(ScriptReadHalfword(ctx)); + u8 elevation = ScriptReadByte(ctx); + u8 direction = ScriptReadByte(ctx); + + sprite_new(graphicsId, v2, x, y, elevation, direction); + return FALSE; +} + +bool8 ScrCmd_turnvobject(struct ScriptContext *ctx) +{ + u8 v1 = ScriptReadByte(ctx); + u8 direction = ScriptReadByte(ctx); + + sub_8069058(v1, direction); + return FALSE; +} + +bool8 ScrCmd_lockall(struct ScriptContext *ctx) +{ + if (is_c1_link_related_active()) + { + return FALSE; + } + else + { + ScriptFreezeMapObjects(); + SetupNativeScript(ctx, sub_8069590); + return TRUE; + } +} + +bool8 ScrCmd_lock(struct ScriptContext *ctx) +{ + if (is_c1_link_related_active()) + { + return FALSE; + } + else + { + if (gMapObjects[gSelectedEventObject].active) + { + LockSelectedMapObject(); + SetupNativeScript(ctx, sub_8069648); + } + else + { + ScriptFreezeMapObjects(); + SetupNativeScript(ctx, sub_8069590); + } + return TRUE; + } +} + +bool8 ScrCmd_releaseall(struct ScriptContext *ctx) +{ + u8 playerObjectId; + + HideFieldMessageBox(); + playerObjectId = GetFieldObjectIdByLocalIdAndMap(0xFF, 0, 0); + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[playerObjectId]); + sub_80974D8(); + UnfreezeMapObjects(); + return FALSE; +} + +bool8 ScrCmd_release(struct ScriptContext *ctx) +{ + u8 playerObjectId; + + HideFieldMessageBox(); + if (gMapObjects[gSelectedEventObject].active) + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[gSelectedEventObject]); + playerObjectId = GetFieldObjectIdByLocalIdAndMap(0xFF, 0, 0); + FieldObjectClearAnimIfSpecialAnimFinished(&gMapObjects[playerObjectId]); + sub_80974D8(); + UnfreezeMapObjects(); + return FALSE; +} + +bool8 ScrCmd_textcolor(struct ScriptContext *ctx) +{ + gUnknown_20370DC = gUnknown_20370DA; + gUnknown_20370DA = ScriptReadByte(ctx); + return FALSE; +} + +bool8 ScrCmd_message(struct ScriptContext *ctx) +{ + const u8 *msg = (const u8 *)ScriptReadWord(ctx); + + if (msg == NULL) + msg = (const u8 *)ctx->data[0]; + ShowFieldMessage(msg); + return FALSE; +} + +bool8 ScrCmd_loadhelp(struct ScriptContext *ctx) +{ + const u8 *msg = (const u8 *)ScriptReadWord(ctx); + + if (msg == NULL) + msg = (const u8 *)ctx->data[0]; + sub_80F7974(msg); + CopyWindowToVram(GetStartMenuWindowId(), 1); + return FALSE; +} + +bool8 ScrCmd_unloadhelp(struct ScriptContext *ctx) +{ + sub_80F7998(); + return FALSE; +} + +bool8 ScrCmd_messageautoscroll(struct ScriptContext *ctx) +{ + const u8 *msg = (const u8 *)ScriptReadWord(ctx); + + if (msg == NULL) + msg = (const u8 *)ctx->data[0]; + ShowFieldAutoScrollMessage(msg); + return FALSE; +} + +bool8 ScrCmd_waitmessage(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, IsFieldMessageBoxHidden); + return TRUE; +} + +bool8 ScrCmd_closemessage(struct ScriptContext *ctx) +{ + HideFieldMessageBox(); + return FALSE; +} + +static bool8 WaitForAorBPress(void) +{ + if (gMain.newKeys & A_BUTTON) + return TRUE; + if (gMain.newKeys & B_BUTTON) + return TRUE; + + if (sub_806B93C(gUnknown_3005070) == TRUE) + { + u8 r4 = sub_806B96C(gUnknown_3005070); + sub_8069998(r4); + if (r4) + { + if (gUnknown_203ADFA != 2) + { + sub_80699F8(); + if (r4 < 9 || r4 > 10) + sub_8069964(); + else + { + sub_80699A4(); + sub_8069970(); + } + return TRUE; + } + } + } + if (sub_8112CAC() == 1 || gUnknown_203ADFA == 2) + { + if (gUnknown_20370AC == 120) + return TRUE; + else + gUnknown_20370AC++; + } + + return FALSE; +} + +static bool8 sub_806B93C(struct ScriptContext * ctx) +{ + const u8 * script = ctx->scriptPtr; + u8 nextCmd = *script; + if (nextCmd == 3) // return + { + script = ctx->stack[ctx->stackDepth - 1]; + nextCmd = *script; + } + if (nextCmd < 0x6B || nextCmd > 0x6C) // releaseall or release + return FALSE; + else + return TRUE; +} + +static u8 sub_806B96C(struct ScriptContext * ctx) +{ + if (gMain.heldKeys & DPAD_UP && gSpecialVar_Facing != 2) + return 1; + + if (gMain.heldKeys & DPAD_DOWN && gSpecialVar_Facing != 1) + return 2; + + if (gMain.heldKeys & DPAD_LEFT && gSpecialVar_Facing != 3) + return 3; + + if (gMain.heldKeys & DPAD_RIGHT && gSpecialVar_Facing != 4) + return 4; + + if (gMain.newKeys & L_BUTTON) + return 5; + + if (gMain.heldKeys & R_BUTTON) + return 6; + + if (gMain.heldKeys & START_BUTTON) + return 7; + + if (gMain.heldKeys & SELECT_BUTTON) + return 8; + + if (gMain.newKeys & A_BUTTON) + return 9; + + if (gMain.newKeys & B_BUTTON) + return 10; + + return 0; +} + +bool8 ScrCmd_waitbuttonpress(struct ScriptContext *ctx) +{ + gUnknown_3005070 = ctx; + + if (sub_8112CAC() == 1 || gUnknown_203ADFA == 2) + gUnknown_20370AC = 0; + SetupNativeScript(ctx, WaitForAorBPress); + return TRUE; +} + +bool8 ScrCmd_yesnobox(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + + if (ScriptMenu_YesNo(left, top) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool8 ScrCmd_multichoice(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 multichoiceId = ScriptReadByte(ctx); + u8 ignoreBPress = ScriptReadByte(ctx); + + if (ScriptMenu_Multichoice(left, top, multichoiceId, ignoreBPress) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool8 ScrCmd_multichoicedefault(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 multichoiceId = ScriptReadByte(ctx); + u8 defaultChoice = ScriptReadByte(ctx); + u8 ignoreBPress = ScriptReadByte(ctx); + + if (ScriptMenu_MultichoiceWithDefault(left, top, multichoiceId, ignoreBPress, defaultChoice) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool8 ScrCmd_drawbox(struct ScriptContext *ctx) +{ + /*u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 right = ScriptReadByte(ctx); + u8 bottom = ScriptReadByte(ctx); + + MenuDrawTextWindow(left, top, right, bottom);*/ + return FALSE; +} + +bool8 ScrCmd_multichoicegrid(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 multichoiceId = ScriptReadByte(ctx); + u8 numColumns = ScriptReadByte(ctx); + u8 ignoreBPress = ScriptReadByte(ctx); + + if (ScriptMenu_MultichoiceGrid(left, top, multichoiceId, ignoreBPress, numColumns) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + } + else + { + return FALSE; + } +} + +bool8 ScrCmd_erasebox(struct ScriptContext *ctx) +{ + u8 left = ScriptReadByte(ctx); + u8 top = ScriptReadByte(ctx); + u8 right = ScriptReadByte(ctx); + u8 bottom = ScriptReadByte(ctx); + + // MenuZeroFillWindowRect(left, top, right, bottom); + return FALSE; +} + +bool8 ScrCmd_drawboxtext(struct ScriptContext *ctx) +{ +// u8 left = ScriptReadByte(ctx); +// u8 top = ScriptReadByte(ctx); +// u8 multichoiceId = ScriptReadByte(ctx); +// u8 ignoreBPress = ScriptReadByte(ctx); + + /*if (Multichoice(left, top, multichoiceId, ignoreBPress) == TRUE) + { + ScriptContext1_Stop(); + return TRUE; + }*/ + return FALSE; +} + +bool8 ScrCmd_showmonpic(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + + ScriptMenu_ShowPokemonPic(species, x, y); + PlayCry7(species, 0); + return FALSE; +} + +bool8 ScrCmd_hidemonpic(struct ScriptContext *ctx) +{ + bool8 (*func)(void) = ScriptMenu_GetPicboxWaitFunc(); + + if (func == NULL) + return FALSE; + SetupNativeScript(ctx, func); + return TRUE; +} + +bool8 ScrCmd_showcontestwinner(struct ScriptContext *ctx) +{ + u8 v1 = ScriptReadByte(ctx); + + /* + if (v1) + sub_812FDA8(v1); + ShowContestWinner(); + ScriptContext1_Stop(); + return TRUE; + */ + + return FALSE; +} + +bool8 ScrCmd_braillemessage(struct ScriptContext *ctx) +{ + u8 *ptr = (u8 *)ScriptReadWord(ctx); + if (ptr == NULL) + ptr = (u8 *)ctx->data[0]; + + sub_80F6E9C(); + DrawDialogueFrame(0, 1); + AddTextPrinterParameterized(0, 6, ptr, 0, 1, 0, NULL); + return FALSE; +} + +bool8 ScrCmd_getbraillestringwidth(struct ScriptContext *ctx) +{ + u8 *ptr = (u8 *)ScriptReadWord(ctx); + if (ptr == NULL) + ptr = (u8 *)ctx->data[0]; + + gSpecialVar_0x8004 = GetStringWidth(6, ptr, -1); + return FALSE; +} + +bool8 ScrCmd_vmessage(struct ScriptContext *ctx) +{ + u32 v1 = ScriptReadWord(ctx); + + ShowFieldMessage((u8 *)(v1 - gVScriptOffset)); + return FALSE; +} + +u8 * const sScriptStringVars[] = +{ + gStringVar1, + gStringVar2, + gStringVar3, +}; + +bool8 ScrCmd_bufferspeciesname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 species = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], gSpeciesNames[species]); + return FALSE; +} + +bool8 ScrCmd_bufferleadmonspeciesname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + + u8 *dest = sScriptStringVars[stringVarIndex]; + u8 partyIndex = GetLeadMonIndex(); + u32 species = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES, NULL); + StringCopy(dest, gSpeciesNames[species]); + return FALSE; +} + +bool8 ScrCmd_bufferpartymonnick(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + GetMonData(&gPlayerParty[partyIndex], MON_DATA_NICKNAME, sScriptStringVars[stringVarIndex]); + StringGetEnd10(sScriptStringVars[stringVarIndex]); + return FALSE; +} + +bool8 ScrCmd_bufferitemname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + + CopyItemName(itemId, sScriptStringVars[stringVarIndex]); + return FALSE; +} + +const u8 gUnknown_83A72A0[] = _("S"); +const u8 gUnknown_83A72A2[] = _("IES"); + +bool8 ScrCmd_bufferitemnameplural(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 itemId = VarGet(ScriptReadHalfword(ctx)); + u16 quantity = VarGet(ScriptReadHalfword(ctx)); + + CopyItemName(itemId, sScriptStringVars[stringVarIndex]); + if (itemId == ITEM_POKE_BALL && quantity >= 2) + StringAppend(sScriptStringVars[stringVarIndex], gUnknown_83A72A0); + else if (itemId >= ITEM_CHERI_BERRY && itemId < ITEM_ENIGMA_BERRY && quantity >= 2) + { + u16 strlength = StringLength(sScriptStringVars[stringVarIndex]); + if (strlength != 0) + { + u8 * endptr = sScriptStringVars[stringVarIndex] + strlength; + endptr[-1] = EOS; + StringAppend(sScriptStringVars[stringVarIndex], gUnknown_83A72A2); + } + } + + return FALSE; +} + +bool8 ScrCmd_bufferdecorationname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 decorId = VarGet(ScriptReadHalfword(ctx)); + +// StringCopy(sScriptStringVars[stringVarIndex], gDecorations[decorId].name); + return FALSE; +} + +bool8 ScrCmd_buffermovename(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 moveId = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], gMoveNames[moveId]); + return FALSE; +} + +bool8 ScrCmd_buffernumberstring(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 v1 = VarGet(ScriptReadHalfword(ctx)); + u8 v2 = CountDigits(v1); + + ConvertIntToDecimalStringN(sScriptStringVars[stringVarIndex], v1, 0, v2); + return FALSE; +} + +bool8 ScrCmd_bufferstdstring(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 index = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], gStdStringPtrs[index]); + return FALSE; +} + +/* +bool8 ScrCmd_buffercontesttype(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 index = VarGet(ScriptReadHalfword(ctx)); + + sub_818E868(sScriptStringVars[stringVarIndex], index); + return FALSE; +} +*/ + +bool8 ScrCmd_bufferstring(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + const u8 *text = (u8 *)ScriptReadWord(ctx); + + StringCopy(sScriptStringVars[stringVarIndex], text); + return FALSE; +} + +bool8 ScrCmd_vloadword(struct ScriptContext *ctx) +{ + const u8 *ptr = (u8 *)(ScriptReadWord(ctx) - gVScriptOffset); + + StringExpandPlaceholders(gStringVar4, ptr); + return FALSE; +} + +bool8 ScrCmd_vbufferstring(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u32 addr = ScriptReadWord(ctx); + + const u8 *src = (u8 *)(addr - gVScriptOffset); + u8 *dest = sScriptStringVars[stringVarIndex]; + StringCopy(dest, src); + return FALSE; +} + +bool8 ScrCmd_bufferboxname(struct ScriptContext *ctx) +{ + u8 stringVarIndex = ScriptReadByte(ctx); + u16 boxId = VarGet(ScriptReadHalfword(ctx)); + + StringCopy(sScriptStringVars[stringVarIndex], GetBoxNamePtr(boxId)); + return FALSE; +} + +bool8 ScrCmd_givemon(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + u8 level = ScriptReadByte(ctx); + u16 item = VarGet(ScriptReadHalfword(ctx)); + u32 unkParam1 = ScriptReadWord(ctx); + u32 unkParam2 = ScriptReadWord(ctx); + u8 unkParam3 = ScriptReadByte(ctx); + + gSpecialVar_Result = ScriptGiveMon(species, level, item, unkParam1, unkParam2, unkParam3); + return FALSE; +} + +bool8 ScrCmd_giveegg(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = ScriptGiveEgg(species); + return FALSE; +} + +bool8 ScrCmd_setmonmove(struct ScriptContext *ctx) +{ + u8 partyIndex = ScriptReadByte(ctx); + u8 slot = ScriptReadByte(ctx); + u16 move = ScriptReadHalfword(ctx); + + ScriptSetMonMoveSlot(partyIndex, move, slot); + return FALSE; +} + +bool8 ScrCmd_checkpartymove(struct ScriptContext *ctx) +{ + u8 i; + u16 moveId = ScriptReadHalfword(ctx); + + gSpecialVar_Result = PARTY_SIZE; + for (i = 0; i < PARTY_SIZE; i++) + { + u16 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL); + if (!species) + break; + if (!GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) && MonKnowsMove(&gPlayerParty[i], moveId) == TRUE) + { + gSpecialVar_Result = i; + gSpecialVar_0x8004 = species; + break; + } + } + return FALSE; +} + +bool8 ScrCmd_givemoney(struct ScriptContext *ctx) +{ + u32 amount = ScriptReadWord(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + AddMoney(&gSaveBlock1Ptr->money, amount); + return FALSE; +} + +bool8 ScrCmd_takemoney(struct ScriptContext *ctx) +{ + u32 amount = ScriptReadWord(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + RemoveMoney(&gSaveBlock1Ptr->money, amount); + return FALSE; +} + +bool8 ScrCmd_checkmoney(struct ScriptContext *ctx) +{ + u32 amount = ScriptReadWord(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + gSpecialVar_Result = IsEnoughMoney(&gSaveBlock1Ptr->money, amount); + return FALSE; +} + +bool8 ScrCmd_showmoneybox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore && sub_81119D4(sub_809D6D4) != TRUE) + DrawMoneyBox(GetMoney(&gSaveBlock1Ptr->money), x, y); + return FALSE; +} + +bool8 ScrCmd_hidemoneybox(struct ScriptContext *ctx) +{ + /*u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx);*/ + + HideMoneyBox(); + return FALSE; +} + +bool8 ScrCmd_updatemoneybox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + u8 ignore = ScriptReadByte(ctx); + + if (!ignore) + ChangeAmountInMoneyBox(GetMoney(&gSaveBlock1Ptr->money)); + return FALSE; +} + +bool8 ScrCmd_showcoinsbox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + + if (sub_81119D4(sub_809D6D4) != TRUE) + ShowCoinsWindow(GetCoins(), x, y); + return FALSE; +} + +bool8 ScrCmd_hidecoinsbox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + + HideCoinsWindow(); + return FALSE; +} + +bool8 ScrCmd_updatecoinsbox(struct ScriptContext *ctx) +{ + u8 x = ScriptReadByte(ctx); + u8 y = ScriptReadByte(ctx); + + PrintCoinsString(GetCoins()); + return FALSE; +} + +bool8 ScrCmd_trainerbattle(struct ScriptContext *ctx) +{ + ctx->scriptPtr = BattleSetup_ConfigureTrainerBattle(ctx->scriptPtr); + return FALSE; +} + +bool8 ScrCmd_dotrainerbattle(struct ScriptContext *ctx) +{ + BattleSetup_StartTrainerBattle(); + return TRUE; +} + +bool8 ScrCmd_gotopostbattlescript(struct ScriptContext *ctx) +{ + ctx->scriptPtr = BattleSetup_GetScriptAddrAfterBattle(); + return FALSE; +} + +bool8 ScrCmd_gotobeatenscript(struct ScriptContext *ctx) +{ + ctx->scriptPtr = BattleSetup_GetTrainerPostBattleScript(); + return FALSE; +} + +bool8 ScrCmd_checktrainerflag(struct ScriptContext *ctx) +{ + u16 index = VarGet(ScriptReadHalfword(ctx)); + + ctx->comparisonResult = HasTrainerAlreadyBeenFought(index); + return FALSE; +} + +bool8 ScrCmd_settrainerflag(struct ScriptContext *ctx) +{ + u16 index = VarGet(ScriptReadHalfword(ctx)); + + SetTrainerFlag(index); + return FALSE; +} + +bool8 ScrCmd_cleartrainerflag(struct ScriptContext *ctx) +{ + u16 index = VarGet(ScriptReadHalfword(ctx)); + + ClearTrainerFlag(index); + return FALSE; +} + +bool8 ScrCmd_setwildbattle(struct ScriptContext *ctx) +{ + u16 species = ScriptReadHalfword(ctx); + u8 level = ScriptReadByte(ctx); + u16 item = ScriptReadHalfword(ctx); + + CreateScriptedWildMon(species, level, item); + return FALSE; +} + +bool8 ScrCmd_dowildbattle(struct ScriptContext *ctx) +{ + BattleSetup_StartScriptedWildBattle(); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_pokemart(struct ScriptContext *ctx) +{ + const void *ptr = (void *)ScriptReadWord(ctx); + + CreatePokemartMenu(ptr); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_pokemartdecoration(struct ScriptContext *ctx) +{ + const void *ptr = (void *)ScriptReadWord(ctx); + + CreateDecorationShop1Menu(ptr); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_pokemartdecoration2(struct ScriptContext *ctx) +{ + const void *ptr = (void *)ScriptReadWord(ctx); + + CreateDecorationShop2Menu(ptr); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_playslotmachine(struct ScriptContext *ctx) +{ + u8 slotMachineIndex = VarGet(ScriptReadHalfword(ctx)); + + PlaySlotMachine(slotMachineIndex, c2_exit_to_overworld_1_continue_scripts_restart_music); + ScriptContext1_Stop(); + return TRUE; +} + +bool8 ScrCmd_setberrytree(struct ScriptContext *ctx) +{ +// u8 treeId = ScriptReadByte(ctx); +// u8 berry = ScriptReadByte(ctx); +// u8 growthStage = ScriptReadByte(ctx); +// +// if (berry == 0) +// PlantBerryTree(treeId, 0, growthStage, FALSE); +// else +// PlantBerryTree(treeId, berry, growthStage, FALSE); + return FALSE; +} + +bool8 ScrCmd_getpricereduction(struct ScriptContext *ctx) +{ +// u16 value = VarGet(ScriptReadHalfword(ctx)); +// +// gSpecialVar_Result = GetPriceReduction(value); + return FALSE; +} + +bool8 ScrCmd_choosecontestmon(struct ScriptContext *ctx) +{ +// sub_81B9404(); + ScriptContext1_Stop(); + return TRUE; +} + + +bool8 ScrCmd_startcontest(struct ScriptContext *ctx) +{ +// sub_80F840C(); +// ScriptContext1_Stop(); +// return TRUE; + return FALSE; +} + +bool8 ScrCmd_showcontestresults(struct ScriptContext *ctx) +{ +// sub_80F8484(); +// ScriptContext1_Stop(); +// return TRUE; + return FALSE; +} + +bool8 ScrCmd_contestlinktransfer(struct ScriptContext *ctx) +{ +// sub_80F84C4(gSpecialVar_ContestCategory); +// ScriptContext1_Stop(); +// return TRUE; + return FALSE; +} + +bool8 ScrCmd_dofieldeffect(struct ScriptContext *ctx) +{ + u16 effectId = VarGet(ScriptReadHalfword(ctx)); + + sFieldEffectScriptId = effectId; + FieldEffectStart(sFieldEffectScriptId); + return FALSE; +} + +bool8 ScrCmd_setfieldeffectarg(struct ScriptContext *ctx) +{ + u8 argNum = ScriptReadByte(ctx); + + gFieldEffectArguments[argNum] = (s16)VarGet(ScriptReadHalfword(ctx)); + return FALSE; +} + +static bool8 WaitForFieldEffectFinish(void) +{ + if (!FieldEffectActiveListContains(sFieldEffectScriptId)) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_waitfieldeffect(struct ScriptContext *ctx) +{ + sFieldEffectScriptId = VarGet(ScriptReadHalfword(ctx)); + SetupNativeScript(ctx, WaitForFieldEffectFinish); + return TRUE; +} + +bool8 ScrCmd_setrespawn(struct ScriptContext *ctx) +{ + u16 healLocationId = VarGet(ScriptReadHalfword(ctx)); + + SetLastHealLocationWarp(healLocationId); + return FALSE; +} + +bool8 ScrCmd_checkplayergender(struct ScriptContext *ctx) +{ + gSpecialVar_Result = gSaveBlock2Ptr->playerGender; + return FALSE; +} + +bool8 ScrCmd_playmoncry(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + u16 mode = VarGet(ScriptReadHalfword(ctx)); + + PlayCry7(species, mode); + return FALSE; +} + +bool8 ScrCmd_waitmoncry(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, IsCryFinished); + return TRUE; +} + +bool8 ScrCmd_setmetatile(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + u16 tileId = VarGet(ScriptReadHalfword(ctx)); + u16 v8 = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + if (!v8) + MapGridSetMetatileIdAt(x, y, tileId); + else + MapGridSetMetatileIdAt(x, y, tileId | 0xC00); + return FALSE; +} + +bool8 ScrCmd_opendoor(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + PlaySE(GetDoorSoundEffect(x, y)); + FieldAnimateDoorOpen(x, y); + return FALSE; +} + +bool8 ScrCmd_closedoor(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + FieldAnimateDoorClose(x, y); + return FALSE; +} + +static bool8 IsDoorAnimationStopped(void) +{ + if (!FieldIsDoorAnimationRunning()) + return TRUE; + else + return FALSE; +} + +bool8 ScrCmd_waitdooranim(struct ScriptContext *ctx) +{ + SetupNativeScript(ctx, IsDoorAnimationStopped); + return TRUE; +} + +bool8 ScrCmd_setdooropen(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + FieldSetDoorOpened(x, y); + return FALSE; +} + +bool8 ScrCmd_setdoorclosed(struct ScriptContext *ctx) +{ + u16 x = VarGet(ScriptReadHalfword(ctx)); + u16 y = VarGet(ScriptReadHalfword(ctx)); + + x += 7; + y += 7; + FieldSetDoorClosed(x, y); + return FALSE; +} + +bool8 ScrCmd_addelevmenuitem(struct ScriptContext *ctx) +{ +// u8 v3 = ScriptReadByte(ctx); +// u16 v5 = VarGet(ScriptReadHalfword(ctx)); +// u16 v7 = VarGet(ScriptReadHalfword(ctx)); +// u16 v9 = VarGet(ScriptReadHalfword(ctx)); + + //ScriptAddElevatorMenuItem(v3, v5, v7, v9); + return FALSE; +} + +bool8 ScrCmd_showelevmenu(struct ScriptContext *ctx) +{ + /*ScriptShowElevatorMenu(); + ScriptContext1_Stop(); + return TRUE;*/ + return FALSE; +} + +bool8 ScrCmd_checkcoins(struct ScriptContext *ctx) +{ + u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + *ptr = GetCoins(); + return FALSE; +} + +bool8 ScrCmd_givecoins(struct ScriptContext *ctx) +{ + u16 coins = VarGet(ScriptReadHalfword(ctx)); + + if (GiveCoins(coins) == TRUE) + gSpecialVar_Result = 0; + else + gSpecialVar_Result = 1; + return FALSE; +} + +bool8 ScrCmd_takecoins(struct ScriptContext *ctx) +{ + u16 coins = VarGet(ScriptReadHalfword(ctx)); + + if (TakeCoins(coins) == TRUE) + gSpecialVar_Result = 0; + else + gSpecialVar_Result = 1; + return FALSE; +} + +bool8 ScrCmd_signmsg(struct ScriptContext *ctx) +{ + sub_8069A20(); + return FALSE; +} + +bool8 ScrCmd_normalmsg(struct ScriptContext *ctx) +{ + sub_8069A2C(); + return FALSE; +} + +// This command will force the Pokémon to be obedient, you don't get to make it disobedient. +bool8 ScrCmd_setmonobedient(struct ScriptContext *ctx) +{ + bool8 obedient = TRUE; + u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + SetMonData(&gPlayerParty[partyIndex], MON_DATA_OBEDIENCE, &obedient); + return FALSE; +} + +bool8 ScrCmd_checkmonobedience(struct ScriptContext *ctx) +{ + u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = GetMonData(&gPlayerParty[partyIndex], MON_DATA_OBEDIENCE, NULL); + return FALSE; +} + +bool8 ScrCmd_setmonmetlocation(struct ScriptContext *ctx) +{ + u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + u8 location = ScriptReadByte(ctx); + + if (partyIndex < PARTY_SIZE) + SetMonData(&gPlayerParty[partyIndex], MON_DATA_MET_LOCATION, &location); + return FALSE; +} diff --git a/src/script.c b/src/script.c index 59ef4e579..608dc6ba0 100644 --- a/src/script.c +++ b/src/script.c @@ -9,7 +9,7 @@ extern u8 gUnknown_203ADFA; extern void sub_80CBDE8(void); // field_specials extern u16 CalcCRC16WithTable(u8 *data, int length); // util -extern bool32 sub_8143FC8(void); // mevent +extern bool32 ValidateReceivedWonderCard(void); // mevent enum { @@ -19,7 +19,7 @@ enum }; EWRAM_DATA u8 gUnknown_20370A0 = 0; -EWRAM_DATA u8 *gUnknown_20370A4 = NULL; +EWRAM_DATA const u8 *gRAMScriptPtr = NULL; // ewram bss /*IWRAM_DATA*/ static u8 sScriptContext1Status; @@ -485,7 +485,7 @@ bool8 InitRamScript(u8 *script, u16 scriptSize, u8 mapGroup, u8 mapNum, u8 objec u8 *GetRamScript(u8 objectId, u8 *script) { struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data; - gUnknown_20370A4 = NULL; + gRAMScriptPtr = NULL; if (scriptData->magic != RAM_SCRIPT_MAGIC) return script; if (scriptData->mapGroup != gSaveBlock1Ptr->location.mapGroup) @@ -501,7 +501,7 @@ u8 *GetRamScript(u8 objectId, u8 *script) } else { - gUnknown_20370A4 = script; + gRAMScriptPtr = script; return scriptData->script; } } @@ -525,7 +525,7 @@ bool32 sub_8069DFC(void) u8 *sub_8069E48(void) { struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data; - if (!sub_8143FC8()) + if (!ValidateReceivedWonderCard()) return NULL; if (scriptData->magic != RAM_SCRIPT_MAGIC) return NULL; diff --git a/src/seagallop.c b/src/seagallop.c new file mode 100644 index 000000000..ae880b2a3 --- /dev/null +++ b/src/seagallop.c @@ -0,0 +1,499 @@ +#include "global.h" +#include "gpu_regs.h" +#include "bg.h" +#include "palette.h" +#include "malloc.h" +#include "scanline_effect.h" +#include "trainer_pokemon_sprites.h" +#include "window.h" +#include "text_window.h" +#include "sound.h" +#include "task.h" +#include "help_system.h" +#include "overworld.h" +#include "event_data.h" +#include "field_fadetransition.h" +#include "field_weather.h" +#include "constants/songs.h" +#include "constants/maps.h" +#include "seagallop.h" + +#define TILESTAG_FERRY 3000 +#define TILESTAG_WAKE 4000 + +#define PALTAG_FERRY_WAKE 3000 + +static EWRAM_DATA void * sBg3TilemapBuffer = NULL; + +static void CB2_SetUpSeaGallopScene(void); +static void VBlankCB_SeaGallop(void); +static void MainCB2_SeaGallop(void); +static void Task_SeaGallop_0(u8 taskId); +static void Task_SeaGallop_1(u8 taskId); +static void Task_SeaGallop_2(u8 taskId); +static void Task_SeaGallop_3(void); +static void ResetGPU(void); +static void ResetAllAssets(void); +static void SetDispcnt(void); +static void ResetBGPos(void); +static void LoadFerrySpriteResources(void); +static void FreeFerrySpriteResources(void); +static void CreateFerrySprite(void); +static void SpriteCB_Ferry(struct Sprite * sprite); +static void CreateWakeSprite(s16 x); +static void SpriteCB_Wake(struct Sprite * sprite); +static bool8 GetDirectionOfTravel(void); + +static const u16 sWaterTiles[] = INCBIN_U16("data/seagallop/water.4bpp"); +static const u16 sWaterPal[] = INCBIN_U16("data/seagallop/water.gbapal"); +static const u16 sWaterTilemap_WB[] = INCBIN_U16("data/seagallop/wb_tilemap.bin"); +static const u16 sWaterTilemap_EB[] = INCBIN_U16("data/seagallop/eb_tilemap.bin"); +static const u16 sFerrySpriteTiles[] = INCBIN_U16("data/seagallop/ferry_sprite.4bpp"); +static const u16 sFerryAndWakePal[] = INCBIN_U16("data/seagallop/ferry_and_wake.gbapal"); +static const u16 sWakeSpriteTiles[] = INCBIN_U16("data/seagallop/wake.4bpp"); + +static const struct BgTemplate sBGTemplates[] = { + { + .bg = 3, + .charBaseIndex = 3, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0x000 + } +}; + +static const s8 sSeaGallopSpawnTable[][4] = { + // Map X Y + [SEAGALLOP_VERMILION_CITY] = {MAP(VERMILION_CITY), 0x17, 0x20}, + [SEAGALLOP_ONE_ISLAND] = {MAP(ONE_ISLAND_HARBOR), 0x08, 0x05}, + [SEAGALLOP_TWO_ISLAND] = {MAP(TWO_ISLAND_HARBOR), 0x08, 0x05}, + [SEAGALLOP_THREE_ISLAND] = {MAP(THREE_ISLAND_HARBOR), 0x08, 0x05}, + [SEAGALLOP_FOUR_ISLAND] = {MAP(FOUR_ISLAND_HARBOR), 0x08, 0x05}, + [SEAGALLOP_FIVE_ISLAND] = {MAP(FIVE_ISLAND_HARBOR), 0x08, 0x05}, + [SEAGALLOP_SIX_ISLAND] = {MAP(SIX_ISLAND_HARBOR), 0x08, 0x05}, + [SEAGALLOP_SEVEN_ISLAND] = {MAP(SEVEN_ISLAND_HARBOR), 0x08, 0x05}, + [SEAGALLOP_CINNABAR_ISLAND] = {MAP(CINNABAR_ISLAND), 0x15, 0x07}, + [SEAGALLOP_NAVEL_ROCK] = {MAP(NAVEL_ROCK_HARBOR), 0x08, 0x05}, + [SEAGALLOP_BIRTH_ISLAND] = {MAP(BIRTH_ISLAND_HARBOR), 0x08, 0x05} +}; + +// Bitpacked array. In the commented section, right-most bit is the +// flag for traveling from (row port) to Vermilion City, and so on. +// Flags follow these enums: + +enum TravelDirections +{ + DIRN_WESTBOUND = 0, + DIRN_EASTBOUND = 1 +}; + +static const u16 sTravelDirectionMatrix[] = { + [SEAGALLOP_VERMILION_CITY] = 0x6fe, // 11011111110 + [SEAGALLOP_ONE_ISLAND] = 0x6fc, // 11011111100 + [SEAGALLOP_TWO_ISLAND] = 0x6f8, // 11011111000 + [SEAGALLOP_THREE_ISLAND] = 0x6f0, // 11011110000 + [SEAGALLOP_FOUR_ISLAND] = 0x6e0, // 11011100000 + [SEAGALLOP_FIVE_ISLAND] = 0x4c0, // 10011000000 + [SEAGALLOP_SIX_ISLAND] = 0x400, // 10000000000 + [SEAGALLOP_SEVEN_ISLAND] = 0x440, // 10001000000 + [SEAGALLOP_CINNABAR_ISLAND] = 0x7ff, // 11111111111 + [SEAGALLOP_NAVEL_ROCK] = 0x6e0, // 11011100000 + [SEAGALLOP_BIRTH_ISLAND] = 0x000 // 00000000000 +}; + +static const union AnimCmd sSpriteAnims_Ferry_WB[] = { + ANIMCMD_FRAME(0, 10), + ANIMCMD_END +}; + +static const union AnimCmd sSpriteAnims_Ferry_EB[] = { + ANIMCMD_FRAME(0, 10, .hFlip = TRUE), + ANIMCMD_END +}; + +static const union AnimCmd *const sSpriteAnimTable_Ferry[] = { + sSpriteAnims_Ferry_WB, + sSpriteAnims_Ferry_EB +}; + +static const struct OamData sOamData_Ferry = { + .size = 3 +}; + +static const struct SpriteTemplate sFerrySpriteTemplate = { + TILESTAG_FERRY, + PALTAG_FERRY_WAKE, + &sOamData_Ferry, + sSpriteAnimTable_Ferry, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_Ferry +}; + +static const struct SpriteSheet sFerryAndWakeSpriteSheets[] = { + {(const void *)sWakeSpriteTiles, sizeof(sWakeSpriteTiles), TILESTAG_WAKE}, + {(const void *)sFerrySpriteTiles, sizeof(sFerrySpriteTiles), TILESTAG_FERRY}, + {} +}; + +static const struct SpritePalette sFerryAndWakeSpritePalettes[] = { + {sFerryAndWakePal, PALTAG_FERRY_WAKE}, + {} +}; + +static const union AnimCmd sSpriteAnims_Wake_WB[] = { + ANIMCMD_FRAME(0x00, 0x14), + ANIMCMD_FRAME(0x10, 0x14), + ANIMCMD_FRAME(0x20, 0x0f), + ANIMCMD_END, +}; + +static const union AnimCmd sSpriteAnims_Wake_EB[] = { + ANIMCMD_FRAME(0x00, 0x14, .hFlip = TRUE), + ANIMCMD_FRAME(0x10, 0x14, .hFlip = TRUE), + ANIMCMD_FRAME(0x20, 0x0f, .hFlip = TRUE), + ANIMCMD_END, +}; + +static const union AnimCmd *const sSpriteAnimTable_Wake[] = { + sSpriteAnims_Wake_WB, + sSpriteAnims_Wake_EB +}; + +static const struct OamData sOamData_Wake = { + .size = 2 +}; + +static const struct SpriteTemplate sWakeSpriteTemplate = { + TILESTAG_WAKE, + PALTAG_FERRY_WAKE, + &sOamData_Wake, + sSpriteAnimTable_Wake, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_Wake +}; + +void ScrSpecial_SeaGallopFerry(void) +{ + SetVBlankCallback(NULL); + sub_812B478(); + SetMainCallback2(CB2_SetUpSeaGallopScene); +} + +static void CB2_SetUpSeaGallopScene(void) +{ + void ** ptr; + switch (gMain.state) + { + case 0: + SetVBlankCallback(NULL); // redundant since the setup routine already did this + ResetGPU(); + gMain.state++; + break; + case 1: + ResetAllAssets(); + gMain.state++; + break; + case 2: + ptr = &sBg3TilemapBuffer; + *ptr = AllocZeroed(0x800); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBGTemplates, NELEMS(sBGTemplates)); + SetBgTilemapBuffer(3, *ptr); + ResetBGPos(); + gMain.state++; + break; + case 3: + LoadBgTiles(3, sWaterTiles, sizeof(sWaterTiles), 0); + if (GetDirectionOfTravel() == DIRN_EASTBOUND) + { + CopyToBgTilemapBufferRect(3, sWaterTilemap_EB, 0, 0, 32, 32); + } + else + { + CopyToBgTilemapBufferRect(3, sWaterTilemap_WB, 0, 0, 32, 32); + } + LoadPalette(sWaterPal, 0x40, 0x20); + LoadPalette(stdpal_get(2), 0xF0, 0x20); + gMain.state++; + break; + case 4: + if (IsDma3ManagerBusyWithBgCopy() != DIRN_EASTBOUND) + { + ShowBg(0); + ShowBg(3); + CopyBgTilemapBufferToVram(3); + gMain.state++; + } + break; + case 5: + LoadFerrySpriteResources(); + BlendPalettes(0xFFFFFFFF, 16, RGB_BLACK); + gMain.state++; + break; + case 6: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB_BLACK); + gMain.state++; + break; + case 7: + SetDispcnt(); + SetVBlankCallback(VBlankCB_SeaGallop); + PlaySE(SE_NAMINORI); + CreateFerrySprite(); + SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); + SetGpuReg(REG_OFFSET_WININ, 0x3F); + SetGpuReg(REG_OFFSET_WINOUT, 0x00); + SetGpuReg(REG_OFFSET_WIN0H, 0x00F0); + SetGpuReg(REG_OFFSET_WIN0V, 0x1888); + CreateTask(Task_SeaGallop_0, 8); + SetMainCallback2(MainCB2_SeaGallop); + gMain.state = 0; + break; + } +} + +static void VBlankCB_SeaGallop(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void MainCB2_SeaGallop(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +static void Task_SeaGallop_0(u8 taskId) +{ + gTasks[taskId].func = Task_SeaGallop_1; +} + +static void ScrollBG(void) +{ + if (GetDirectionOfTravel() == DIRN_EASTBOUND) + { + ChangeBgX(3, 0x600, 1); + } + else + { + ChangeBgX(3, 0x600, 2); + } +} + +static void Task_SeaGallop_1(u8 taskId) +{ + struct Task * task = &gTasks[taskId]; + + ScrollBG(); + if (++task->data[1] == 140) + { + Overworld_FadeOutMapMusic(); + sub_807DC18(); + task->func = Task_SeaGallop_2; + } +} + +static void Task_SeaGallop_2(u8 taskId) +{ + ScrollBG(); + if (sub_8055FC4() && !gPaletteFade.active) + { + Task_SeaGallop_3(); + sub_812B484(); + DestroyTask(taskId); + } +} + +static void Task_SeaGallop_3(void) +{ + const s8 * warpInfo; + + if (gSpecialVar_0x8006 >= NELEMS(sSeaGallopSpawnTable)) + gSpecialVar_0x8006 = 0; + + warpInfo = sSeaGallopSpawnTable[gSpecialVar_0x8006]; + Overworld_SetWarpDestination(warpInfo[0], warpInfo[1], -1, warpInfo[2], warpInfo[3]); + PlayRainStoppingSoundEffect(); + PlaySE(SE_KAIDAN); + gFieldCallback = sub_807DF64; + warp_in(); + SetMainCallback2(sub_805671C); + ResetInitialPlayerAvatarState(); + FreeFerrySpriteResources(); + Free(sBg3TilemapBuffer); + FreeAllWindowBuffers(); +} + +static void ResetGPU(void) +{ + void * dest = (void *) VRAM; + DmaClearLarge16(3, dest, VRAM_SIZE, 0x1000); + + DmaClear32(3, (void *)OAM, OAM_SIZE); + DmaClear16(3, (void *)PLTT, PLTT_SIZE); + SetGpuReg(REG_OFFSET_DISPCNT, 0); + SetGpuReg(REG_OFFSET_BG0CNT, 0); + SetGpuReg(REG_OFFSET_BG0HOFS, 0); + SetGpuReg(REG_OFFSET_BG0VOFS, 0); + SetGpuReg(REG_OFFSET_BG1CNT, 0); + SetGpuReg(REG_OFFSET_BG1HOFS, 0); + SetGpuReg(REG_OFFSET_BG1VOFS, 0); + SetGpuReg(REG_OFFSET_BG2CNT, 0); + SetGpuReg(REG_OFFSET_BG2HOFS, 0); + SetGpuReg(REG_OFFSET_BG2VOFS, 0); + SetGpuReg(REG_OFFSET_BG3CNT, 0); + SetGpuReg(REG_OFFSET_BG3HOFS, 0); + SetGpuReg(REG_OFFSET_BG3VOFS, 0); + SetGpuReg(REG_OFFSET_WIN0H, 0); + SetGpuReg(REG_OFFSET_WIN0V, 0); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); +} + +static void ResetAllAssets(void) +{ + ScanlineEffect_Stop(); + ResetTasks(); + ResetSpriteData(); + ResetAllPicSprites(); + ResetPaletteFade(); + FreeAllSpritePalettes(); +} + +static void SetDispcnt(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON | DISPCNT_BG3_ON | DISPCNT_OBJ_ON); +} + +static void ResetBGPos(void) +{ + ChangeBgX(0, 0, 0); + ChangeBgY(0, 0, 0); + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(2, 0, 0); + ChangeBgY(2, 0, 0); + ChangeBgX(3, 0, 0); + ChangeBgY(3, 0, 0); +} + +static void LoadFerrySpriteResources(void) +{ + LoadSpriteSheets(sFerryAndWakeSpriteSheets); + LoadSpritePalettes(sFerryAndWakeSpritePalettes); +} + +static void FreeFerrySpriteResources(void) +{ + FreeSpriteTilesByTag(TILESTAG_FERRY); + FreeSpriteTilesByTag(TILESTAG_WAKE); + FreeSpritePaletteByTag(PALTAG_FERRY_WAKE); +} + +static void CreateFerrySprite(void) +{ + u8 spriteId = CreateSprite(&sFerrySpriteTemplate, 0, 92, 0); + gSprites[spriteId].data[0] = 48; + if (GetDirectionOfTravel() == DIRN_EASTBOUND) + { + StartSpriteAnim(&gSprites[spriteId], 1); + } + else + { + gSprites[spriteId].pos1.x = 240; + gSprites[spriteId].data[0] *= -1; + } +} + +static void SpriteCB_Ferry(struct Sprite * sprite) +{ + sprite->data[1] += sprite->data[0]; + sprite->pos2.x = sprite->data[1] >> 4; + if (sprite->data[2] % 5 == 0) + { + CreateWakeSprite(sprite->pos1.x + sprite->pos2.x); + } + sprite->data[2]++; + if ((u16)(300 + sprite->pos2.x) > 600) + { + DestroySprite(sprite); + } +} + +static void CreateWakeSprite(s16 x) +{ + u8 spriteId = CreateSprite(&sWakeSpriteTemplate, x, 92, 8); + if (spriteId != MAX_SPRITES) + { + if (GetDirectionOfTravel() == DIRN_EASTBOUND) + { + StartSpriteAnim(&gSprites[spriteId], 1); + } + } +} + +static void SpriteCB_Wake(struct Sprite * sprite) +{ + if (sprite->animEnded) + { + DestroySprite(sprite); + } +} + +static bool8 GetDirectionOfTravel(void) +{ + if (gSpecialVar_0x8004 >= NELEMS(sTravelDirectionMatrix)) + { + return DIRN_EASTBOUND; + } + return (sTravelDirectionMatrix[gSpecialVar_0x8004] >> gSpecialVar_0x8006) & 1; +} + +u8 sub_8147500(void) +{ + u16 originId, destId; + + originId = gSpecialVar_0x8004; + destId = gSpecialVar_0x8006; + + if (originId == SEAGALLOP_CINNABAR_ISLAND || destId == SEAGALLOP_CINNABAR_ISLAND) + return 1; + + if (originId == SEAGALLOP_VERMILION_CITY || destId == SEAGALLOP_VERMILION_CITY) + return 7; + + if (originId == SEAGALLOP_NAVEL_ROCK || destId == SEAGALLOP_NAVEL_ROCK) + return 10; + + if (originId == SEAGALLOP_BIRTH_ISLAND || destId == SEAGALLOP_BIRTH_ISLAND) + return 12; + + if ((originId == SEAGALLOP_ONE_ISLAND || originId == SEAGALLOP_TWO_ISLAND || originId == SEAGALLOP_THREE_ISLAND) && (destId == SEAGALLOP_ONE_ISLAND || destId == SEAGALLOP_TWO_ISLAND || destId == SEAGALLOP_THREE_ISLAND)) + return 2; + + if ((originId == SEAGALLOP_FOUR_ISLAND || originId == SEAGALLOP_FIVE_ISLAND) && (destId == SEAGALLOP_FOUR_ISLAND || destId == SEAGALLOP_FIVE_ISLAND)) + return 3; + + if ((originId == SEAGALLOP_SIX_ISLAND || originId == SEAGALLOP_SEVEN_ISLAND) && (destId == SEAGALLOP_SIX_ISLAND || destId == SEAGALLOP_SEVEN_ISLAND)) + return 5; + + return 6; +} + +bool8 sub_8147594(void) +{ + if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(VERMILION_CITY) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(VERMILION_CITY) && gSaveBlock1Ptr->pos.x < 24) + return TRUE; + + return FALSE; +} diff --git a/src/sound.c b/src/sound.c index f94e44506..ba6511d1c 100644 --- a/src/sound.c +++ b/src/sound.c @@ -40,7 +40,23 @@ extern struct MusicPlayerInfo gMPlayInfo_SE2; extern struct MusicPlayerInfo gMPlayInfo_SE3; extern struct ToneData gCryTable[]; extern struct ToneData gCryTable2[]; -extern const struct Fanfare sFanfares[]; + +static const struct Fanfare sFanfares[] = { + { MUS_FANFA1, 80 }, + { MUS_FANFA4, 160 }, + { MUS_FANFA5, 220 }, + { MUS_ME_WAZA, 220 }, + { MUS_ME_ASA, 160 }, + { MUS_ME_BACHI, 340 }, + { MUS_ME_WASURE, 180 }, + { MUS_ME_KINOMI, 120 }, + { MUS_ME_B_BIG, 250 }, + { MUS_ME_B_SMALL, 150 }, + { MUS_ME_ZANNEN, 160 }, + { BGM_FRLG_FLUTE, 450 }, + { BGM_FRLG_ME_KEYITEM, 170 }, + { BGM_FRLG_ME_POKEDEX_EVAL, 196 } +}; extern u16 SpeciesToCryId(u16); diff --git a/src/ss_anne.c b/src/ss_anne.c new file mode 100644 index 000000000..f59f17a76 --- /dev/null +++ b/src/ss_anne.c @@ -0,0 +1,200 @@ +#include "global.h" +#include "task.h" +#include "sound.h" +#include "field_map_obj.h" +#include "script.h" +#include "constants/songs.h" + +// Tasks governing the ship's departure after you've gotten HM01 CUT + +#define SPRITE_TAG_WAKE 4000 +#define SPRITE_TAG_SMOKE 4001 + +static void Task_SSAnneInit(u8 taskId); +static void Task_SSAnneRun(u8 taskId); +static void Task_SSAnneFinish(u8 taskId); +static void CreateWakeBehindBoat(void); +static void WakeSpriteCallback(struct Sprite * sprite); +static void CreateSmokeSprite(void); +static void SmokeSpriteCallback(struct Sprite * sprite); + +static const u16 sWakeTiles[] = INCBIN_U16("graphics/ss_anne/unk_8479838.4bpp"); +static const u16 sSmokeTiles[] = INCBIN_U16("graphics/ss_anne/unk_8479A38.4bpp"); + +static const struct SpriteSheet sSpriteSheets[] = { + {(const void *)sWakeTiles, sizeof(sWakeTiles), SPRITE_TAG_WAKE}, + {(const void *)sSmokeTiles, sizeof(sSmokeTiles), SPRITE_TAG_SMOKE}, + {0} +}; + +static const union AnimCmd sWakeAnim[] = { + ANIMCMD_FRAME(0, 12), + ANIMCMD_FRAME(8, 12), + ANIMCMD_JUMP(0) +}; + +static const union AnimCmd *const sWakeAnimTable[] = { + sWakeAnim +}; + +static const struct OamData sWakeOamData = { + .shape = ST_OAM_V_RECTANGLE, + .size = 2 +}; + +static const struct SpriteTemplate sWakeSpriteTemplate = { + SPRITE_TAG_WAKE, + 0xFFFF, + &sWakeOamData, + sWakeAnimTable, + NULL, + gDummySpriteAffineAnimTable, + WakeSpriteCallback +}; + +static const union AnimCmd sSmokeAnim[] = { + ANIMCMD_FRAME( 0, 10), + ANIMCMD_FRAME( 4, 20), + ANIMCMD_FRAME( 8, 20), + ANIMCMD_FRAME(12, 30), + ANIMCMD_END +}; + +static const union AnimCmd *const sSmokeAnimTable[] = { + sSmokeAnim +}; + +static const struct OamData sSmokeOamData = { + .shape = ST_OAM_SQUARE, + .size = 1 +}; + +static const struct SpriteTemplate sSmokeSpriteTemplate = { + SPRITE_TAG_SMOKE, + 0xFFFF, + &sSmokeOamData, + sSmokeAnimTable, + NULL, + gDummySpriteAffineAnimTable, + SmokeSpriteCallback +}; + +void Special_SSAnneDepartureCutscene(void) +{ + u8 taskId; + + PlaySE(SE_SHIP_HORN); + taskId = CreateTask(Task_SSAnneInit, 8); + gTasks[taskId].data[0] = 50; +} + +static void Task_SSAnneInit(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (--data[0] == 0) + { + LoadSpriteSheets(sSpriteSheets); + CreateWakeBehindBoat(); + gTasks[taskId].func = Task_SSAnneRun; + } +} + +static void Task_SSAnneRun(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u8 mapObjectId; + struct MapObject * boatObject; + s16 x; + + data[1]++; + data[2]++; + if (data[1] == 70) + { + data[1] = 0; + CreateSmokeSprite(); + } + TryGetFieldObjectIdByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &mapObjectId); + boatObject = &gMapObjects[mapObjectId]; + if (gSprites[boatObject->spriteId].pos1.x + gSprites[boatObject->spriteId].pos2.x < -120) + { + PlaySE(SE_SHIP_HORN); + gTasks[taskId].func = Task_SSAnneFinish; + } + else + { + x = data[2] / 5; + gSprites[boatObject->spriteId].pos2.x = -x; + } +} + +static void Task_SSAnneFinish(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (++data[3] == 40) + { + FreeSpriteTilesByTag(SPRITE_TAG_WAKE); + FreeSpriteTilesByTag(SPRITE_TAG_SMOKE); + DestroyTask(taskId); + EnableBothScriptContexts(); + } +} + +static void CreateWakeBehindBoat(void) +{ + u8 mapObjectId; + struct MapObject * boatObject; + u16 x; + u8 spriteId; + + TryGetFieldObjectIdByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &mapObjectId); + boatObject = &gMapObjects[mapObjectId]; + x = gSprites[boatObject->spriteId].pos1.x + gSprites[boatObject->spriteId].pos2.x + 80; + spriteId = CreateSprite(&sWakeSpriteTemplate, x, 109, 0xFF); + gSprites[spriteId].oam.priority = 2; + gSprites[spriteId].oam.paletteNum = 10; +} + +static void WakeSpriteCallback(struct Sprite * sprite) +{ + u8 mapObjectId; + struct MapObject * boatObject; + u16 x; + + TryGetFieldObjectIdByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &mapObjectId); + boatObject = &gMapObjects[mapObjectId]; + x = gSprites[boatObject->spriteId].pos1.x + gSprites[boatObject->spriteId].pos2.x + 80; + sprite->pos1.x = x; + if (sprite->data[0] / 6 < 22) + sprite->data[0]++; + sprite->pos2.x = sprite->data[0] / 6; + if (sprite->pos1.x + sprite->pos2.x < -18) + DestroySprite(sprite); +} + +static void CreateSmokeSprite(void) +{ + u8 mapObjectId; + struct MapObject * boatObject; + u16 x; + u8 spriteId; + + TryGetFieldObjectIdByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &mapObjectId); + boatObject = &gMapObjects[mapObjectId]; + x = gSprites[boatObject->spriteId].pos1.x + gSprites[boatObject->spriteId].pos2.x + 49; + if ((s16)x >= -32) + { + spriteId = CreateSprite(&sSmokeSpriteTemplate, x, 78, 8); + if (spriteId != MAX_SPRITES) + gSprites[spriteId].oam.paletteNum = 10; + } +} + +static void SmokeSpriteCallback(struct Sprite * sprite) +{ + sprite->data[0]++; + sprite->pos2.x = sprite->data[0] / 4; + if (sprite->animEnded) + DestroySprite(sprite); +} diff --git a/src/teachy_tv.c b/src/teachy_tv.c new file mode 100644 index 000000000..efffe2840 --- /dev/null +++ b/src/teachy_tv.c @@ -0,0 +1,1416 @@ +#include "task.h" +#include "menu.h" +#include "palette.h" +#include "sprite.h" +#include "menu_helpers.h" +#include "new_menu_helpers.h" +#include "sound.h" +#include "malloc.h" +#include "scanline_effect.h" +#include "bg.h" +#include "gpu_regs.h" +#include "decompress.h" +#include "window.h" +#include "list_menu.h" +#include "item_menu.h" +#include "item.h" +#include "menu_indicators.h" +#include "field_map_obj.h" +#include "random.h" +#include "text.h" +#include "constants/songs.h" +#include "constants/items.h" +#include "event_data.h" +#include "load_save.h" +#include "battle_transition.h" +#include "battle_2.h" +#include "battle.h" +#include "global.fieldmap.h" +#include "teachy_tv.h" +#include "help_system.h" +#include "overworld.h" +#include "unk_8159F40.h" +#include "graphics.h" +#include "fieldmap.h" +#include "strings.h" + +enum TeachyTvScript +{ + TTVSCR_BATTLE, + TTVSCR_STATUS, + TTVSCR_MATCHUPS, + TTVSCR_CATCHING, + TTVSCR_TMS, + TTVSCR_REGISTER +}; + +struct TeachyTvCtrlBlk +{ + MainCallback callback; + u8 mode; + u8 whichScript; + u16 scrollOffset; + u16 selectedRow; +}; + +struct TeachyTvBuf +{ + MainCallback savedCallback; + u16 buffer1[0x800]; + u16 buffer2[0x800]; + u16 buffer3[0x800]; + u16 buffer4[0x800]; + u8 grassAnimCounterLo; + u8 grassAnimCounterHi; + u8 grassAnimDisabled; + u8 scrollIndicatorArrowPairId; +}; + +static EWRAM_DATA struct TeachyTvCtrlBlk sStaticResources = {0}; +static EWRAM_DATA struct TeachyTvBuf * sResources = NULL; + +static void TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos(u8 taskId); +static void TTVcmd_ClearBg2TeachyTvGraphic(u8 taskId); +static void TTVcmd_NpcMoveAndSetupTextPrinter(u8 taskId); +static void TTVcmd_IdleIfTextPrinterIsActive(u8 taskId); +static void TTVcmd_TextPrinterSwitchStringByOptionChosen(u8 taskId); +static void TTVcmd_TextPrinterSwitchStringByOptionChosen2(u8 taskId); +static void TTVcmd_IdleIfTextPrinterIsActive2(u8 taskId); +static void TTVcmd_EraseTextWindowIfKeyPressed(u8 taskId); +static void TTVcmd_StartAnimNpcWalkIntoGrass(u8 taskId); +static void TTVcmd_DudeMoveUp(u8 taskId); +static void TTVcmd_DudeMoveRight(u8 taskId); +static void TTVcmd_DudeTurnLeft(u8 taskId); +static void TTVcmd_DudeMoveLeft(u8 taskId); +static void TTVcmd_RenderAndRemoveBg1EndGraphic(u8 taskId); +static void TTVcmd_TaskBattleOrFadeByOptionChosen(u8 taskId); +static void TeachyTvCallback(void); +static void TeachyTvMainCallback(void); +static void TeachyTvVblankHandler(void); +static void TeachyTvCreateAndRenderRbox(void); +static void TeachyTvInitIo(void); +static u8 TeachyTvSetupObjEventAndOam(void); +static void TeachyTvSetupPostBattleWindowAndObj(u8); +static u8 TeachyTvSetupWindow(void); +static void TeachyTvSetupScrollIndicatorArrowPair(void); +static void TeachyTvSetWindowRegs(void); +static void TeachyTvSetupBg(void); +static void TeachyTvLoadGraphic(void); +static void TeachyTvPostBattleFadeControl(u8); +static void TeachyTvOptionListController(u8); +static void TeachyTvAudioByInput(s32, bool8, struct ListMenu *); +static void TeachyTvQuitFadeControlAndTaskDel(u8 taskId); +static void TeachyTvRenderMsgAndSwitchClusterFuncs(u8 taskId); +static void TeachyTvClearBg1EndGraphicText(void); +static void TTVcmd_End(u8 taskId); +static void TeachyTvSetupBagItemsByOptionChosen(void); +static void TeachyTvPrepBattle(u8 taskId); +static void TeachyTvGrassAnimationMain(u8 taskId, s16 x, s16 y, u8 subpriority, bool8 mode); +static void TeachyTvLoadBg3Map(u16 *); +static u8 TeachyTvGrassAnimationCheckIfNeedsToGenerateGrassObj(s16 x, s16 y); +static void TeachyTvGrassAnimationObjCallback(struct Sprite *sprite); +static void TeachyTvRestorePlayerPartyCallback(void); +static void TeachyTvPreBattleAnimAndSetBattleCallback(u8 taskId); +static void TeachyTvLoadMapTilesetToBuffer(struct Tileset *ts, u8 *dstBuffer, u16 size); +static void TeachyTvPushBackNewMapPalIndexArrayEntry(const struct MapData *mStruct, u16 *buf1, u8 *palIndexArray, u16 mapEntry, u16 offset); +static void TeachyTvComputeMapTilesFromTilesetAndMetaTiles(u16 *metaTilesArray, u8 *blockBuf, u8 *tileset); +static void TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(u8 *blockBuf, u8 *tileset, u8 metaTile); +static u16 TeachyTvComputePalIndexArrayEntryByMetaTile(u8 *palIndexArrayBuf, u16 metaTile); +static void TeachyTvLoadMapPalette(const struct MapData * mStruct, const u8 *palIndexArray); + +static const struct BgTemplate sBgTemplates[] = +{ + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0x000, + }, + { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0x000, + }, + { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 29, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0x000, + }, + { + .bg = 3, + .charBaseIndex = 2, + .mapBaseIndex = 28, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0x000, + }, +}; + +static const struct WindowTemplate sWindowTemplates[] = +{ + { + .bg = 1, + .tilemapLeft = 2, + .tilemapTop = 15, + .width = 26, + .height = 4, + .paletteNum = 0x3, + .baseBlock = 0x0EA, + }, + { + .bg = 0, + .tilemapLeft = 4, + .tilemapTop = 1, + .width = 22, + .height = 12, + .paletteNum = 0x3, + .baseBlock = 0x152, + }, + DUMMY_WIN_TEMPLATE, +}; + +static const struct ListMenuItem sListMenuItems[] = +{ + { + .label = gTeachyTvString_TeachBattle, + .index = TTVSCR_BATTLE + }, + { + .label = gTeachyTvString_StatusProblems, + .index = TTVSCR_STATUS + }, + { + .label = gTeachyTvString_TypeMatchups, + .index = TTVSCR_MATCHUPS + }, + { + .label = gTeachyTvString_CatchPkmn, + .index = TTVSCR_CATCHING + }, + { + .label = gTeachyTvString_AboutTMs, + .index = TTVSCR_TMS + }, + { + .label = gTeachyTvString_RegisterItem, + .index = TTVSCR_REGISTER + }, + + { + .label = gTeachyTvString_Cancel, + .index = -2 + }, +}; + +static const struct ListMenuItem sListMenuItems_NoTMCase[] = +{ + { + .label = gTeachyTvString_TeachBattle, + .index = TTVSCR_BATTLE + }, + { + .label = gTeachyTvString_StatusProblems, + .index = TTVSCR_STATUS + }, + { + .label = gTeachyTvString_TypeMatchups, + .index = TTVSCR_MATCHUPS + }, + { + .label = gTeachyTvString_CatchPkmn, + .index = TTVSCR_CATCHING + }, + { + .label = gTeachyTvString_Cancel, + .index = -2 + }, +}; + +static const struct ListMenuTemplate sListMenuTemplate = +{ + .items = sListMenuItems, + .moveCursorFunc = NULL, + .itemPrintFunc = NULL, + .totalItems = 7, + .maxShowed = 6, + .windowId = 0, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 6, + .cursorPal = 0x1, + .fillValue = 0x0, + .cursorShadowPal = 0x2, + .lettersSpacing = 0x0, + .itemVerticalPadding = 0x0, + .scrollMultiple = 0x1, + .fontId = 0x2, + .cursorKind = 0x0, +}; + +static const struct ScrollArrowsTemplate sScrollIndicatorArrowPair = +{ + .firstArrowType = 0x2, + .firstX = 0x78, + .firstY = 0xC, + .secondArrowType = 0x3, + .secondX = 0x78, + .secondY = 0x64, + .fullyUpThreshold = 0, + .fullyDownThreshold = 1, + .tileTag = 0x800, + .palTag = 0x800, + .palNum = 0x0, +}; + +static const u8 sWhereToReturnToFromBattle[] = +{ + 12, + 12, + 12, + 12, + 9, + 9 +}; + +static void (* const sBattleScript[])(u8) = +{ + TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos, + TTVcmd_ClearBg2TeachyTvGraphic, + TTVcmd_NpcMoveAndSetupTextPrinter, + TTVcmd_IdleIfTextPrinterIsActive, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_TextPrinterSwitchStringByOptionChosen, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_StartAnimNpcWalkIntoGrass, + TTVcmd_DudeMoveUp, + TTVcmd_DudeMoveRight, + TTVcmd_TaskBattleOrFadeByOptionChosen, + TTVcmd_TextPrinterSwitchStringByOptionChosen2, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_DudeTurnLeft, + TTVcmd_DudeMoveLeft, + TTVcmd_RenderAndRemoveBg1EndGraphic, + TTVcmd_End, +}; + +static void (* const sStatusScript[])(u8) = +{ + TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos, + TTVcmd_ClearBg2TeachyTvGraphic, + TTVcmd_NpcMoveAndSetupTextPrinter, + TTVcmd_IdleIfTextPrinterIsActive, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_TextPrinterSwitchStringByOptionChosen, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_StartAnimNpcWalkIntoGrass, + TTVcmd_DudeMoveUp, + TTVcmd_DudeMoveRight, + TTVcmd_TaskBattleOrFadeByOptionChosen, + TTVcmd_TextPrinterSwitchStringByOptionChosen2, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_DudeTurnLeft, + TTVcmd_DudeMoveLeft, + TTVcmd_RenderAndRemoveBg1EndGraphic, + TTVcmd_End, +}; + +static void (* const sMatchupsScript[])(u8) = +{ + TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos, + TTVcmd_ClearBg2TeachyTvGraphic, + TTVcmd_NpcMoveAndSetupTextPrinter, + TTVcmd_IdleIfTextPrinterIsActive, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_TextPrinterSwitchStringByOptionChosen, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_StartAnimNpcWalkIntoGrass, + TTVcmd_DudeMoveUp, + TTVcmd_DudeMoveRight, + TTVcmd_TaskBattleOrFadeByOptionChosen, + TTVcmd_TextPrinterSwitchStringByOptionChosen2, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_DudeTurnLeft, + TTVcmd_DudeMoveLeft, + TTVcmd_RenderAndRemoveBg1EndGraphic, + TTVcmd_End, +}; + +static void (* const sCatchingScript[])(u8) = +{ + TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos, + TTVcmd_ClearBg2TeachyTvGraphic, + TTVcmd_NpcMoveAndSetupTextPrinter, + TTVcmd_IdleIfTextPrinterIsActive, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_TextPrinterSwitchStringByOptionChosen, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_StartAnimNpcWalkIntoGrass, + TTVcmd_DudeMoveUp, + TTVcmd_DudeMoveRight, + TTVcmd_TaskBattleOrFadeByOptionChosen, + TTVcmd_TextPrinterSwitchStringByOptionChosen2, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_DudeTurnLeft, + TTVcmd_DudeMoveLeft, + TTVcmd_RenderAndRemoveBg1EndGraphic, + TTVcmd_End, +}; + +static void (* const sTMsScript[])(u8) = +{ + TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos, + TTVcmd_ClearBg2TeachyTvGraphic, + TTVcmd_NpcMoveAndSetupTextPrinter, + TTVcmd_IdleIfTextPrinterIsActive, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_TextPrinterSwitchStringByOptionChosen, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_TaskBattleOrFadeByOptionChosen, + TTVcmd_TextPrinterSwitchStringByOptionChosen2, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_DudeTurnLeft, + TTVcmd_DudeMoveLeft, + TTVcmd_RenderAndRemoveBg1EndGraphic, + TTVcmd_End, +}; + +static void (* const sRegisterKeyItemScript[])(u8) = +{ + TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos, + TTVcmd_ClearBg2TeachyTvGraphic, + TTVcmd_NpcMoveAndSetupTextPrinter, + TTVcmd_IdleIfTextPrinterIsActive, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_TextPrinterSwitchStringByOptionChosen, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_TaskBattleOrFadeByOptionChosen, + TTVcmd_TextPrinterSwitchStringByOptionChosen2, + TTVcmd_IdleIfTextPrinterIsActive2, + TTVcmd_EraseTextWindowIfKeyPressed, + TTVcmd_DudeTurnLeft, + TTVcmd_DudeMoveLeft, + TTVcmd_RenderAndRemoveBg1EndGraphic, + TTVcmd_End, +}; + +static void TeachyTvCallback(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +static void TeachyTvVblankHandler(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +void InitTeachyTvController(u8 mode, MainCallback cb) +{ + sStaticResources.mode = mode; + sStaticResources.callback = cb; + if (mode == 0) + { + sStaticResources.scrollOffset = 0; + sStaticResources.selectedRow = 0; + sStaticResources.whichScript = TTVSCR_BATTLE; + } + if (mode == 1) + { + sStaticResources.mode = 0; + } + SetMainCallback2(TeachyTvMainCallback); +} + +void CB2_ReturnToTeachyTV(void) +{ + if (sStaticResources.mode == 1) + InitTeachyTvController(1, sStaticResources.callback); + else + InitTeachyTvController(2, sStaticResources.callback); +} + +void SetTeachyTvControllerModeToResume(void) +{ + sStaticResources.mode = 1; +} + +static void TeachyTvMainCallback(void) +{ + u8 taskId; + struct Task *taskAddr; + + switch (gMain.state) + { + case 0: + sResources = AllocZeroed(sizeof(struct TeachyTvBuf)); + sResources->savedCallback = NULL; + sResources->grassAnimDisabled = 0; + sResources->scrollIndicatorArrowPairId = 0xFF; + VblankHblankHandlerSetZero(); + clear_scheduled_bg_copies_to_vram(); + ScanlineEffect_Stop(); + FreeAllSpritePalettes(); + ResetPaletteFade(); + ResetSpriteData(); + ResetTasks(); + TeachyTvSetupBg(); + TeachyTvLoadGraphic(); + ++gMain.state; + break; + case 1: + if (free_temp_tile_data_buffers_if_possible() == TRUE) + return; + TeachyTvCreateAndRenderRbox(); + TeachyTvInitIo(); + if (sStaticResources.mode == 2) + { + taskId = CreateTask(TeachyTvPostBattleFadeControl, 0); + gTasks[taskId].data[1] = TeachyTvSetupObjEventAndOam(); + TeachyTvSetupPostBattleWindowAndObj(taskId); + } + else + { + taskId = CreateTask(TeachyTvOptionListController, 0); + gTasks[taskId].data[0] = TeachyTvSetupWindow(); + gTasks[taskId].data[1] = TeachyTvSetupObjEventAndOam(); + TeachyTvSetupScrollIndicatorArrowPair(); + PlayNewMapMusic(BGM_FRLG_TEACHY_TV); + TeachyTvSetWindowRegs(); + } + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); + schedule_bg_copy_tilemap_to_vram(3); + sub_812B1E0(9); // help system something + BlendPalettes(0xFFFFFFFF, 0x10, 0); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0x10, 0, 0); + SetVBlankCallback(TeachyTvVblankHandler); + SetMainCallback2(TeachyTvCallback); + break; + } +} + +static void TeachyTvSetupBg(void) +{ + InitBgReg(); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBgTemplates, 4); + SetBgTilemapBuffer(1, sResources->buffer1); + SetBgTilemapBuffer(2, sResources->buffer2); + SetBgTilemapBuffer(3, sResources->buffer3); + SetGpuReg(REG_OFFSET_DISPCNT, 0x3040); + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); + ChangeBgX(3, 0x1000, 2); + ChangeBgY(3, 0x2800, 1); + sResources->grassAnimCounterLo = 0; + sResources->grassAnimCounterHi = 3; + SetGpuReg(REG_OFFSET_BLDCNT, 0); +} + +static void TeachyTvLoadGraphic(void) +{ + u16 src = RGB_BLACK; + reset_temp_tile_data_buffers(); + decompress_and_copy_tile_data_to_vram(1, gUnknown_8E86240, 0, 0, 0); + LZDecompressWram(gUnknown_8E86BE8, sResources->buffer1); + LZDecompressWram(gUnknown_8E86D6C, sResources->buffer4); + LoadCompressedPalette(gUnknown_8E86F98, 0, 0x80); + LoadPalette(&src, 0, sizeof(src)); + LoadSpritePalette(&gUnknown_83A5348); + TeachyTvLoadBg3Map(sResources->buffer3); +} + +static void TeachyTvCreateAndRenderRbox(void) +{ + InitWindows(sWindowTemplates); + DeactivateAllTextPrinters(); + FillWindowPixelBuffer(0, 0xCC); + PutWindowTilemap(0); + PutWindowTilemap(1); + CopyWindowToVram(0, 2); +} + +static u8 TeachyTvSetupWindow(void) +{ + gMultiuseListMenuTemplate = sListMenuTemplate; + gMultiuseListMenuTemplate.windowId = 1; + gMultiuseListMenuTemplate.moveCursorFunc = TeachyTvAudioByInput; + if (!CheckBagHasItem(ITEM_TM_CASE, 1)) + { + gMultiuseListMenuTemplate.items = sListMenuItems_NoTMCase; + gMultiuseListMenuTemplate.totalItems = 5; + gMultiuseListMenuTemplate.maxShowed = 5; + gMultiuseListMenuTemplate.upText_Y = (gMultiuseListMenuTemplate.upText_Y + 8) & 0xF; + } + return ListMenuInit( + &gMultiuseListMenuTemplate, + sStaticResources.scrollOffset, + sStaticResources.selectedRow + ); +} + +static void TeachyTvSetupScrollIndicatorArrowPair(void) +{ + if (!CheckBagHasItem(ITEM_TM_CASE, 1)) + { + struct TeachyTvBuf * temp = sResources; + temp->scrollIndicatorArrowPairId = 0xFF; + } + else + { + sResources->scrollIndicatorArrowPairId = AddScrollIndicatorArrowPair(&sScrollIndicatorArrowPair, &(sStaticResources.scrollOffset)); + } +} + +static void TeachyTvRemoveScrollIndicatorArrowPair(void) +{ + if (sResources->scrollIndicatorArrowPairId != 0xFF) + { + RemoveScrollIndicatorArrowPair(sResources->scrollIndicatorArrowPairId); + sResources->scrollIndicatorArrowPairId = 0xFF; + } +} + +static void TeachyTvAudioByInput(s32 notUsed, bool8 play, struct ListMenu *notUsedAlt) +{ + if (play != TRUE) + PlaySE(SE_SELECT); +} + +static void TeachyTvInitIo(void) +{ + SetGpuReg(REG_OFFSET_WININ, 0x3F); + SetGpuReg(REG_OFFSET_WINOUT, 0x1F); + SetGpuReg(REG_OFFSET_BLDCNT, 0xCC); + SetGpuReg(REG_OFFSET_BLDY, 0x5); +} + +static u8 TeachyTvSetupObjEventAndOam(void) +{ + u8 objId = AddPseudoEventObject(90, SpriteCallbackDummy, 0, 0, 8); + gSprites[objId].oam.priority = 2; + gSprites[objId].invisible = 1; + return objId; +} + +static void TeachyTvSetSpriteCoordsAndSwitchFrame(u8 objId, u16 x, u16 y, u8 frame) +{ + gSprites[objId].pos2.x = x; + gSprites[objId].pos2.y = y; + gSprites[objId].invisible = 0; + StartSpriteAnim(&gSprites[objId], frame); +} + +static void TeachyTvSetWindowRegs(void) +{ + SetGpuReg(REG_OFFSET_WIN0V, 0xC64); + SetGpuReg(REG_OFFSET_WIN0H, 0x1CD4); +} + +static void TeachyTvClearWindowRegs(void) +{ + SetGpuReg(REG_OFFSET_WIN0V, 0x0); + SetGpuReg(REG_OFFSET_WIN0H, 0x0); +} + +static void TeachyTvBg2AnimController(void) +{ + u16 * tilemapBuffer = GetBgTilemapBuffer(2); + u8 i, j; + for (i = 1; i < 13; i++) + { + for (j = 2; j < 28; j++) + { + tilemapBuffer[32 * i + j] = ((Random() & 3) << 10) + 0x301F; + } + } + schedule_bg_copy_tilemap_to_vram(2); +} + +static void TeachyTvSetupPostBattleWindowAndObj(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + struct Sprite *objAddr = &gSprites[data[1]]; + + ClearWindowTilemap(1); + TeachyTvClearWindowRegs(); + switch (sStaticResources.whichScript) + { + case TTVSCR_BATTLE: + case TTVSCR_STATUS: + case TTVSCR_MATCHUPS: + case TTVSCR_CATCHING: + TeachyTvSetSpriteCoordsAndSwitchFrame(data[1], 0x78, 0x38, 0); + ChangeBgX(3, 0x3000, 1); + ChangeBgY(3, 0x3000, 2); + sResources->grassAnimCounterLo += 3; + sResources->grassAnimCounterHi -= 3; + break; + case TTVSCR_TMS: + case TTVSCR_REGISTER: + TeachyTvSetSpriteCoordsAndSwitchFrame(data[1], 0x78, 0x38, 0); + break; + } + + data[4] = 0; + data[5] = 0; + TeachyTvGrassAnimationMain(taskId, objAddr->pos2.x, objAddr->pos2.y, 0, 1); +} + +static void TeachyTvInitTextPrinter(const u8 *text) +{ + gTextFlags.autoScroll = 0; + AddTextPrinterParameterized2(0, 4, text, GetTextSpeedSetting(), 0, 1, 0xC, 3); +} + +static void TeachyTvFree(void) +{ + Free(sResources); + sResources = NULL; + FreeAllWindowBuffers(); +} + +static void TeachyTvQuitBeginFade(u8 taskId) +{ + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0); + gTasks[taskId].func = TeachyTvQuitFadeControlAndTaskDel; +} + +static void TeachyTvQuitFadeControlAndTaskDel(u8 taskId) +{ + if (!(gPaletteFade.active)) + { + if (sResources->savedCallback != NULL) + { + SetMainCallback2(sResources->savedCallback); + } + else + { + sub_8055DC4(); + SetMainCallback2(sStaticResources.callback); + } + TeachyTvFree(); + DestroyTask(taskId); + } +} + +static void TeachyTvOptionListController(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + s32 input; + + TeachyTvBg2AnimController(); + if (!gPaletteFade.active) + { + input = ListMenuHandleInput(data[0]); + ListMenuGetScrollAndRow(data[0], &sStaticResources.scrollOffset, &sStaticResources.selectedRow); + if ((JOY_NEW(SELECT_BUTTON) && sStaticResources.callback != ReturnToBagFromKeyItem)) + { + PlaySE(SE_SELECT); + TeachyTvQuitBeginFade(taskId); + } + else + { + switch (input) + { + case -1: + break; + case -2: + PlaySE(SE_SELECT); + TeachyTvQuitBeginFade(taskId); + break; + default: + PlaySE(SE_SELECT); + sStaticResources.whichScript = input; + DestroyListMenu(data[0], &sStaticResources.scrollOffset, &sStaticResources.selectedRow); + TeachyTvClearWindowRegs(); + ClearWindowTilemap(1); + schedule_bg_copy_tilemap_to_vram(0); + TeachyTvRemoveScrollIndicatorArrowPair(); + data[3] = 0; + data[2] = 0; + gTasks[taskId].func = TeachyTvRenderMsgAndSwitchClusterFuncs; + break; + } + } + } +} + +static void TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + TeachyTvBg2AnimController(); + if (++data[2] > 63) + { + CopyToBgTilemapBufferRect_ChangePalette(2, sResources->buffer4, 0, 0, 0x20, 0x20, 0x11); + TeachyTvSetSpriteCoordsAndSwitchFrame(data[1], 8, 0x38, 7); + schedule_bg_copy_tilemap_to_vram(2); + data[2] = 0; + ++data[3]; + PlayNewMapMusic(BGM_FRLG_FOLLOW_ME); + } +} + +static void TTVcmd_ClearBg2TeachyTvGraphic(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (++data[2] == 134) + { + FillBgTilemapBufferRect_Palette0(2, 0, 2, 1, 0x1A, 0xC); + schedule_bg_copy_tilemap_to_vram(2); + data[2] = 0; + ++data[3]; + } +} + +static void TTVcmd_NpcMoveAndSetupTextPrinter(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + struct Sprite * spriteAddr = &gSprites[data[1]]; + if (data[2] != 35) + ++data[2]; + else { + if (spriteAddr->pos2.x == 0x78) + { + StartSpriteAnim(&gSprites[data[1]], 0); + TeachyTvInitTextPrinter(gTeachyTvText_PokeDudeSaysHello); + data[2] = 0; + ++data[3]; + } + else + ++spriteAddr->pos2.x; + } +} + +static void TTVcmd_IdleIfTextPrinterIsActive(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (!sub_80BF518(0)) + ++data[3]; +} + +static void TeachyTvRenderMsgAndSwitchClusterFuncs(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (JOY_NEW(B_BUTTON)) + { + sResources->grassAnimDisabled = 1; + TeachyTvSetSpriteCoordsAndSwitchFrame(data[1], 0, 0, 0); + FillWindowPixelBuffer(0, 0xCC); + CopyWindowToVram(0, 2); + TeachyTvClearBg1EndGraphicText(); + data[2] = 0; + data[3] = 0; + gTasks[taskId].func = TTVcmd_End; + } + else + { + static void (* const * const array[])(u8) = + { + sBattleScript, + sStatusScript, + sMatchupsScript, + sCatchingScript, + sTMsScript, + sRegisterKeyItemScript, + }; + void (*const *cluster)(u8) = array[sStaticResources.whichScript]; + cluster[data[3]](taskId); + } +} + +static void TTVcmd_TextPrinterSwitchStringByOptionChosen(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + static const u8 *const texts[] = { + gTeachyTvText_BattleScript1, + gTeachyTvText_StatusScript1, + gTeachyTvText_MatchupsScript1, + gTeachyTvText_CatchingScript1, + gTeachyTvText_TMsScript1, + gTeachyTvText_RegisterScript1, + }; + TeachyTvInitTextPrinter(texts[sStaticResources.whichScript]); + ++data[3]; +} + +static void TTVcmd_TextPrinterSwitchStringByOptionChosen2(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + static const u8 *const texts[] = + { + gTeachyTvText_BattleScript2, + gTeachyTvText_StatusScript2, + gTeachyTvText_MatchupsScript2, + gTeachyTvText_CatchingScript2, + gTeachyTvText_TMsScript2, + gTeachyTvText_RegisterScript2, + }; + TeachyTvInitTextPrinter(texts[sStaticResources.whichScript]); + ++data[3]; +} + +static const u16 sBg1EndGraphic[] = +{ + 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, + 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, +}; + +static const struct Subsprite sSubspriteArray[] = +{ + { + .x = -0x8, + .y = -0x8, + .shape = 0x1, + .size = 0x0, + .tileOffset = 0x0, + .priority = 0x3, + }, + { + .x = -0x8, + .y = 0x0, + .shape = 0x1, + .size = 0x0, + .tileOffset = 0x2, + .priority = 0x2, + }, +}; + +static const struct SubspriteTable sSubspriteTableArray[] = +{ + { + .subspriteCount = 0, + .subsprites = NULL, + }, + { + .subspriteCount = 2, + .subsprites = sSubspriteArray, + }, +}; + +static const u8 sGrassAnimArray[] = +{ + 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, +}; + +static void TTVcmd_IdleIfTextPrinterIsActive2(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (!sub_80BF518(0)) + ++data[3]; +} + +static void TTVcmd_EraseTextWindowIfKeyPressed(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + FillWindowPixelBuffer(0, 0xCC); + CopyWindowToVram(0, 2); + ++data[3]; + } +} + +static void TTVcmd_StartAnimNpcWalkIntoGrass(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + StartSpriteAnim(&gSprites[data[1]], 5); + data[2] = 0; + data[4] = 0; + data[5] = 1; + ++data[3]; +} + +static void TTVcmd_DudeMoveUp(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + struct Sprite *obj = &gSprites[data[1]]; + ChangeBgY(3, 0x100, 2); + if (!(++data[2] & 0xF)) + { + --sResources->grassAnimCounterHi; + TeachyTvGrassAnimationMain(taskId, obj->pos2.x, obj->pos2.y, 0, 0); + } + if (data[2] == 48) + { + data[2] = 0; + data[4] = -1; + data[5] = 0; + StartSpriteAnim(obj, 7); + ++data[3]; + } +} + +static void TTVcmd_DudeMoveRight(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + struct Sprite *obj = &gSprites[data[1]]; + ChangeBgX(3, 0x100, 1); + if (!(++data[2] & 0xF)) + ++sResources->grassAnimCounterLo; + if (!((data[2] + 8) & 0xF)) + TeachyTvGrassAnimationMain(taskId, obj->pos2.x + 8, obj->pos2.y, 0, 0); + if (data[2] == 0x30) + { + data[2] = 0; + data[4] = 0; + data[5] = 0; + StartSpriteAnim(obj, 3); + ++data[3]; + } +} + +static void TTVcmd_DudeTurnLeft(u8 taskId) +{ + + s16 *data = gTasks[taskId].data; + struct Sprite *objAddr = &gSprites[data[1]]; + StartSpriteAnim(objAddr, 6); + ++data[3]; + data[4] = 0; + data[5] = 0; + TeachyTvGrassAnimationMain(taskId, objAddr->pos2.x, objAddr->pos2.y, 0, 0); +} + +static void TTVcmd_DudeMoveLeft(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + struct Sprite *objAddr = &gSprites[data[1]]; + + if (!(objAddr->pos2.x & 0xF)) + TeachyTvGrassAnimationMain(taskId, objAddr->pos2.x - 8, objAddr->pos2.y, 0, 0); + if (objAddr->pos2.x == 8) + ++data[3]; + else + --objAddr->pos2.x; +} + +static void TTVcmd_RenderAndRemoveBg1EndGraphic(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (!data[2]) + { + CopyToBgTilemapBufferRect_ChangePalette(1, sBg1EndGraphic, 20, 10, 8, 2, 0x11); + schedule_bg_copy_tilemap_to_vram(1); + } + if (++data[2] > 126) + { + TeachyTvClearBg1EndGraphicText(); + data[2] = 0; + ++data[3]; + } +} + +static void TeachyTvClearBg1EndGraphicText(void) +{ + FillBgTilemapBufferRect_Palette0(1, 0, 20, 10, 8, 2); + schedule_bg_copy_tilemap_to_vram(1); +} + +static void TTVcmd_End(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (data[2] == 0) + PlayNewMapMusic(BGM_FRLG_TEACHY_TV); + TeachyTvBg2AnimController(); + if (++data[2] > 63) + { + data[2] = 0; + data[3] = 0; + data[0] = TeachyTvSetupWindow(); + gTasks[taskId].func = TeachyTvOptionListController; + PutWindowTilemap(0); + TeachyTvSetupScrollIndicatorArrowPair(); + TeachyTvSetWindowRegs(); + schedule_bg_copy_tilemap_to_vram(0); + ChangeBgX(3, 0x0, 0); + ChangeBgY(3, 0x0, 0); + ChangeBgX(3, 0x1000, 2); + ChangeBgY(3, 0x2800, 1); + sResources->grassAnimCounterLo = 0; + sResources->grassAnimCounterHi = 3; + sResources->grassAnimDisabled = 0; + } +} + +static void TTVcmd_TaskBattleOrFadeByOptionChosen(u8 taskId) +{ + switch (sStaticResources.whichScript) + { + case TTVSCR_BATTLE: + case TTVSCR_STATUS: + case TTVSCR_MATCHUPS: + case TTVSCR_CATCHING: + TeachyTvPrepBattle(taskId); + break; + case TTVSCR_TMS: + case TTVSCR_REGISTER: + sResources->savedCallback = TeachyTvSetupBagItemsByOptionChosen; + TeachyTvQuitBeginFade(taskId); + break; + } +} + +static void TeachyTvSetupBagItemsByOptionChosen(void) +{ + if (sStaticResources.whichScript == TTVSCR_TMS) + sub_810B108(10); + else + sub_810B108(9); +} + +static void TeachyTvPostBattleFadeControl(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (!(gPaletteFade.active)) + { + data[3] = sWhereToReturnToFromBattle[sStaticResources.whichScript]; + gTasks[taskId].func = TeachyTvRenderMsgAndSwitchClusterFuncs; + } +} + +static void TeachyTvGrassAnimationMain(u8 taskId, s16 x, s16 y, u8 subpriority, bool8 mode) +{ + struct Sprite *obj; + u8 spriteId; + + if (sResources->grassAnimDisabled != 1 && TeachyTvGrassAnimationCheckIfNeedsToGenerateGrassObj(x - 0x10, y)) + { + spriteId = CreateSprite(gUnknown_83A0010[4], 0, 0, subpriority); + obj = &gSprites[spriteId]; + obj->pos2.x = x; + obj->pos2.y = y + 8; + obj->callback = TeachyTvGrassAnimationObjCallback; + obj->data[0] = taskId; + if (mode == 1) + { + SeekSpriteAnim(obj, 4); + obj->oam.priority = 2; + } + else + { + SetSubspriteTables(obj, sSubspriteTableArray); + obj->subspriteTableNum = 0; + obj->subspriteMode = 1; + } + } +} + +static void TeachyTvGrassAnimationObjCallback(struct Sprite *sprite) +{ + s16 diff1, diff2; + s16 *data = gTasks[sprite->data[0]].data; + struct Sprite *objAddr = &gSprites[data[1]]; + + if (sResources->grassAnimDisabled == 1) + DestroySprite(sprite); + else + { + if (sprite->animCmdIndex == 0) + sprite->subspriteTableNum = 1; + else + sprite->subspriteTableNum = 0; + sprite->pos2.x += data[4]; + sprite->pos2.y += data[5]; + if (sprite->animEnded) + { + sprite->subpriority = 0; + diff1 = sprite->pos2.x - objAddr->pos2.x; + diff2 = sprite->pos2.y - objAddr->pos2.y; + if (diff1 <= -16 || diff1 >= 16 || diff2 <= -16 || diff2 >= 24) + DestroySprite(sprite); + } + } +} + +static u8 TeachyTvGrassAnimationCheckIfNeedsToGenerateGrassObj(s16 x, s16 y) +{ + const u8 * arr; + struct TeachyTvBuf *ptr; + int high, low; + if ((x < 0) || (y < 0)) + return 0; + arr = sGrassAnimArray; + high = ((y >> 4) + sResources->grassAnimCounterHi) << 4; + low = ((x >> 4) + sResources->grassAnimCounterLo); + return arr[high+low]; +} + +static void TeachyTvPrepBattle(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + TeachyTvFree(); + gSpecialVar_0x8004 = sStaticResources.whichScript; + gMain.savedCallback = TeachyTvRestorePlayerPartyCallback; + SavePlayerParty(); + sub_8159F40(); + PlayMapChosenOrBattleBGM(MUS_DUMMY); + if (sStaticResources.whichScript == TTVSCR_BATTLE) + data[6] = 9; + else + data[6] = 8; + data[7] = 0; + gTasks[taskId].func = TeachyTvPreBattleAnimAndSetBattleCallback; +} + +static void TeachyTvPreBattleAnimAndSetBattleCallback(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + switch (data[7]) + { + case 0: + sub_80D08B8(data[6]); + ++data[7]; + break; + case 1: + if (sub_80D08F8()) + { + SetMainCallback2(sub_800FD9C); + DestroyTask(taskId); + } + break; + } +} + +static void TeachyTvRestorePlayerPartyCallback(void) +{ + LoadPlayerParty(); + if (gBattleOutcome == B_OUTCOME_DREW) + SetTeachyTvControllerModeToResume(); + else + PlayNewMapMusic(BGM_FRLG_FOLLOW_ME); + CB2_ReturnToTeachyTV(); +} + +static void TeachyTvLoadBg3Map(u16 *buffer) +{ + u16 * bgTilesBuffer; + u8 * mapTilesRowBuffer; + u16 i, j, k; + u16 currentBlockIdx; + void * tilesetsBuffer; + void * palIndicesBuffer; + u16 numMapTilesRows = 0; + const struct MapData *layout = &Route1_Layout; + u16 * blockIndicesBuffer = AllocZeroed(0x800); + tilesetsBuffer = AllocZeroed(0x8000); + palIndicesBuffer = Alloc(16); + memset(palIndicesBuffer, 0xFF, 16); + + TeachyTvLoadMapTilesetToBuffer(layout->primaryTileset, tilesetsBuffer, 0x280); + TeachyTvLoadMapTilesetToBuffer(layout->secondaryTileset, tilesetsBuffer + 0x5000, 0x180); + + for (i = 0; i < 9; i++) + { + for (j = 0; j < 16; j++) + { + currentBlockIdx = layout->map[8 + (i + 6) * layout->width + j] & 0x3FF; + for (k = 0; k < (i << 4) + j; k++) + { + if (blockIndicesBuffer[k] == 0) + break; + if (blockIndicesBuffer[k] == currentBlockIdx) + break; + } + if (blockIndicesBuffer[k] == 0) + { + blockIndicesBuffer[k] = currentBlockIdx; + numMapTilesRows++; + } + TeachyTvPushBackNewMapPalIndexArrayEntry(layout, &buffer[64 * i + 2 * j], palIndicesBuffer, currentBlockIdx, k); + } + } + + bgTilesBuffer = Alloc(numMapTilesRows * 0x80); + mapTilesRowBuffer = Alloc(0x80); + for (i = 0; i < numMapTilesRows; i++) + { + memset(mapTilesRowBuffer, 0, 0x80); + if (blockIndicesBuffer[i] < 0x280) + { + TeachyTvComputeMapTilesFromTilesetAndMetaTiles(layout->primaryTileset->metatiles + blockIndicesBuffer[i] * 16, mapTilesRowBuffer, tilesetsBuffer); + } + else + { + TeachyTvComputeMapTilesFromTilesetAndMetaTiles(layout->secondaryTileset->metatiles + (blockIndicesBuffer[i] - 0x280) * 16, mapTilesRowBuffer, tilesetsBuffer); + } + CpuFastCopy(mapTilesRowBuffer, bgTilesBuffer + i * 0x40, 0x80); + } + + LoadBgTiles(3, bgTilesBuffer, numMapTilesRows * 0x80, 0); + TeachyTvLoadMapPalette(layout, palIndicesBuffer); + + Free(mapTilesRowBuffer); + Free(bgTilesBuffer); + Free(palIndicesBuffer); + Free(tilesetsBuffer); + Free(blockIndicesBuffer); +} + +static void TeachyTvLoadMapTilesetToBuffer(struct Tileset *ts, u8 *dstBuffer, u16 size) +{ + if (ts) + { + if (!ts->isCompressed) + CpuFastSet(ts->tiles, dstBuffer, 8 * size); + else + LZDecompressWram(ts->tiles, dstBuffer); + } +} + +static void TeachyTvPushBackNewMapPalIndexArrayEntry(const struct MapData *mStruct, u16 *buf1, u8 *palIndexArray, u16 mapEntry, u16 offset) +{ + u16 * metaTileEntryAddr = mapEntry <= 0x27F ? &((u16*)(mStruct->primaryTileset->metatiles))[8 * mapEntry] : &((u16*)(mStruct->secondaryTileset->metatiles))[8 * (mapEntry - 0x280)]; + buf1[0] = (TeachyTvComputePalIndexArrayEntryByMetaTile(palIndexArray, metaTileEntryAddr[0]) << 12) + 4 * offset; + buf1[1] = (TeachyTvComputePalIndexArrayEntryByMetaTile(palIndexArray, metaTileEntryAddr[1]) << 12) + 4 * offset + 1; + buf1[32] = (TeachyTvComputePalIndexArrayEntryByMetaTile(palIndexArray, metaTileEntryAddr[2]) << 12) + 4 * offset + 2; + buf1[33] = (TeachyTvComputePalIndexArrayEntryByMetaTile(palIndexArray, metaTileEntryAddr[3]) << 12) + 4 * offset + 3; +} + +static void TeachyTvComputeMapTilesFromTilesetAndMetaTiles(u16 *metaTilesArray, u8 *blockBuf, u8 *tileset) +{ + TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(blockBuf, &tileset[0x20 * (*metaTilesArray & 0x3FF)], (*metaTilesArray >> 10) & 3); + TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(blockBuf, &tileset[0x20 * (metaTilesArray[4] & 0x3FF)], (metaTilesArray[4] >> 10) & 3); + TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(blockBuf + 0x20, &tileset[0x20 * (metaTilesArray[1] & 0x3FF)], (metaTilesArray[1] >> 10) & 3); + TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(blockBuf + 0x20, &tileset[0x20 * (metaTilesArray[5] & 0x3FF)], (metaTilesArray[5] >> 10) & 3); + TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(blockBuf + 0x40, &tileset[0x20 * (metaTilesArray[2] & 0x3FF)], (metaTilesArray[2] >> 10) & 3); + TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(blockBuf + 0x40, &tileset[0x20 * (metaTilesArray[6] & 0x3FF)], (metaTilesArray[6] >> 10) & 3); + blockBuf += 0x60; + TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(blockBuf, &tileset[0x20 * (metaTilesArray[3] & 0x3FF)], (metaTilesArray[3] >> 10) & 3); + TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(blockBuf, &tileset[0x20 * (metaTilesArray[7] & 0x3FF)], (metaTilesArray[7] >> 10) & 3); +} + +static void TeachyTvComputeSingleMapTileBlockFromTilesetAndMetaTiles(u8 *blockBuf, u8 *tileset, u8 metaTile) +{ + u8 i, j; + u8 * buffer = AllocZeroed(0x20); + u8 * src = AllocZeroed(0x20); + CpuFastSet(tileset, buffer, 8); + if (metaTile & 1) + { + for (i = 0; i < 8; ++i) + { + for (j = 0; j < 4; ++j) + { + u32 offset = j - 3; + u8 value = buffer[(i << 2) - offset]; + src[(i << 2) + j] = ((value & 0xF) << 4) + ((value & 0xF0) >> 4); + } + } + CpuFastSet(src, buffer, 8); + } + if (metaTile & 2) + { + for (i = 0; i < 8; ++i) + memcpy(&src[4 * i], &buffer[4 * (7 - i)], 4); + CpuFastSet(src, buffer, 8); + } + for (i = 0; i < 32; ++i) + { + if (buffer[i] & 0xF0) + blockBuf[i] = (blockBuf[i] & 0xF) + (buffer[i] & 0xF0); + if (buffer[i] & 0xF) + blockBuf[i] = (blockBuf[i] & 0xF0) + (buffer[i] & 0xF); + } + Free(src); + Free(buffer); +} + +static u16 TeachyTvComputePalIndexArrayEntryByMetaTile(u8 *palIndexArrayBuf, u16 metaTile) +{ + u16 i; + int firstEntry; + int temp; + u32 pal = metaTile >> 12; + i = 0; + firstEntry = *palIndexArrayBuf; + if (firstEntry != pal) + { + if (firstEntry == 0xFF) + { + *palIndexArrayBuf = pal; + } + else + { + while (++i < 16) + { + temp = palIndexArrayBuf[i]; + if (temp == pal) + break; + if (temp == 0xFF) + { + palIndexArrayBuf[i] = pal; + break; + } + } + } + } + return (0xF - i); +} + +static void TeachyTvLoadMapPalette(const struct MapData * mStruct, const u8 * palIndexArray) +{ + u8 i; + const struct Tileset * ts; + u16 * dest; + + for (i = 0; i < 16; i++) + { + if (palIndexArray[i] == 0xFF) + break; + if (palIndexArray[i] > 6) + dest = (u16 *)mStruct->secondaryTileset->palettes + 0x10 * palIndexArray[i]; + else + dest = (u16 *)mStruct->primaryTileset->palettes + 0x10 * palIndexArray[i]; + LoadPalette(dest, 0x10 * (15 - i), 0x20); + } +} diff --git a/src/text.c b/src/text.c index 874e12fd5..f84420352 100644 --- a/src/text.c +++ b/src/text.c @@ -5,13 +5,13 @@ #include "window.h" #include "text.h" #include "sprite.h" +#include "blit.h" extern u8 gGlyphInfo[0x90]; extern u8 gUnknown_203ADFA; -extern u16 gUnknown_841F408[]; -extern const struct OamData gUnknown_83AC9D0; +extern u16 gTMCaseMainWindowPalette[]; +extern const struct OamData gOamData_83AC9D0; -extern void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); extern void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); extern void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight); extern u8 GetKeypadIconWidth(u8 keypadIconId); @@ -52,7 +52,7 @@ const struct SpriteSheet gUnknown_81EA68C[] = const struct SpritePalette gUnknown_81EA6A4[] = { - {gUnknown_841F408, 0x8000}, + {gTMCaseMainWindowPalette, 0x8000}, {NULL} }; @@ -60,7 +60,7 @@ const struct SpriteTemplate gUnknown_81EA6B4 = { .tileTag = 0x8000, .paletteTag = 0x8000, - .oam = &gUnknown_83AC9D0, + .oam = &gOamData_83AC9D0, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, @@ -453,7 +453,7 @@ void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - if (gTextFlags.flag_2 == 1) + if (gTextFlags.autoScroll == 1) subStruct->frames_visible_counter = 0; else { @@ -467,7 +467,7 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; const u8 *arrowTiles; - if (gTextFlags.flag_2 == 0) + if (gTextFlags.autoScroll == 0) { if (subStruct->field_1 != 0) { @@ -483,7 +483,7 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) 10, 12); - switch (gTextFlags.flag_1) + switch (gTextFlags.useAlternateDownArrow) { case 0: default: @@ -544,7 +544,7 @@ bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter) bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) { bool8 result = FALSE; - if (gTextFlags.flag_2 != 0) + if (gTextFlags.autoScroll != 0) { result = TextPrinterWaitAutoMode(textPrinter); } @@ -563,7 +563,7 @@ bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) bool16 TextPrinterWait(struct TextPrinter *textPrinter) { bool16 result = FALSE; - if (gTextFlags.flag_2 != 0) + if (gTextFlags.autoScroll != 0) { result = TextPrinterWaitAutoMode(textPrinter); } @@ -591,7 +591,7 @@ void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *c FillWindowPixelRect(windowId, (bgColor << 4) | bgColor, x, y, 10, 12); if (drawArrow == 0) { - switch (gTextFlags.flag_1) + switch (gTextFlags.useAlternateDownArrow) { case 0: default: @@ -1791,7 +1791,7 @@ void sub_80062B0(struct Sprite *sprite) } } -u8 sub_8006300(u8 sheetId, u16 x, u16 y, u8 priority, u8 subpriority) +u8 CreateTextCursorSpriteForOakSpeech(u8 sheetId, u16 x, u16 y, u8 priority, u8 subpriority) { u8 spriteId; LoadSpriteSheet(&gUnknown_81EA68C[sheetId & 1]); diff --git a/src/text_printer.c b/src/text_printer.c index 04de1af4c..6c124b448 100644 --- a/src/text_printer.c +++ b/src/text_printer.c @@ -48,11 +48,11 @@ void DeactivateAllTextPrinters (void) sTextPrinters[printer].sub_union.sub.active = 0; } -u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextSubPrinter *, u16)) +u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) { - struct TextSubPrinter subPrinter; + struct TextPrinterTemplate subPrinter; - subPrinter.current_text_offset = str; + subPrinter.currentChar = str; subPrinter.windowId = windowId; subPrinter.fontId = fontId; subPrinter.x = x; @@ -61,14 +61,14 @@ u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 subPrinter.currentY = y; subPrinter.letterSpacing = gFonts[fontId].letterSpacing; subPrinter.lineSpacing = gFonts[fontId].lineSpacing; - subPrinter.fontColor_l = gFonts[fontId].fontColor_l; - subPrinter.fontColor_h = gFonts[fontId].fontColor_h; + subPrinter.unk = gFonts[fontId].unk; + subPrinter.fgColor = gFonts[fontId].fgColor; subPrinter.bgColor = gFonts[fontId].bgColor; subPrinter.shadowColor = gFonts[fontId].shadowColor; return AddTextPrinter(&subPrinter, speed, callback); } -bool16 AddTextPrinter(struct TextSubPrinter *textSubPrinter, u8 speed, void (*callback)(struct TextSubPrinter *, u16)) +bool16 AddTextPrinter(struct TextPrinterTemplate *textSubPrinter, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) { int i; u16 j; @@ -92,7 +92,7 @@ bool16 AddTextPrinter(struct TextSubPrinter *textSubPrinter, u8 speed, void (*ca sTempTextPrinter.minLetterSpacing = 0; sTempTextPrinter.japanese = 0; - GenerateFontHalfRowLookupTable(textSubPrinter->fontColor_h, textSubPrinter->bgColor, textSubPrinter->shadowColor); + GenerateFontHalfRowLookupTable(textSubPrinter->fgColor, textSubPrinter->bgColor, textSubPrinter->shadowColor); if (speed != TEXT_SPEED_FF && speed != 0x0) { --sTempTextPrinter.text_speed; diff --git a/src/text_window.c b/src/text_window.c new file mode 100644 index 000000000..0c562b195 --- /dev/null +++ b/src/text_window.c @@ -0,0 +1,169 @@ +#include "global.h" +#include "bg.h" +#include "palette.h" +#include "text.h" +#include "window.h" +#include "text_window.h" +#include "text_window_graphics.h" +#include "quest_log.h" + +extern const u16 gUnknown_841F1C8[]; + +void sub_814FFC4(u8 windowId, u8 frameType, u16 destOffset, u8 palIdx); + +void sub_814FD04(u8 bgId, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(bgId, gUnknown_84566A8, 0x280, destOffset); + LoadPalette(stdpal_get(2), palIdx, 32); +} + +void sub_814FD38(u8 bgId, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(bgId, gUnknown_841F1C8, 0x280, destOffset); + LoadPalette(stdpal_get(0), palIdx, 32); +} + +void sub_814FD6C(u8 bgId, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(bgId, gUnknown_8470B0C, 0x260, destOffset); + LoadPalette(stdpal_get(1), palIdx, 32); +} + +void sub_814FDA0(u8 bgId, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(bgId, gStdFrame0, 0x120, destOffset); + LoadPalette(stdpal_get(3), palIdx, 32); +} + +void sub_814FDD4(u8 bgId, u16 destOffset) +{ + LoadBgTiles(bgId, gStdFrame1, 0x280, destOffset); +} + +void sub_814FDF4(u8 bgId, u8 frameType, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(bgId, gUserFrames[frameType].tiles, 0x120, destOffset); + LoadPalette(gUserFrames[frameType].palette, palIdx, 32); +} + +void LoadUserWindowBorderGfx(u8 windowId, u16 destOffset, u8 palIdx) +{ + sub_814FFC4(windowId, gSaveBlock2Ptr->optionsWindowFrameType, destOffset, palIdx); +} + +void sub_814FE6C(u8 windowId, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_BG), gUnknown_84566A8, 0x280, destOffset); + LoadPalette(stdpal_get(2), palIdx, 32); +} + +void TextWindow_SetBubbleFrame_841F1C8(u8 windowId, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_BG), gUnknown_841F1C8, 0x280, destOffset); + LoadPalette(stdpal_get(0), palIdx, 32); +} + +void sub_814FEEC(u8 windowId, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_BG), gUnknown_8470B0C, 0x260, destOffset); + LoadPalette(stdpal_get(1), palIdx, 32); +} + +void TextWindow_SetStdFrame0_WithPal(u8 windowId, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_BG), gStdFrame0, 0x120, destOffset); + LoadPalette(stdpal_get(3), palIdx, 32); +} + +void sub_814FF6C(u8 windowId, u16 destOffset) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_BG), gStdFrame0, 0x120, destOffset); +} + +void sub_814FF98(u8 windowId, u16 destOffset) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_BG), gStdFrame1, 0x280, destOffset); +} + +void sub_814FFC4(u8 windowId, u8 frameType, u16 destOffset, u8 palIdx) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_BG), gUserFrames[frameType].tiles, 0x120, destOffset); + LoadPalette(gUserFrames[frameType].palette, palIdx, 32); +} + +void TextWindow_SetUserSelectedFrame(u8 windowId, u16 destOffset, u8 palIdx) +{ + sub_814FFC4(windowId, gSaveBlock2Ptr->optionsWindowFrameType, destOffset, palIdx); +} + +void DrawTextBorderOuter(u8 windowId, u16 tileNum, u8 palNum) +{ + u8 bgLayer = GetWindowAttribute(windowId, WINDOW_BG); + u16 tilemapLeft = GetWindowAttribute(windowId, WINDOW_TILEMAP_LEFT); + u16 tilemapTop = GetWindowAttribute(windowId, WINDOW_TILEMAP_TOP); + u16 width = GetWindowAttribute(windowId, WINDOW_WIDTH); + u16 height = GetWindowAttribute(windowId, WINDOW_HEIGHT); + + FillBgTilemapBufferRect(bgLayer, tileNum + 0, tilemapLeft - 1, tilemapTop - 1, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 1, tilemapLeft, tilemapTop - 1, width, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 2, tilemapLeft + width, tilemapTop - 1, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 3, tilemapLeft - 1, tilemapTop, 1, height, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 5, tilemapLeft + width, tilemapTop, 1, height, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 6, tilemapLeft - 1, tilemapTop + height, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 7, tilemapLeft, tilemapTop + height, width, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 8, tilemapLeft + width, tilemapTop + height, 1, 1, palNum); +} + +void DrawTextBorderInner(u8 windowId, u16 tileNum, u8 palNum) +{ + u8 bgLayer = GetWindowAttribute(windowId, WINDOW_BG); + u16 tilemapLeft = GetWindowAttribute(windowId, WINDOW_TILEMAP_LEFT); + u16 tilemapTop = GetWindowAttribute(windowId, WINDOW_TILEMAP_TOP); + u16 width = GetWindowAttribute(windowId, WINDOW_WIDTH); + u16 height = GetWindowAttribute(windowId, WINDOW_HEIGHT); + + FillBgTilemapBufferRect(bgLayer, tileNum + 0, tilemapLeft, tilemapTop, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 1, tilemapLeft + 1, tilemapTop, width - 2, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 2, tilemapLeft + width - 1, tilemapTop, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 3, tilemapLeft, tilemapTop + 1, 1, height - 2, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 5, tilemapLeft + width - 1, tilemapTop + 1, 1, height - 2, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 6, tilemapLeft, tilemapTop + height - 1, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 7, tilemapLeft + 1, tilemapTop + height - 1, width - 2, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 8, tilemapLeft + width - 1, tilemapTop + height - 1, 1, 1, palNum); +} + +void rbox_fill_rectangle(u8 windowId) +{ + u8 bgLayer = GetWindowAttribute(windowId, WINDOW_BG); + u16 tilemapLeft = GetWindowAttribute(windowId, WINDOW_TILEMAP_LEFT); + u16 tilemapTop = GetWindowAttribute(windowId, WINDOW_TILEMAP_TOP); + u16 width = GetWindowAttribute(windowId, WINDOW_WIDTH); + u16 height = GetWindowAttribute(windowId, WINDOW_HEIGHT); + + FillBgTilemapBufferRect(bgLayer, 0, tilemapLeft - 1, tilemapTop - 1, width + 2, height + 2, 0x11); +} + +const u16 *stdpal_get(u8 id) +{ + switch (id) + { + case 0: + id = 0; + break; + case 1: + id = 0x10; + break; + case 2: + id = 0x20; + break; + case 3: + id = 0x30; + break; + case 4: + default: + id = 0x40; + break; + } + + return (const u16 *)(gUnknown_8471DEC) + id; +} diff --git a/src/text_window_graphics.c b/src/text_window_graphics.c new file mode 100644 index 000000000..e16037a34 --- /dev/null +++ b/src/text_window_graphics.c @@ -0,0 +1,60 @@ +#include "global.h" +#include "text_window_graphics.h" + +const u16 gUnknown_8470B0C[] = INCBIN_U16("graphics/text_window/unk_8470B0C.4bpp"); + +static const u16 gUnknown_8470D6C[] = INCBIN_U16("graphics/text_window/unk_8470D6C.4bpp"); +static const u16 gUnknown_8470E8C[] = INCBIN_U16("graphics/text_window/unk_8470E8C.4bpp"); +static const u16 gUnk_Empty_Space_8470FAC[16] = {0}; +static const u16 gUnknown_8470FCC[] = INCBIN_U16("graphics/text_window/unk_8470FCC.4bpp"); +static const u16 gUnknown_84710EC[] = INCBIN_U16("graphics/text_window/unk_84710EC.4bpp"); +static const u16 gUnknown_847120C[] = INCBIN_U16("graphics/text_window/unk_847120C.4bpp"); +static const u16 gUnknown_847132C[] = INCBIN_U16("graphics/text_window/unk_847132C.4bpp"); +static const u16 gUnknown_847144C[] = INCBIN_U16("graphics/text_window/unk_847144C.4bpp"); +static const u16 gUnknown_847156C[] = INCBIN_U16("graphics/text_window/unk_847156C.4bpp"); +static const u16 gUnk_Empty_Space_847168C[16] = {0}; +static const u16 gUnknown_84716AC[] = INCBIN_U16("graphics/text_window/unk_84716AC.4bpp"); +static const u16 gUnknown_84717CC[] = INCBIN_U16("graphics/text_window/unk_84717CC.4bpp"); +static const u16 gUnk_Empty_Space_84718EC[16] = {0}; +static const u16 gUnknown_847190C[] = INCBIN_U16("graphics/text_window/unk_8470D6C.gbapal"); +static const u16 gUnknown_847192C[] = INCBIN_U16("graphics/text_window/unk_8470E8C.gbapal"); +static const u16 gUnknown_847194C[] = INCBIN_U16("graphics/text_window/unk_8470FCC.gbapal"); +static const u16 gUnknown_847196C[] = INCBIN_U16("graphics/text_window/unk_84710EC.gbapal"); +static const u16 gUnknown_847198C[] = INCBIN_U16("graphics/text_window/unk_847120C.gbapal"); +static const u16 gUnknown_84719AC[] = INCBIN_U16("graphics/text_window/unk_847132C.gbapal"); +static const u16 gUnknown_84719CC[] = INCBIN_U16("graphics/text_window/unk_847144C.gbapal"); +static const u16 gUnknown_84719EC[] = INCBIN_U16("graphics/text_window/unk_847156C.gbapal"); +static const u16 gUnknown_8471A0C[] = INCBIN_U16("graphics/text_window/unk_84716AC.gbapal"); +static const u16 gUnknown_8471A2C[] = INCBIN_U16("graphics/text_window/unk_84717CC.gbapal"); + +const u16 gStdFrame0[] = INCBIN_U16("graphics/text_window/unk_8471A4C.4bpp"); +const u16 gStdFrame1[] = INCBIN_U16("graphics/text_window/unk_8471B6C.4bpp"); + +const u16 gUnknown_8471DEC[][16] = { + INCBIN_U16("graphics/text_window/stdpal_0.gbapal"), + INCBIN_U16("graphics/text_window/stdpal_1.gbapal"), + INCBIN_U16("graphics/text_window/stdpal_2.gbapal"), + INCBIN_U16("graphics/text_window/stdpal_3.gbapal"), + INCBIN_U16("graphics/text_window/stdpal_4.gbapal") +}; + +const struct TextWindowGraphics gUserFrames[] = { + {gUnknown_8470D6C, gUnknown_847190C}, + {gUnknown_8470E8C, gUnknown_847192C}, + {gUnknown_8470FCC, gUnknown_847194C}, + {gUnknown_84710EC, gUnknown_847196C}, + {gUnknown_847120C, gUnknown_847198C}, + {gUnknown_847132C, gUnknown_84719AC}, + {gUnknown_847144C, gUnknown_84719CC}, + {gUnknown_847156C, gUnknown_84719EC}, + {gUnknown_84716AC, gUnknown_8471A0C}, + {gUnknown_84717CC, gUnknown_8471A2C} +}; // NELEMS = 10 + +const struct TextWindowGraphics * sub_8069788(u8 idx) +{ + if (idx >= 20) // if (idx >= NELEMS(gUserFrames)) + return &gUserFrames[0]; + else + return &gUserFrames[idx]; +} diff --git a/src/tm_case.c b/src/tm_case.c new file mode 100644 index 000000000..28aba57a0 --- /dev/null +++ b/src/tm_case.c @@ -0,0 +1,1537 @@ +#include "global.h" +#include "malloc.h" +#include "bg.h" +#include "decompress.h" +#include "gpu_regs.h" +#include "palette.h" +#include "graphics.h" +#include "task.h" +#include "text.h" +#include "text_window.h" +#include "menu.h" +#include "menu_helpers.h" +#include "new_menu_helpers.h" +#include "list_menu.h" +#include "item.h" +#include "item_menu.h" +#include "link.h" +#include "money.h" +#include "shop.h" +#include "teachy_tv.h" +#include "pokemon_storage_system.h" +#include "string_util.h" +#include "party_menu.h" +#include "data2.h" +#include "scanline_effect.h" +#include "sound.h" +#include "strings.h" +#include "tm_case.h" +#include "menu_indicators.h" +#include "constants/items.h" +#include "constants/songs.h" + +#define TM_CASE_TM_TAG 400 + +struct UnkStruct_203B10C +{ + void (* savedCallback)(void); + u8 tmCaseMenuType; + u8 unk_05; + u8 unk_06; + u16 selectedRow; + u16 scrollOffset; +}; + +struct UnkStruct_203B118 +{ + void (* savedCallback)(void); + u8 tmSpriteId; + u8 maxTMsShown; + u8 numTMs; + u8 contextMenuWindowId; + u8 scrollIndicatorArrowPairId; + u16 currItem; + const u8 * menuActionIndices; + u8 numMenuActions; + s16 seqId; + u8 filler_14[8]; +}; + +struct UnkStruct_203B11C +{ + struct ItemSlot bagPocket_TMHM[BAG_TMHM_COUNT]; + struct ItemSlot bagPocket_KeyItems[BAG_KEYITEMS_COUNT]; + u16 unk_160; + u16 unk_162; +}; + +static EWRAM_DATA struct UnkStruct_203B10C sTMCaseStaticResources = {}; +static EWRAM_DATA struct UnkStruct_203B118 * sTMCaseDynamicResources = NULL; +static EWRAM_DATA struct UnkStruct_203B11C * sPokeDudePackBackup = NULL; +static EWRAM_DATA void * sTilemapBuffer = NULL; // tilemap buffer +static EWRAM_DATA struct ListMenuItem * sListMenuItemsBuffer = NULL; +static EWRAM_DATA u8 (* sListMenuStringsBuffer)[29] = NULL; +static EWRAM_DATA u16 * sTMSpritePaletteBuffer = NULL; + +static void CB2_SetUpTMCaseUI_Blocking(void); +static bool8 DoSetUpTMCaseUI(void); +static void ResetBufferPointers_NoFree(void); +static void LoadBGTemplates(void); +static bool8 HandleLoadTMCaseGraphicsAndPalettes(void); +static void CreateTMCaseListMenuBuffers(void); +static void InitTMCaseListMenuItems(void); +static void GetTMNumberAndMoveString(u8 * dest, u16 itemId); +static void TMCase_MoveCursorFunc(s32 itemIndex, bool8 onInit, struct ListMenu *list); +static void TMCase_ItemPrintFunc(u8 windowId, s32 itemId, u8 y); +static void TMCase_MoveCursor_UpdatePrintedDescription(s32 itemIndex); +static void PrintListMenuCursorAt_WithColorIdx(u8 a0, u8 a1); +static void CreateTMCaseScrollIndicatorArrowPair_Main(void); +static void TMCaseSetup_GetTMCount(void); +static void TMCaseSetup_InitListMenuPositions(void); +static void TMCaseSetup_UpdateVisualMenuOffset(void); +static void Task_FadeOutAndCloseTMCase(u8 taskId); +static void Task_TMCaseMain(u8 taskId); +static void Task_SelectTMAction_FromFieldBag(u8 taskId); +static void Task_TMContextMenu_HandleInput(u8 taskId); +static void TMHMContextMenuAction_Use(u8 taskId); +static void TMHMContextMenuAction_Give(u8 taskId); +static void PrintError_ThereIsNoPokemon(u8 taskId); +static void PrintError_ItemCantBeHeld(u8 taskId); +static void Task_WaitButtonAfterErrorPrint(u8 taskId); +static void Subtask_CloseContextMenuAndReturnToMain(u8 taskId); +static void TMHMContextMenuAction_Exit(u8 taskId); +static void Task_SelectTMAction_Type1(u8 taskId); +static void Task_SelectTMAction_Type3(u8 taskId); +static void Task_SelectTMAction_FromSellMenu(u8 taskId); +static void Task_AskConfirmSaleWithAmount(u8 taskId); +static void Task_PlaceYesNoBox(u8 taskId); +static void Task_SaleOfTMsCancelled(u8 taskId); +static void Task_InitQuantitySelectUI(u8 taskId); +static void SellTM_PrintQuantityAndSalePrice(s16 quantity, s32 value); +static void Task_QuantitySelect_HandleInput(u8 taskId); +static void Task_PrintSaleConfirmedText(u8 taskId); +static void Task_DoSaleOfTMs(u8 taskId); +static void Task_AfterSale_ReturnToList(u8 taskId); +static void Task_TMCaseDude1(u8 taskId); +static void Task_TMCaseDude_Playback(u8 taskId); +static void InitWindowTemplatesAndPals(void); +static void AddTextPrinterParameterized_ColorByIndex(u8 windowId, u8 fontId, const u8 * str, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, u8 speed, u8 colorIdx); +static void TMCase_SetWindowBorder1(u8 windowId); +static void TMCase_SetWindowBorder2(u8 windowId); +static void TMCase_PrintMessageWithFollowupTask(u8 taskId, u8 windowId, const u8 * str, TaskFunc func); +static void PrintStringTMCaseOnWindow3(void); +static void DrawMoveInfoUIMarkers(void); +static void TMCase_MoveCursor_UpdatePrintedTMInfo(u16 itemId); +static void PlaceHMTileInWindow(u8 windowId, u8 x, u8 y); +static void HandlePrintMoneyOnHand(void); +static void HandleCreateYesNoMenu(u8 taskId, const struct YesNoFuncTable * ptrs); +static u8 AddTMContextMenu(u8 * a0, u8 a1); +static void RemoveTMContextMenu(u8 * a0); +static u8 CreateTMSprite(u16 itemId); +static void SetTMSpriteAnim(struct Sprite * sprite, u8 var); +static void TintTMSpriteByType(u8 type); +static void UpdateTMSpritePosition(struct Sprite * sprite, u8 var); +static void InitSelectedTMSpriteData(u8 a0, u16 itemId); +static void SpriteCB_MoveTMSpriteInCase(struct Sprite * sprite); +static void LoadTMTypePalettes(void); + +static const struct BgTemplate sBGTemplates[] = { + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0x000 + }, { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0x000 + }, { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 29, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0x000 + } +}; + +static void (*const sSelectTMActionTasks[])(u8 taskId) = { + Task_SelectTMAction_FromFieldBag, + Task_SelectTMAction_Type1, + Task_SelectTMAction_FromSellMenu, + Task_SelectTMAction_Type3 +}; + +static const struct MenuAction sMenuActions_UseGiveExit[] = { + {gOtherText_Use, TMHMContextMenuAction_Use }, + {gOtherText_Give, TMHMContextMenuAction_Give}, + {gOtherText_Exit, TMHMContextMenuAction_Exit}, +}; + +static const u8 sMenuActionIndices_Field[] = {0, 1, 2}; +static const u8 sMenuActionIndices_UnionRoom[] = {1, 2}; +static const struct YesNoFuncTable sYesNoFuncTable = {Task_PrintSaleConfirmedText, Task_SaleOfTMsCancelled}; + +static const u8 sText_ClearTo18[] = _("{CLEAR_TO 18}"); +static const u8 sText_SingleSpace[] = _(" "); + +static ALIGNED(4) const u16 sPal3Override[] = {RGB(8, 8, 8), RGB(30, 16, 6)}; + +static const struct TextColor sTextColors[] = { + {0, 1, 2}, + {0, 2, 3}, + {0, 3, 6}, + {0, 14, 10} +}; + +static const struct WindowTemplate sWindowTemplates[] = { + {0x00, 0x0a, 0x01, 0x13, 0x0a, 0x0f, 0x0081}, + {0x00, 0x0c, 0x0c, 0x12, 0x08, 0x0a, 0x013f}, + {0x01, 0x05, 0x0f, 0x0f, 0x04, 0x0d, 0x01f9}, + {0x00, 0x00, 0x01, 0x0a, 0x02, 0x0f, 0x0235}, + {0x00, 0x01, 0x0d, 0x05, 0x06, 0x0c, 0x0249}, + {0x00, 0x07, 0x0d, 0x05, 0x06, 0x0c, 0x0267}, + {0x01, 0x02, 0x0f, 0x1a, 0x04, 0x0b, 0x0285}, + {0x01, 0x11, 0x09, 0x0c, 0x04, 0x0f, 0x02ed}, + {0x01, 0x01, 0x01, 0x08, 0x03, 0x0d, 0x031d}, + DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate sYesNoWindowTemplate = {0x01, 0x15, 0x09, 0x06, 0x04, 0x0f, 0x0335}; + +static const struct WindowTemplate sTMContextWindowTemplates[] = { + {0x01, 0x16, 0x0d, 0x07, 0x06, 0x0f, 0x01cf}, + {0x01, 0x16, 0x0f, 0x07, 0x04, 0x0f, 0x01cf} +}; + +static const struct OamData sTMSpriteOamData = { + .size = 2, + .priority = 2 +}; + +static const union AnimCmd sTMSpriteAnim0[] = { + ANIMCMD_FRAME(0, 0), + ANIMCMD_END +}; + +static const union AnimCmd sTMSpriteAnim1[] = { + ANIMCMD_FRAME(16, 0), + ANIMCMD_END +}; + +static const union AnimCmd *const sTMSpriteAnims[] = { + sTMSpriteAnim0, + sTMSpriteAnim1 +}; + +static const struct CompressedSpriteSheet sTMSpriteSheet = { + (const void *)gTMCase_TMSpriteGfx, + 0x400, + TM_CASE_TM_TAG +}; + +static const struct SpriteTemplate sTMSpriteTemplate = { + TM_CASE_TM_TAG, + TM_CASE_TM_TAG, + &sTMSpriteOamData, + sTMSpriteAnims, + NULL, + gDummySpriteAffineAnimTable, + SpriteCallbackDummy +}; + +static const u16 sTMSpritePaletteOffsetByType[] = { + [TYPE_NORMAL] = 0x000, + [TYPE_FIRE] = 0x010, + [TYPE_WATER] = 0x020, + [TYPE_GRASS] = 0x030, + [TYPE_ELECTRIC] = 0x040, + [TYPE_ROCK] = 0x050, + [TYPE_GROUND] = 0x060, + [TYPE_ICE] = 0x070, + [TYPE_FLYING] = 0x080, + [TYPE_FIGHTING] = 0x090, + [TYPE_GHOST] = 0x0a0, + [TYPE_BUG] = 0x0b0, + [TYPE_POISON] = 0x0c0, + [TYPE_PSYCHIC] = 0x0d0, + [TYPE_STEEL] = 0x0e0, + [TYPE_DARK] = 0x0f0, + [TYPE_DRAGON] = 0x100 +}; + +void InitTMCase(u8 type, void (* callback)(void), u8 a2) +{ + ResetBufferPointers_NoFree(); + sTMCaseDynamicResources = Alloc(sizeof(struct UnkStruct_203B118)); + sTMCaseDynamicResources->savedCallback = 0; + sTMCaseDynamicResources->scrollIndicatorArrowPairId = 0xFF; + sTMCaseDynamicResources->contextMenuWindowId = 0xFF; + if (type != 5) + sTMCaseStaticResources.tmCaseMenuType = type; + if (callback != NULL) + sTMCaseStaticResources.savedCallback = callback; + if (a2 != 0xFF) + sTMCaseStaticResources.unk_05 = a2; + gTextFlags.autoScroll = FALSE; + SetMainCallback2(CB2_SetUpTMCaseUI_Blocking); +} + +static void CB2_Idle(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +static void VBlankCB_Idle(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void CB2_SetUpTMCaseUI_Blocking(void) +{ + while (1) + { + if (sub_80BF72C() == TRUE) + break; + if (DoSetUpTMCaseUI() == TRUE) + break; + if (MenuHelpers_LinkSomething() == TRUE) + break; + } +} + +static bool8 DoSetUpTMCaseUI(void) +{ + u8 taskId; + + switch (gMain.state) + { + case 0: + VblankHblankHandlerSetZero(); + clear_scheduled_bg_copies_to_vram(); + gMain.state++; + break; + case 1: + ScanlineEffect_Stop(); + gMain.state++; + break; + case 2: + FreeAllSpritePalettes(); + gMain.state++; + break; + case 3: + ResetPaletteFade(); + gMain.state++; + break; + case 4: + ResetSpriteData(); + gMain.state++; + break; + case 5: + ResetTasks(); + gMain.state++; + break; + case 6: + LoadBGTemplates(); + sTMCaseDynamicResources->seqId = 0; + gMain.state++; + break; + case 7: + InitWindowTemplatesAndPals(); + gMain.state++; + break; + case 8: + if (HandleLoadTMCaseGraphicsAndPalettes()) + gMain.state++; + break; + case 9: + SortPocketAndPlaceHMsFirst(&gBagPockets[POCKET_TM_CASE - 1]); + gMain.state++; + break; + case 10: + TMCaseSetup_GetTMCount(); + TMCaseSetup_InitListMenuPositions(); + TMCaseSetup_UpdateVisualMenuOffset(); + gMain.state++; + break; + case 11: + DrawMoveInfoUIMarkers(); + gMain.state++; + break; + case 12: + CreateTMCaseListMenuBuffers(); + InitTMCaseListMenuItems(); + gMain.state++; + break; + case 13: + PrintStringTMCaseOnWindow3(); + gMain.state++; + break; + case 14: + if (sTMCaseStaticResources.tmCaseMenuType == 4) + taskId = CreateTask(Task_TMCaseDude1, 0); + else + taskId = CreateTask(Task_TMCaseMain, 0); + gTasks[taskId].data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sTMCaseStaticResources.scrollOffset, sTMCaseStaticResources.selectedRow); + gMain.state++; + break; + case 15: + CreateTMCaseScrollIndicatorArrowPair_Main(); + gMain.state++; + break; + case 16: + sTMCaseDynamicResources->tmSpriteId = CreateTMSprite(BagGetItemIdByPocketPosition(POCKET_TM_CASE, sTMCaseStaticResources.scrollOffset + sTMCaseStaticResources.selectedRow)); + gMain.state++; + break; + case 17: + BlendPalettes(0xFFFFFFFF, 16, 0); + gMain.state++; + break; + case 18: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB_BLACK); + gMain.state++; + break; + default: + SetVBlankCallback(VBlankCB_Idle); + SetMainCallback2(CB2_Idle); + return TRUE; + } + + return FALSE; +} + +static void ResetBufferPointers_NoFree(void) +{ + sTMCaseDynamicResources = NULL; + sTilemapBuffer = NULL; + sListMenuItemsBuffer = NULL; + sListMenuStringsBuffer = NULL; + sTMSpritePaletteBuffer = NULL; +} + +static void LoadBGTemplates(void) +{ + void ** ptr; + InitBgReg(); + ptr = &sTilemapBuffer; + *ptr = AllocZeroed(0x800); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBGTemplates, NELEMS(sBGTemplates)); + SetBgTilemapBuffer(2, *ptr); + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + ShowBg(0); + ShowBg(1); + ShowBg(2); +} + +static bool8 HandleLoadTMCaseGraphicsAndPalettes(void) +{ + switch (sTMCaseDynamicResources->seqId) + { + case 0: + reset_temp_tile_data_buffers(); + decompress_and_copy_tile_data_to_vram(1, gUnknown_8E845D8, 0, 0, 0); + sTMCaseDynamicResources->seqId++; + break; + case 1: + if (free_temp_tile_data_buffers_if_possible() != TRUE) + { + LZDecompressWram(gUnknown_8E84A24, sTilemapBuffer); + sTMCaseDynamicResources->seqId++; + } + break; + case 2: + LZDecompressWram(gUnknown_8E84B70, GetBgTilemapBuffer(1)); + sTMCaseDynamicResources->seqId++; + break; + case 3: + if (gSaveBlock2Ptr->playerGender == MALE) + LoadCompressedPalette(gUnknown_8E84CB0, 0, 0x80); + else + LoadCompressedPalette(gUnknown_8E84D20, 0, 0x80); + sTMCaseDynamicResources->seqId++; + break; + case 4: + LoadCompressedObjectPic(&sTMSpriteSheet); + sTMCaseDynamicResources->seqId++; + break; + default: + LoadTMTypePalettes(); + sTMCaseDynamicResources->seqId = 0; + return TRUE; + } + + return FALSE; +} + +static void CreateTMCaseListMenuBuffers(void) +{ + struct BagPocket * pocket = &gBagPockets[POCKET_TM_CASE - 1]; + sListMenuItemsBuffer = Alloc((pocket->capacity + 1) * sizeof(struct ListMenuItem)); + sListMenuStringsBuffer = Alloc(sTMCaseDynamicResources->numTMs * 29); +} + +static void InitTMCaseListMenuItems(void) +{ + struct BagPocket * pocket = &gBagPockets[POCKET_TM_CASE - 1]; + u16 i; + + for (i = 0; i < sTMCaseDynamicResources->numTMs; i++) + { + GetTMNumberAndMoveString(sListMenuStringsBuffer[i], pocket->itemSlots[i].itemId); + sListMenuItemsBuffer[i].label = sListMenuStringsBuffer[i]; + sListMenuItemsBuffer[i].index = i; + } + sListMenuItemsBuffer[i].label = gText_Close; + sListMenuItemsBuffer[i].index = -2; + gMultiuseListMenuTemplate.items = sListMenuItemsBuffer; + gMultiuseListMenuTemplate.totalItems = sTMCaseDynamicResources->numTMs + 1; + gMultiuseListMenuTemplate.windowId = 0; + gMultiuseListMenuTemplate.header_X = 0; + gMultiuseListMenuTemplate.item_X = 8; + gMultiuseListMenuTemplate.cursor_X = 0; + gMultiuseListMenuTemplate.lettersSpacing = 0; + gMultiuseListMenuTemplate.itemVerticalPadding = 2; + gMultiuseListMenuTemplate.upText_Y = 2; + gMultiuseListMenuTemplate.maxShowed = sTMCaseDynamicResources->maxTMsShown; + gMultiuseListMenuTemplate.fontId = 2; + gMultiuseListMenuTemplate.cursorPal = 2; + gMultiuseListMenuTemplate.fillValue = 0; + gMultiuseListMenuTemplate.cursorShadowPal = 3; + gMultiuseListMenuTemplate.moveCursorFunc = TMCase_MoveCursorFunc; + gMultiuseListMenuTemplate.itemPrintFunc = TMCase_ItemPrintFunc; + gMultiuseListMenuTemplate.cursorKind = 0; + gMultiuseListMenuTemplate.scrollMultiple = 0; +} + +static void GetTMNumberAndMoveString(u8 * dest, u16 itemId) +{ + StringCopy(gStringVar4, gText_FontSize0); + if (itemId >= ITEM_HM01) + { + StringAppend(gStringVar4, sText_ClearTo18); + StringAppend(gStringVar4, gOtherText_UnkF9_08_Clear_01); + ConvertIntToDecimalStringN(gStringVar1, itemId - ITEM_HM01 + 1, STR_CONV_MODE_LEADING_ZEROS, 1); + StringAppend(gStringVar4, gStringVar1); + } + else + { + StringAppend(gStringVar4, gOtherText_UnkF9_08_Clear_01); + ConvertIntToDecimalStringN(gStringVar1, itemId - ITEM_TM01 + 1, STR_CONV_MODE_LEADING_ZEROS, 2); + StringAppend(gStringVar4, gStringVar1); + } + StringAppend(gStringVar4, sText_SingleSpace); + StringAppend(gStringVar4, gText_FontSize2); + StringAppend(gStringVar4, gMoveNames[ItemIdToBattleMoveId(itemId)]); + StringCopy(dest, gStringVar4); +} + +static void TMCase_MoveCursorFunc(s32 itemIndex, bool8 onInit, struct ListMenu *list) +{ + u16 itemId; + + if (itemIndex == -2) + itemId = 0; + else + itemId = BagGetItemIdByPocketPosition(POCKET_TM_CASE, itemIndex); + + if (onInit != TRUE) + { + PlaySE(SE_SELECT); + InitSelectedTMSpriteData(sTMCaseDynamicResources->tmSpriteId, itemId); + } + TMCase_MoveCursor_UpdatePrintedDescription(itemIndex); + TMCase_MoveCursor_UpdatePrintedTMInfo(itemId); +} + +static void TMCase_ItemPrintFunc(u8 windowId, s32 itemId, u8 y) +{ + if (itemId != -2) + { + if (!itemid_is_unique(BagGetItemIdByPocketPosition(POCKET_TM_CASE, itemId))) + { + ConvertIntToDecimalStringN(gStringVar1, BagGetQuantityByPocketPosition(POCKET_TM_CASE, itemId), STR_CONV_MODE_RIGHT_ALIGN, 3); + StringExpandPlaceholders(gStringVar4, gText_TimesStrVar1); + AddTextPrinterParameterized_ColorByIndex(windowId, 0, gStringVar4, 0x7E, y, 0, 0, 0xFF, 1); + } + else + { + PlaceHMTileInWindow(windowId, 8, y); + } + } +} + +static void TMCase_MoveCursor_UpdatePrintedDescription(s32 itemIndex) +{ + const u8 * str; + if (itemIndex != -2) + { + str = ItemId_GetDescription(BagGetItemIdByPocketPosition(POCKET_TM_CASE, itemIndex)); + } + else + { + str = gText_TMCaseWillBePutAway; + } + FillWindowPixelBuffer(1, 0); + AddTextPrinterParameterized_ColorByIndex(1, 2, str, 2, 3, 1, 0, 0, 0); +} + +static void FillBG2RowWithPalette_2timesNplus1(s32 a0) +{ + SetBgRectPal(2, 0, 12, 30, 8, 2 * a0 + 1); + schedule_bg_copy_tilemap_to_vram(2); +} + +static void PrintListMenuCursorByID_WithColorIdx(u8 a0, u8 a1) +{ + PrintListMenuCursorAt_WithColorIdx(ListMenuGetYCoordForPrintingArrowCursor(a0), a1); +} + +static void PrintListMenuCursorAt_WithColorIdx(u8 a0, u8 a1) +{ + if (a1 == 0xFF) + { + FillWindowPixelRect(0, 0, 0, a0, GetFontAttribute(2, 0), GetFontAttribute(2, 1)); + CopyWindowToVram(0, 2); + } + else + { + AddTextPrinterParameterized_ColorByIndex(0, 2, gFameCheckerText_ListMenuCursor, 0, a0, 0, 0, 0, a1); + } +} + +static void CreateTMCaseScrollIndicatorArrowPair_Main(void) +{ + sTMCaseDynamicResources->scrollIndicatorArrowPairId = AddScrollIndicatorArrowPairParameterized(2, 0xA0, 0x08, 0x58, sTMCaseDynamicResources->numTMs - sTMCaseDynamicResources->maxTMsShown + 1, 0x6E, 0x6E, &sTMCaseStaticResources.scrollOffset); +} + +static void CreateTMCaseScrollIndicatorArrowPair_SellQuantitySelect(void) +{ + sTMCaseDynamicResources->currItem = 1; + sTMCaseDynamicResources->scrollIndicatorArrowPairId = AddScrollIndicatorArrowPairParameterized(2, 0x98, 0x48, 0x68, 2, 0x6E, 0x6E, &sTMCaseDynamicResources->currItem); +} + +static void RemoveTMCaseScrollIndicatorArrowPair(void) +{ + if (sTMCaseDynamicResources->scrollIndicatorArrowPairId != 0xFF) + { + RemoveScrollIndicatorArrowPair(sTMCaseDynamicResources->scrollIndicatorArrowPairId); + sTMCaseDynamicResources->scrollIndicatorArrowPairId = 0xFF; + } +} + +void ResetTMCaseCursorPos(void) +{ + sTMCaseStaticResources.selectedRow = 0; + sTMCaseStaticResources.scrollOffset = 0; +} + +static void TMCaseSetup_GetTMCount(void) +{ + struct BagPocket * pocket = &gBagPockets[POCKET_TM_CASE - 1]; + u16 i; + + BagPocketCompaction(pocket->itemSlots, pocket->capacity); + sTMCaseDynamicResources->numTMs = 0; + for (i = 0; i < pocket->capacity; i++) + { + if (pocket->itemSlots[i].itemId == ITEM_NONE) + break; + sTMCaseDynamicResources->numTMs++; + } + sTMCaseDynamicResources->maxTMsShown = min(sTMCaseDynamicResources->numTMs + 1, 5); +} + +static void TMCaseSetup_InitListMenuPositions(void) +{ + if (sTMCaseStaticResources.scrollOffset != 0) + { + if (sTMCaseStaticResources.scrollOffset + sTMCaseDynamicResources->maxTMsShown > sTMCaseDynamicResources->numTMs + 1) + sTMCaseStaticResources.scrollOffset = sTMCaseDynamicResources->numTMs + 1 - sTMCaseDynamicResources->maxTMsShown; + } + if (sTMCaseStaticResources.scrollOffset + sTMCaseStaticResources.selectedRow >= sTMCaseDynamicResources->numTMs + 1) + { + if (sTMCaseDynamicResources->numTMs + 1 < 2) + sTMCaseStaticResources.selectedRow = 0; + else + sTMCaseStaticResources.selectedRow = sTMCaseDynamicResources->numTMs; + } +} + +static void TMCaseSetup_UpdateVisualMenuOffset(void) +{ + u8 i; + if (sTMCaseStaticResources.selectedRow > 3) + { + for (i = 0; i <= sTMCaseStaticResources.selectedRow - 3 && sTMCaseStaticResources.scrollOffset + sTMCaseDynamicResources->maxTMsShown != sTMCaseDynamicResources->numTMs + 1; i++) + { + do {} while (0); + sTMCaseStaticResources.selectedRow--; + sTMCaseStaticResources.scrollOffset++; + } + } +} + +static void DestroyTMCaseBuffers(void) +{ + if (sTMCaseDynamicResources != NULL) + Free(sTMCaseDynamicResources); + if (sTilemapBuffer != NULL) + Free(sTilemapBuffer); + if (sListMenuItemsBuffer != NULL) + Free(sListMenuItemsBuffer); + if (sListMenuStringsBuffer != NULL) + Free(sListMenuStringsBuffer); + if (sTMSpritePaletteBuffer != NULL) + Free(sTMSpritePaletteBuffer); + FreeAllWindowBuffers(); +} + +static void Task_BeginFadeOutFromTMCase(u8 taskId) +{ + BeginNormalPaletteFade(0xFFFFFFFF, -2, 0, 16, RGB_BLACK); + gTasks[taskId].func = Task_FadeOutAndCloseTMCase; +} + +static void Task_FadeOutAndCloseTMCase(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!gPaletteFade.active) + { + DestroyListMenu(data[0], &sTMCaseStaticResources.scrollOffset, &sTMCaseStaticResources.selectedRow); + if (sTMCaseDynamicResources->savedCallback != NULL) + SetMainCallback2(sTMCaseDynamicResources->savedCallback); + else + SetMainCallback2(sTMCaseStaticResources.savedCallback); + RemoveTMCaseScrollIndicatorArrowPair(); + DestroyTMCaseBuffers(); + DestroyTask(taskId); + } +} + +static void Task_TMCaseMain(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + s32 input; + + if (!gPaletteFade.active) + { + if (sub_80BF72C() != TRUE) + { + input = ListMenuHandleInput(data[0]); + ListMenuGetScrollAndRow(data[0], &sTMCaseStaticResources.scrollOffset, &sTMCaseStaticResources.selectedRow); + if (JOY_NEW(SELECT_BUTTON) && sTMCaseStaticResources.unk_05 == 1) + { + PlaySE(SE_SELECT); + gSpecialVar_ItemId = ITEM_NONE; + Task_BeginFadeOutFromTMCase(taskId); + } + else + { + switch (input) + { + case -1: + break; + case -2: + PlaySE(SE_SELECT); + gSpecialVar_ItemId = 0; + Task_BeginFadeOutFromTMCase(taskId); + break; + default: + PlaySE(SE_SELECT); + FillBG2RowWithPalette_2timesNplus1(1); + RemoveTMCaseScrollIndicatorArrowPair(); + PrintListMenuCursorByID_WithColorIdx(data[0], 2); + data[1] = input; + data[2] = BagGetQuantityByPocketPosition(POCKET_TM_CASE, input); + gSpecialVar_ItemId = BagGetItemIdByPocketPosition(POCKET_TM_CASE, input); + gTasks[taskId].func = sSelectTMActionTasks[sTMCaseStaticResources.tmCaseMenuType]; + break; + } + } + } + } +} + +static void Subtask_ReturnToTMCaseMain(u8 taskId) +{ + FillBG2RowWithPalette_2timesNplus1(0); + CreateTMCaseScrollIndicatorArrowPair_Main(); + gTasks[taskId].func = Task_TMCaseMain; +} + +static void Task_SelectTMAction_FromFieldBag(u8 taskId) +{ + u8 * strbuf; + TMCase_SetWindowBorder2(2); + if (!MenuHelpers_LinkSomething() && InUnionRoom() != TRUE) + { + AddTMContextMenu(&sTMCaseDynamicResources->contextMenuWindowId, 0); + sTMCaseDynamicResources->menuActionIndices = sMenuActionIndices_Field; + sTMCaseDynamicResources->numMenuActions = NELEMS(sMenuActionIndices_Field); + } + else + { + AddTMContextMenu(&sTMCaseDynamicResources->contextMenuWindowId, 1); + sTMCaseDynamicResources->menuActionIndices = sMenuActionIndices_UnionRoom; + sTMCaseDynamicResources->numMenuActions = NELEMS(sMenuActionIndices_UnionRoom); + } + AddItemMenuActionTextPrinters(sTMCaseDynamicResources->contextMenuWindowId, 2, GetMenuCursorDimensionByFont(2, 0), 2, 0, GetFontAttribute(2, 1) + 2, sTMCaseDynamicResources->numMenuActions, sMenuActions_UseGiveExit, sTMCaseDynamicResources->menuActionIndices); + ProgramAndPlaceMenuCursorOnWindow(sTMCaseDynamicResources->contextMenuWindowId, 2, 0, 2, GetFontAttribute(2, 1) + 2, sTMCaseDynamicResources->numMenuActions, 0); + strbuf = Alloc(256); + GetTMNumberAndMoveString(strbuf, gSpecialVar_ItemId); + StringAppend(strbuf, gText_IsSelected); + AddTextPrinterParameterized_ColorByIndex(2, 2, strbuf, 0, 2, 1, 0, 0, 1); + Free(strbuf); + if (itemid_is_unique(gSpecialVar_ItemId)) + { + PlaceHMTileInWindow(2, 0, 2); + CopyWindowToVram(2, 2); + } + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + gTasks[taskId].func = Task_TMContextMenu_HandleInput; +} + +static void Task_TMContextMenu_HandleInput(u8 taskId) +{ + s8 input; + + if (sub_80BF72C() != TRUE) + { + input = ProcessMenuInputNoWrapAround(); + switch (input) + { + case -1: + PlaySE(SE_SELECT); + sMenuActions_UseGiveExit[sTMCaseDynamicResources->menuActionIndices[sTMCaseDynamicResources->numMenuActions - 1]].func.void_u8(taskId); + break; + case -2: + break; + default: + PlaySE(SE_SELECT); + sMenuActions_UseGiveExit[sTMCaseDynamicResources->menuActionIndices[input]].func.void_u8(taskId); + break; + } + } +} + +static void TMHMContextMenuAction_Use(u8 taskId) +{ + RemoveTMContextMenu(&sTMCaseDynamicResources->contextMenuWindowId); + ClearMenuWindow(2, 0); + ClearWindowTilemap(2); + PutWindowTilemap(0); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + if (CalculatePlayerPartyCount() == 0) + { + PrintError_ThereIsNoPokemon(taskId); + } + else + { + gUnknown_3005E98 = sub_8125B40; + sTMCaseDynamicResources->savedCallback = sub_8124C8C; + Task_BeginFadeOutFromTMCase(taskId); + } +} + +static void TMHMContextMenuAction_Give(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + u16 itemId = BagGetItemIdByPocketPosition(POCKET_TM_CASE, data[1]); + RemoveTMContextMenu(&sTMCaseDynamicResources->contextMenuWindowId); + ClearMenuWindow(2, 0); + ClearWindowTilemap(2); + PutWindowTilemap(1); + PutWindowTilemap(4); + PutWindowTilemap(5); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + if (!itemid_is_unique(itemId)) + { + if (CalculatePlayerPartyCount() == 0) + { + PrintError_ThereIsNoPokemon(taskId); + } + else + { + sTMCaseDynamicResources->savedCallback = sub_8126EDC; + Task_BeginFadeOutFromTMCase(taskId); + } + } + else + { + PrintError_ItemCantBeHeld(taskId); + } +} + +static void PrintError_ThereIsNoPokemon(u8 taskId) +{ + TMCase_PrintMessageWithFollowupTask(taskId, 2, gText_ThereIsNoPokemon, Task_WaitButtonAfterErrorPrint); +} + +static void PrintError_ItemCantBeHeld(u8 taskId) +{ + CopyItemName(gSpecialVar_ItemId, gStringVar1); + StringExpandPlaceholders(gStringVar4, gText_ItemCantBeHeld); + TMCase_PrintMessageWithFollowupTask(taskId, 2, gStringVar4, Task_WaitButtonAfterErrorPrint); +} + +static void Task_WaitButtonAfterErrorPrint(u8 taskId) +{ + if (JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + Subtask_CloseContextMenuAndReturnToMain(taskId); + } +} + +static void Subtask_CloseContextMenuAndReturnToMain(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + DestroyListMenu(data[0], &sTMCaseStaticResources.scrollOffset, &sTMCaseStaticResources.selectedRow); + data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sTMCaseStaticResources.scrollOffset, sTMCaseStaticResources.selectedRow); + PrintListMenuCursorByID_WithColorIdx(data[0], 1); + ClearMenuWindow_BorderThickness2(6, 0); + ClearWindowTilemap(6); + PutWindowTilemap(1); + PutWindowTilemap(4); + PutWindowTilemap(5); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + Subtask_ReturnToTMCaseMain(taskId); +} + +static void TMHMContextMenuAction_Exit(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + RemoveTMContextMenu(&sTMCaseDynamicResources->contextMenuWindowId); + ClearMenuWindow(2, 0); + ClearWindowTilemap(2); + PutWindowTilemap(0); + PrintListMenuCursorByID_WithColorIdx(data[0], 1); + PutWindowTilemap(1); + PutWindowTilemap(4); + PutWindowTilemap(5); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + Subtask_ReturnToTMCaseMain(taskId); +} + +static void Task_SelectTMAction_Type1(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!itemid_is_unique(BagGetItemIdByPocketPosition(POCKET_TM_CASE, data[1]))) + { + sTMCaseDynamicResources->savedCallback = c2_8123744; + Task_BeginFadeOutFromTMCase(taskId); + } + else + { + PrintError_ItemCantBeHeld(taskId); + } +} + +static void Task_SelectTMAction_Type3(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!itemid_is_unique(BagGetItemIdByPocketPosition(POCKET_TM_CASE, data[1]))) + { + sTMCaseDynamicResources->savedCallback = sub_808CE60; + Task_BeginFadeOutFromTMCase(taskId); + } + else + { + PrintError_ItemCantBeHeld(taskId); + } +} + +static void Task_SelectTMAction_FromSellMenu(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (itemid_get_market_price(gSpecialVar_ItemId) == 0) + { + CopyItemName(gSpecialVar_ItemId, gStringVar1); + StringExpandPlaceholders(gStringVar4, gText_OhNoICantBuyThat); + TMCase_PrintMessageWithFollowupTask(taskId, sub_80BF8E4(), gStringVar4, Subtask_CloseContextMenuAndReturnToMain); + } + else + { + data[8] = 1; + if (data[2] == 1) + { + HandlePrintMoneyOnHand(); + Task_AskConfirmSaleWithAmount(taskId); + } + else + { + if (data[2] > 99) + data[2] = 99; + CopyItemName(gSpecialVar_ItemId, gStringVar1); + StringExpandPlaceholders(gStringVar4, gText_HowManyWouldYouLikeToSell); + TMCase_PrintMessageWithFollowupTask(taskId, sub_80BF8E4(), gStringVar4, Task_InitQuantitySelectUI); + } + } +} + +static void Task_AskConfirmSaleWithAmount(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + ConvertIntToDecimalStringN(gStringVar3, itemid_get_market_price(BagGetItemIdByPocketPosition(POCKET_TM_CASE, data[1])) / 2 * data[8], STR_CONV_MODE_LEFT_ALIGN, 6); + StringExpandPlaceholders(gStringVar4, gText_ICanPayThisMuch_WouldThatBeOkay); + TMCase_PrintMessageWithFollowupTask(taskId, sub_80BF8E4(), gStringVar4, Task_PlaceYesNoBox); +} + +static void Task_PlaceYesNoBox(u8 taskId) +{ + HandleCreateYesNoMenu(taskId, &sYesNoFuncTable); +} + +static void Task_SaleOfTMsCancelled(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + ClearMenuWindow(8, 0); + ClearMenuWindow_BorderThickness2(6, 0); + PutWindowTilemap(0); + PutWindowTilemap(1); + PutWindowTilemap(3); + PutWindowTilemap(4); + PutWindowTilemap(5); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + PrintListMenuCursorByID_WithColorIdx(data[0], 1); + Subtask_ReturnToTMCaseMain(taskId); +} + +static void Task_InitQuantitySelectUI(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + TMCase_SetWindowBorder1(7); + ConvertIntToDecimalStringN(gStringVar1, 1, STR_CONV_MODE_LEADING_ZEROS, 2); + StringExpandPlaceholders(gStringVar4, gText_TimesStrVar1); + AddTextPrinterParameterized_ColorByIndex(7, 0, gStringVar4, 4, 10, 1, 0, 0, 1); + SellTM_PrintQuantityAndSalePrice(1, itemid_get_market_price(BagGetItemIdByPocketPosition(POCKET_TM_CASE, data[1])) / 2 * data[8]); + HandlePrintMoneyOnHand(); + CreateTMCaseScrollIndicatorArrowPair_SellQuantitySelect(); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + gTasks[taskId].func = Task_QuantitySelect_HandleInput; +} + +static void SellTM_PrintQuantityAndSalePrice(s16 quantity, s32 amount) +{ + FillWindowPixelBuffer(7, 0x11); + ConvertIntToDecimalStringN(gStringVar1, quantity, STR_CONV_MODE_LEADING_ZEROS, 2); + StringExpandPlaceholders(gStringVar4, gText_TimesStrVar1); + AddTextPrinterParameterized_ColorByIndex(7, 0, gStringVar4, 4, 10, 1, 0, 0, 1); + PrintMoneyAmount(7, 0x38, 0x0A, amount, 0); +} + +static void Task_QuantitySelect_HandleInput(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (sub_80BF848(&data[8], data[2]) == 1) + { + SellTM_PrintQuantityAndSalePrice(data[8], itemid_get_market_price(BagGetItemIdByPocketPosition(POCKET_TM_CASE, data[1])) / 2 * data[8]); + } + else if (JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + ClearMenuWindow(7, 0); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + RemoveTMCaseScrollIndicatorArrowPair(); + Task_AskConfirmSaleWithAmount(taskId); + } + else if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + ClearMenuWindow(7, 0); + ClearMenuWindow(8, 0); + ClearMenuWindow_BorderThickness2(6, 0); + PutWindowTilemap(3); + PutWindowTilemap(0); + PutWindowTilemap(1); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + RemoveTMCaseScrollIndicatorArrowPair(); + PrintListMenuCursorByID_WithColorIdx(data[0], 1); + Subtask_ReturnToTMCaseMain(taskId); + } +} + +static void Task_PrintSaleConfirmedText(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + PutWindowTilemap(0); + schedule_bg_copy_tilemap_to_vram(0); + CopyItemName(gSpecialVar_ItemId, gStringVar1); + ConvertIntToDecimalStringN(gStringVar3, itemid_get_market_price(BagGetItemIdByPocketPosition(POCKET_TM_CASE, data[1])) / 2 * data[8], STR_CONV_MODE_LEFT_ALIGN, 6); + StringExpandPlaceholders(gStringVar4, gText_TurnedOverItemsWorthYen); + TMCase_PrintMessageWithFollowupTask(taskId, 2, gStringVar4, Task_DoSaleOfTMs); +} + +static void Task_DoSaleOfTMs(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + PlaySE(0xF8); + RemoveBagItem(gSpecialVar_ItemId, data[8]); + AddMoney(&gSaveBlock1Ptr->money, itemid_get_market_price(gSpecialVar_ItemId) / 2 * data[8]); + sub_809C09C(gSpecialVar_ItemId, data[8], 2); + DestroyListMenu(data[0], &sTMCaseStaticResources.scrollOffset, &sTMCaseStaticResources.selectedRow); + TMCaseSetup_GetTMCount(); + TMCaseSetup_InitListMenuPositions(); + InitTMCaseListMenuItems(); + data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sTMCaseStaticResources.scrollOffset, sTMCaseStaticResources.selectedRow); + PrintListMenuCursorByID_WithColorIdx(data[0], 2); + PrintMoneyAmountInMoneyBox(8, GetMoney(&gSaveBlock1Ptr->money), 0); + gTasks[taskId].func = Task_AfterSale_ReturnToList; +} + +static void Task_AfterSale_ReturnToList(u8 taskId) +{ + if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + ClearMenuWindow(8, 0); + ClearMenuWindow_BorderThickness2(6, 0); + PutWindowTilemap(1); + PutWindowTilemap(3); + PutWindowTilemap(4); + PutWindowTilemap(5); + Subtask_CloseContextMenuAndReturnToMain(taskId); + } +} + +void PokeDude_InitTMCase(void) +{ + sPokeDudePackBackup = AllocZeroed(sizeof(*sPokeDudePackBackup)); + memcpy(sPokeDudePackBackup->bagPocket_TMHM, gSaveBlock1Ptr->bagPocket_TMHM, sizeof(gSaveBlock1Ptr->bagPocket_TMHM)); + memcpy(sPokeDudePackBackup->bagPocket_KeyItems, gSaveBlock1Ptr->bagPocket_KeyItems, sizeof(gSaveBlock1Ptr->bagPocket_KeyItems)); + sPokeDudePackBackup->unk_160 = sTMCaseStaticResources.selectedRow; + sPokeDudePackBackup->unk_162 = sTMCaseStaticResources.scrollOffset; + ClearItemSlots(gSaveBlock1Ptr->bagPocket_TMHM, NELEMS(gSaveBlock1Ptr->bagPocket_TMHM)); + ClearItemSlots(gSaveBlock1Ptr->bagPocket_KeyItems, NELEMS(gSaveBlock1Ptr->bagPocket_KeyItems)); + ResetTMCaseCursorPos(); + AddBagItem(ITEM_TM01, 1); + AddBagItem(ITEM_TM03, 1); + AddBagItem(ITEM_TM09, 1); + AddBagItem(ITEM_TM35, 1); + InitTMCase(4, CB2_ReturnToTeachyTV, 0); +} + +static void Task_TMCaseDude1(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (!gPaletteFade.active) + { + data[8] = 0; + data[9] = 0; + gTasks[taskId].func = Task_TMCaseDude_Playback; + } +} + +static void Task_TMCaseDude_Playback(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (JOY_NEW(B_BUTTON)) + { + if (data[8] < 21) + { + data[8] = 21; + SetTeachyTvControllerModeToResume(); + } + } + + switch (data[8]) + { + case 0: + BeginNormalPaletteFade(0xFFFF8405, 4, 0, 6, 0); + FillBG2RowWithPalette_2timesNplus1(1); + data[8]++; + break; + case 1: + case 11: + if (!gPaletteFade.active) + { + data[9]++; + if (data[9] > 0x65) + { + data[9] = 0; + data[8]++; + } + } + break; + case 2: + case 3: + case 4: + case 12: + case 13: + case 14: + if (data[9] == 0) + { + gMain.newKeys = 0; + gMain.newAndRepeatedKeys = DPAD_DOWN; + ListMenuHandleInput(data[0]); + } + data[9]++; + if (data[9] > 0x65) + { + data[9] = 0; + data[8]++; + } + break; + case 5: + case 6: + case 7: + case 15: + case 16: + case 17: + if (data[9] == 0) + { + gMain.newKeys = 0; + gMain.newAndRepeatedKeys = DPAD_UP; + ListMenuHandleInput(data[0]); + } + data[9]++; + if (data[9] > 0x65) + { + data[9] = 0; + data[8]++; + } + break; + case 8: + FillBG2RowWithPalette_2timesNplus1(1); + TMCase_PrintMessageWithFollowupTask(taskId, 4, gPokeDudeText_TMTypes, 0); + gTasks[taskId].func = Task_TMCaseDude_Playback; + data[8]++; + break; + case 9: + case 19: + RunTextPrinters(); + if (!IsTextPrinterActive(6)) + data[8]++; + break; + case 10: + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + FillBG2RowWithPalette_2timesNplus1(0); + BeginNormalPaletteFade(0x00000400, 0, 6, 0, 0); + ClearMenuWindow_BorderThickness2(6, 0); + schedule_bg_copy_tilemap_to_vram(1); + data[8]++; + } + break; + case 18: + FillBG2RowWithPalette_2timesNplus1(1); + TMCase_PrintMessageWithFollowupTask(taskId, 4, gPokeDudeText_ReadTMDescription, NULL); + gTasks[taskId].func = Task_TMCaseDude_Playback; // this function + data[8]++; + break; + case 20: + if (JOY_NEW(A_BUTTON | B_BUTTON)) + data[8]++; + break; + case 21: + if (!gPaletteFade.active) + { + memcpy(gSaveBlock1Ptr->bagPocket_TMHM, sPokeDudePackBackup->bagPocket_TMHM, sizeof(gSaveBlock1Ptr->bagPocket_TMHM)); + memcpy(gSaveBlock1Ptr->bagPocket_KeyItems, sPokeDudePackBackup->bagPocket_KeyItems, sizeof(gSaveBlock1Ptr->bagPocket_KeyItems)); + DestroyListMenu(data[0], NULL, NULL); + sTMCaseStaticResources.selectedRow = sPokeDudePackBackup->unk_160; + sTMCaseStaticResources.scrollOffset = sPokeDudePackBackup->unk_162; + Free(sPokeDudePackBackup); + CpuFastCopy(gPlttBufferFaded, gPlttBufferUnfaded, 0x400); + sub_8108CF0(); + BeginNormalPaletteFade(0xFFFFFFFF, -2, 0, 16, 0); + data[8]++; + } + break; + default: + if (!gPaletteFade.active) + { + SetMainCallback2(sTMCaseStaticResources.savedCallback); + RemoveTMCaseScrollIndicatorArrowPair(); + DestroyTMCaseBuffers(); + DestroyTask(taskId); + } + break; + } +} + +static void InitWindowTemplatesAndPals(void) +{ + u8 i; + + InitWindows(sWindowTemplates); + DeactivateAllTextPrinters(); + TextWindow_SetUserSelectedFrame(0, 0x5B, 0xE0); + TextWindow_SetBubbleFrame_841F1C8(0, 0x64, 0xB0); + TextWindow_SetStdFrame0_WithPal(0, 0x78, 0xD0); + LoadPalette(gTMCaseMainWindowPalette, 0xF0, 0x20); + LoadPalette(gTMCaseMainWindowPalette, 0xA0, 0x20); + LoadPalette(sPal3Override, 0xF6, 0x04); + LoadPalette(sPal3Override, 0xD6, 0x04); + sub_8107D38(0xc0, 0x01); + for (i = 0; i < 9; i++) + FillWindowPixelBuffer(i, 0x00); + PutWindowTilemap(0); + PutWindowTilemap(1); + PutWindowTilemap(3); + PutWindowTilemap(4); + PutWindowTilemap(5); + schedule_bg_copy_tilemap_to_vram(0); +} + +static void AddTextPrinterParameterized_ColorByIndex(u8 windowId, u8 fontId, const u8 * str, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, u8 speed, u8 colorIdx) +{ + AddTextPrinterParameterized4(windowId, fontId, x, y, letterSpacing, lineSpacing, &sTextColors[colorIdx], speed, str); +} + +static void TMCase_SetWindowBorder1(u8 windowId) +{ + SetWindowBorderStyle(windowId, FALSE, 0x5B, 0x0E); +} + +static void TMCase_SetWindowBorder2(u8 windowId) +{ + SetWindowBorderStyle(windowId, FALSE, 0x78, 0x0D); +} + +static void TMCase_PrintMessageWithFollowupTask(u8 taskId, u8 windowId, const u8 * str, TaskFunc func) +{ + DisplayMessageAndContinueTask(taskId, 6, 0x64, 0x0B, windowId, GetTextSpeedSetting(), str, func); + schedule_bg_copy_tilemap_to_vram(1); +} + +static void PrintStringTMCaseOnWindow3(void) +{ + u32 distance = 72 - GetStringWidth(1, gText_TMCase, 0); + AddTextPrinterParameterized3(3, 1, distance / 2, 1, &sTextColors[0], 0, gText_TMCase); +} + +static void DrawMoveInfoUIMarkers(void) +{ + blit_move_info_icon(4, 19, 0, 0); + blit_move_info_icon(4, 20, 0, 12); + blit_move_info_icon(4, 21, 0, 24); + blit_move_info_icon(4, 22, 0, 36); + CopyWindowToVram(4, 2); +} + +static void TMCase_MoveCursor_UpdatePrintedTMInfo(u16 itemId) +{ + u8 i; + u16 move; + const u8 * str; + + FillWindowPixelRect(5, 0, 0, 0, 40, 48); + if (itemId == ITEM_NONE) + { + for (i = 0; i < 4; i++) + { + AddTextPrinterParameterized_ColorByIndex(5, 3, gText_ThreeHyphens, 7, 12 * i, 0, 0, 0xFF, 3); + } + CopyWindowToVram(5, 2); + } + else + { + move = ItemIdToBattleMoveId(itemId); + blit_move_info_icon(5, gBattleMoves[move].type + 1, 0, 0); + if (gBattleMoves[move].power < 2) + str = gText_ThreeHyphens; + else + { + ConvertIntToDecimalStringN(gStringVar1, gBattleMoves[move].power, STR_CONV_MODE_RIGHT_ALIGN, 3); + str = gStringVar1; + } + AddTextPrinterParameterized_ColorByIndex(5, 3, str, 7, 12, 0, 0, 0xFF, 3); + if (gBattleMoves[move].accuracy == 0) + str = gText_ThreeHyphens; + else + { + ConvertIntToDecimalStringN(gStringVar1, gBattleMoves[move].accuracy, STR_CONV_MODE_RIGHT_ALIGN, 3); + str = gStringVar1; + } + AddTextPrinterParameterized_ColorByIndex(5, 3, str, 7, 24, 0, 0, 0xFF, 3); + ConvertIntToDecimalStringN(gStringVar1, gBattleMoves[move].pp, STR_CONV_MODE_RIGHT_ALIGN, 3); + AddTextPrinterParameterized_ColorByIndex(5, 3, gStringVar1, 7, 36, 0, 0, 0xFF, 3); + CopyWindowToVram(5, 2); + } +} + +static void PlaceHMTileInWindow(u8 windowId, u8 x, u8 y) +{ + BlitBitmapToWindow(windowId, gUnknown_8E99118, x, y, 16, 12); +} + +static void HandlePrintMoneyOnHand(void) +{ + PrintMoneyAmountInMoneyBoxWithBorder(8, 0x78, 0xD, GetMoney(&gSaveBlock1Ptr->money)); +} + +static void HandleCreateYesNoMenu(u8 taskId, const struct YesNoFuncTable *ptrs) +{ + CreateYesNoMenuWithCallbacks(taskId, &sYesNoWindowTemplate, 2, 0, 2, 0x5B, 0x0E, ptrs); +} + +static u8 AddTMContextMenu(u8 * a0, u8 a1) +{ + if (*a0 == 0xFF) + { + *a0 = AddWindow(&sTMContextWindowTemplates[a1]); + TMCase_SetWindowBorder1(*a0); + schedule_bg_copy_tilemap_to_vram(0); + } + return *a0; +} + +static void RemoveTMContextMenu(u8 * a0) +{ + ClearMenuWindow(*a0, FALSE); + ClearWindowTilemap(*a0); + RemoveWindow(*a0); + schedule_bg_copy_tilemap_to_vram(0); + *a0 = 0xFF; +} + +static u8 CreateTMSprite(u16 itemId) +{ + u8 spriteId = CreateSprite(&sTMSpriteTemplate, 0x29, 0x2E, 0); + u8 r5; + if (itemId == ITEM_NONE) + { + UpdateTMSpritePosition(&gSprites[spriteId], 0xFF); + return spriteId; + } + else + { + r5 = itemId - 33; + SetTMSpriteAnim(&gSprites[spriteId], r5); + TintTMSpriteByType(gBattleMoves[ItemIdToBattleMoveId(itemId)].type); + UpdateTMSpritePosition(&gSprites[spriteId], r5); + return spriteId; + } +} + +static void SetTMSpriteAnim(struct Sprite * sprite, u8 idx) +{ + if (idx >= 50) + StartSpriteAnim(sprite, 1); + else + StartSpriteAnim(sprite, 0); +} + +static void TintTMSpriteByType(u8 type) +{ + u8 palIndex = IndexOfSpritePaletteTag(TM_CASE_TM_TAG) << 4; + LoadPalette(sTMSpritePaletteBuffer + sTMSpritePaletteOffsetByType[type], 0x100 | palIndex, 0x20); + if (sTMCaseStaticResources.tmCaseMenuType == 4) + { + BlendPalettes(1 << (0x10 + palIndex), 4, RGB_BLACK); + } +} + +static void UpdateTMSpritePosition(struct Sprite * sprite, u8 var) +{ + s32 x, y; + if (var == 0xFF) + { + x = 0x1B; + y = 0x36; + sprite->pos2.y = 0x14; + } + else + { + if (var >= 50) + var -= 50; + else + var += 8; + x = 0x29 - (((0xE00 * var) / 58) >> 8); + y = 0x2E + (((0x800 * var) / 58) >> 8); + } + sprite->pos1.x = x; + sprite->pos1.y = y; +} + +static void InitSelectedTMSpriteData(u8 spriteId, u16 itemId) +{ + gSprites[spriteId].data[0] = itemId; + gSprites[spriteId].data[1] = 0; + gSprites[spriteId].callback = SpriteCB_MoveTMSpriteInCase; +} + +static void SpriteCB_MoveTMSpriteInCase(struct Sprite * sprite) +{ + switch (sprite->data[1]) + { + case 0: + if (sprite->pos2.y >= 20) + { + if (sprite->data[0] != ITEM_NONE) + { + sprite->data[1]++; + TintTMSpriteByType(gBattleMoves[ItemIdToBattleMoveId(sprite->data[0])].type); + sprite->data[0] -= ITEM_TM01; + SetTMSpriteAnim(sprite, sprite->data[0]); + UpdateTMSpritePosition(sprite, sprite->data[0]); + } + else + sprite->callback = SpriteCallbackDummy; + } + else + { + sprite->pos2.y += 10; + } + break; + case 1: + if (sprite->pos2.y <= 0) + sprite->callback = SpriteCallbackDummy; + else + sprite->pos2.y -= 10; + } +} + +static void LoadTMTypePalettes(void) +{ + struct SpritePalette spritePalette; + + sTMSpritePaletteBuffer = Alloc(0x110 * sizeof(u16)); + LZDecompressWram(gUnknown_8E84F20, sTMSpritePaletteBuffer); + LZDecompressWram(gUnknown_8E85068, sTMSpritePaletteBuffer + 0x100); + spritePalette.data = sTMSpritePaletteBuffer + 0x110; + spritePalette.tag = TM_CASE_TM_TAG; + LoadSpritePalette(&spritePalette); +} diff --git a/src/trainer_pokemon_sprites.c b/src/trainer_pokemon_sprites.c new file mode 100644 index 000000000..ecd889d80 --- /dev/null +++ b/src/trainer_pokemon_sprites.c @@ -0,0 +1,324 @@ +#include "global.h" +#include "sprite.h" +#include "window.h" +#include "malloc.h" +#include "constants/species.h" +#include "palette.h" +#include "decompress.h" +#include "trainer_pokemon_sprites.h" +#include "pokemon.h" +#include "constants/trainer_classes.h" + +extern const struct CompressedSpriteSheet gMonFrontPicTable[]; +extern const struct CompressedSpriteSheet gMonBackPicTable[]; +extern const struct CompressedSpriteSheet gTrainerFrontPicTable[]; +extern const struct CompressedSpriteSheet gTrainerBackPicTable[]; +extern const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[]; +extern const union AnimCmd *const gUnknown_82349BC[]; +extern const union AnimCmd *const *const gTrainerFrontAnimsPtrTable[]; + +// Static type declarations + +struct PicData +{ + u8 *frames; + struct SpriteFrameImage *images; + u16 paletteTag; + u8 spriteId; + u8 active; +}; + +// Static RAM declarations +#define PICS_COUNT 8 + +static EWRAM_DATA struct SpriteTemplate sCreatingSpriteTemplate = {}; +static EWRAM_DATA struct PicData sSpritePics[PICS_COUNT] = {}; + +// Static ROM declarations + +// .rodata + +static const struct PicData gUnknown_8453178 = {}; + +static const struct OamData gUnknown_8453184 = +{ + .shape = SPRITE_SHAPE(64x64), + .size = SPRITE_SIZE(64x64) +}; + +// .text + +void DummyPicSpriteCallback(struct Sprite *sprite) +{ + +} + +bool16 ResetAllPicSprites(void) +{ + int i; + + for (i = 0; i < PICS_COUNT; i ++) + sSpritePics[i] = gUnknown_8453178; + + return FALSE; +} + +static bool16 DecompressPic(u16 species, u32 personality, bool8 isFrontPic, u8 *dest, bool8 isTrainer, bool8 ignoreDeoxys) +{ + if (!isTrainer) + { + if (isFrontPic) + { + if (!ignoreDeoxys) + LoadSpecialPokePic(&gMonFrontPicTable[species], dest, species, personality, isFrontPic); + else + LoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[species], dest, species, personality, isFrontPic); + } + else + { + if (!ignoreDeoxys) + LoadSpecialPokePic(&gMonBackPicTable[species], dest, species, personality, isFrontPic); + else + LoadSpecialPokePic_DontHandleDeoxys(&gMonBackPicTable[species], dest, species, personality, isFrontPic); + } + } + else + { + if (isFrontPic) + DecompressPicFromTable(&gTrainerFrontPicTable[species], dest, species); + else + DecompressPicFromTable(&gTrainerBackPicTable[species], dest, species); + } + return FALSE; +} + +static bool16 DecompressPic_HandleDeoxys(u16 species, u32 personality, bool8 isFrontPic, u8 *dest, bool8 isTrainer) +{ + return DecompressPic(species, personality, isFrontPic, dest, isTrainer, FALSE); +} + +void LoadPicPaletteByTagOrSlot(u16 species, u32 otId, u32 personality, u8 paletteSlot, u16 paletteTag, bool8 isTrainer) +{ + if (!isTrainer) + { + if (paletteTag == 0xFFFF) + { + sCreatingSpriteTemplate.paletteTag = 0xFFFF; + LoadCompressedPalette(GetFrontSpritePalFromSpeciesAndPersonality(species, otId, personality), 0x100 + paletteSlot * 0x10, 0x20); + } + else + { + sCreatingSpriteTemplate.paletteTag = paletteTag; + LoadCompressedObjectPalette(GetMonSpritePalStructFromOtIdPersonality(species, otId, personality)); + } + } + else + { + if (paletteTag == 0xFFFF) + { + sCreatingSpriteTemplate.paletteTag = 0xFFFF; + LoadCompressedPalette(gTrainerFrontPicPaletteTable[species].data, 0x100 + paletteSlot * 0x10, 0x20); + } + else + { + sCreatingSpriteTemplate.paletteTag = paletteTag; + LoadCompressedObjectPalette(&gTrainerFrontPicPaletteTable[species]); + } + } +} + +void LoadPicPaletteBySlot(u16 species, u32 otId, u32 personality, u8 paletteSlot, bool8 isTrainer) +{ + if (!isTrainer) + LoadCompressedPalette(GetFrontSpritePalFromSpeciesAndPersonality(species, otId, personality), paletteSlot * 0x10, 0x20); + else + LoadCompressedPalette(gTrainerFrontPicPaletteTable[species].data, paletteSlot * 0x10, 0x20); +} + +void AssignSpriteAnimsTable(bool8 isTrainer) +{ + if (!isTrainer) + sCreatingSpriteTemplate.anims = gUnknown_82349BC; + else + sCreatingSpriteTemplate.anims = gTrainerFrontAnimsPtrTable[0]; +} + +u16 CreatePicSprite(u16 species, u32 otId, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag, bool8 isTrainer, bool8 ignoreDeoxys) +{ + u8 i; + u8 *framePics; + struct SpriteFrameImage *images; + int j; + u8 spriteId; + + for (i = 0; i < PICS_COUNT; i ++) + { + if (!sSpritePics[i].active) + { + break; + } + } + if (i == PICS_COUNT) + { + return 0xFFFF; + } + framePics = Alloc(4 * 0x800); + if (!framePics) + { + return 0xFFFF; + } + images = Alloc(4 * sizeof(struct SpriteFrameImage)); + if (!images) + { + Free(framePics); + return 0xFFFF; + } + if (DecompressPic(species, personality, isFrontPic, framePics, isTrainer, ignoreDeoxys)) + { + // debug trap? + return 0xFFFF; + } + for (j = 0; j < 4; j ++) + { + images[j].data = framePics + 0x800 * j; + images[j].size = 0x800; + } + sCreatingSpriteTemplate.tileTag = 0xFFFF; + sCreatingSpriteTemplate.oam = &gUnknown_8453184; + AssignSpriteAnimsTable(isTrainer); + sCreatingSpriteTemplate.images = images; + sCreatingSpriteTemplate.affineAnims = gDummySpriteAffineAnimTable; + sCreatingSpriteTemplate.callback = DummyPicSpriteCallback; + LoadPicPaletteByTagOrSlot(species, otId, personality, paletteSlot, paletteTag, isTrainer); + spriteId = CreateSprite(&sCreatingSpriteTemplate, x, y, 0); + if (paletteTag == 0xFFFF) + { + gSprites[spriteId].oam.paletteNum = paletteSlot; + } + sSpritePics[i].frames = framePics; + sSpritePics[i].images = images; + sSpritePics[i].paletteTag = paletteTag; + sSpritePics[i].spriteId = spriteId; + sSpritePics[i].active = TRUE; + return spriteId; +} + +u16 CreatePicSprite_HandleDeoxys(u16 species, u32 otId, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag, bool8 isTrainer) +{ + return CreatePicSprite(species, otId, personality, isFrontPic, x, y, paletteSlot, paletteTag, isTrainer, FALSE); +} + +u16 FreeAndDestroyPicSpriteInternal(u16 spriteId) +{ + u8 i; + u8 *framePics; + struct SpriteFrameImage *images; + + for (i = 0; i < PICS_COUNT; i ++) + { + if (sSpritePics[i].spriteId == spriteId) + { + break; + } + } + if (i == PICS_COUNT) + { + return 0xFFFF; + } + framePics = sSpritePics[i].frames; + images = sSpritePics[i].images; + if (sSpritePics[i].paletteTag != 0xFFFF) + { + FreeSpritePaletteByTag(GetSpritePaletteTagByPaletteNum(gSprites[spriteId].oam.paletteNum)); + } + DestroySprite(&gSprites[spriteId]); + Free(framePics); + Free(images); + sSpritePics[i] = gUnknown_8453178; + return 0; +} + +u16 sub_810C050(u16 species, u32 otId, u32 personality, bool8 isFrontPic, u8 paletteSlot, u8 windowId, bool8 isTrainer) +{ + if (DecompressPic_HandleDeoxys(species, personality, isFrontPic, (u8 *)GetWindowAttribute(windowId, WINDOW_TILE_DATA), FALSE)) + { + return 0xFFFF; + } + LoadPicPaletteBySlot(species, otId, personality, paletteSlot, isTrainer); + return 0; +} + +u16 sub_810C0C0(u16 species, u32 otId, u32 personality, bool8 isFrontPic, u16 destX, u16 destY, u8 paletteSlot, u8 windowId, bool8 isTrainer) +{ + u8 *framePics; + + framePics = Alloc(4 * 0x800); + if (framePics && !DecompressPic_HandleDeoxys(species, personality, isFrontPic, framePics, isTrainer)) + { + BlitBitmapRectToWindow(windowId, framePics, 0, 0, 0x40, 0x40, destX, destY, 0x40, 0x40); + LoadPicPaletteBySlot(species, otId, personality, paletteSlot, isTrainer); + Free(framePics); + return 0; + } + return 0xFFFF; +} + +u16 CreateMonPicSprite(u16 species, u32 otId, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag, bool8 ignoreDeoxys) +{ + return CreatePicSprite(species, otId, personality, isFrontPic, x, y, paletteSlot, paletteTag, FALSE, ignoreDeoxys); +} + +u16 CreateMonPicSprite_HandleDeoxys(u16 species, u32 otId, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag) +{ + return CreateMonPicSprite(species, otId, personality, isFrontPic, x, y, paletteSlot, paletteTag, FALSE); +} + +u16 FreeAndDestroyMonPicSprite(u16 spriteId) +{ + return FreeAndDestroyPicSpriteInternal(spriteId); +} + +u16 sub_810C228(u16 species, u32 otId, u32 personality, bool8 isFrontPic, u8 paletteSlot, u8 windowId) +{ + return sub_810C0C0(species, otId, personality, isFrontPic, 0, 0, paletteSlot, windowId, FALSE); +} + +u16 sub_810C25C(u16 species, u32 otId, u32 personality, bool8 isFrontPic, u16 destX, u16 destY, u8 paletteSlot, u8 windowId) +{ + return sub_810C0C0(species, otId, personality, isFrontPic, destX, destY, paletteSlot, windowId, FALSE); +} + +u16 CreateTrainerPicSprite(u16 species, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag) +{ + return CreatePicSprite_HandleDeoxys(species, 0, 0, isFrontPic, x, y, paletteSlot, paletteTag, TRUE); +} + +u16 FreeAndDestroyTrainerPicSprite(u16 spriteId) +{ + return FreeAndDestroyPicSpriteInternal(spriteId); +} + +u16 sub_810C2FC(u16 species, bool8 isFrontPic, u8 paletteSlot, u8 windowId) +{ + return sub_810C050(species, 0, 0, isFrontPic, paletteSlot, windowId, TRUE); +} + +u16 sub_810C330(u16 species, bool8 isFrontPic, u16 destX, u16 destY, u8 paletteSlot, u8 windowId) +{ + return sub_810C0C0(species, 0, 0, isFrontPic, destX, destY, paletteSlot, windowId, TRUE); +} + +u16 PlayerGenderToFrontTrainerPicId_Debug(u8 gender, bool8 getClass) +{ + if (getClass == TRUE) + { + switch (gender) + { + default: + return gFacilityClassToPicIndex[0x87]; + case MALE: + return gFacilityClassToPicIndex[0x86]; + } + } + return gender; +} diff --git a/src/trainer_tower.c b/src/trainer_tower.c index 91132c07b..ef2a12ce0 100644 --- a/src/trainer_tower.c +++ b/src/trainer_tower.c @@ -1,7 +1,10 @@ #include "global.h" #include "main.h" +#include "task.h" #include "constants/flags.h" #include "constants/vars.h" +#include "constants/items.h" +#include "constants/species.h" #include "malloc.h" #include "save.h" #include "util.h" @@ -11,7 +14,16 @@ #include "cereader_tool.h" #include "easy_chat.h" #include "text.h" +#include "battle_setup.h" +#include "battle_transition.h" +#include "battle.h" +#include "battle_2.h" #include "overworld.h" +#include "item.h" +#include "window.h" +#include "menu.h" +#include "new_menu_helpers.h" +#include "sound.h" struct UnkStruct_8479D34 { @@ -23,45 +35,10 @@ struct UnkStruct_8479D34 u8 flags3[8]; }; -struct UnkSubstruct_203F458_000C_004 -{ - /* 0x000 */ u8 unk_000[11]; - /* 0x00B */ u8 unk_00B; - /* 0x00C */ u8 unk_00C; - /* 0x00D */ u8 unk_00D; - /* 0x00E */ u16 unk_00E[6]; - /* 0x01A */ u16 unk_01A[6]; - /* 0x026 */ u16 unk_026[6]; - /* 0x032 */ u16 unk_032[6]; - /* 0x040 */ struct BattleTowerPokemon unk_040[PARTY_SIZE]; -}; // size: 328 - -struct UnkSubstruct_203F458_000C -{ - /* 0x000 */ u8 filler_000[2]; - /* 0x002 */ u8 unk_002; - /* 0x003 */ u8 unk_003; - /* 0x004 */ struct UnkSubstruct_203F458_000C_004 unk_004[3]; - /* 0x3DC */ u8 filler_3DC[4]; -}; - -struct Unk_203F458_Header -{ - u8 unk0; - u8 unk1; - u32 unk4; -}; - -struct UnkStruct_203F458_SaveBlock -{ - struct Unk_203F458_Header unk_0000; - struct UnkSubstruct_203F458_000C unk_0008[8]; -}; - struct UnkStruct_203F458 { /* 0x0000 */ u8 unk_0000; - /* 0x0004 */ struct UnkStruct_203F458_SaveBlock unk_0004; + /* 0x0004 */ struct TrainerTowerData unk_0004; }; struct UnkStruct_203F45C @@ -92,8 +69,15 @@ struct UnkStruct_847A024 bool8 unk4; }; +struct UnkStruct_847A074 +{ + u8 unk0; + u8 unk1; +}; + EWRAM_DATA struct UnkStruct_203F458 * gUnknown_203F458 = NULL; EWRAM_DATA struct UnkStruct_203F45C * gUnknown_203F45C = NULL; +EWRAM_DATA u8 unused_variable = 0; void sub_815D96C(void); void sub_815DC8C(void); // setup @@ -122,38 +106,430 @@ void sub_815E8CC(void); void sub_815E908(void); void sub_815E948(void); void sub_815E9C8(void); +void sub_815E9FC(void); +static s32 GetPartyMaxLevel(void); void sub_815EC0C(void); +u32 sub_815EDDC(u32 *); +void sub_815EDF4(u32 *, u32); -extern const struct UnkStruct_8479D34 gUnknown_8479D34[15]; -extern void (*const gUnknown_847A230[])(void); -extern const struct Unk_203F458_Header gUnknown_84827AC; -extern const struct UnkSubstruct_203F458_000C *const gUnknown_84827B4[][8]; -extern const u16 gUnknown_847A284[8][3]; -extern const struct UnkStruct_8479ED8 gUnknown_8479ED8[83]; -extern const struct UnkStruct_847A024 gUnknown_847A024[10]; +extern const u8 gUnknown_83FE982[]; +extern const u8 gUnknown_83FE998[]; +extern const u8 *const gUnknown_83FE9C4[]; -bool32 sub_815D7BC(void * dest, void * buffer) -{ - if (TryCopySpecialSaveSection(30, buffer) != 1) - return FALSE; - memcpy(dest + 0x000, buffer, 0xF88); +const struct UnkStruct_8479D34 gUnknown_8479D34[] = { + { + 0x03, 0x26, + .flags1 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0x99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x27, + .flags1 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0x9a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x01, 0x1f, + .flags1 = {0x4c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x01, 0x22, + .flags1 = {0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x41, + .flags1 = {0x40, 0x41, 0x42, 0x43, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x01, 0x02, + .flags1 = {0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0xff, 0xff}, + .flags2 = {0x54, 0x55, 0x56, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x01, 0x6d, + .flags1 = {0x5b, 0x5d, 0x5e, 0x5f, 0x63, 0x64, 0x65, 0x66}, + .flags2 = {0x5b, 0x5d, 0x5e, 0x5f, 0x63, 0x64, 0x65, 0xff}, + .flags3 = {0x5a, 0x5c, 0x60, 0x61, 0x62, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x2e, + .flags1 = {0x6b, 0x6c, 0x6d, 0x6e, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0xff, 0xff}, + .flags3 = {0x6b, 0x6c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x30, + .flags1 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0xa6, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x0f, + .flags1 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0xa8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xa9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x39, + .flags1 = {0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x36, + .flags1 = {0xae, 0xb0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0xaf, 0xb1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x3a, + .flags1 = {0xb2, 0xb3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x3b, + .flags1 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xb4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { + 0x03, 0x3e, + .flags1 = {0xb9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags2 = {0xba, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .flags3 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, +}; - if (TryCopySpecialSaveSection(31, buffer) != 1) - return FALSE; - memcpy(dest + 0xF88, buffer, 0xF80); +const struct UnkStruct_8479ED8 gUnknown_8479ED8[] = { + {0x1c, 0x03, 0x01}, + {0x38, 0x04, 0x00}, + {0x25, 0x06, 0x01}, + {0x26, 0x07, 0x00}, + {0x29, 0x08, 0x00}, + {0x2a, 0x09, 0x01}, + {0x34, 0x0a, 0x00}, + {0x1c, 0x0b, 0x01}, + {0x1d, 0x0c, 0x01}, + {0x13, 0x0d, 0x00}, + {0x34, 0x0e, 0x00}, + {0x2d, 0x0f, 0x00}, + {0x36, 0x10, 0x00}, + {0x1a, 0x11, 0x00}, + {0x1a, 0x12, 0x00}, + {0x27, 0x13, 0x00}, + {0x34, 0x14, 0x00}, + {0x13, 0x15, 0x00}, + {0x17, 0x16, 0x01}, + {0x3d, 0x17, 0x00}, + {0x13, 0x1d, 0x00}, + {0x17, 0x1e, 0x01}, + {0x1e, 0x20, 0x00}, + {0x1f, 0x21, 0x01}, + {0x20, 0x22, 0x00}, + {0x23, 0x23, 0x01}, + {0x12, 0x24, 0x00}, + {0x39, 0x26, 0x00}, + {0x29, 0x2d, 0x00}, + {0x1a, 0x2e, 0x00}, + {0x10, 0x2f, 0x00}, + {0x18, 0x30, 0x01}, + {0x1d, 0x31, 0x01}, + {0x2e, 0x32, 0x01}, + {0x28, 0x33, 0x01}, + {0x3e, 0x35, 0x00}, + {0x1b, 0x38, 0x00}, + {0x19, 0x40, 0x00}, + {0x1c, 0x41, 0x01}, + {0x27, 0x42, 0x00}, + {0x28, 0x43, 0x01}, + {0x16, 0x47, 0x01}, + {0x14, 0x48, 0x00}, + {0x38, 0x49, 0x00}, + {0x12, 0x58, 0x00}, + {0x14, 0x59, 0x00}, + {0x16, 0x5a, 0x01}, + {0x3e, 0x5b, 0x00}, + {0x27, 0x5c, 0x00}, + {0x28, 0x5d, 0x01}, + {0x34, 0x5e, 0x00}, + {0x34, 0x5f, 0x00}, + {0x38, 0x60, 0x00}, + {0x35, 0x61, 0x00}, + {0x34, 0x62, 0x00}, + {0x1e, 0x63, 0x00}, + {0x39, 0x64, 0x00}, + {0x2d, 0x65, 0x00}, + {0x35, 0x66, 0x00}, + {0x20, 0x67, 0x00}, + {0x1d, 0x68, 0x01}, + {0x2e, 0x69, 0x01}, + {0x13, 0x6a, 0x00}, + {0x1a, 0x6b, 0x00}, + {0x1a, 0x6c, 0x00}, + {0x19, 0x6d, 0x00}, + {0x1a, 0x6e, 0x00}, + {0x36, 0x6f, 0x00}, + {0x37, 0x71, 0x00}, + {0x29, 0x74, 0x00}, + {0x2a, 0x75, 0x01}, + {0x3d, 0x7a, 0x00}, + {0x3a, 0x7d, 0x01}, + {0x17, 0x89, 0x01}, + {0x18, 0x8a, 0x01}, + {0x25, 0x8b, 0x01}, + {0x1c, 0x8c, 0x01}, + {0x27, 0x8d, 0x00}, + {0x28, 0x8e, 0x01}, + {0x1c, 0x8f, 0x01}, + {0x38, 0x90, 0x00}, + {0x1c, 0x91, 0x01}, + {0x16, 0x92, 0x01} +}; - if (!sub_815D6B4(dest)) - return FALSE; - return TRUE; -} +const struct UnkStruct_847A024 gUnknown_847A024[] = { + {0x1d, 0x17, 0x1f, 0x01, 0x01}, + {0x11, 0x11, 0x34, 0x01, 0x01}, + {0x1d, 0x19, 0x4a, 0x01, 0x00}, + {0x20, 0x23, 0x4b, 0x00, 0x01}, + {0x26, 0x2e, 0x4c, 0x00, 0x01}, + {0x11, 0x11, 0x7e, 0x01, 0x01}, + {0x29, 0x2a, 0x7f, 0x00, 0x01}, + {0x1d, 0x19, 0x80, 0x01, 0x00}, + {0x18, 0x36, 0x81, 0x01, 0x00}, + {0x2e, 0x26, 0x82, 0x01, 0x00} +}; -bool32 sub_815D80C(void * dest) -{ - void * buffer = AllocZeroed(0x1000); - bool32 success = sub_815D7BC(dest, buffer); - Free(buffer); - return success; -} +const struct UnkStruct_847A074 gUnknown_847A074[105] = { + {0x03, 0x06}, + {0x37, 0x06}, + {0x02, 0x06}, + {0x67, 0x01}, + {0x04, 0x01}, + {0x24, 0x04}, + {0x4a, 0x01}, + {0x26, 0x01}, + {0x2a, 0x00}, + {0x42, 0x03}, + {0x1b, 0x09}, + {0x4c, 0x03}, + {0x44, 0x03}, + {0x21, 0x04}, + {0x43, 0x03}, + {0x6a, 0x01}, + {0x5d, 0x05}, + {0x56, 0x05}, + {0x09, 0x05}, + {0x11, 0x04}, + {0x48, 0x03}, + {0x3c, 0x00}, + {0x29, 0x00}, + {0x5c, 0x09}, + {0x28, 0x09}, + {0x06, 0x0c}, + {0x68, 0x0b}, + {0x05, 0x0b}, + {0x58, 0x0d}, + {0x16, 0x0d}, + {0x46, 0x08}, + {0x0f, 0x01}, + {0x3f, 0x03}, + {0x0e, 0x03}, + {0x5f, 0x04}, + {0x63, 0x04}, + {0x50, 0x04}, + {0x10, 0x04}, + {0x52, 0x03}, + {0x35, 0x04}, + {0x5b, 0x03}, + {0x14, 0x03}, + {0x3d, 0x00}, + {0x13, 0x00}, + {0x12, 0x0b}, + {0x30, 0x07}, + {0x38, 0x07}, + {0x2f, 0x07}, + {0x3b, 0x01}, + {0x31, 0x01}, + {0x4e, 0x0b}, + {0x3a, 0x00}, + {0x32, 0x00}, + {0x23, 0x03}, + {0x0d, 0x0d}, + {0x0a, 0x03}, + {0x49, 0x01}, + {0x0c, 0x01}, + {0x69, 0x01}, + {0x0b, 0x01}, + {0x25, 0x01}, + {0x3e, 0x02}, + {0x27, 0x02}, + {0x65, 0x01}, + {0x2d, 0x01}, + {0x61, 0x01}, + {0x2b, 0x03}, + {0x66, 0x05}, + {0x2e, 0x05}, + {0x2c, 0x00}, + {0x5e, 0x02}, + {0x34, 0x02}, + {0x51, 0x00}, + {0x59, 0x00}, + {0x40, 0x03}, + {0x55, 0x06}, + {0x53, 0x06}, + {0x4b, 0x04}, + {0x15, 0x04}, + {0x1a, 0x09}, + {0x57, 0x0a}, + {0x17, 0x01}, + {0x47, 0x03}, + {0x62, 0x01}, + {0x39, 0x00}, + {0x1d, 0x00}, + {0x1c, 0x04}, + {0x20, 0x00}, + {0x4f, 0x05}, + {0x22, 0x05}, + {0x45, 0x0b}, + {0x1f, 0x0b}, + {0x5a, 0x00}, + {0x1e, 0x00}, + {0x08, 0x00}, + {0x64, 0x02}, + {0x07, 0x02}, + {0x60, 0x08}, + {0x36, 0x08}, + {0x41, 0x0b}, + {0x33, 0x0b}, + {0x54, 0x00}, + {0x18, 0x01}, + {0x4d, 0x0b}, + {0x19, 0x00} +}; + +const struct WindowTemplate gUnknown_847A218[] = { + {0, 3, 1, 27, 18, 15, 0x001}, + DUMMY_WIN_TEMPLATE +}; + +const u32 gUnknown_847A228 = 0x70; // unused + +const struct TextColor gUnknown_847A22C = {0, 2, 3}; + +void (*const gUnknown_847A230[])(void) = { + sub_815DD44, + sub_815DF54, + sub_815E160, + sub_815E1C0, + sub_815E1F0, + sub_815E218, + sub_815E28C, + sub_815E394, + sub_815E408, + sub_815E4B0, + sub_815E56C, + sub_815E5C4, + sub_815E5F0, + sub_815E658, + sub_815E720, + sub_815E88C, + sub_815E8B4, + sub_815E8CC, + sub_815E908, + sub_815E948, + sub_815E9C8 +}; + +const u16 gUnknown_847A284[8][3] = { + {0x012a, 0x016e, 0x0176}, + {0x012b, 0x016f, 0x0177}, + {0x012c, 0x0170, 0x0178}, + {0x012d, 0x0171, 0x0179}, + {0x012e, 0x0172, 0x017a}, + {0x012f, 0x0173, 0x017b}, + {0x0130, 0x0174, 0x017c}, + {0x0131, 0x0175, 0x017d} +}; + +const u16 gUnknown_847A2B4[] = { + ITEM_HP_UP, + ITEM_PROTEIN, + ITEM_IRON, + ITEM_CARBOS, + ITEM_CALCIUM, + ITEM_ZINC, + ITEM_BRIGHT_POWDER, + ITEM_WHITE_HERB, + ITEM_MENTAL_HERB, + ITEM_CHOICE_BAND, + ITEM_KINGS_ROCK, + ITEM_SCOPE_LENS, + ITEM_METAL_COAT, + ITEM_DRAGON_SCALE, + ITEM_UP_GRADE +}; + +const u16 gUnknown_847A2D2[] = { + 0x011d, + 0x011c, + 0x011c, + 0x011b, + 0x011d, + 0x011d, + 0x011b, + 0x011b, + 0x011d, + 0x011c, + 0x011d, + 0x011d, + 0x011d, + 0x011d +}; + +const u8 gUnknown_847A2EE[][2] = { + {0x00, 0x02}, + {0x01, 0x03}, + {0x02, 0x04}, + {0x03, 0x05}, + {0x04, 0x01}, + {0x05, 0x02}, + {0x00, 0x03}, + {0x01, 0x04} +}; + +const u8 gUnknown_847A2FE[][2] = { + {0x00, 0x01}, + {0x01, 0x03}, + {0x02, 0x00}, + {0x03, 0x04}, + {0x04, 0x02}, + {0x05, 0x02}, + {0x00, 0x03}, + {0x01, 0x05} +}; + +const u8 gUnknown_847A30E[][3] = { + {0x00, 0x02, 0x04}, + {0x01, 0x03, 0x05}, + {0x02, 0x03, 0x01}, + {0x03, 0x04, 0x00}, + {0x04, 0x01, 0x02}, + {0x05, 0x00, 0x03}, + {0x00, 0x05, 0x02}, + {0x01, 0x04, 0x05} +}; + +extern const struct Unk_203F458_Header gUnknown_84827AC; +extern const struct TrainerTowerTrainer *const gUnknown_84827B4[][8]; bool32 sub_815D834(void) { @@ -263,24 +639,24 @@ void sub_815DA54(void) sub_815DC8C(); gUnknown_203F45C = AllocZeroed(sizeof(*gUnknown_203F45C)); r10 = VarGet(VAR_0x4001); - StringCopyN(gUnknown_203F45C->unk_00, gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r10].unk_000, 11); + StringCopyN(gUnknown_203F45C->unk_00, gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r10].unk_000, 11); for (r9 = 0; r9 < 6; r9++) { - gUnknown_203F45C->unk_0C[r9] = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r10].unk_01A[r9]; - gUnknown_203F45C->unk_18[r9] = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r10].unk_026[r9]; + gUnknown_203F45C->unk_0C[r9] = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r10].unk_01A[r9]; + gUnknown_203F45C->unk_18[r9] = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r10].unk_026[r9]; - if (gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_002 == 1) + if (gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_002 == 1) { - gUnknown_203F45C->unk_24[r9] = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r10 + 1].unk_01A[r9]; - gUnknown_203F45C->unk_30[r9] = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r10 + 1].unk_026[r9]; + gUnknown_203F45C->unk_24[r9] = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r10 + 1].unk_01A[r9]; + gUnknown_203F45C->unk_30[r9] = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r10 + 1].unk_026[r9]; } } - gUnknown_203F45C->unk_3C = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_002; - gUnknown_203F45C->unk_3D = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r10].unk_00B; - gUnknown_203F45C->unk_3E = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r10].unk_00C; - SetVBlankCounter1Ptr(gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx]); + gUnknown_203F45C->unk_3C = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_002; + gUnknown_203F45C->unk_3D = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r10].unk_00B; + gUnknown_203F45C->unk_3E = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r10].unk_00C; + SetVBlankCounter1Ptr(&gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0); sub_815DD2C(); } @@ -317,12 +693,12 @@ void sub_815DC8C(void) // fakematching { u32 whichTimer = gSaveBlock1Ptr->unkArrayIdx; s32 r4; - const struct UnkSubstruct_203F458_000C *const * r7; + const struct TrainerTowerTrainer *const * r7; gUnknown_203F458 = AllocZeroed(sizeof(*gUnknown_203F458)); gUnknown_203F458->unk_0000 = gMapHeader.mapDataId - 0x2A; if (sub_815D834() == TRUE) - sub_815D80C(&gUnknown_203F458->unk_0004); + CEReaderTool_LoadTrainerTower(&gUnknown_203F458->unk_0004); else { struct UnkStruct_203F458 * r0_ = gUnknown_203F458; @@ -334,12 +710,12 @@ void sub_815DC8C(void) // fakematching for (r4 = 0; r4 < 8; r4++) { void * r0 = gUnknown_203F458; - r0 = r4 * sizeof(struct UnkSubstruct_203F458_000C) + r0; - r0 += offsetof(struct UnkStruct_203F458, unk_0004.unk_0008); - memcpy(r0, r7[r4], sizeof(struct UnkSubstruct_203F458_000C)); + r0 = r4 * sizeof(struct TrainerTowerTrainer) + r0; + r0 += offsetof(struct UnkStruct_203F458, unk_0004.trainers); + memcpy(r0, r7[r4], sizeof(struct TrainerTowerTrainer)); // r0[r4] = *r7[r4]; } - gUnknown_203F458->unk_0004.unk_0000.unk4 = CalcByteArraySum((void *)gUnknown_203F458->unk_0004.unk_0008, sizeof(gUnknown_203F458->unk_0004.unk_0008)); + gUnknown_203F458->unk_0004.unk4 = CalcByteArraySum((void *)gUnknown_203F458->unk_0004.trainers, sizeof(gUnknown_203F458->unk_0004.trainers)); sub_815EC0C(); } } @@ -366,7 +742,7 @@ void sub_815DC8C(void) "\tbne _0815DCD0\n" "\tldr r0, [r4]\n" "\tadds r0, 0x4\n" - "\tbl sub_815D80C\n" + "\tbl CEReaderTool_LoadTrainerTower\n" "\tb _0815DD18\n" "\t.align 2, 0\n" "_0815DCBC: .4byte gSaveBlock1Ptr\n" @@ -427,15 +803,15 @@ void sub_815DD2C(void) void sub_815DD44(void) { - if (gMapHeader.mapDataId - 0x129 > gUnknown_203F458->unk_0004.unk_0000.unk0) + if (gMapHeader.mapDataId - 0x129 > gUnknown_203F458->unk_0004.count) { gSpecialVar_Result = 3; - sub_8055D40(0x132); + SetCurrentMapLayout(0x132); } else { - gSpecialVar_Result = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_002; - sub_8055D40(gUnknown_847A284[gUnknown_203F458->unk_0000][gSpecialVar_Result]); + gSpecialVar_Result = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_002; + SetCurrentMapLayout(gUnknown_847A284[gUnknown_203F458->unk_0000][gSpecialVar_Result]); sub_815DDB0(); } } @@ -444,10 +820,10 @@ void sub_815DDB0(void) { s32 r3, r4; u8 r1, r2, r4_; - switch (gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_002) + switch (gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_002) { case 0: - r2 = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[0].unk_00B; + r2 = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[0].unk_00B; for (r3 = 0; r3 < NELEMS(gUnknown_8479ED8); r3++) { if (gUnknown_8479ED8[r3].unk1 == r2) @@ -460,7 +836,7 @@ void sub_815DDB0(void) VarSet(VAR_0x4011, r1); break; case 1: - r2 = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[0].unk_00B; + r2 = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[0].unk_00B; for (r3 = 0; r3 < NELEMS(gUnknown_847A024); r3++) { if (gUnknown_847A024[r3].unk2 == r2) @@ -482,7 +858,7 @@ void sub_815DDB0(void) case 2: for (r4 = 0; r4 < 3; r4++) { - r2 = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r4].unk_00B; + r2 = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_00B; for (r3 = 0; r3 < NELEMS(gUnknown_8479ED8); r3++) { if (gUnknown_8479ED8[r3].unk1 == r2) @@ -529,25 +905,25 @@ void sub_815DF54(void) { u16 r4 = gSpecialVar_0x8006; u8 r1; - u8 r5 = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_002; + u8 r5 = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_002; // HOW DO I MATCH THIS CONTROL FLOW?!?! - r1 = gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r5 == 1 ? 0 : r4].unk_00B; + r1 = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r5 == 1 ? 0 : r4].unk_00B; switch (gSpecialVar_0x8005) { case 2: sub_815E068(r5, r1); - sub_815DEFC(gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r4].unk_00E, gStringVar4); + sub_815DEFC(gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_00E, gStringVar4); break; case 3: sub_815E068(r5, r1); - sub_815DEFC(gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r4].unk_01A, gStringVar4); + sub_815DEFC(gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_01A, gStringVar4); break; case 4: sub_815E068(r5, r1); - sub_815DEFC(gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r4].unk_026, gStringVar4); + sub_815DEFC(gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_026, gStringVar4); break; case 5: - sub_815DEFC(gUnknown_203F458->unk_0004.unk_0008[gUnknown_203F458->unk_0000].unk_004[r4].unk_032, gStringVar4); + sub_815DEFC(gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_032, gStringVar4); break; } } @@ -692,3 +1068,402 @@ void sub_815DF54(void) "_0815E064: .4byte gStringVar4"); } #endif // NONMATCHING + +void sub_815E068(u8 battleType, u8 facilityClass) +{ + u16 r5 = FALSE; + s32 r4; + switch (battleType) + { + case 0: + case 2: + for (r4 = 0; r4 < NELEMS(gUnknown_8479ED8); r4++) + { + if (gUnknown_8479ED8[r4].unk1 == facilityClass) + break; + } + if (r4 != NELEMS(gUnknown_8479ED8)) + r5 = gUnknown_8479ED8[r4].unk2; + break; + case 1: + for (r4 = 0; r4 < NELEMS(gUnknown_847A024); r4++) + { + if (gUnknown_847A024[r4].unk2 == facilityClass) + break; + } + if (r4 != NELEMS(gUnknown_847A024)) + { + if (VarGet(VAR_0x4003)) + r5 = gUnknown_847A024[r4].unk4; + else + r5 = gUnknown_847A024[r4].unk3; + } + break; + } + gUnknown_20370DC = gUnknown_20370DA; + gUnknown_20370DA = r5; +} + +void sub_815E114(void) +{ + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); +} + +void sub_815E124(u8 taskId) +{ + if (sub_80D08F8() == TRUE) + { + gMain.savedCallback = sub_815E114; + CleanupOverworldWindowsAndTilemaps(); + SetMainCallback2(sub_800FD9C); + DestroyTask(taskId); + } +} + +void sub_815E160(void) +{ + gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_FACTORY; + if (gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_002 == 1) + gBattleTypeFlags |= BATTLE_TYPE_DOUBLE; + gTrainerBattleOpponent_A = 0; + sub_815E9FC(); + CreateTask(sub_815E124, 1); + PlayMapChosenOrBattleBGM(0); + sub_80D08B8(sub_8080060()); +} + +void sub_815E1C0(void) +{ + if (!gSpecialVar_0x8005) + gSpecialVar_Result = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_002; +} + +void sub_815E1F0(void) +{ + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk8++; +} + +void sub_815E218(void) +{ + u16 mapDataId = gMapHeader.mapDataId; + if (mapDataId - 0x12A == gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk8 && mapDataId - 0x129 <= gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_001) + gSpecialVar_Result = FALSE; + else + gSpecialVar_Result = TRUE; +} + +void sub_815E28C(void) +{ + gSaveBlock1Ptr->unkArrayIdx = gSpecialVar_0x8005; + if (gSaveBlock1Ptr->unkArrayIdx >= NELEMS(gSaveBlock1Ptr->unkArray)) + gSaveBlock1Ptr->unkArrayIdx = 0; + sub_815EC0C(); + if (!sub_815D834()) + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_5 = TRUE; + else + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_5 = FALSE; + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk8 = 0; + SetVBlankCounter1Ptr(&gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0); + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0 = 0; + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_2 = FALSE; + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_1 = FALSE; +} + +void sub_815E394(void) +{ + DisableVBlankCounter1(); + gSpecialVar_Result = 0; + if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_2) + gSpecialVar_Result++; + if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_0 && gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_1) + gSpecialVar_Result++; + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_2 = TRUE; +} + +void sub_815E408(void) +{ + u16 itemId = gUnknown_847A2B4[gUnknown_203F458->unk_0004.trainers->unk_003]; + if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_0) + gSpecialVar_Result = 2; + else if (AddBagItem(itemId, 1) == 1) + { + CopyItemName(itemId, gStringVar2); + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_0 = TRUE; + gSpecialVar_Result = 0; + } + else + gSpecialVar_Result = 1; +} + +void sub_815E4B0(void) +{ + if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_1) + gSpecialVar_Result = 2; + else if (sub_815EDDC(&gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk4) > gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0) + { + sub_815EDF4(&gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk4, gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0); + gSpecialVar_Result = 0; + } + else + gSpecialVar_Result = 1; + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_1 = TRUE; +} + +void sub_815E56C(void) +{ + if (!gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_2) + { + if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0 >= 215999) + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0 = 215999; + else + SetVBlankCounter1Ptr(&gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0); + } +} + +void sub_815E5C4(void) +{ + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_3 = 1; +} + +void sub_815E5F0(void) +{ + if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_3) + { + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_3 = FALSE; + gSpecialVar_Result = 0; + } + else if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_4) + { + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_4 = FALSE; + gSpecialVar_Result = 1; + } + else + { + gSpecialVar_Result = 2; + } +} + +#define PRINT_TOWER_TIME(src) ({ \ + s32 minutes, seconds, centiseconds, frames; \ + \ + frames = (src); \ + \ + minutes = frames / 3600; \ + frames %= 3600; \ + seconds = frames / 60; \ + frames %= 60; \ + centiseconds = frames * 168 / 100; \ + \ + ConvertIntToDecimalStringN(gStringVar1, minutes, STR_CONV_MODE_RIGHT_ALIGN, 2); \ + ConvertIntToDecimalStringN(gStringVar2, seconds, STR_CONV_MODE_RIGHT_ALIGN, 2); \ + ConvertIntToDecimalStringN(gStringVar3, centiseconds, STR_CONV_MODE_LEADING_ZEROS, 2); \ +}) + +void sub_815E658(void) +{ + if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0 >= 215999) + { + DisableVBlankCounter1(); + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0 = 215999; + } + + PRINT_TOWER_TIME(gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk0); +} + +void sub_815E720(void) +{ + u8 windowId; + s32 i; + s32 minutes, seconds, centiseconds; + + sub_815EC0C(); + windowId = AddWindow(gUnknown_847A218); + sub_80F6E9C(); + DrawStdWindowFrame(windowId, FALSE); + AddTextPrinterParameterized(windowId, 2, gUnknown_83FE982, 0x4A, 0, 0xFF, NULL); + + for (i = 0; i < 4; i++) + { + PRINT_TOWER_TIME(sub_815EDDC(&gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk4)); + + StringExpandPlaceholders(gStringVar4, gUnknown_83FE998); + AddTextPrinterParameterized(windowId, 2, gUnknown_83FE9C4[i - 1], 0x18, 0x24 + 0x14 * i, 0xFF, NULL); + AddTextPrinterParameterized(windowId, 2, gStringVar4, 0x60, 0x2E + 0x14 * i, 0xFF, NULL); + } + + PutWindowTilemap(windowId); + CopyWindowToVram(windowId, 3); + VarSet(VAR_0x4001, windowId); +} + +void sub_815E88C(void) +{ + u8 windowId = VarGet(VAR_0x4001); + ClearMenuWindow(windowId, TRUE); + RemoveWindow(windowId); +} + +void sub_815E8B4(void) +{ + gSpecialVar_Result = GetMonsStateToDoubles(); +} + +void sub_815E8CC(void) +{ + if (gUnknown_203F458->unk_0004.count != gUnknown_203F458->unk_0004.trainers[0].unk_001) + { + ConvertIntToDecimalStringN(gStringVar1, gUnknown_203F458->unk_0004.count, STR_CONV_MODE_LEFT_ALIGN, 1); + gSpecialVar_Result = TRUE; + } + else + { + gSpecialVar_Result = FALSE; + } +} + +void sub_815E908(void) +{ + if (gMapHeader.mapDataId == 0x0129 && VarGet(VAR_0x4082) == 0) + { + gSpecialVar_Result = FALSE; + } + else + { + gSpecialVar_Result = FALSE; + } +} + +void sub_815E948(void) +{ + s32 i; + u16 var_4001 = VarGet(VAR_0x4001); + u8 r1 = gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[var_4001].unk_00B; + + for (i = 0; i < NELEMS(gUnknown_847A074); i++) + { + if (gUnknown_847A074[i].unk0 == gFacilityClassToTrainerClass[r1]) + break; + } + if (i != NELEMS(gUnknown_847A074)) + { + var_4001 = gUnknown_847A074[i].unk1; + } + else + { + var_4001 = 0; + } + PlayNewMapMusic(gUnknown_847A2D2[var_4001]); +} + +void sub_815E9C8(void) +{ + gSpecialVar_Result = gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_2; +} + +void sub_815E9FC(void) +{ + u16 r4 = VarGet(VAR_0x4001); + s32 r9 = GetPartyMaxLevel(); + u8 r5 = gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk8; + s32 r6; + u8 r2; + + ZeroEnemyPartyMons(); + + switch (gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_002) + { + case 0: + default: + for (r6 = 0; r6 < 2; r6++) + { + r2 = gUnknown_847A2EE[r5][r6]; + gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_040[r2].level = r9; + sub_803E0A4(&gEnemyParty[r6], &gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_040[r2]); + } + break; + case 1: + r2 = gUnknown_847A2FE[r5][0]; + gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[0].unk_040[r2].level = r9; + sub_803E0A4(&gEnemyParty[0], &gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[0].unk_040[r2]); + r2 = gUnknown_847A2FE[r5][1]; + gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[1].unk_040[r2].level = r9; + sub_803E0A4(&gEnemyParty[1], &gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[1].unk_040[r2]); + break; + case 2: + r2 = gUnknown_847A30E[r5][r4]; + gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_040[r2].level = r9; + sub_803E0A4(&gEnemyParty[0], &gUnknown_203F458->unk_0004.trainers[gUnknown_203F458->unk_0000].unk_004[r4].unk_040[r2]); + break; + } +} + +static s32 GetPartyMaxLevel(void) +{ + s32 topLevel = 0; + s32 i; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL) != 0 && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2, NULL) != SPECIES_EGG) + { + s32 currLevel = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL, NULL); + if (currLevel > topLevel) + topLevel = currLevel; + } + } + + return topLevel; +} + +void sub_815EC0C(void) +{ + if (gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk9 != gUnknown_203F458->unk_0004.id) + { + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk9 = gUnknown_203F458->unk_0004.id; + sub_815EDF4(&gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unk4, 215999); + gSaveBlock1Ptr->unkArray[gSaveBlock1Ptr->unkArrayIdx].unkA_0 = FALSE; + } +} + +void sub_815EC8C(void) +{ + s32 i; + u8 windowId = 0; + + sub_815DC8C(); + FillWindowPixelRect(0, 0, 0, 0, 0xd8, 0x90); + sub_815EC0C(); + AddTextPrinterParameterized3(0, 2, 0x4a, 0, &gUnknown_847A22C, 0, gUnknown_83FE982); + + for (i = 0; i < 4; i++) + { + PRINT_TOWER_TIME(sub_815EDDC(&gSaveBlock1Ptr->unkArray[i].unk4)); + StringExpandPlaceholders(gStringVar4, gUnknown_83FE998); + AddTextPrinterParameterized3(windowId, 2, 0x18, 0x24 + 0x14 * i, &gUnknown_847A22C, 0, gUnknown_83FE9C4[i]); + AddTextPrinterParameterized3(windowId, 2, 0x60, 0x24 + 0x14 * i, &gUnknown_847A22C, 0, gStringVar4); + } + + PutWindowTilemap(windowId); + CopyWindowToVram(windowId, 3); + sub_815DD2C(); +} + +u32 sub_815EDDC(u32 * counter) +{ + return *counter ^ gSaveBlock2Ptr->encryptionKey; +} + +void sub_815EDF4(u32 * counter, u32 value) +{ + *counter = value ^ gSaveBlock2Ptr->encryptionKey; +} + +void sub_815EE0C(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + sub_815EDF4(&gSaveBlock1Ptr->unkArray[i].unk4, 215999); + } +} diff --git a/src/trig.c b/src/trig.c new file mode 100644 index 000000000..c2bca3059 --- /dev/null +++ b/src/trig.c @@ -0,0 +1,543 @@ +#include "global.h" +#include "trig.h" + +// Values of sin(x*(π/128)) as Q8.8 fixed-point numbers from x = 0 to x = 319 +const s16 gSineTable[] = +{ + Q_8_8(0), // sin(0*(π/128)) + Q_8_8(0.0234375), // sin(1*(π/128)) + Q_8_8(0.046875), // sin(2*(π/128)) + Q_8_8(0.0703125), // sin(3*(π/128)) + Q_8_8(0.09765625), // sin(4*(π/128)) + Q_8_8(0.12109375), // sin(5*(π/128)) + Q_8_8(0.14453125), // sin(6*(π/128)) + Q_8_8(0.16796875), // sin(7*(π/128)) + Q_8_8(0.19140625), // sin(8*(π/128)) + Q_8_8(0.21875), // sin(9*(π/128)) + Q_8_8(0.2421875), // sin(10*(π/128)) + Q_8_8(0.265625), // sin(11*(π/128)) + Q_8_8(0.2890625), // sin(12*(π/128)) + Q_8_8(0.3125), // sin(13*(π/128)) + Q_8_8(0.3359375), // sin(14*(π/128)) + Q_8_8(0.359375), // sin(15*(π/128)) + Q_8_8(0.37890625), // sin(16*(π/128)) + Q_8_8(0.40234375), // sin(17*(π/128)) + Q_8_8(0.42578125), // sin(18*(π/128)) + Q_8_8(0.44921875), // sin(19*(π/128)) + Q_8_8(0.46875), // sin(20*(π/128)) + Q_8_8(0.4921875), // sin(21*(π/128)) + Q_8_8(0.51171875), // sin(22*(π/128)) + Q_8_8(0.53125), // sin(23*(π/128)) + Q_8_8(0.5546875), // sin(24*(π/128)) + Q_8_8(0.57421875), // sin(25*(π/128)) + Q_8_8(0.59375), // sin(26*(π/128)) + Q_8_8(0.61328125), // sin(27*(π/128)) + Q_8_8(0.6328125), // sin(28*(π/128)) + Q_8_8(0.65234375), // sin(29*(π/128)) + Q_8_8(0.66796875), // sin(30*(π/128)) + Q_8_8(0.6875), // sin(31*(π/128)) + Q_8_8(0.70703125), // sin(32*(π/128)) + Q_8_8(0.72265625), // sin(33*(π/128)) + Q_8_8(0.73828125), // sin(34*(π/128)) + Q_8_8(0.75390625), // sin(35*(π/128)) + Q_8_8(0.76953125), // sin(36*(π/128)) + Q_8_8(0.78515625), // sin(37*(π/128)) + Q_8_8(0.80078125), // sin(38*(π/128)) + Q_8_8(0.81640625), // sin(39*(π/128)) + Q_8_8(0.828125), // sin(40*(π/128)) + Q_8_8(0.84375), // sin(41*(π/128)) + Q_8_8(0.85546875), // sin(42*(π/128)) + Q_8_8(0.8671875), // sin(43*(π/128)) + Q_8_8(0.87890625), // sin(44*(π/128)) + Q_8_8(0.890625), // sin(45*(π/128)) + Q_8_8(0.90234375), // sin(46*(π/128)) + Q_8_8(0.9140625), // sin(47*(π/128)) + Q_8_8(0.921875), // sin(48*(π/128)) + Q_8_8(0.9296875), // sin(49*(π/128)) + Q_8_8(0.94140625), // sin(50*(π/128)) + Q_8_8(0.94921875), // sin(51*(π/128)) + Q_8_8(0.953125), // sin(52*(π/128)) + Q_8_8(0.9609375), // sin(53*(π/128)) + Q_8_8(0.96875), // sin(54*(π/128)) + Q_8_8(0.97265625), // sin(55*(π/128)) + Q_8_8(0.98046875), // sin(56*(π/128)) + Q_8_8(0.984375), // sin(57*(π/128)) + Q_8_8(0.98828125), // sin(58*(π/128)) + Q_8_8(0.9921875), // sin(59*(π/128)) + Q_8_8(0.9921875), // sin(60*(π/128)) + Q_8_8(0.99609375), // sin(61*(π/128)) + Q_8_8(0.99609375), // sin(62*(π/128)) + Q_8_8(0.99609375), // sin(63*(π/128)) + Q_8_8(1), // sin(64*(π/128)) + Q_8_8(0.99609375), // sin(65*(π/128)) + Q_8_8(0.99609375), // sin(66*(π/128)) + Q_8_8(0.99609375), // sin(67*(π/128)) + Q_8_8(0.9921875), // sin(68*(π/128)) + Q_8_8(0.9921875), // sin(69*(π/128)) + Q_8_8(0.98828125), // sin(70*(π/128)) + Q_8_8(0.984375), // sin(71*(π/128)) + Q_8_8(0.98046875), // sin(72*(π/128)) + Q_8_8(0.97265625), // sin(73*(π/128)) + Q_8_8(0.96875), // sin(74*(π/128)) + Q_8_8(0.9609375), // sin(75*(π/128)) + Q_8_8(0.953125), // sin(76*(π/128)) + Q_8_8(0.94921875), // sin(77*(π/128)) + Q_8_8(0.94140625), // sin(78*(π/128)) + Q_8_8(0.9296875), // sin(79*(π/128)) + Q_8_8(0.921875), // sin(80*(π/128)) + Q_8_8(0.9140625), // sin(81*(π/128)) + Q_8_8(0.90234375), // sin(82*(π/128)) + Q_8_8(0.890625), // sin(83*(π/128)) + Q_8_8(0.87890625), // sin(84*(π/128)) + Q_8_8(0.8671875), // sin(85*(π/128)) + Q_8_8(0.85546875), // sin(86*(π/128)) + Q_8_8(0.84375), // sin(87*(π/128)) + Q_8_8(0.828125), // sin(88*(π/128)) + Q_8_8(0.81640625), // sin(89*(π/128)) + Q_8_8(0.80078125), // sin(90*(π/128)) + Q_8_8(0.78515625), // sin(91*(π/128)) + Q_8_8(0.76953125), // sin(92*(π/128)) + Q_8_8(0.75390625), // sin(93*(π/128)) + Q_8_8(0.73828125), // sin(94*(π/128)) + Q_8_8(0.72265625), // sin(95*(π/128)) + Q_8_8(0.70703125), // sin(96*(π/128)) + Q_8_8(0.6875), // sin(97*(π/128)) + Q_8_8(0.66796875), // sin(98*(π/128)) + Q_8_8(0.65234375), // sin(99*(π/128)) + Q_8_8(0.6328125), // sin(100*(π/128)) + Q_8_8(0.61328125), // sin(101*(π/128)) + Q_8_8(0.59375), // sin(102*(π/128)) + Q_8_8(0.57421875), // sin(103*(π/128)) + Q_8_8(0.5546875), // sin(104*(π/128)) + Q_8_8(0.53125), // sin(105*(π/128)) + Q_8_8(0.51171875), // sin(106*(π/128)) + Q_8_8(0.4921875), // sin(107*(π/128)) + Q_8_8(0.46875), // sin(108*(π/128)) + Q_8_8(0.44921875), // sin(109*(π/128)) + Q_8_8(0.42578125), // sin(110*(π/128)) + Q_8_8(0.40234375), // sin(111*(π/128)) + Q_8_8(0.37890625), // sin(112*(π/128)) + Q_8_8(0.359375), // sin(113*(π/128)) + Q_8_8(0.3359375), // sin(114*(π/128)) + Q_8_8(0.3125), // sin(115*(π/128)) + Q_8_8(0.2890625), // sin(116*(π/128)) + Q_8_8(0.265625), // sin(117*(π/128)) + Q_8_8(0.2421875), // sin(118*(π/128)) + Q_8_8(0.21875), // sin(119*(π/128)) + Q_8_8(0.19140625), // sin(120*(π/128)) + Q_8_8(0.16796875), // sin(121*(π/128)) + Q_8_8(0.14453125), // sin(122*(π/128)) + Q_8_8(0.12109375), // sin(123*(π/128)) + Q_8_8(0.09765625), // sin(124*(π/128)) + Q_8_8(0.0703125), // sin(125*(π/128)) + Q_8_8(0.046875), // sin(126*(π/128)) + Q_8_8(0.0234375), // sin(127*(π/128)) + Q_8_8(0), // sin(128*(π/128)) + Q_8_8(-0.0234375), // sin(129*(π/128)) + Q_8_8(-0.046875), // sin(130*(π/128)) + Q_8_8(-0.0703125), // sin(131*(π/128)) + Q_8_8(-0.09765625), // sin(132*(π/128)) + Q_8_8(-0.12109375), // sin(133*(π/128)) + Q_8_8(-0.14453125), // sin(134*(π/128)) + Q_8_8(-0.16796875), // sin(135*(π/128)) + Q_8_8(-0.19140625), // sin(136*(π/128)) + Q_8_8(-0.21875), // sin(137*(π/128)) + Q_8_8(-0.2421875), // sin(138*(π/128)) + Q_8_8(-0.265625), // sin(139*(π/128)) + Q_8_8(-0.2890625), // sin(140*(π/128)) + Q_8_8(-0.3125), // sin(141*(π/128)) + Q_8_8(-0.3359375), // sin(142*(π/128)) + Q_8_8(-0.359375), // sin(143*(π/128)) + Q_8_8(-0.37890625), // sin(144*(π/128)) + Q_8_8(-0.40234375), // sin(145*(π/128)) + Q_8_8(-0.42578125), // sin(146*(π/128)) + Q_8_8(-0.44921875), // sin(147*(π/128)) + Q_8_8(-0.46875), // sin(148*(π/128)) + Q_8_8(-0.4921875), // sin(149*(π/128)) + Q_8_8(-0.51171875), // sin(150*(π/128)) + Q_8_8(-0.53125), // sin(151*(π/128)) + Q_8_8(-0.5546875), // sin(152*(π/128)) + Q_8_8(-0.57421875), // sin(153*(π/128)) + Q_8_8(-0.59375), // sin(154*(π/128)) + Q_8_8(-0.61328125), // sin(155*(π/128)) + Q_8_8(-0.6328125), // sin(156*(π/128)) + Q_8_8(-0.65234375), // sin(157*(π/128)) + Q_8_8(-0.66796875), // sin(158*(π/128)) + Q_8_8(-0.6875), // sin(159*(π/128)) + Q_8_8(-0.70703125), // sin(160*(π/128)) + Q_8_8(-0.72265625), // sin(161*(π/128)) + Q_8_8(-0.73828125), // sin(162*(π/128)) + Q_8_8(-0.75390625), // sin(163*(π/128)) + Q_8_8(-0.76953125), // sin(164*(π/128)) + Q_8_8(-0.78515625), // sin(165*(π/128)) + Q_8_8(-0.80078125), // sin(166*(π/128)) + Q_8_8(-0.81640625), // sin(167*(π/128)) + Q_8_8(-0.828125), // sin(168*(π/128)) + Q_8_8(-0.84375), // sin(169*(π/128)) + Q_8_8(-0.85546875), // sin(170*(π/128)) + Q_8_8(-0.8671875), // sin(171*(π/128)) + Q_8_8(-0.87890625), // sin(172*(π/128)) + Q_8_8(-0.890625), // sin(173*(π/128)) + Q_8_8(-0.90234375), // sin(174*(π/128)) + Q_8_8(-0.9140625), // sin(175*(π/128)) + Q_8_8(-0.921875), // sin(176*(π/128)) + Q_8_8(-0.9296875), // sin(177*(π/128)) + Q_8_8(-0.94140625), // sin(178*(π/128)) + Q_8_8(-0.94921875), // sin(179*(π/128)) + Q_8_8(-0.953125), // sin(180*(π/128)) + Q_8_8(-0.9609375), // sin(181*(π/128)) + Q_8_8(-0.96875), // sin(182*(π/128)) + Q_8_8(-0.97265625), // sin(183*(π/128)) + Q_8_8(-0.98046875), // sin(184*(π/128)) + Q_8_8(-0.984375), // sin(185*(π/128)) + Q_8_8(-0.98828125), // sin(186*(π/128)) + Q_8_8(-0.9921875), // sin(187*(π/128)) + Q_8_8(-0.9921875), // sin(188*(π/128)) + Q_8_8(-0.99609375), // sin(189*(π/128)) + Q_8_8(-0.99609375), // sin(190*(π/128)) + Q_8_8(-0.99609375), // sin(191*(π/128)) + Q_8_8(-1), // sin(192*(π/128)) + Q_8_8(-0.99609375), // sin(193*(π/128)) + Q_8_8(-0.99609375), // sin(194*(π/128)) + Q_8_8(-0.99609375), // sin(195*(π/128)) + Q_8_8(-0.9921875), // sin(196*(π/128)) + Q_8_8(-0.9921875), // sin(197*(π/128)) + Q_8_8(-0.98828125), // sin(198*(π/128)) + Q_8_8(-0.984375), // sin(199*(π/128)) + Q_8_8(-0.98046875), // sin(200*(π/128)) + Q_8_8(-0.97265625), // sin(201*(π/128)) + Q_8_8(-0.96875), // sin(202*(π/128)) + Q_8_8(-0.9609375), // sin(203*(π/128)) + Q_8_8(-0.953125), // sin(204*(π/128)) + Q_8_8(-0.94921875), // sin(205*(π/128)) + Q_8_8(-0.94140625), // sin(206*(π/128)) + Q_8_8(-0.9296875), // sin(207*(π/128)) + Q_8_8(-0.921875), // sin(208*(π/128)) + Q_8_8(-0.9140625), // sin(209*(π/128)) + Q_8_8(-0.90234375), // sin(210*(π/128)) + Q_8_8(-0.890625), // sin(211*(π/128)) + Q_8_8(-0.87890625), // sin(212*(π/128)) + Q_8_8(-0.8671875), // sin(213*(π/128)) + Q_8_8(-0.85546875), // sin(214*(π/128)) + Q_8_8(-0.84375), // sin(215*(π/128)) + Q_8_8(-0.828125), // sin(216*(π/128)) + Q_8_8(-0.81640625), // sin(217*(π/128)) + Q_8_8(-0.80078125), // sin(218*(π/128)) + Q_8_8(-0.78515625), // sin(219*(π/128)) + Q_8_8(-0.76953125), // sin(220*(π/128)) + Q_8_8(-0.75390625), // sin(221*(π/128)) + Q_8_8(-0.73828125), // sin(222*(π/128)) + Q_8_8(-0.72265625), // sin(223*(π/128)) + Q_8_8(-0.70703125), // sin(224*(π/128)) + Q_8_8(-0.6875), // sin(225*(π/128)) + Q_8_8(-0.66796875), // sin(226*(π/128)) + Q_8_8(-0.65234375), // sin(227*(π/128)) + Q_8_8(-0.6328125), // sin(228*(π/128)) + Q_8_8(-0.61328125), // sin(229*(π/128)) + Q_8_8(-0.59375), // sin(230*(π/128)) + Q_8_8(-0.57421875), // sin(231*(π/128)) + Q_8_8(-0.5546875), // sin(232*(π/128)) + Q_8_8(-0.53125), // sin(233*(π/128)) + Q_8_8(-0.51171875), // sin(234*(π/128)) + Q_8_8(-0.4921875), // sin(235*(π/128)) + Q_8_8(-0.46875), // sin(236*(π/128)) + Q_8_8(-0.44921875), // sin(237*(π/128)) + Q_8_8(-0.42578125), // sin(238*(π/128)) + Q_8_8(-0.40234375), // sin(239*(π/128)) + Q_8_8(-0.37890625), // sin(240*(π/128)) + Q_8_8(-0.359375), // sin(241*(π/128)) + Q_8_8(-0.3359375), // sin(242*(π/128)) + Q_8_8(-0.3125), // sin(243*(π/128)) + Q_8_8(-0.2890625), // sin(244*(π/128)) + Q_8_8(-0.265625), // sin(245*(π/128)) + Q_8_8(-0.2421875), // sin(246*(π/128)) + Q_8_8(-0.21875), // sin(247*(π/128)) + Q_8_8(-0.19140625), // sin(248*(π/128)) + Q_8_8(-0.16796875), // sin(249*(π/128)) + Q_8_8(-0.14453125), // sin(250*(π/128)) + Q_8_8(-0.12109375), // sin(251*(π/128)) + Q_8_8(-0.09765625), // sin(252*(π/128)) + Q_8_8(-0.0703125), // sin(253*(π/128)) + Q_8_8(-0.046875), // sin(254*(π/128)) + Q_8_8(-0.0234375), // sin(255*(π/128)) + Q_8_8(0), // sin(256*(π/128)) + Q_8_8(0.0234375), // sin(257*(π/128)) + Q_8_8(0.046875), // sin(258*(π/128)) + Q_8_8(0.0703125), // sin(259*(π/128)) + Q_8_8(0.09765625), // sin(260*(π/128)) + Q_8_8(0.12109375), // sin(261*(π/128)) + Q_8_8(0.14453125), // sin(262*(π/128)) + Q_8_8(0.16796875), // sin(263*(π/128)) + Q_8_8(0.19140625), // sin(264*(π/128)) + Q_8_8(0.21875), // sin(265*(π/128)) + Q_8_8(0.2421875), // sin(266*(π/128)) + Q_8_8(0.265625), // sin(267*(π/128)) + Q_8_8(0.2890625), // sin(268*(π/128)) + Q_8_8(0.3125), // sin(269*(π/128)) + Q_8_8(0.3359375), // sin(270*(π/128)) + Q_8_8(0.359375), // sin(271*(π/128)) + Q_8_8(0.37890625), // sin(272*(π/128)) + Q_8_8(0.40234375), // sin(273*(π/128)) + Q_8_8(0.42578125), // sin(274*(π/128)) + Q_8_8(0.44921875), // sin(275*(π/128)) + Q_8_8(0.46875), // sin(276*(π/128)) + Q_8_8(0.4921875), // sin(277*(π/128)) + Q_8_8(0.51171875), // sin(278*(π/128)) + Q_8_8(0.53125), // sin(279*(π/128)) + Q_8_8(0.5546875), // sin(280*(π/128)) + Q_8_8(0.57421875), // sin(281*(π/128)) + Q_8_8(0.59375), // sin(282*(π/128)) + Q_8_8(0.61328125), // sin(283*(π/128)) + Q_8_8(0.6328125), // sin(284*(π/128)) + Q_8_8(0.65234375), // sin(285*(π/128)) + Q_8_8(0.66796875), // sin(286*(π/128)) + Q_8_8(0.6875), // sin(287*(π/128)) + Q_8_8(0.70703125), // sin(288*(π/128)) + Q_8_8(0.72265625), // sin(289*(π/128)) + Q_8_8(0.73828125), // sin(290*(π/128)) + Q_8_8(0.75390625), // sin(291*(π/128)) + Q_8_8(0.76953125), // sin(292*(π/128)) + Q_8_8(0.78515625), // sin(293*(π/128)) + Q_8_8(0.80078125), // sin(294*(π/128)) + Q_8_8(0.81640625), // sin(295*(π/128)) + Q_8_8(0.828125), // sin(296*(π/128)) + Q_8_8(0.84375), // sin(297*(π/128)) + Q_8_8(0.85546875), // sin(298*(π/128)) + Q_8_8(0.8671875), // sin(299*(π/128)) + Q_8_8(0.87890625), // sin(300*(π/128)) + Q_8_8(0.890625), // sin(301*(π/128)) + Q_8_8(0.90234375), // sin(302*(π/128)) + Q_8_8(0.9140625), // sin(303*(π/128)) + Q_8_8(0.921875), // sin(304*(π/128)) + Q_8_8(0.9296875), // sin(305*(π/128)) + Q_8_8(0.94140625), // sin(306*(π/128)) + Q_8_8(0.94921875), // sin(307*(π/128)) + Q_8_8(0.953125), // sin(308*(π/128)) + Q_8_8(0.9609375), // sin(309*(π/128)) + Q_8_8(0.96875), // sin(310*(π/128)) + Q_8_8(0.97265625), // sin(311*(π/128)) + Q_8_8(0.98046875), // sin(312*(π/128)) + Q_8_8(0.984375), // sin(313*(π/128)) + Q_8_8(0.98828125), // sin(314*(π/128)) + Q_8_8(0.9921875), // sin(315*(π/128)) + Q_8_8(0.9921875), // sin(316*(π/128)) + Q_8_8(0.99609375), // sin(317*(π/128)) + Q_8_8(0.99609375), // sin(318*(π/128)) + Q_8_8(0.99609375), // sin(319*(π/128)) +}; + +// values of sin(x) as Q4.12 fixed-point numbers from x = 0° to x = 179° +const s16 gSineDegreeTable[] = +{ + Q_4_12(0), // sin(0°) + Q_4_12(0.017333984375), // sin(1°) + Q_4_12(0.034912109375), // sin(2°) + Q_4_12(0.05224609375), // sin(3°) + Q_4_12(0.06982421875), // sin(4°) + Q_4_12(0.087158203125), // sin(5°) + Q_4_12(0.1044921875), // sin(6°) + Q_4_12(0.121826171875), // sin(7°) + Q_4_12(0.13916015625), // sin(8°) + Q_4_12(0.156494140625), // sin(9°) + Q_4_12(0.173583984375), // sin(10°) + Q_4_12(0.19091796875), // sin(11°) + Q_4_12(0.2080078125), // sin(12°) + Q_4_12(0.224853515625), // sin(13°) + Q_4_12(0.241943359375), // sin(14°) + Q_4_12(0.2587890625), // sin(15°) + Q_4_12(0.275634765625), // sin(16°) + Q_4_12(0.29248046875), // sin(17°) + Q_4_12(0.30908203125), // sin(18°) + Q_4_12(0.32568359375), // sin(19°) + Q_4_12(0.342041015625), // sin(20°) + Q_4_12(0.3583984375), // sin(21°) + Q_4_12(0.37451171875), // sin(22°) + Q_4_12(0.390625), // sin(23°) + Q_4_12(0.40673828125), // sin(24°) + Q_4_12(0.422607421875), // sin(25°) + Q_4_12(0.4384765625), // sin(26°) + Q_4_12(0.4541015625), // sin(27°) + Q_4_12(0.469482421875), // sin(28°) + Q_4_12(0.48486328125), // sin(29°) + Q_4_12(0.5), // sin(30°) + Q_4_12(0.51513671875), // sin(31°) + Q_4_12(0.530029296875), // sin(32°) + Q_4_12(0.544677734375), // sin(33°) + Q_4_12(0.55908203125), // sin(34°) + Q_4_12(0.573486328125), // sin(35°) + Q_4_12(0.587890625), // sin(36°) + Q_4_12(0.601806640625), // sin(37°) + Q_4_12(0.61572265625), // sin(38°) + Q_4_12(0.62939453125), // sin(39°) + Q_4_12(0.642822265625), // sin(40°) + Q_4_12(0.656005859375), // sin(41°) + Q_4_12(0.669189453125), // sin(42°) + Q_4_12(0.681884765625), // sin(43°) + Q_4_12(0.694580078125), // sin(44°) + Q_4_12(0.70703125), // sin(45°) + Q_4_12(0.71923828125), // sin(46°) + Q_4_12(0.7314453125), // sin(47°) + Q_4_12(0.7431640625), // sin(48°) + Q_4_12(0.754638671875), // sin(49°) + Q_4_12(0.76611328125), // sin(50°) + Q_4_12(0.777099609375), // sin(51°) + Q_4_12(0.7880859375), // sin(52°) + Q_4_12(0.798583984375), // sin(53°) + Q_4_12(0.80908203125), // sin(54°) + Q_4_12(0.819091796875), // sin(55°) + Q_4_12(0.8291015625), // sin(56°) + Q_4_12(0.838623046875), // sin(57°) + Q_4_12(0.84814453125), // sin(58°) + Q_4_12(0.857177734375), // sin(59°) + Q_4_12(0.865966796875), // sin(60°) + Q_4_12(0.87451171875), // sin(61°) + Q_4_12(0.883056640625), // sin(62°) + Q_4_12(0.89111328125), // sin(63°) + Q_4_12(0.898681640625), // sin(64°) + Q_4_12(0.90625), // sin(65°) + Q_4_12(0.91357421875), // sin(66°) + Q_4_12(0.92041015625), // sin(67°) + Q_4_12(0.92724609375), // sin(68°) + Q_4_12(0.93359375), // sin(69°) + Q_4_12(0.939697265625), // sin(70°) + Q_4_12(0.945556640625), // sin(71°) + Q_4_12(0.951171875), // sin(72°) + Q_4_12(0.956298828125), // sin(73°) + Q_4_12(0.961181640625), // sin(74°) + Q_4_12(0.9658203125), // sin(75°) + Q_4_12(0.97021484375), // sin(76°) + Q_4_12(0.974365234375), // sin(77°) + Q_4_12(0.97802734375), // sin(78°) + Q_4_12(0.981689453125), // sin(79°) + Q_4_12(0.98486328125), // sin(80°) + Q_4_12(0.98779296875), // sin(81°) + Q_4_12(0.990234375), // sin(82°) + Q_4_12(0.992431640625), // sin(83°) + Q_4_12(0.994384765625), // sin(84°) + Q_4_12(0.99609375), // sin(85°) + Q_4_12(0.99755859375), // sin(86°) + Q_4_12(0.99853515625), // sin(87°) + Q_4_12(0.999267578125), // sin(88°) + Q_4_12(0.999755859375), // sin(89°) + Q_4_12(1), // sin(90°) + Q_4_12(0.999755859375), // sin(91°) + Q_4_12(0.999267578125), // sin(92°) + Q_4_12(0.99853515625), // sin(93°) + Q_4_12(0.99755859375), // sin(94°) + Q_4_12(0.99609375), // sin(95°) + Q_4_12(0.994384765625), // sin(96°) + Q_4_12(0.992431640625), // sin(97°) + Q_4_12(0.990234375), // sin(98°) + Q_4_12(0.98779296875), // sin(99°) + Q_4_12(0.98486328125), // sin(100°) + Q_4_12(0.981689453125), // sin(101°) + Q_4_12(0.97802734375), // sin(102°) + Q_4_12(0.974365234375), // sin(103°) + Q_4_12(0.97021484375), // sin(104°) + Q_4_12(0.9658203125), // sin(105°) + Q_4_12(0.961181640625), // sin(106°) + Q_4_12(0.956298828125), // sin(107°) + Q_4_12(0.951171875), // sin(108°) + Q_4_12(0.945556640625), // sin(109°) + Q_4_12(0.939697265625), // sin(110°) + Q_4_12(0.93359375), // sin(111°) + Q_4_12(0.92724609375), // sin(112°) + Q_4_12(0.92041015625), // sin(113°) + Q_4_12(0.91357421875), // sin(114°) + Q_4_12(0.90625), // sin(115°) + Q_4_12(0.898681640625), // sin(116°) + Q_4_12(0.89111328125), // sin(117°) + Q_4_12(0.883056640625), // sin(118°) + Q_4_12(0.87451171875), // sin(119°) + Q_4_12(0.865966796875), // sin(120°) + Q_4_12(0.857177734375), // sin(121°) + Q_4_12(0.84814453125), // sin(122°) + Q_4_12(0.838623046875), // sin(123°) + Q_4_12(0.8291015625), // sin(124°) + Q_4_12(0.819091796875), // sin(125°) + Q_4_12(0.80908203125), // sin(126°) + Q_4_12(0.798583984375), // sin(127°) + Q_4_12(0.7880859375), // sin(128°) + Q_4_12(0.777099609375), // sin(129°) + Q_4_12(0.76611328125), // sin(130°) + Q_4_12(0.754638671875), // sin(131°) + Q_4_12(0.7431640625), // sin(132°) + Q_4_12(0.7314453125), // sin(133°) + Q_4_12(0.71923828125), // sin(134°) + Q_4_12(0.70703125), // sin(135°) + Q_4_12(0.694580078125), // sin(136°) + Q_4_12(0.681884765625), // sin(137°) + Q_4_12(0.669189453125), // sin(138°) + Q_4_12(0.656005859375), // sin(139°) + Q_4_12(0.642822265625), // sin(140°) + Q_4_12(0.62939453125), // sin(141°) + Q_4_12(0.61572265625), // sin(142°) + Q_4_12(0.601806640625), // sin(143°) + Q_4_12(0.587890625), // sin(144°) + Q_4_12(0.573486328125), // sin(145°) + Q_4_12(0.55908203125), // sin(146°) + Q_4_12(0.544677734375), // sin(147°) + Q_4_12(0.530029296875), // sin(148°) + Q_4_12(0.51513671875), // sin(149°) + Q_4_12(0.5), // sin(150°) + Q_4_12(0.48486328125), // sin(151°) + Q_4_12(0.469482421875), // sin(152°) + Q_4_12(0.4541015625), // sin(153°) + Q_4_12(0.4384765625), // sin(154°) + Q_4_12(0.422607421875), // sin(155°) + Q_4_12(0.40673828125), // sin(156°) + Q_4_12(0.390625), // sin(157°) + Q_4_12(0.37451171875), // sin(158°) + Q_4_12(0.3583984375), // sin(159°) + Q_4_12(0.342041015625), // sin(160°) + Q_4_12(0.32568359375), // sin(161°) + Q_4_12(0.30908203125), // sin(162°) + Q_4_12(0.29248046875), // sin(163°) + Q_4_12(0.275634765625), // sin(164°) + Q_4_12(0.2587890625), // sin(165°) + Q_4_12(0.241943359375), // sin(166°) + Q_4_12(0.224853515625), // sin(167°) + Q_4_12(0.2080078125), // sin(168°) + Q_4_12(0.19091796875), // sin(169°) + Q_4_12(0.173583984375), // sin(170°) + Q_4_12(0.156494140625), // sin(171°) + Q_4_12(0.13916015625), // sin(172°) + Q_4_12(0.121826171875), // sin(173°) + Q_4_12(0.1044921875), // sin(174°) + Q_4_12(0.087158203125), // sin(175°) + Q_4_12(0.06982421875), // sin(176°) + Q_4_12(0.05224609375), // sin(177°) + Q_4_12(0.034912109375), // sin(178°) + Q_4_12(0.017333984375), // sin(179°) +}; + +// amplitude * sin(index*(π/128)) +s16 Sin(s16 index, s16 amplitude) +{ + return (amplitude * gSineTable[index]) >> 8; +} + +// amplitude * cos(index*(π/128)) +s16 Cos(s16 index, s16 amplitude) +{ + return (amplitude * gSineTable[index + 64]) >> 8; +} + +// angle in degrees +s16 Sin2(u16 angle) +{ + s32 angleMod = angle % 180; + s32 negate = ((angle / 180) & 1); + s16 value = gSineDegreeTable[angleMod]; + + if (negate) + return -value; + else + return value; +} + +// angle in degrees +s16 Cos2(u16 angle) +{ + return Sin2(angle + 90); +} diff --git a/src/unk_8159F40.c b/src/unk_8159F40.c new file mode 100644 index 000000000..a6f6e67fc --- /dev/null +++ b/src/unk_8159F40.c @@ -0,0 +1,622 @@ +#include "global.h" +#include "battle.h" +#include "event_data.h" +#include "quest_log.h" +#include "fieldmap.h" +#include "field_player_avatar.h" +#include "metatile_behavior.h" +#include "link.h" +#include "link_rfu.h" + +struct UnkStruct_84792D0 +{ + u8 field_0; + u8 field_1; + u16 field_2; + u16 field_4[4]; + u8 field_C; + u8 field_D; +}; + +extern const struct UnkStruct_84792D0 *const gUnknown_84792D0[]; + +void sub_8159F40(void) +{ + s32 i, j; + struct Pokemon *mon; + s32 myIdx = 0; + s32 opIdx = 0; + const struct UnkStruct_84792D0 * data; + + gBattleTypeFlags = BATTLE_TYPE_DOME; + ZeroPlayerPartyMons(); + ZeroEnemyPartyMons(); + data = gUnknown_84792D0[gSpecialVar_0x8004]; + + i = 0; + do + { + if (data[i].field_0 == 0) + { + mon = &gPlayerParty[myIdx]; + myIdx++; + } + else + { + mon = &gEnemyParty[opIdx]; + opIdx++; + } + CreateMonWithGenderNatureLetter(mon, data[i].field_2, data[i].field_1, 0, data[i].field_D, data[i].field_C, 0); + for (j = 0; j < 4; j++) + { + SetMonMoveSlot(mon, data[i].field_4[j], j); + } + i++; + } while (data[i].field_0 != 0xFF); +} + +void sub_815A008(struct QuestLog * questLog) +{ + u32 i; + + for (i = 0; i < MAP_OBJECTS_COUNT; i++) + { + questLog->unk_008[i].active = gMapObjects[i].active; + questLog->unk_008[i].mapobj_bit_3 = gMapObjects[i].mapobj_bit_3; + questLog->unk_008[i].mapobj_bit_4 = gMapObjects[i].mapobj_bit_4; + questLog->unk_008[i].mapobj_bit_5 = gMapObjects[i].mapobj_bit_5; + questLog->unk_008[i].mapobj_bit_8 = gMapObjects[i].mapobj_bit_8; + questLog->unk_008[i].mapobj_bit_9 = gMapObjects[i].mapobj_bit_9; + questLog->unk_008[i].mapobj_bit_10 = gMapObjects[i].mapobj_bit_10; + questLog->unk_008[i].mapobj_bit_11 = gMapObjects[i].mapobj_bit_11; + questLog->unk_008[i].mapobj_bit_12 = gMapObjects[i].mapobj_bit_12; + questLog->unk_008[i].mapobj_bit_13 = gMapObjects[i].mapobj_bit_13; + questLog->unk_008[i].mapobj_bit_14 = gMapObjects[i].mapobj_bit_14; + questLog->unk_008[i].mapobj_bit_15 = gMapObjects[i].mapobj_bit_15; + questLog->unk_008[i].mapobj_bit_16 = gMapObjects[i].mapobj_bit_16; + questLog->unk_008[i].mapobj_bit_23 = gMapObjects[i].mapobj_bit_23; + questLog->unk_008[i].mapobj_bit_24 = gMapObjects[i].mapobj_bit_24; + questLog->unk_008[i].mapobj_bit_25 = gMapObjects[i].mapobj_bit_25; + questLog->unk_008[i].mapobj_bit_26 = gMapObjects[i].mapobj_bit_26; + questLog->unk_008[i].mapobj_unk_18 = gMapObjects[i].mapobj_unk_18; + questLog->unk_008[i].mapobj_unk_0B_0 = gMapObjects[i].mapobj_unk_0B_0; + questLog->unk_008[i].elevation = gMapObjects[i].elevation; + questLog->unk_008[i].graphicsId = gMapObjects[i].graphicsId; + questLog->unk_008[i].animPattern = gMapObjects[i].animPattern; + questLog->unk_008[i].trainerType = gMapObjects[i].trainerType; + questLog->unk_008[i].localId = gMapObjects[i].localId; + questLog->unk_008[i].mapNum = gMapObjects[i].mapNum; + questLog->unk_008[i].mapGroup = gMapObjects[i].mapGroup; + questLog->unk_008[i].x = gMapObjects[i].coords2.x; + questLog->unk_008[i].y = gMapObjects[i].coords2.y; + questLog->unk_008[i].trainerRange_berryTreeId = gMapObjects[i].trainerRange_berryTreeId; + questLog->unk_008[i].mapobj_unk_1F = gMapObjects[i].mapobj_unk_1F; + questLog->unk_008[i].mapobj_unk_21 = gMapObjects[i].mapobj_unk_21; + questLog->unk_008[i].animId = gMapObjects[i].animId; + } +} + +#ifdef NONMATCHING +void sub_815A1F8(const struct QuestLog * questLog, const struct MapObjectTemplate * templates) +{ + u32 i, j; + const struct QuestLogMapObject * questLogMapObjects = questLog->unk_008; + + CpuFill16(0, gMapObjects, sizeof(gMapObjects)); + + for (i = 0; i < MAP_OBJECTS_COUNT; i++) + { + gMapObjects[i].active = questLogMapObjects[i].active; + gMapObjects[i].mapobj_bit_3 = questLogMapObjects[i].mapobj_bit_3; + gMapObjects[i].mapobj_bit_4 = questLogMapObjects[i].mapobj_bit_4; + gMapObjects[i].mapobj_bit_5 = questLogMapObjects[i].mapobj_bit_5; + gMapObjects[i].mapobj_bit_8 = questLogMapObjects[i].mapobj_bit_8; + gMapObjects[i].mapobj_bit_9 = questLogMapObjects[i].mapobj_bit_9; + gMapObjects[i].mapobj_bit_10 = questLogMapObjects[i].mapobj_bit_10; + gMapObjects[i].mapobj_bit_11 = questLogMapObjects[i].mapobj_bit_11; + gMapObjects[i].mapobj_bit_12 = questLogMapObjects[i].mapobj_bit_12; + gMapObjects[i].mapobj_bit_13 = questLogMapObjects[i].mapobj_bit_13; + gMapObjects[i].mapobj_bit_14 = questLogMapObjects[i].mapobj_bit_14; + gMapObjects[i].mapobj_bit_15 = questLogMapObjects[i].mapobj_bit_15; + gMapObjects[i].mapobj_bit_16 = questLogMapObjects[i].mapobj_bit_16; + gMapObjects[i].mapobj_bit_23 = questLogMapObjects[i].mapobj_bit_23; + gMapObjects[i].mapobj_bit_24 = questLogMapObjects[i].mapobj_bit_24; + gMapObjects[i].mapobj_bit_25 = questLogMapObjects[i].mapobj_bit_25; + gMapObjects[i].mapobj_bit_26 = questLogMapObjects[i].mapobj_bit_26; + gMapObjects[i].mapobj_unk_18 = questLogMapObjects[i].mapobj_unk_18; + gMapObjects[i].mapobj_unk_0B_0 = questLogMapObjects[i].mapobj_unk_0B_0; + gMapObjects[i].elevation = questLogMapObjects[i].elevation; + gMapObjects[i].graphicsId = questLogMapObjects[i].graphicsId; + gMapObjects[i].animPattern = questLogMapObjects[i].animPattern; + gMapObjects[i].trainerType = questLogMapObjects[i].trainerType; + gMapObjects[i].localId = questLogMapObjects[i].localId; + gMapObjects[i].mapNum = questLogMapObjects[i].mapNum; + gMapObjects[i].mapGroup = questLogMapObjects[i].mapGroup; + gMapObjects[i].coords2.x = questLogMapObjects[i].x; + gMapObjects[i].coords2.y = questLogMapObjects[i].y; + gMapObjects[i].trainerRange_berryTreeId = questLogMapObjects[i].trainerRange_berryTreeId; + gMapObjects[i].mapobj_unk_1F = questLogMapObjects[i].mapobj_unk_1F; + gMapObjects[i].mapobj_unk_21 = questLogMapObjects[i].mapobj_unk_21; + gMapObjects[i].animId = questLogMapObjects[i].animId; + + for (j = 0; j < 0x40; j++) + { + if (gMapObjects[i].localId == templates[j].localId) + { + gMapObjects[i].coords1.x = templates[j].x + 7; + gMapObjects[i].coords1.y = templates[j].y + 7; + gMapObjects[i].range.as_nybbles.x = templates[j].range.as_nybbles.x; + gMapObjects[i].range.as_nybbles.y = templates[j].range.as_nybbles.y; + } + } + + gMapObjects[i].mapobj_unk_1E = MapGridGetMetatileBehaviorAt(gMapObjects[i].coords2.x, gMapObjects[i].coords2.y); + if (gMapObjects[i].mapobj_unk_1F == MapGridGetMetatileBehaviorAt((s16)(gMapObjects[i].coords2.x), (s16)(gMapObjects[i].coords2.y))) + { + gMapObjects[i].coords3.x = gMapObjects[i].coords2.x; + gMapObjects[i].coords3.y = gMapObjects[i].coords2.y; + } + else if (gMapObjects[i].mapobj_unk_1F == MapGridGetMetatileBehaviorAt((s16)(gMapObjects[i].coords2.x - 1), (s16)(gMapObjects[i].coords2.y))) + { + gMapObjects[i].coords3.x = gMapObjects[i].coords2.x - 1; + gMapObjects[i].coords3.y = gMapObjects[i].coords2.y; + } + else if (gMapObjects[i].mapobj_unk_1F == MapGridGetMetatileBehaviorAt((s16)(gMapObjects[i].coords2.x + 1), (s16)(gMapObjects[i].coords2.y))) + { + gMapObjects[i].coords3.x = gMapObjects[i].coords2.x + 1; + gMapObjects[i].coords3.y = gMapObjects[i].coords2.y; + } + else if (gMapObjects[i].mapobj_unk_1F == MapGridGetMetatileBehaviorAt((s16)(gMapObjects[i].coords2.x), (s16)(gMapObjects[i].coords2.y - 1))) + { + gMapObjects[i].coords3.x = gMapObjects[i].coords2.x; + gMapObjects[i].coords3.y = gMapObjects[i].coords2.y - 1; + } + else if (gMapObjects[i].mapobj_unk_1F == MapGridGetMetatileBehaviorAt((s16)(gMapObjects[i].coords2.x), (s16)(gMapObjects[i].coords2.y + 1))) + { + gMapObjects[i].coords3.x = gMapObjects[i].coords2.x; + gMapObjects[i].coords3.y = gMapObjects[i].coords2.y + 1; + } + } + + CpuCopy16(gMapObjects, gSaveBlock1Ptr->mapObjects, sizeof(gMapObjects)); +} +#else +NAKED +void sub_815A1F8(const struct QuestLog * questLog, const struct MapObjectTemplate * templates) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tmov r7, r10\n" + "\tmov r6, r9\n" + "\tmov r5, r8\n" + "\tpush {r5-r7}\n" + "\tsub sp, 0x10\n" + "\tstr r1, [sp, 0x4]\n" + "\tadds r0, 0x8\n" + "\tstr r0, [sp, 0x8]\n" + "\tmov r1, sp\n" + "\tmovs r0, 0\n" + "\tstrh r0, [r1]\n" + "\tldr r4, _0815A480 @ =gMapObjects\n" + "\tldr r2, _0815A484 @ =0x01000120\n" + "\tmov r0, sp\n" + "\tadds r1, r4, 0\n" + "\tbl CpuSet\n" + "\tmovs r0, 0\n" + "\tmov r12, r0\n" + "\tmovs r1, 0x1\n" + "\tmov r10, r1\n" + "_0815A224:\n" + "\tmov r2, r12\n" + "\tlsls r7, r2, 3\n" + "\tadds r5, r7, r2\n" + "\tlsls r5, 2\n" + "\tldr r0, _0815A480 @ =gMapObjects\n" + "\tadds r5, r0\n" + "\tlsls r6, r2, 2\n" + "\tadd r6, r12\n" + "\tlsls r6, 2\n" + "\tldr r1, [sp, 0x8]\n" + "\tadds r6, r1\n" + "\tldrb r0, [r6]\n" + "\tlsls r0, 31\n" + "\tlsrs r0, 31\n" + "\tmov r2, r10\n" + "\tands r0, r2\n" + "\tldrb r2, [r5]\n" + "\tmovs r1, 0x2\n" + "\tnegs r1, r1\n" + "\tands r1, r2\n" + "\torrs r1, r0\n" + "\tstrb r1, [r5]\n" + "\tldrb r0, [r6]\n" + "\tlsls r0, 30\n" + "\tlsrs r0, 31\n" + "\tmov r2, r10\n" + "\tands r0, r2\n" + "\tlsls r0, 3\n" + "\tmovs r2, 0x9\n" + "\tnegs r2, r2\n" + "\tands r2, r1\n" + "\torrs r2, r0\n" + "\tstrb r2, [r5]\n" + "\tldrb r0, [r6]\n" + "\tlsls r0, 29\n" + "\tlsrs r0, 31\n" + "\tmov r1, r10\n" + "\tands r0, r1\n" + "\tlsls r0, 4\n" + "\tmovs r1, 0x11\n" + "\tnegs r1, r1\n" + "\tands r1, r2\n" + "\torrs r1, r0\n" + "\tstrb r1, [r5]\n" + "\tldrb r0, [r6]\n" + "\tlsls r0, 28\n" + "\tlsrs r0, 31\n" + "\tmov r2, r10\n" + "\tands r0, r2\n" + "\tlsls r0, 5\n" + "\tmovs r4, 0x21\n" + "\tnegs r4, r4\n" + "\tands r1, r4\n" + "\torrs r1, r0\n" + "\tstrb r1, [r5]\n" + "\tldrb r0, [r6]\n" + "\tlsls r0, 27\n" + "\tlsrs r0, 31\n" + "\tands r0, r2\n" + "\tldrb r1, [r5, 0x1]\n" + "\tmovs r2, 0x2\n" + "\tnegs r2, r2\n" + "\tands r2, r1\n" + "\torrs r2, r0\n" + "\tstrb r2, [r5, 0x1]\n" + "\tldrb r0, [r6]\n" + "\tlsls r0, 26\n" + "\tlsrs r0, 31\n" + "\tmov r1, r10\n" + "\tands r0, r1\n" + "\tlsls r0, 1\n" + "\tmovs r1, 0x3\n" + "\tnegs r1, r1\n" + "\tmov r8, r1\n" + "\tmov r3, r8\n" + "\tands r3, r2\n" + "\torrs r3, r0\n" + "\tstrb r3, [r5, 0x1]\n" + "\tldrb r0, [r6]\n" + "\tlsls r0, 25\n" + "\tlsrs r0, 31\n" + "\tmov r2, r10\n" + "\tands r0, r2\n" + "\tlsls r0, 2\n" + "\tsubs r1, 0x2\n" + "\tmov r9, r1\n" + "\tands r1, r3\n" + "\torrs r1, r0\n" + "\tstrb r1, [r5, 0x1]\n" + "\tldrb r0, [r6]\n" + "\tlsrs r0, 7\n" + "\tands r0, r2\n" + "\tlsls r0, 3\n" + "\tmovs r2, 0x9\n" + "\tnegs r2, r2\n" + "\tands r2, r1\n" + "\torrs r2, r0\n" + "\tstrb r2, [r5, 0x1]\n" + "\tldrb r0, [r6, 0x1]\n" + "\tlsls r0, 31\n" + "\tlsrs r0, 31\n" + "\tmov r1, r10\n" + "\tands r0, r1\n" + "\tlsls r0, 4\n" + "\tmovs r1, 0x11\n" + "\tnegs r1, r1\n" + "\tands r1, r2\n" + "\torrs r1, r0\n" + "\tstrb r1, [r5, 0x1]\n" + "\tldrb r0, [r6, 0x1]\n" + "\tlsls r0, 30\n" + "\tlsrs r0, 31\n" + "\tmov r2, r10\n" + "\tands r0, r2\n" + "\tlsls r0, 5\n" + "\tands r4, r1\n" + "\torrs r4, r0\n" + "\tstrb r4, [r5, 0x1]\n" + "\tldrb r0, [r6, 0x1]\n" + "\tlsls r0, 29\n" + "\tlsrs r0, 31\n" + "\tands r0, r2\n" + "\tlsls r0, 6\n" + "\tmovs r2, 0x41\n" + "\tnegs r2, r2\n" + "\tadds r1, r2, 0\n" + "\tands r4, r1\n" + "\torrs r4, r0\n" + "\tstrb r4, [r5, 0x1]\n" + "\tldrb r0, [r6, 0x1]\n" + "\tlsls r0, 28\n" + "\tlsrs r0, 31\n" + "\tlsls r0, 7\n" + "\tmovs r3, 0x7F\n" + "\tands r4, r3\n" + "\torrs r4, r0\n" + "\tstrb r4, [r5, 0x1]\n" + "\tldrb r0, [r6, 0x1]\n" + "\tlsls r0, 27\n" + "\tlsrs r0, 31\n" + "\tmov r1, r10\n" + "\tands r0, r1\n" + "\tldrb r2, [r5, 0x2]\n" + "\tmovs r1, 0x2\n" + "\tnegs r1, r1\n" + "\tands r1, r2\n" + "\torrs r1, r0\n" + "\tstrb r1, [r5, 0x2]\n" + "\tldrb r0, [r6, 0x1]\n" + "\tlsls r0, 26\n" + "\tlsrs r0, 31\n" + "\tlsls r0, 7\n" + "\tands r1, r3\n" + "\torrs r1, r0\n" + "\tstrb r1, [r5, 0x2]\n" + "\tldrb r0, [r6, 0x1]\n" + "\tlsls r0, 25\n" + "\tlsrs r0, 31\n" + "\tmov r2, r10\n" + "\tands r0, r2\n" + "\tldrb r2, [r5, 0x3]\n" + "\tmovs r1, 0x2\n" + "\tnegs r1, r1\n" + "\tands r1, r2\n" + "\torrs r1, r0\n" + "\tstrb r1, [r5, 0x3]\n" + "\tldrb r0, [r6, 0x1]\n" + "\tlsrs r0, 7\n" + "\tmov r2, r10\n" + "\tands r0, r2\n" + "\tlsls r0, 1\n" + "\tmov r2, r8\n" + "\tands r2, r1\n" + "\torrs r2, r0\n" + "\tmov r8, r2\n" + "\tstrb r2, [r5, 0x3]\n" + "\tldrb r0, [r6, 0x2]\n" + "\tlsls r0, 31\n" + "\tlsrs r0, 31\n" + "\tmov r1, r10\n" + "\tands r0, r1\n" + "\tlsls r0, 2\n" + "\tmov r1, r9\n" + "\tands r2, r1\n" + "\torrs r2, r0\n" + "\tstrb r2, [r5, 0x3]\n" + "\tldrb r1, [r6, 0x2]\n" + "\tlsls r1, 27\n" + "\tlsrs r1, 28\n" + "\tldrb r2, [r5, 0x18]\n" + "\tmovs r4, 0x10\n" + "\tnegs r4, r4\n" + "\tadds r0, r4, 0\n" + "\tands r0, r2\n" + "\torrs r0, r1\n" + "\tstrb r0, [r5, 0x18]\n" + "\tldrb r1, [r6, 0x3]\n" + "\tlsls r1, 28\n" + "\tmovs r3, 0xF\n" + "\tlsrs r1, 28\n" + "\tldrb r2, [r5, 0xB]\n" + "\tadds r0, r4, 0\n" + "\tands r0, r2\n" + "\torrs r0, r1\n" + "\tstrb r0, [r5, 0xB]\n" + "\tldrb r1, [r6, 0x3]\n" + "\tlsrs r1, 4\n" + "\tlsls r1, 4\n" + "\tands r0, r3\n" + "\torrs r0, r1\n" + "\tstrb r0, [r5, 0xB]\n" + "\tldrb r0, [r6, 0x4]\n" + "\tstrb r0, [r5, 0x5]\n" + "\tldrb r0, [r6, 0x5]\n" + "\tstrb r0, [r5, 0x6]\n" + "\tldrb r0, [r6, 0x6]\n" + "\tstrb r0, [r5, 0x7]\n" + "\tldrb r0, [r6, 0x7]\n" + "\tstrb r0, [r5, 0x8]\n" + "\tldrb r0, [r6, 0x8]\n" + "\tstrb r0, [r5, 0x9]\n" + "\tldrb r0, [r6, 0x9]\n" + "\tstrb r0, [r5, 0xA]\n" + "\tldrh r0, [r6, 0xA]\n" + "\tstrh r0, [r5, 0x10]\n" + "\tldrh r0, [r6, 0xC]\n" + "\tstrh r0, [r5, 0x12]\n" + "\tldrb r0, [r6, 0xE]\n" + "\tstrb r0, [r5, 0x1D]\n" + "\tldrb r0, [r6, 0xF]\n" + "\tstrb r0, [r5, 0x1F]\n" + "\tldrb r0, [r6, 0x10]\n" + "\tadds r1, r5, 0\n" + "\tadds r1, 0x21\n" + "\tstrb r0, [r1]\n" + "\tldrb r0, [r6, 0x11]\n" + "\tadds r1, 0x1\n" + "\tstrb r0, [r1]\n" + "\tmovs r6, 0\n" + "\tmov r8, r7\n" + "\tmov r2, r12\n" + "\tadds r2, 0x1\n" + "\tstr r2, [sp, 0xC]\n" + "\tldrb r7, [r5, 0x8]\n" + "\tldr r3, [sp, 0x4]\n" + "\tmovs r0, 0xF\n" + "\tmov r9, r0\n" + "_0815A412:\n" + "\tldrb r1, [r3]\n" + "\tcmp r7, r1\n" + "\tbne _0815A444\n" + "\tldrh r0, [r3, 0x4]\n" + "\tadds r0, 0x7\n" + "\tstrh r0, [r5, 0xC]\n" + "\tldrh r0, [r3, 0x6]\n" + "\tadds r0, 0x7\n" + "\tstrh r0, [r5, 0xE]\n" + "\tldrb r1, [r3, 0xA]\n" + "\tlsls r1, 28\n" + "\tlsrs r1, 28\n" + "\tmov r2, r9\n" + "\tands r1, r2\n" + "\tldrb r0, [r5, 0x19]\n" + "\tands r0, r4\n" + "\torrs r0, r1\n" + "\tstrb r0, [r5, 0x19]\n" + "\tldrb r1, [r3, 0xA]\n" + "\tlsrs r1, 4\n" + "\tlsls r1, 4\n" + "\tmovs r2, 0xF\n" + "\tands r0, r2\n" + "\torrs r0, r1\n" + "\tstrb r0, [r5, 0x19]\n" + "_0815A444:\n" + "\tadds r3, 0x18\n" + "\tadds r6, 0x1\n" + "\tcmp r6, 0x3F\n" + "\tbls _0815A412\n" + "\tmov r0, r8\n" + "\tadd r0, r12\n" + "\tlsls r0, 2\n" + "\tldr r1, _0815A480 @ =gMapObjects\n" + "\tadds r6, r0, r1\n" + "\tmovs r2, 0x10\n" + "\tldrsh r0, [r6, r2]\n" + "\tmovs r2, 0x12\n" + "\tldrsh r1, [r6, r2]\n" + "\tbl MapGridGetMetatileBehaviorAt\n" + "\tstrb r0, [r6, 0x1E]\n" + "\tldrb r4, [r6, 0x1F]\n" + "\tmovs r1, 0x10\n" + "\tldrsh r0, [r6, r1]\n" + "\tmovs r2, 0x12\n" + "\tldrsh r1, [r6, r2]\n" + "\tbl MapGridGetMetatileBehaviorAt\n" + "\tcmp r4, r0\n" + "\tbne _0815A488\n" + "\tldrh r0, [r6, 0x10]\n" + "\tstrh r0, [r6, 0x14]\n" + "\tldrh r0, [r6, 0x12]\n" + "\tb _0815A506\n" + "\t.align 2, 0\n" + "_0815A480: .4byte gMapObjects\n" + "_0815A484: .4byte 0x01000120\n" + "_0815A488:\n" + "\tldrb r4, [r6, 0x1F]\n" + "\tldrh r0, [r6, 0x10]\n" + "\tsubs r0, 0x1\n" + "\tlsls r0, 16\n" + "\tasrs r0, 16\n" + "\tmovs r2, 0x12\n" + "\tldrsh r1, [r6, r2]\n" + "\tbl MapGridGetMetatileBehaviorAt\n" + "\tcmp r4, r0\n" + "\tbne _0815A4A8\n" + "\tldrh r0, [r6, 0x10]\n" + "\tsubs r0, 0x1\n" + "\tstrh r0, [r6, 0x14]\n" + "\tldrh r0, [r6, 0x12]\n" + "\tb _0815A506\n" + "_0815A4A8:\n" + "\tldrb r4, [r6, 0x1F]\n" + "\tldrh r0, [r6, 0x10]\n" + "\tadds r0, 0x1\n" + "\tlsls r0, 16\n" + "\tasrs r0, 16\n" + "\tmovs r2, 0x12\n" + "\tldrsh r1, [r6, r2]\n" + "\tbl MapGridGetMetatileBehaviorAt\n" + "\tcmp r4, r0\n" + "\tbne _0815A4C8\n" + "\tldrh r0, [r6, 0x10]\n" + "\tadds r0, 0x1\n" + "\tstrh r0, [r6, 0x14]\n" + "\tldrh r0, [r6, 0x12]\n" + "\tb _0815A506\n" + "_0815A4C8:\n" + "\tldrb r4, [r6, 0x1F]\n" + "\tmovs r1, 0x10\n" + "\tldrsh r0, [r6, r1]\n" + "\tldrh r1, [r6, 0x12]\n" + "\tsubs r1, 0x1\n" + "\tlsls r1, 16\n" + "\tasrs r1, 16\n" + "\tbl MapGridGetMetatileBehaviorAt\n" + "\tcmp r4, r0\n" + "\tbne _0815A4E8\n" + "\tldrh r0, [r6, 0x10]\n" + "\tstrh r0, [r6, 0x14]\n" + "\tldrh r0, [r6, 0x12]\n" + "\tsubs r0, 0x1\n" + "\tb _0815A506\n" + "_0815A4E8:\n" + "\tldrb r4, [r6, 0x1F]\n" + "\tmovs r2, 0x10\n" + "\tldrsh r0, [r6, r2]\n" + "\tldrh r1, [r6, 0x12]\n" + "\tadds r1, 0x1\n" + "\tlsls r1, 16\n" + "\tasrs r1, 16\n" + "\tbl MapGridGetMetatileBehaviorAt\n" + "\tcmp r4, r0\n" + "\tbne _0815A508\n" + "\tldrh r0, [r6, 0x10]\n" + "\tstrh r0, [r6, 0x14]\n" + "\tldrh r0, [r6, 0x12]\n" + "\tadds r0, 0x1\n" + "_0815A506:\n" + "\tstrh r0, [r6, 0x16]\n" + "_0815A508:\n" + "\tldr r0, [sp, 0xC]\n" + "\tmov r12, r0\n" + "\tcmp r0, 0xF\n" + "\tbhi _0815A512\n" + "\tb _0815A224\n" + "_0815A512:\n" + "\tldr r0, _0815A538 @ =gMapObjects\n" + "\tldr r1, _0815A53C @ =gSaveBlock1Ptr\n" + "\tldr r1, [r1]\n" + "\tmovs r2, 0xD4\n" + "\tlsls r2, 3\n" + "\tadds r1, r2\n" + "\tmovs r2, 0x90\n" + "\tlsls r2, 1\n" + "\tbl CpuSet\n" + "\tadd sp, 0x10\n" + "\tpop {r3-r5}\n" + "\tmov r8, r3\n" + "\tmov r9, r4\n" + "\tmov r10, r5\n" + "\tpop {r4-r7}\n" + "\tpop {r0}\n" + "\tbx r0\n" + "\t.align 2, 0\n" + "_0815A538: .4byte gMapObjects\n" + "_0815A53C: .4byte gSaveBlock1Ptr"); +} +#endif // NONMATCHING + +void sub_815A540(void) +{ + if (gUnknown_203ADFA == 2) + { + s16 x, y; + + PlayerGetDestCoords(&x, &y); + if (!MetatileBehavior_IsSurfable(MapGridGetMetatileBehaviorAt(x, y)) && TestPlayerAvatarFlags(0x08)) + { + struct MapObject *mapObject = &gMapObjects[gPlayerAvatar.mapObjectId]; + SetPlayerAvatarTransitionFlags(0x01); + DestroySprite(&gSprites[mapObject->mapobj_unk_1A]); + } + } +} diff --git a/src/unk_815C980.c b/src/unk_815C980.c new file mode 100644 index 000000000..b90d2fb03 --- /dev/null +++ b/src/unk_815C980.c @@ -0,0 +1,437 @@ +#include "global.h" +#include "malloc.h" +#include "decompress.h" +#include "unk_815C980.h" +#include "main.h" +#include "battle.h" + +struct UnkStruct2 +{ + bool8 isActive; + u8 firstOamId; + u8 field_2; + u8 oamCount; + u8 palTagIndex; + u8 size; + u8 shape; + u8 priority; + u8 xDelta; + u8 field_9; + u16 tileStart; + s16 x; + s16 y; + u16 tileTag; + u16 palTag; + u32 field_14; + s32 field_18; +}; + +struct UnkStruct1 +{ + u32 count; + struct UnkStruct2 *array; +}; + +// this file's functions +static u8 sub_815D244(u8 arg0);; +static void sub_815CC28(struct UnkStruct2 *arg0); +static void sub_815CDDC(struct UnkStruct2 *arg0, s32 arg1, bool32 arg2); +static void sub_815CE90(struct UnkStruct2 *arg0, s32 arg1, bool32 arg2); +static void sub_815CFEC(struct UnkStruct2 *arg0, s32 arg1, bool32 arg2); +static bool32 SharesTileWithAnyActive(u32 id); +static bool32 SharesPalWithAnyActive(u32 id); +static void sub_8035648(void); +static u8 sub_815D324(u32 shape, u32 size); + +// ewram +static EWRAM_DATA struct UnkStruct1 *gUnknown_203F454 = {0}; + +// const rom data +static const u8 gUnknown_8479658[][4] = +{ + {0x01, 0x04, 0x10, 0x40}, + {0x02, 0x04, 0x08, 0x20}, + {0x02, 0x04, 0x08, 0x20}, + {0x00, 0x00, 0x00, 0x00} +}; + +// code +bool32 sub_815C980(u32 count) +{ + u32 i; + + if (gUnknown_203F454 != NULL) + sub_815C9F4(); + + gUnknown_203F454 = Alloc(sizeof(*gUnknown_203F454)); + if (gUnknown_203F454 == NULL) + return FALSE; + + gUnknown_203F454->array = Alloc(sizeof(struct UnkStruct2) * count); + if (gUnknown_203F454->array == NULL) + { + Free(gUnknown_203F454); + return FALSE; + } + + gUnknown_203F454->count = count; + for (i = 0; i < count; i++) + { + gUnknown_203F454->array[i].isActive = FALSE; + gUnknown_203F454->array[i].firstOamId = 0xFF; + } + + return TRUE; +} + +void sub_815C9F4(void) +{ + if (gUnknown_203F454 != NULL) + { + if (gUnknown_203F454->array != NULL) + { + u32 i; + + for (i = 0; i < gUnknown_203F454->count; i++) + sub_815D108(i); + + Free(gUnknown_203F454->array); + } + + FREE_AND_SET_NULL(gUnknown_203F454); + } +} + +bool32 sub_815CA40(u32 id, s32 arg1, const struct UnkStruct3 *arg2) +{ + u32 i; + + if (gUnknown_203F454 == NULL) + return FALSE; + if (gUnknown_203F454->array[id].isActive) + return FALSE; + + gUnknown_203F454->array[id].firstOamId = sub_815D244(arg2->field_1); + if (gUnknown_203F454->array[id].firstOamId == 0xFF) + return FALSE; + + gUnknown_203F454->array[id].tileStart = GetSpriteTileStartByTag(arg2->spriteSheet->tag); + if (gUnknown_203F454->array[id].tileStart == 0xFFFF) + { + if (arg2->spriteSheet->size != 0) + { + gUnknown_203F454->array[id].tileStart = LoadSpriteSheet(arg2->spriteSheet); + } + else + { + struct CompressedSpriteSheet compObjectPic; + + compObjectPic = *(struct CompressedSpriteSheet*)(arg2->spriteSheet); + compObjectPic.size = GetDecompressedDataSize(arg2->spriteSheet->data); + gUnknown_203F454->array[id].tileStart = LoadCompressedObjectPic(&compObjectPic); + } + + if (gUnknown_203F454->array[id].tileStart == 0xFFFF) + return FALSE; + } + + gUnknown_203F454->array[id].palTagIndex = IndexOfSpritePaletteTag(arg2->spritePal->tag); + if (gUnknown_203F454->array[id].palTagIndex == 0xFF) + gUnknown_203F454->array[id].palTagIndex = LoadSpritePalette(arg2->spritePal); + + gUnknown_203F454->array[id].field_2 = arg2->field_0_0; + gUnknown_203F454->array[id].oamCount = arg2->field_1; + gUnknown_203F454->array[id].x = arg2->x; + gUnknown_203F454->array[id].y = arg2->y; + gUnknown_203F454->array[id].shape = arg2->shape; + gUnknown_203F454->array[id].size = arg2->size; + gUnknown_203F454->array[id].priority = arg2->priority; + gUnknown_203F454->array[id].xDelta = arg2->xDelta; + gUnknown_203F454->array[id].field_9 = sub_815D324(arg2->shape, arg2->size); + gUnknown_203F454->array[id].tileTag = arg2->spriteSheet->tag; + gUnknown_203F454->array[id].palTag = arg2->spritePal->tag; + gUnknown_203F454->array[id].isActive = TRUE; + gUnknown_203F454->array[id].field_14 = 1; + + for (i = 1; i < arg2->field_1; i++) + gUnknown_203F454->array[id].field_14 *= 10; + + sub_815CC28(&gUnknown_203F454->array[id]); + sub_815CD70(id, arg1); + + return TRUE; +} + +static void sub_815CC28(struct UnkStruct2 *arg0) +{ + u32 i; + u32 oamId = arg0->firstOamId; + u32 x = arg0->x; + u32 oamCount = arg0->oamCount + 1; + + CpuFill16(0, &gMain.oamBuffer[oamId], sizeof(struct OamData) * oamCount); + for (i = 0, oamId = arg0->firstOamId; i < oamCount; i++, oamId++) + { + gMain.oamBuffer[oamId].y = arg0->y; + gMain.oamBuffer[oamId].x = x; + gMain.oamBuffer[oamId].shape = arg0->shape; + gMain.oamBuffer[oamId].size = arg0->size; + gMain.oamBuffer[oamId].tileNum = arg0->tileStart; + gMain.oamBuffer[oamId].priority = arg0->priority; + gMain.oamBuffer[oamId].paletteNum = arg0->palTagIndex; + + x += arg0->xDelta; + } + + oamId--; + gMain.oamBuffer[oamId].x = arg0->x - arg0->xDelta; + gMain.oamBuffer[oamId].affineMode = 2; + gMain.oamBuffer[oamId].tileNum = arg0->tileStart + (arg0->field_9 * 10); +} + +void sub_815CD70(u32 id, s32 arg1) +{ + bool32 r2; + + if (gUnknown_203F454 == NULL) + return; + if (!gUnknown_203F454->array[id].isActive) + return; + + gUnknown_203F454->array[id].field_18 = arg1; + if (arg1 < 0) + { + r2 = TRUE; + arg1 *= -1; + } + else + { + r2 = FALSE; + } + + switch (gUnknown_203F454->array[id].field_2) + { + case 0: + default: + sub_815CDDC(&gUnknown_203F454->array[id], arg1, r2); + break; + case 1: + sub_815CE90(&gUnknown_203F454->array[id], arg1, r2); + break; + case 2: + sub_815CFEC(&gUnknown_203F454->array[id], arg1, r2); + break; + } +} + +static void sub_815CDDC(struct UnkStruct2 *arg0, s32 arg1, bool32 arg2) +{ + u32 r5 = arg0->field_14; + u32 oamId = arg0->firstOamId; + + while (r5 != 0) + { + u32 r4 = arg1 / r5; + arg1 -= (r4 * r5); + r5 /= 10; + + gMain.oamBuffer[oamId].tileNum = (r4 * arg0->field_9) + arg0->tileStart; + oamId++; + } + + if (arg2) + gMain.oamBuffer[oamId].affineMode = 0; + else + gMain.oamBuffer[oamId].affineMode = 2; +} + +static void sub_815CE90(struct UnkStruct2 *arg0, s32 arg1, bool32 arg2) +{ + u32 r5 = arg0->field_14; + static int gUnknown_3002078; + static int gUnknown_300207C; + static int gUnknown_3002080; + + gUnknown_3002078 = arg0->firstOamId; + gUnknown_300207C = 0; + gUnknown_3002080 = -1; + + while (r5 != 0) + { + u32 r4 = arg1 / r5; + arg1 -= (r4 * r5); + r5 /= 10; + + if (r4 != 0 || gUnknown_3002080 != -1 || r5 == 0) + { + gMain.oamBuffer[gUnknown_3002078].tileNum = (r4 * arg0->field_9) + arg0->tileStart; + gMain.oamBuffer[gUnknown_3002078].affineMode = 0; + + if (gUnknown_3002080 == -1) + gUnknown_3002080 = gUnknown_300207C; + } + else + { + gMain.oamBuffer[gUnknown_3002078].affineMode = 2; + } + + gUnknown_3002078++; + gUnknown_300207C++; + } + + if (arg2) + { + gMain.oamBuffer[gUnknown_3002078].affineMode = 0; + gMain.oamBuffer[gUnknown_3002078].x = arg0->x + ((gUnknown_3002080 - 1) * arg0->xDelta); + } + else + { + gMain.oamBuffer[gUnknown_3002078].affineMode = 2; + } +} + +static void sub_815CFEC(struct UnkStruct2 *arg0, s32 arg1, bool32 arg2) +{ + u32 r5 = arg0->field_14; + u32 oamId = arg0->firstOamId; + u32 var_28 = 0; + s32 r9 = 0; + + while (r5 != 0) + { + u32 r4 = arg1 / r5; + arg1 -= (r4 * r5); + r5 /= 10; + + if (r4 != 0 || var_28 != 0 || r5 == 0) + { + var_28 = 1; + gMain.oamBuffer[oamId].tileNum = (r4 * arg0->field_9) + arg0->tileStart; + gMain.oamBuffer[oamId].affineMode = 0; + + oamId++; + r9++; + } + } + + while (r9 < arg0->oamCount) + { + gMain.oamBuffer[oamId].affineMode = 2; + oamId++; + r9++; + } + + if (arg2) + gMain.oamBuffer[oamId].affineMode = 0; + else + gMain.oamBuffer[oamId].affineMode = 2; +} + +void sub_815D108(u32 id) +{ + s32 oamId, oamCount, i; + + if (gUnknown_203F454 == NULL) + return; + if (!gUnknown_203F454->array[id].isActive) + return; + + oamCount = gUnknown_203F454->array[id].oamCount + 1; + oamId = gUnknown_203F454->array[id].firstOamId; + + for (i = 0; i < oamCount; i++, oamId++) + gMain.oamBuffer[oamId].affineMode = 2; + + if (!SharesTileWithAnyActive(id)) + FreeSpriteTilesByTag(gUnknown_203F454->array[id].tileTag); + if (!SharesPalWithAnyActive(id)) + FreeSpritePaletteByTag(gUnknown_203F454->array[id].palTag); + + gUnknown_203F454->array[id].isActive = FALSE; +} + +void sub_815D1A8(u32 id, bool32 arg1) +{ + s32 oamId, oamCount, i; + + if (gUnknown_203F454 == NULL) + return; + if (!gUnknown_203F454->array[id].isActive) + return; + + oamCount = gUnknown_203F454->array[id].oamCount + 1; + oamId = gUnknown_203F454->array[id].firstOamId; + if (arg1) + { + for (i = 0; i < oamCount; i++, oamId++) + gMain.oamBuffer[oamId].affineMode = 2; + } + else + { + for (i = 0; i < oamCount; i++, oamId++) + gMain.oamBuffer[oamId].affineMode = 0; + + sub_815CD70(id, gUnknown_203F454->array[id].field_18); + } +} + +static u8 sub_815D244(u8 arg0) +{ + u32 i; + u16 oamCount = 64; + + for (i = 0; i < gUnknown_203F454->count; i++) + { + if (!gUnknown_203F454->array[i].isActive) + { + if (gUnknown_203F454->array[i].firstOamId != 0xFF && gUnknown_203F454->array[i].oamCount <= arg0) + return gUnknown_203F454->array[i].firstOamId; + } + else + { + oamCount += 1 + gUnknown_203F454->array[i].oamCount; + } + } + + if (oamCount + arg0 + 1 > 128) + return 0xFF; + else + return oamCount; +} + +static bool32 SharesTileWithAnyActive(u32 id) +{ + u32 i; + + for (i = 0; i < gUnknown_203F454->count; i++) + { + if (gUnknown_203F454->array[i].isActive && i != id + && gUnknown_203F454->array[i].tileTag == gUnknown_203F454->array[id].tileTag) + { + return TRUE; + } + } + + return FALSE; +} + +static bool32 SharesPalWithAnyActive(u32 id) +{ + u32 i; + + for (i = 0; i < gUnknown_203F454->count; i++) + { + if (gUnknown_203F454->array[i].isActive && i != id + && gUnknown_203F454->array[i].palTag == gUnknown_203F454->array[id].palTag) + { + return TRUE; + } + } + + return FALSE; +} + +static u8 sub_815D324(u32 shape, u32 size) +{ + return gUnknown_8479658[shape][size]; +} diff --git a/src/unk_815F138.c b/src/unk_815F138.c new file mode 100644 index 000000000..8941f1559 --- /dev/null +++ b/src/unk_815F138.c @@ -0,0 +1,322 @@ +#include "global.h" +#include "decompress.h" +#include "sound.h" +#include "task.h" +#include "trig.h" +#include "constants/songs.h" + +void sub_815F1AC(u8 taskId); +bool32 sub_815F2AC(u8 spriteId); +void sub_815F3E0(u8 spriteId1, u8 spriteId2, u8 spriteId3); +bool32 sub_815F444(u8 spriteId); +void sub_815F470(struct Sprite * sprite); +void sub_815F564(u16 tilesTag, u16 palTag); +u8 sub_815F5BC(u16 tilesTag, u16 palTag, s16 x, s16 y, u8 subpriority); +void sub_815F610(u16 tilesTag, u16 palTag, s16 x, s16 y, u8 subpriority, s16 * spriteId2_p, s16 * spriteId3_p); + +void sub_815F138(u16 tilesTag, u16 palTag, s16 x, s16 y, u8 subpriority) +{ + u8 taskId = CreateTask(sub_815F1AC, 80); + gTasks[taskId].data[2] = tilesTag; + gTasks[taskId].data[3] = palTag; + gTasks[taskId].data[4] = x; + gTasks[taskId].data[5] = y; + gTasks[taskId].data[6] = subpriority; +} + +bool8 sub_815F198(void) +{ + return FuncIsActiveTask(sub_815F1AC); +} + +void sub_815F1AC(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + switch (data[0]) + { + case 0: + sub_815F564(data[2], data[3]); + data[7] = sub_815F5BC(data[2], data[3], data[4], data[5], data[6]); + sub_815F610(data[2], data[3], data[4], data[5], data[6], &data[8], &data[9]); + data[0]++; + break; + case 1: + if (!sub_815F2AC(data[7])) + { + sub_815F3E0(data[7], data[8], data[9]); + FreeSpriteOamMatrix(&gSprites[data[7]]); + DestroySprite(&gSprites[data[7]]); + data[0]++; + } + break; + case 2: + if (!sub_815F444(data[8])) + { + DestroySprite(&gSprites[data[8]]); + DestroySprite(&gSprites[data[9]]); + FreeSpriteTilesByTag(data[2]); + FreeSpritePaletteByTag(data[3]); + DestroyTask(taskId); + } + break; + } +} + +bool32 sub_815F2AC(u8 spriteId) +{ + struct Sprite * sprite = &gSprites[spriteId]; + + switch (sprite->data[0]) + { + case 0: + sub_8007FFC(sprite, 0x800, 0x1A); + sprite->data[0]++; + // fallthrough + case 1: + if (sprite->data[2] == 0) + PlaySE(SE_TRACK_STOP); + if (++sprite->data[2] >= 20) + { + sprite->data[2] = 0; + StartSpriteAffineAnim(sprite, 1); + sprite->data[0]++; + } + break; + case 2: + if (sprite->affineAnimEnded) + sprite->data[0]++; + break; + case 3: + if (++sprite->data[2] >= 4) + { + sprite->data[2] = 0; + sprite->data[0]++; + StartSpriteAffineAnim(sprite, 2); + } + break; + case 4: + sprite->pos1.y -= 4; + if (++sprite->data[2] >= 8) + { + if (sprite->data[4] < 2) + { + StartSpriteAnim(sprite, sprite->data[4] + 1); + sprite->data[2] = 0; + sprite->data[0]++; + } + else + { + sprite->data[0] = 7; + return FALSE; + } + } + break; + case 5: + sprite->pos1.y += 4; + if (++sprite->data[2] >= 8) + { + sprite->data[2] = 0; + StartSpriteAffineAnim(sprite, 3); + sprite->data[0]++; + } + break; + case 6: + if (sprite->affineAnimEnded) + { + sprite->data[4]++; + sprite->data[0] = 1; + } + break; + case 7: + return FALSE; + } + return TRUE; +} + +void sub_815F3E0(u8 spriteId1, u8 spriteId2, u8 spriteId3) +{ + gSprites[spriteId2].pos2.y = -40; + gSprites[spriteId3].pos2.y = -40; + gSprites[spriteId2].invisible = FALSE; + gSprites[spriteId3].invisible = FALSE; + gSprites[spriteId2].callback = sub_815F470; + gSprites[spriteId3].callback = sub_815F470; +} + +bool32 sub_815F444(u8 spriteId) +{ + return gSprites[spriteId].callback == sub_815F470; +} + +void sub_815F470(struct Sprite * sprite) +{ + s16 * data = sprite->data; + s32 y; + + switch (sprite->data[0]) + { + case 0: + data[4] = 64; + data[5] = sprite->pos2.y << 4; + data[0]++; + //fallthrough + case 1: + data[5] += data[4]; + data[4]++; + sprite->pos2.y = data[5] >> 4; + if (sprite->pos2.y >= 0) + { + PlaySE(SE_TRACK_STOP); + sprite->pos2.y = 0; + data[0]++; + } + break; + case 2: + data[1] += 12; + if (data[1] >= 128) + { + PlaySE(SE_TRACK_STOP); + data[1] = 0; + data[0]++; + } + y = gSineTable[data[1]]; + sprite->pos2.y = -(y >> 4); + break; + case 3: + data[1] += 16; + if (data[1] >= 128) + { + PlaySE(SE_TRACK_STOP); + data[1] = 0; + data[0]++; + } + sprite->pos2.y = -(gSineTable[data[1]] >> 5); + break; + case 4: + if (++data[1] > 40) + sprite->callback = SpriteCallbackDummy; + break; + } +} + +const u16 gUnknown_847A328[] = INCBIN_U16("data/graphics/unk_847a348.gbapal"); +const u16 gUnknown_847A348[] = INCBIN_U16("data/graphics/unk_847a348.4bpp.lz"); + +void sub_815F564(u16 tilesTag, u16 palTag) +{ + struct CompressedSpriteSheet spriteSheet = {(const void *)gUnknown_847A348, 0xE00}; + struct SpritePalette spritePalette = {gUnknown_847A328}; + spriteSheet.tag = tilesTag; + spritePalette.tag = palTag; + LoadCompressedObjectPic(&spriteSheet); + LoadSpritePalette(&spritePalette); +} + +const struct OamData gOamData_847A7AC = { + .affineMode = ST_OAM_AFFINE_DOUBLE, + .shape = ST_OAM_SQUARE, + .size = 2 +}; + +const struct OamData gOamData_847A7B4 = { + .affineMode = ST_OAM_AFFINE_OFF, + .shape = ST_OAM_H_RECTANGLE, + .size = 3 +}; + +const union AnimCmd gUnknown_847A7BC[] = { + ANIMCMD_FRAME( 0, 1), + ANIMCMD_END +}; + +const union AnimCmd gUnknown_847A7C4[] = { + ANIMCMD_FRAME(16, 1), + ANIMCMD_END +}; + +const union AnimCmd gUnknown_847A7CC[] = { + ANIMCMD_FRAME(32, 1), + ANIMCMD_END +}; + +const union AnimCmd *const gUnknown_847A7D4[] = { + gUnknown_847A7BC, + gUnknown_847A7C4, + gUnknown_847A7CC +}; + +const union AnimCmd gUnknown_847A7E0[] = { + ANIMCMD_FRAME(48, 1), + ANIMCMD_END +}; + +const union AnimCmd gUnknown_847A7E8[] = { + ANIMCMD_FRAME(80, 1), + ANIMCMD_END +}; + +const union AnimCmd *const gUnknown_847A7F0[] = { + gUnknown_847A7E0, + gUnknown_847A7E8 +}; + +const union AffineAnimCmd gUnknown_847A7F8[] = { + AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), + AFFINEANIMCMD_END +}; + +const union AffineAnimCmd gUnknown_847A808[] = { + AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME( 0x10, -0x10, 0, 8), + AFFINEANIMCMD_END +}; + +const union AffineAnimCmd gUnknown_847A820[] = { + AFFINEANIMCMD_FRAME(-0x12, 0x12, 0, 8), + AFFINEANIMCMD_END +}; + +const union AffineAnimCmd gUnknown_847A830[] = { + AFFINEANIMCMD_FRAME( 0x6, -0x6, 0, 8), + AFFINEANIMCMD_FRAME( -0x4, 0x4, 0, 8), + AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), + AFFINEANIMCMD_END +}; + +const union AffineAnimCmd *const gUnknown_847A850[] = { + gUnknown_847A7F8, + gUnknown_847A808, + gUnknown_847A820, + gUnknown_847A830 +}; + +u8 sub_815F5BC(u16 tilesTag, u16 palTag, s16 x, s16 y, u8 subpriority) +{ + struct SpriteTemplate spriteTemplate = { + .oam = &gOamData_847A7AC, + .anims = gUnknown_847A7D4, + .affineAnims = gUnknown_847A850, + .callback = SpriteCallbackDummy + }; + spriteTemplate.tileTag = tilesTag; + spriteTemplate.paletteTag = palTag; + return CreateSprite(&spriteTemplate, x, y, subpriority); +} + +void sub_815F610(u16 tilesTag, u16 palTag, s16 x, s16 y, u8 subpriority, s16 * spriteId2_p, s16 * spriteId3_p) +{ + struct SpriteTemplate spriteTemplate = { + .oam = &gOamData_847A7B4, + .anims = gUnknown_847A7F0, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy + }; + spriteTemplate.tileTag = tilesTag; + spriteTemplate.paletteTag = palTag; + *spriteId2_p = CreateSprite(&spriteTemplate, x - 32, y, subpriority); + *spriteId3_p = CreateSprite(&spriteTemplate, x + 32, y, subpriority); + gSprites[*spriteId2_p].invisible = TRUE; + gSprites[*spriteId3_p].invisible = TRUE; + StartSpriteAnim(&gSprites[*spriteId3_p], 1); +} diff --git a/src/util.c b/src/util.c new file mode 100644 index 000000000..5b5fdbb9d --- /dev/null +++ b/src/util.c @@ -0,0 +1,513 @@ +#include "global.h" +#include "util.h" + +const u32 gBitTable[] = +{ + 1 << 0, + 1 << 1, + 1 << 2, + 1 << 3, + 1 << 4, + 1 << 5, + 1 << 6, + 1 << 7, + 1 << 8, + 1 << 9, + 1 << 10, + 1 << 11, + 1 << 12, + 1 << 13, + 1 << 14, + 1 << 15, + 1 << 16, + 1 << 17, + 1 << 18, + 1 << 19, + 1 << 20, + 1 << 21, + 1 << 22, + 1 << 23, + 1 << 24, + 1 << 25, + 1 << 26, + 1 << 27, + 1 << 28, + 1 << 29, + 1 << 30, + 1 << 31, +}; + +static const struct SpriteTemplate gInvisibleSpriteTemplate = +{ + .tileTag = 0, + .paletteTag = 0, + .oam = &gDummyOamData, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +static const u8 sSpriteDimensions[3][4][2] = +{ + // square + { + {1, 1}, + {2, 2}, + {4, 4}, + {8, 8}, + }, + + // horizontal rectangle + { + {2, 1}, + {4, 1}, + {4, 2}, + {8, 4}, + }, + + // vertical rectangle + { + {1, 2}, + {1, 4}, + {2, 4}, + {4, 8}, + }, +}; + +static const u16 gCrc16Table[] = +{ + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, + 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, + 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, + 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, + 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, + 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, + 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, + 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, + 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, + 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, + 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, + 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, + 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, + 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, + 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, + 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, + 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, + 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, + 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, + 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, + 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, + 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, + 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, + 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, + 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, + 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, + 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, + 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, + 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, + 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78, +}; + +const u8 gMiscBlank_Gfx[] = INCBIN_U8("graphics/interface/blank.4bpp"); + +u8 CreateInvisibleSpriteWithCallback(void (*callback)(struct Sprite *)) +{ + u8 sprite = CreateSprite(&gInvisibleSpriteTemplate, 248, 168, 14); + gSprites[sprite].invisible = TRUE; + gSprites[sprite].callback = callback; + return sprite; +} + +void StoreWordInTwoHalfwords(u16 *h, u32 w) +{ + h[0] = (u16)(w); + h[1] = (u16)(w >> 16); +} + +void LoadWordFromTwoHalfwords(u16 *h, u32 *w) +{ + *w = h[0] | (s16)h[1] << 16; +} + +void SetBgAffineStruct(struct BgAffineSrcData *src, u32 texX, u32 texY, s16 scrX, s16 scrY, s16 sx, s16 sy, u16 alpha) +{ + src->texX = texX; + src->texY = texY; + src->scrX = scrX; + src->scrY = scrY; + src->sx = sx; + src->sy = sy; + src->alpha = alpha; +} + +void DoBgAffineSet(struct BgAffineDstData *dest, u32 texX, u32 texY, s16 scrX, s16 scrY, s16 sx, s16 sy, u16 alpha) +{ + struct BgAffineSrcData src; + + SetBgAffineStruct(&src, texX, texY, scrX, scrY, sx, sy, alpha); + BgAffineSet(&src, dest, 1); +} + +#ifdef NONMATCHING +void CopySpriteTiles(u8 shape, u8 size, u8 *tiles, u16 *tilemap, u8 *output) +{ + u8 x, y; + s8 i, j; + u8 xflip[32]; + u8 h = sSpriteDimensions[shape][size][1]; + u8 w = sSpriteDimensions[shape][size][0]; + + for (y = 0; y < h; y++) + { + int filler = 32 - w; + + for (x = 0; x < w; x++) + { + int tile = (*tilemap & 0x3ff) * 32; + int attr = *tilemap & 0xc00; + + if (attr == 0) + { + DmaCopy32Defvars(3, tiles + tile, output, 32); + } + else if (attr == 0x800) // yflip + { + for (i = 0; i < 8; i++) + { + DmaCopy32Defvars(3, (7 - i) * 4 + tile + tiles, output + i * 4, 4); + } + } + else // xflip + { + for (i = 0; i < 8; i++) + { + for (j = 0; j < 4; j++) + { + u8 i2 = i * 4; + xflip[i2 + (3-j)] = (tiles[tile + i2 + j] & 0xf) << 4; + xflip[i2 + (3-j)] |= tiles[tile + i2 + j] >> 4; + } + } + if (*tilemap & 0x800) // yflip + { + for (i = 0; i < 8; i++) + { + DmaCopy32Defvars(3, (7 - i) * 4 + xflip, output + i * 4, 4); + } + } + else + { + DmaCopy32Defvars(3, xflip, output, 32); + } + } + tilemap++; + output += 32; + } + tilemap += filler; + } +} +#else +NAKED +void CopySpriteTiles(u8 shape, u8 size, u8 *tiles, u16 *tilemap, u8 *output) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tmov r7, r10\n" + "\tmov r6, r9\n" + "\tmov r5, r8\n" + "\tpush {r5-r7}\n" + "\tsub sp, 0x3C\n" + "\tstr r2, [sp, 0x20]\n" + "\tadds r4, r3, 0\n" + "\tldr r7, [sp, 0x5C]\n" + "\tlsls r0, 24\n" + "\tlsls r1, 24\n" + "\tldr r2, _0804504C @ =sSpriteDimensions\n" + "\tlsrs r1, 23\n" + "\tlsrs r0, 21\n" + "\tadds r1, r0\n" + "\tadds r0, r2, 0x1\n" + "\tadds r0, r1, r0\n" + "\tldrb r0, [r0]\n" + "\tstr r0, [sp, 0x24]\n" + "\tadds r1, r2\n" + "\tldrb r1, [r1]\n" + "\tstr r1, [sp, 0x28]\n" + "\tmovs r1, 0\n" + "\tcmp r1, r0\n" + "\tbcc _08044FF8\n" + "\tb _0804517A\n" + "_08044FF8:\n" + "\tmovs r0, 0x20\n" + "\tldr r2, [sp, 0x28]\n" + "\tsubs r0, r2\n" + "\tlsls r0, 1\n" + "\tstr r0, [sp, 0x2C]\n" + "_08045002:\n" + "\tmovs r2, 0\n" + "\tadds r1, 0x1\n" + "\tstr r1, [sp, 0x34]\n" + "\tldr r3, [sp, 0x28]\n" + "\tcmp r2, r3\n" + "\tbcc _08045010\n" + "\tb _08045168\n" + "_08045010:\n" + "\tldr r0, _08045050 @ =0x040000d4\n" + "\tmov r8, r0\n" + "_08045014:\n" + "\tldrh r1, [r4]\n" + "\tldr r0, _08045054 @ =0x000003ff\n" + "\tands r0, r1\n" + "\tlsls r0, 5\n" + "\tmov r12, r0\n" + "\tmovs r0, 0xC0\n" + "\tlsls r0, 4\n" + "\tands r0, r1\n" + "\tmov r3, sp\n" + "\tstrh r1, [r3, 0x38]\n" + "\tcmp r0, 0\n" + "\tbne _0804505C\n" + "\tldr r0, [sp, 0x20]\n" + "\tadd r0, r12\n" + "\tmov r1, r8\n" + "\tstr r0, [r1]\n" + "\tstr r7, [r1, 0x4]\n" + "\tldr r3, _08045058 @ =0x84000008\n" + "\tstr r3, [r1, 0x8]\n" + "\tldr r0, [r1, 0x8]\n" + "\tadds r4, 0x2\n" + "\tstr r4, [sp, 0x30]\n" + "\tadds r7, 0x20\n" + "\tmov r10, r7\n" + "\tadds r2, 0x1\n" + "\tmov r9, r2\n" + "\tb _08045156\n" + "\t.align 2, 0\n" + "_0804504C: .4byte sSpriteDimensions\n" + "_08045050: .4byte 0x040000d4\n" + "_08045054: .4byte 0x000003ff\n" + "_08045058: .4byte 0x84000008\n" + "_0804505C:\n" + "\tmovs r1, 0x80\n" + "\tlsls r1, 4\n" + "\tcmp r0, r1\n" + "\tbne _080450AC\n" + "\tmovs r3, 0\n" + "\tadds r4, 0x2\n" + "\tstr r4, [sp, 0x30]\n" + "\tmovs r0, 0x20\n" + "\tadds r0, r7\n" + "\tmov r10, r0\n" + "\tadds r2, 0x1\n" + "\tmov r9, r2\n" + "\tldr r4, _080450A4 @ =0x040000d4\n" + "\tldr r6, _080450A8 @ =0x84000001\n" + "\tmovs r5, 0x7\n" + "_0804507A:\n" + "\tlsls r2, r3, 24\n" + "\tasrs r2, 24\n" + "\tsubs r0, r5, r2\n" + "\tlsls r0, 2\n" + "\tadd r0, r12\n" + "\tldr r1, [sp, 0x20]\n" + "\tadds r0, r1, r0\n" + "\tlsls r1, r2, 2\n" + "\tadds r1, r7, r1\n" + "\tstr r0, [r4]\n" + "\tstr r1, [r4, 0x4]\n" + "\tstr r6, [r4, 0x8]\n" + "\tldr r0, [r4, 0x8]\n" + "\tadds r2, 0x1\n" + "\tlsls r2, 24\n" + "\tlsrs r3, r2, 24\n" + "\tasrs r2, 24\n" + "\tcmp r2, 0x7\n" + "\tble _0804507A\n" + "\tb _08045156\n" + "\t.align 2, 0\n" + "_080450A4: .4byte 0x040000d4\n" + "_080450A8: .4byte 0x84000001\n" + "_080450AC:\n" + "\tmovs r3, 0\n" + "\tadds r4, 0x2\n" + "\tstr r4, [sp, 0x30]\n" + "\tmovs r0, 0x20\n" + "\tadds r0, r7\n" + "\tmov r10, r0\n" + "\tadds r2, 0x1\n" + "\tmov r9, r2\n" + "_080450BC:\n" + "\tmovs r2, 0\n" + "\tlsls r4, r3, 24\n" + "\tlsls r0, r4, 2\n" + "\tlsrs r0, 24\n" + "\tadds r6, r0, 0x3\n" + "\tmov r1, r12\n" + "\tadds r5, r1, r0\n" + "_080450CA:\n" + "\tlsls r1, r2, 24\n" + "\tasrs r1, 24\n" + "\tsubs r0, r6, r1\n" + "\tmov r2, sp\n" + "\tadds r3, r2, r0\n" + "\tadds r0, r5, r1\n" + "\tldr r2, [sp, 0x20]\n" + "\tadds r0, r2, r0\n" + "\tldrb r2, [r0]\n" + "\tmovs r0, 0xF\n" + "\tands r0, r2\n" + "\tlsls r0, 4\n" + "\tlsrs r2, 4\n" + "\torrs r0, r2\n" + "\tstrb r0, [r3]\n" + "\tadds r1, 0x1\n" + "\tlsls r1, 24\n" + "\tlsrs r2, r1, 24\n" + "\tasrs r1, 24\n" + "\tcmp r1, 0x3\n" + "\tble _080450CA\n" + "\tmovs r3, 0x80\n" + "\tlsls r3, 17\n" + "\tadds r0, r4, r3\n" + "\tlsrs r3, r0, 24\n" + "\tasrs r0, 24\n" + "\tcmp r0, 0x7\n" + "\tble _080450BC\n" + "\tmovs r0, 0x80\n" + "\tlsls r0, 4\n" + "\tmov r1, sp\n" + "\tldrh r1, [r1, 0x38]\n" + "\tands r0, r1\n" + "\tcmp r0, 0\n" + "\tbeq _08045148\n" + "\tmovs r3, 0\n" + "\tldr r4, _08045140 @ =0x040000d4\n" + "\tldr r6, _08045144 @ =0x84000001\n" + "\tmovs r5, 0x7\n" + "_08045118:\n" + "\tlsls r1, r3, 24\n" + "\tasrs r1, 24\n" + "\tsubs r0, r5, r1\n" + "\tlsls r0, 2\n" + "\tmov r3, sp\n" + "\tadds r2, r3, r0\n" + "\tlsls r0, r1, 2\n" + "\tadds r0, r7, r0\n" + "\tstr r2, [r4]\n" + "\tstr r0, [r4, 0x4]\n" + "\tstr r6, [r4, 0x8]\n" + "\tldr r0, [r4, 0x8]\n" + "\tadds r1, 0x1\n" + "\tlsls r1, 24\n" + "\tlsrs r3, r1, 24\n" + "\tasrs r1, 24\n" + "\tcmp r1, 0x7\n" + "\tble _08045118\n" + "\tb _08045156\n" + "\t.align 2, 0\n" + "_08045140: .4byte 0x040000d4\n" + "_08045144: .4byte 0x84000001\n" + "_08045148:\n" + "\tmov r0, sp\n" + "\tmov r1, r8\n" + "\tstr r0, [r1]\n" + "\tstr r7, [r1, 0x4]\n" + "\tldr r2, _0804518C @ =0x84000008\n" + "\tstr r2, [r1, 0x8]\n" + "\tldr r0, [r1, 0x8]\n" + "_08045156:\n" + "\tldr r4, [sp, 0x30]\n" + "\tmov r7, r10\n" + "\tmov r3, r9\n" + "\tlsls r0, r3, 24\n" + "\tlsrs r2, r0, 24\n" + "\tldr r0, [sp, 0x28]\n" + "\tcmp r2, r0\n" + "\tbcs _08045168\n" + "\tb _08045014\n" + "_08045168:\n" + "\tldr r1, [sp, 0x2C]\n" + "\tadds r4, r1\n" + "\tldr r2, [sp, 0x34]\n" + "\tlsls r0, r2, 24\n" + "\tlsrs r1, r0, 24\n" + "\tldr r3, [sp, 0x24]\n" + "\tcmp r1, r3\n" + "\tbcs _0804517A\n" + "\tb _08045002\n" + "_0804517A:\n" + "\tadd sp, 0x3C\n" + "\tpop {r3-r5}\n" + "\tmov r8, r3\n" + "\tmov r9, r4\n" + "\tmov r10, r5\n" + "\tpop {r4-r7}\n" + "\tpop {r0}\n" + "\tbx r0\n" + "\t.align 2, 0\n" + "_0804518C: .4byte 0x84000008"); +} +#endif // NONMATCHING + +int CountTrailingZeroBits(u32 value) +{ + u8 i; + + for (i = 0; i < 32; i++) + { + if ((value & 1) == 0) + value >>= 1; + else + return i; + } + return 0; +} + +u16 CalcCRC16(const u8 *data, u32 length) +{ + u16 i, j; + u16 crc = 0x1121; + + for (i = 0; i < length; i++) + { + crc ^= data[i]; + for (j = 0; j < 8; j++) + { + if (crc & 1) + crc = (crc >> 1) ^ 0x8408; + else + crc >>= 1; + } + } + return ~crc; +} + +u16 CalcCRC16WithTable(const u8 *data, u32 length) +{ + u16 i; + u16 crc = 0x1121; + u8 byte; + + for (i = 0; i < length; i++) + { + byte = crc >> 8; + crc ^= data[i]; + crc = byte ^ gCrc16Table[(u8)crc]; + } + return ~crc; +} + +u32 CalcByteArraySum(const u8 * array, u32 size) +{ + s32 i; + u32 result = 0; + + for (i = 0; i < size; i++) + { + result += array[i]; + } + + return result; +} diff --git a/src/vs_seeker.c b/src/vs_seeker.c index 4d42f270d..e3df77242 100644 --- a/src/vs_seeker.c +++ b/src/vs_seeker.c @@ -1,5 +1,4 @@ #include "global.h" -#include "songs.h" #include "sound.h" #include "task.h" #include "malloc.h" @@ -19,9 +18,11 @@ #include "random.h" #include "field_map_obj.h" #include "field_player_avatar.h" +#include "map_obj_80688E4.h" #include "map_obj_8097404.h" #include "unk_810c3a4.h" #include "constants/movement_commands.h" +#include "constants/songs.h" #include "vs_seeker.h" typedef enum @@ -65,11 +66,13 @@ struct VsSeekerStruct extern u16 gSpecialVar_LastTalked; extern struct MapObject gMapObjects[MAP_OBJECTS_COUNT]; -extern u8 gUnknown_3005074; +extern u8 gSelectedEventObject; // static declarations static EWRAM_DATA struct VsSeekerStruct *sVsSeeker = NULL; +static void sub_810C3B8(u8 taskId); +static void sub_810C594(void); static void Task_VsSeeker_1(u8 taskId); static void Task_VsSeeker_2(u8 taskId); static void GatherNearbyTrainerInfo(void); @@ -565,6 +568,229 @@ static const u8 gUnknown_8453F67[] = { 0x08, 0x08, 0x07, 0x09, 0x0a }; // text + + +void sub_810C3A4(void) +{ + CreateTask(sub_810C3B8, 80); +} + +static void sub_810C3B8(u8 taskId) +{ + struct Task * task = &gTasks[taskId]; + u8 i; + + if (task->data[0] == 0 && walkrun_is_standing_still() == TRUE) + { + sub_805C270(); + task->data[0] = 1; + } + + if (task->data[1] == 0) + { + for (i = 0; i < MAP_OBJECTS_COUNT; i++) + { + if (sub_810CF04(i) == TRUE) + { + if (gMapObjects[i].mapobj_bit_1) + return; + FreezeMapObject(&gMapObjects[i]); + } + } + } + + task->data[1] = 1; + if (task->data[0] != 0) + { + DestroyTask(taskId); + sub_805C780(); + EnableBothScriptContexts(); + } +} + +void sub_810C444(void) +{ + struct MapObjectTemplate * templates = gSaveBlock1Ptr->mapObjectTemplates; + u8 i; + u8 r6; + u8 sp0; + struct MapObject * mapObject; + + for (i = 0; i < gMapHeader.events->mapObjectCount; i++) + { + if ((templates[i].unkC == 1 || templates[i].unkC == 3) && (templates[i].movementType == 0x4D || templates[i].movementType == 0x4E || templates[i].movementType == 0x4F)) + { + r6 = sub_810CF54(); + TryGetFieldObjectIdByLocalIdAndMap(templates[i].localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &sp0); + mapObject = &gMapObjects[sp0]; + if (sub_810CF04(sp0) == TRUE) + { + npc_set_running_behaviour_etc(mapObject, r6); + } + templates[i].movementType = r6; + } + } +} + +#ifdef NONMATCHING +bool8 sub_810C4EC(void) +{ + if (CheckBagHasItem(ITEM_VS_SEEKER, 1) == TRUE) + { + if ((gSaveBlock1Ptr->trainerRematchStepCounter & 0xFF) < 100) + gSaveBlock1Ptr->trainerRematchStepCounter++; + } + + if (FlagGet(0x801) == TRUE) + { + u16 x; + do { + x = (gSaveBlock1Ptr->trainerRematchStepCounter >> 8) & 0xFF; + } while (0); + if (x < 100) + { + x++; + gSaveBlock1Ptr->trainerRematchStepCounter = ((u16)(x << 8)) | (gSaveBlock1Ptr->trainerRematchStepCounter & 0xFF); + } + do { + x = (gSaveBlock1Ptr->trainerRematchStepCounter >> 8) & 0xFF; + } while (0); + if (x == 100) + { + FlagClear(0x801); + sub_810C640(); + sub_810D0D0(); + return TRUE; + } + } + + return FALSE; +} +#else +NAKED +bool8 sub_810C4EC(void) +{ + asm_unified("\tpush {r4-r7,lr}\n" + "\tmovs r0, 0xB5\n" + "\tlsls r0, 1\n" + "\tmovs r1, 0x1\n" + "\tbl CheckBagHasItem\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tcmp r0, 0x1\n" + "\tbne _0810C516\n" + "\tldr r0, _0810C568 @ =gSaveBlock1Ptr\n" + "\tldr r0, [r0]\n" + "\tmovs r2, 0xC7\n" + "\tlsls r2, 3\n" + "\tadds r1, r0, r2\n" + "\tldrh r2, [r1]\n" + "\tldrb r0, [r1]\n" + "\tcmp r0, 0x63\n" + "\tbhi _0810C516\n" + "\tadds r0, r2, 0x1\n" + "\tstrh r0, [r1]\n" + "_0810C516:\n" + "\tldr r7, _0810C56C @ =0x00000801\n" + "\tadds r0, r7, 0\n" + "\tbl FlagGet\n" + "\tlsls r0, 24\n" + "\tlsrs r0, 24\n" + "\tcmp r0, 0x1\n" + "\tbne _0810C570\n" + "\tldr r6, _0810C568 @ =gSaveBlock1Ptr\n" + "\tldr r0, [r6]\n" + "\tmovs r5, 0xC7\n" + "\tlsls r5, 3\n" + "\tadds r3, r0, r5\n" + "\tldrh r2, [r3]\n" + "\tlsrs r1, r2, 8\n" + "\tmovs r4, 0xFF\n" + "\tcmp r1, 0x63\n" + "\tbhi _0810C548\n" + "\tadds r1, 0x1\n" + "\tlsls r1, 24\n" + "\tmovs r0, 0xFF\n" + "\tands r0, r2\n" + "\tlsrs r1, 16\n" + "\torrs r0, r1\n" + "\tstrh r0, [r3]\n" + "_0810C548:\n" + "\tldr r0, [r6]\n" + "\tadds r0, r5\n" + "\tldrh r0, [r0]\n" + "\tlsrs r0, 8\n" + "\tands r0, r4\n" + "\tcmp r0, 0x64\n" + "\tbne _0810C570\n" + "\tadds r0, r7, 0\n" + "\tbl FlagClear\n" + "\tbl sub_810C640\n" + "\tbl sub_810D0D0\n" + "\tmovs r0, 0x1\n" + "\tb _0810C572\n" + "\t.align 2, 0\n" + "_0810C568: .4byte gSaveBlock1Ptr\n" + "_0810C56C: .4byte 0x00000801\n" + "_0810C570:\n" + "\tmovs r0, 0\n" + "_0810C572:\n" + "\tpop {r4-r7}\n" + "\tpop {r1}\n" + "\tbx r1"); +} +#endif + +void sub_810C578(void) +{ + FlagClear(0x801); + sub_810C640(); + sub_810D0D0(); + sub_810C594(); +} + +static void sub_810C594(void) +{ + u8 i; + + for (i = 0; i < MAP_OBJECTS_COUNT; i++) + { + struct MapObject * mapObject = &gMapObjects[i]; + if (mapObject->animPattern == 0x4D || mapObject->animPattern == 0x4E || mapObject->animPattern == 0x4F) + { + u8 r3 = sub_810CF54(); + if (mapObject->active && gSprites[mapObject->spriteId].data[0] == i) + { + gSprites[mapObject->spriteId].pos2.x = 0; + gSprites[mapObject->spriteId].pos2.y = 0; + npc_set_running_behaviour_etc(mapObject, r3); + } + } + } +} + +void sub_810C604(void) +{ + gSaveBlock1Ptr->trainerRematchStepCounter &= 0xFF00; +} + +void sub_810C620(void) +{ + gSaveBlock1Ptr->trainerRematchStepCounter &= 0xFF00; + gSaveBlock1Ptr->trainerRematchStepCounter |= 100; +} + +void sub_810C640(void) +{ + gSaveBlock1Ptr->trainerRematchStepCounter &= 0x00FF; +} + +void sub_810C654(void) +{ + gSaveBlock1Ptr->trainerRematchStepCounter &= 0x00FF; + gSaveBlock1Ptr->trainerRematchStepCounter |= (100 << 8); +} + void Task_VsSeeker_0(u8 taskId) { u8 i; @@ -588,7 +814,7 @@ void Task_VsSeeker_0(u8 taskId) } else if (respval == 2) { - sub_80A2294(4, 0, gSpecialVar_ItemId, 0xffff); + ItemUse_SetQuestLogEvent(4, 0, gSpecialVar_ItemId, 0xffff); FieldEffectStart(FLDEFF_UNK_41); // TODO: name this enum gTasks[taskId].func = Task_VsSeeker_1; gTasks[taskId].data[0] = 15; @@ -663,7 +889,7 @@ static void Task_VsSeeker_3(u8 taskId) { if (sVsSeeker->responseCode == 2) StartAllRespondantIdleMovements(); - sub_80F6F54(0, 1); + ClearDialogWindowAndFrame(0, 1); sub_80696C0(); ScriptContext2_Disable(); DestroyTask(taskId); @@ -1012,7 +1238,7 @@ void sub_810CB90(void) sub_810CF54(&r4[r8]); // You are using this function incorrectly. Please consult the manual. sub_805FE7C(r4_2, gUnknown_8453F67[r4_2->mapobj_unk_18]); gSaveBlock1Ptr->trainerRematches[r4[r8].localId] = 0; - if (gUnknown_3005074 == sp0) + if (gSelectedEventObject == sp0) r4_2->animPattern = gUnknown_8453F67[r4_2->mapobj_unk_18]; else r4_2->animPattern = 0x08; @@ -1225,7 +1451,7 @@ static u16 GetTrainerFlagFromScript(const u8 *script) * because the ARM processor requires shorts to be 16-bit * aligned, this function needs to perform explicit bitwise * operations to get the correct flag. - * + * * 5c XX YY ZZ ... * -- -- */ @@ -1360,7 +1586,7 @@ static void StartAllRespondantIdleMovements(void) u8 dummy = 0; s32 i; s32 j; - + for (i = 0; i < sVsSeeker->numRematchableTrainers; i++) { for (j = 0; sVsSeeker->trainerInfo[j].localId != 0xFF; j++) diff --git a/src/window.c b/src/window.c index e760fc8e4..4c302885c 100644 --- a/src/window.c +++ b/src/window.c @@ -2,17 +2,13 @@ #include "window.h" #include "malloc.h" #include "bg.h" +#include "blit.h" u8 gWindowClearTile; void *gWindowBgTilemapBuffers[4]; EWRAM_DATA struct Window gWindows[WINDOWS_MAX] = {0}; -extern void BlitBitmapRect4Bit(struct Bitmap *src, struct Bitmap *dest, u16 srcX, u16 srcY, u16 destX, u16 destY, u16 width, u16 height, u8 colorKey); -extern void BlitBitmapRect4BitTo8Bit(struct Bitmap *src, struct Bitmap *dest, u16 srcX, u16 srcY, u16 destX, u16 destY, u16 width, u16 height, u8 colorKey, u8 paletteNum); -extern void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); -extern void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); - static u8 GetNumActiveWindowsOnBg(u8 bgId); static const struct WindowTemplate sDummyWindowTemplate = {0xFF, 0, 0, 0, 0, 0, 0}; @@ -47,7 +43,7 @@ bool16 InitWindows(const struct WindowTemplate *templates) gWindows[i].tileData = NULL; } - for (i = 0, allocatedBaseBlock = 0, bgLayer = templates[i].priority; bgLayer != 0xFF && i < 0x20; ++i, bgLayer = templates[i].priority) + for (i = 0, allocatedBaseBlock = 0, bgLayer = templates[i].bg; bgLayer != 0xFF && i < 0x20; ++i, bgLayer = templates[i].bg) { if (gWindowTileAutoAllocEnabled == TRUE) { @@ -116,14 +112,14 @@ u16 AddWindow(const struct WindowTemplate *template) for (win = 0; win < 0x20; ++win) { - if ((bgLayer = gWindows[win].window.priority) == 0xFF) + if ((bgLayer = gWindows[win].window.bg) == 0xFF) break; } if (win == 0x20) return 0xFF; - bgLayer = template->priority; + bgLayer = template->bg; allocatedBaseBlock = 0; if (gWindowTileAutoAllocEnabled == TRUE) @@ -179,7 +175,7 @@ u16 AddWindow(const struct WindowTemplate *template) void RemoveWindow(u8 windowId) { - u8 bgLayer = gWindows[windowId].window.priority; + u8 bgLayer = gWindows[windowId].window.bg; if (gWindowTileAutoAllocEnabled == TRUE) { @@ -235,14 +231,14 @@ void CopyWindowToVram(u8 windowId, u8 mode) switch (mode) { case 1: - CopyBgTilemapBufferToVram(windowLocal.window.priority); + CopyBgTilemapBufferToVram(windowLocal.window.bg); break; case 2: - LoadBgTiles(windowLocal.window.priority, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); break; case 3: - LoadBgTiles(windowLocal.window.priority, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); - CopyBgTilemapBufferToVram(windowLocal.window.priority); + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); + CopyBgTilemapBufferToVram(windowLocal.window.bg); break; } } @@ -252,8 +248,8 @@ void PutWindowTilemap(u8 windowId) struct Window windowLocal = gWindows[windowId]; WriteSequenceToBgTilemapBuffer( - windowLocal.window.priority, - GetBgAttribute(windowLocal.window.priority, 0xA) + windowLocal.window.baseBlock, + windowLocal.window.bg, + GetBgAttribute(windowLocal.window.bg, 0xA) + windowLocal.window.baseBlock, windowLocal.window.tilemapLeft, windowLocal.window.tilemapTop, windowLocal.window.width, @@ -265,13 +261,13 @@ void PutWindowTilemap(u8 windowId) void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette) { struct Window windowLocal = gWindows[windowId]; - u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.priority, 0xA); + u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, 0xA); int i; for (i = 0; i < height; ++i) { WriteSequenceToBgTilemapBuffer( - windowLocal.window.priority, + windowLocal.window.bg, currentRow, windowLocal.window.tilemapLeft + x, windowLocal.window.tilemapTop + y + i, @@ -289,7 +285,7 @@ void ClearWindowTilemap(u8 windowId) struct Window windowLocal = gWindows[windowId]; FillBgTilemapBufferRect( - windowLocal.window.priority, + windowLocal.window.bg, gWindowClearTile, windowLocal.window.tilemapLeft, windowLocal.window.tilemapTop, @@ -301,13 +297,13 @@ void ClearWindowTilemap(u8 windowId) void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height) { struct Window windowLocal = gWindows[windowId]; - u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.priority, 0xA); + u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, 0xA); int i; for (i = 0; i < height; ++i) { WriteSequenceToBgTilemapBuffer( - windowLocal.window.priority, + windowLocal.window.bg, currentRow, windowLocal.window.tilemapLeft + x, windowLocal.window.tilemapTop + y + i, @@ -320,7 +316,7 @@ void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height) } } -void BlitBitmapToWindow(u8 windowId, u8 *pixels, u16 x, u16 y, u16 width, u16 height) +void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height) { BlitBitmapRectToWindow(windowId, pixels, 0, 0, width, height, x, y, width, height); } @@ -1073,10 +1069,10 @@ _08004046:\n\ } #endif // NONMATCHING -void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)) +void CallWindowFunction(u8 windowId, WindowFunc func) { struct WindowTemplate window = gWindows[windowId].window; - func(window.priority, window.tilemapLeft, window.tilemapTop, window.width, window.height, window.paletteNum); + func(window.bg, window.tilemapLeft, window.tilemapTop, window.width, window.height, window.paletteNum); } bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value) @@ -1096,7 +1092,7 @@ bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value) gWindows[windowId].window.baseBlock = value; return FALSE; case WINDOW_TILE_DATA: - case WINDOW_PRIORITY: + case WINDOW_BG: case WINDOW_WIDTH: case WINDOW_HEIGHT: default: @@ -1108,8 +1104,8 @@ u32 GetWindowAttribute(u8 windowId, u8 attributeId) { switch (attributeId) { - case WINDOW_PRIORITY: - return gWindows[windowId].window.priority; + case WINDOW_BG: + return gWindows[windowId].window.bg; case WINDOW_TILEMAP_LEFT: return gWindows[windowId].window.tilemapLeft; case WINDOW_TILEMAP_TOP: @@ -1135,7 +1131,7 @@ static u8 GetNumActiveWindowsOnBg(u8 bgId) s32 i; for (i = 0; i < WINDOWS_MAX; i++) { - if (gWindows[i].window.priority == bgId) + if (gWindows[i].window.bg == bgId) windowsNum++; } return windowsNum; diff --git a/src/window_8bpp.c b/src/window_8bpp.c index 5eac3c558..c58c13802 100644 --- a/src/window_8bpp.c +++ b/src/window_8bpp.c @@ -2,13 +2,11 @@ #include "window.h" #include "malloc.h" #include "bg.h" +#include "blit.h" EWRAM_DATA static struct Window* sWindowPtr = NULL; EWRAM_DATA static u16 sWindowSize = 0; -extern void BlitBitmapRect4BitTo8Bit(struct Bitmap *src, struct Bitmap *dest, u16 srcX, u16 srcY, u16 destX, u16 destY, u16 width, u16 height, u8 colorKey, u8 paletteNum); -extern void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); - static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId); static void nullsub_9(void) @@ -23,12 +21,12 @@ u16 AddWindow8Bit(struct WindowTemplate *template) for (windowId = 0; windowId < 32; windowId++) { - if (gWindows[windowId].window.priority == 0xFF) + if (gWindows[windowId].window.bg == 0xFF) break; } if (windowId == WINDOWS_MAX) return 0xFF; - bgLayer = template->priority; + bgLayer = template->bg; if (gWindowBgTilemapBuffers[bgLayer] == 0) { u16 attribute = GetBgAttribute(bgLayer, 8); @@ -107,14 +105,14 @@ void CopyWindowToVram8Bit(u8 windowId, u8 mode) switch (mode) { case 1: - CopyBgTilemapBufferToVram(sWindowPtr->window.priority); + CopyBgTilemapBufferToVram(sWindowPtr->window.bg); break; case 2: - LoadBgTiles(sWindowPtr->window.priority, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); + LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); break; case 3: - LoadBgTiles(sWindowPtr->window.priority, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); - CopyBgTilemapBufferToVram(sWindowPtr->window.priority); + LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); + CopyBgTilemapBufferToVram(sWindowPtr->window.bg); break; } } @@ -125,7 +123,7 @@ static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId) s32 i; for (i = 0; i < WINDOWS_MAX; i++) { - if (gWindows[i].window.priority == bgId) + if (gWindows[i].window.bg == bgId) windowsNum++; } return windowsNum; diff --git a/src/wireless_communication_status_screen.c b/src/wireless_communication_status_screen.c new file mode 100644 index 000000000..1eb29be1b --- /dev/null +++ b/src/wireless_communication_status_screen.c @@ -0,0 +1,436 @@ +#include "global.h" +#include "bg.h" +#include "palette.h" +#include "gpu_regs.h" +#include "malloc.h" +#include "task.h" +#include "text.h" +#include "window.h" +#include "new_menu_helpers.h" +#include "scanline_effect.h" +#include "m4a.h" +#include "string_util.h" +#include "unk_text_util.h" +#include "overworld.h" +#include "sound.h" +#include "menu.h" +#include "librfu.h" +#include "link_rfu.h" +#include "union_room.h" +#include "constants/songs.h" + +struct WirelessCommunicationStatusScreenStruct +{ + u32 field_00[4]; + u32 field_10[4]; + u32 field_20[16]; + u8 field_60; + u8 field_61; + u8 filler_62[0xA]; +}; + +struct WirelessCommunicationStatusScreenStruct * gUnknown_3002040; + +extern const u8 gUnknown_841E2B4[]; +extern const u8 gUnknown_841E2BF[]; +extern const u8 gUnknown_841E2C9[]; +extern const u8 gUnknown_841E2D4[]; +extern const u8 gUnknown_841E245[]; +extern const u8 gUnknown_841E263[]; +extern const u8 gUnknown_841E273[]; +extern const u8 gUnknown_841E284[]; +extern const u8 gUnknown_841E29E[]; + +void sub_814F1E4(void); +void sub_814F46C(u8 taskId); +void sub_814F65C(u8 windowId, u8 fontId, const u8 * str, u8 x, u8 y, u8 palIdx); +bool32 sub_814F7E4(u32 * a0, u32 * a1, u32 * a2, u8 taskId); + +const u16 gUnknown_846F4D0[][16] = { + INCBIN_U16("graphics/misc/unk_846f4d0.gbapal"), + INCBIN_U16("graphics/misc/unk_846f4f0.gbapal"), + INCBIN_U16("graphics/misc/unk_846f510.gbapal"), + INCBIN_U16("graphics/misc/unk_846f530.gbapal"), + INCBIN_U16("graphics/misc/unk_846f550.gbapal"), + INCBIN_U16("graphics/misc/unk_846f570.gbapal"), + INCBIN_U16("graphics/misc/unk_846f590.gbapal"), + INCBIN_U16("graphics/misc/unk_846f5b0.gbapal"), + INCBIN_U16("graphics/misc/unk_846f5d0.gbapal"), + INCBIN_U16("graphics/misc/unk_846f5f0.gbapal"), + INCBIN_U16("graphics/misc/unk_846f610.gbapal"), + INCBIN_U16("graphics/misc/unk_846f630.gbapal"), + INCBIN_U16("graphics/misc/unk_846f650.gbapal"), + INCBIN_U16("graphics/misc/unk_846f670.gbapal"), + INCBIN_U16("graphics/misc/unk_846f690.gbapal"), + INCBIN_U16("graphics/misc/unk_846f6b0.gbapal") +}; + +const u32 gUnknown_846F6D0[] = INCBIN_U32("graphics/misc/unk_846f6d0.4bpp.lz"); +const u16 gUnknown_846F8E0[] = INCBIN_U16("graphics/misc/unk_846f8e0.bin"); + +const struct BgTemplate gUnknown_846FA74[] = { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0x000 + }, { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 8, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0x000 + } +}; + +const struct WindowTemplate gUnknown_846FA7C[] = { + { + .bg = 0x00, + .tilemapLeft = 0x03, + .tilemapTop = 0x00, + .width = 0x18, + .height = 0x03, + .paletteNum = 0x0f, + .baseBlock = 0x0001 + }, { + .bg = 0x00, + .tilemapLeft = 0x03, + .tilemapTop = 0x04, + .width = 0x16, + .height = 0x0f, + .paletteNum = 0x0f, + .baseBlock = 0x0049 + }, { + .bg = 0x00, + .tilemapLeft = 0x19, + .tilemapTop = 0x04, + .width = 0x02, + .height = 0x0f, + .paletteNum = 0x0f, + .baseBlock = 0x0193 + }, DUMMY_WIN_TEMPLATE +}; + +const u8 *const gUnknown_846FA9C[] = { + gUnknown_841E2B4, + gUnknown_841E2BF, + gUnknown_841E2C9, + gUnknown_841E2D4 +}; +const u8 *const gUnknown_846FAAC[] = { + gUnknown_841E245, + gUnknown_841E263, + gUnknown_841E273, + gUnknown_841E284, + gUnknown_841E29E +}; + +const u8 gUnknown_846FAC0[][3] = { + {0x01, 0x01, 0x02}, + {0x02, 0x01, 0x02}, + {0x03, 0x01, 0x04}, + {0x04, 0x00, 0x02}, + {0x15, 0x03, 0x02}, + {0x16, 0x03, 0x02}, + {0x09, 0x04, 0x00}, + {0x0a, 0x04, 0x00}, + {0x0b, 0x04, 0x00}, + {0x0c, 0xff, 0x00}, + {0x0d, 0x00, 0x00}, + {0x0e, 0xff, 0x00}, + {0x0f, 0x04, 0x00}, + {0x10, 0xff, 0x00}, + {0x40, 0x02, 0x01}, + {0x41, 0x02, 0x02}, + {0x44, 0x02, 0x02}, + {0x45, 0x02, 0x00}, + {0x48, 0x02, 0x02}, + {0x54, 0x02, 0x01}, + {0x53, 0x02, 0x02}, + {0x51, 0x02, 0x01}, + {0x52, 0x02, 0x01} +}; + +void sub_814F19C(void) +{ + if (!IsDma3ManagerBusyWithBgCopy()) + { + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); + } +} + +void sub_814F1C0(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +void sub_814F1D4(void) +{ + SetMainCallback2(sub_814F1E4); +} + +void sub_814F1E4(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, 0); + gUnknown_3002040 = AllocZeroed(sizeof(*gUnknown_3002040)); + SetVBlankCallback(NULL); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, gUnknown_846FA74, NELEMS(gUnknown_846FA74)); + SetBgTilemapBuffer(1, Alloc(0x800)); + SetBgTilemapBuffer(0, Alloc(0x800)); + DecompressAndLoadBgGfxUsingHeap(1, gUnknown_846F6D0, 0, 0, 0); + CopyToBgTilemapBuffer(1, gUnknown_846F8E0, 0, 0); + InitWindows(gUnknown_846FA7C); + DeactivateAllTextPrinters(); + ResetPaletteFade(); + ResetSpriteData(); + ResetTasks(); + ScanlineEffect_Stop(); + m4aSoundVSyncOn(); + SetVBlankCallback(sub_814F1C0); + gUnknown_3002040->field_60 = CreateTask(sub_814F46C, 0); + gUnknown_3002040->field_61 = sub_8116DE0(); + gUnknown_3002040->field_10[3] = 1; + ChangeBgX(0, 0, 0); + ChangeBgY(0, 0, 0); + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + LoadPalette(gUnknown_846F4D0, 0, 0x20); + Menu_LoadStdPalAt(0xf0); + UnkTextUtil_Reset(); + FillBgTilemapBufferRect(0, 0x000, 0, 0, 32, 32, 0xF); + CopyBgTilemapBufferToVram(1); + SetMainCallback2(sub_814F19C); + RunTasks(); + RunTextPrinters(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +void sub_814F32C(void) +{ + s32 i; + + FreeAllWindowBuffers(); + for (i = 0; i < 2; i++) + { + Free(GetBgTilemapBuffer(i)); + } + Free(gUnknown_3002040); + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); +} + +void sub_814F364(s16 * unk0, s16 * unk1) +{ + s32 idx; + (*unk0)++; + if (*unk0 > 5) + { + (*unk1)++; + if (*unk1 == 14) + { + *unk1 = 0; + } + *unk0 = 0; + } + idx = *unk1 + 2; + LoadPalette(gUnknown_846F4D0[idx], 0, 16); +} + +void sub_814F3A8(void) +{ + s32 i; + u32 width; + + FillWindowPixelBuffer(0, 0); + FillWindowPixelBuffer(1, 0); + FillWindowPixelBuffer(2, 0); + width = 0xC0 - GetStringWidth(3, gUnknown_846FAAC[0], 0); + sub_814F65C(0, 3, gUnknown_846FAAC[0], width / 2, 6, 3); + for (i = 0; i < 3; i++) + { + sub_814F65C(1, 3, gUnknown_846FAAC[i + 1], 0, 30 * i + 10, 1); + } + sub_814F65C(1, 3, gUnknown_846FAAC[i + 1], 0, 30 * i + 10, 2); + PutWindowTilemap(0); + CopyWindowToVram(0, 2); + PutWindowTilemap(1); + CopyWindowToVram(1, 2); +} + +void sub_814F46C(u8 taskId) +{ + s32 i; + switch (gTasks[taskId].data[0]) + { + case 0: + sub_814F3A8(); + gTasks[taskId].data[0]++; + break; + case 1: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB_BLACK); + ShowBg(1); + CopyBgTilemapBufferToVram(0); + ShowBg(0); + gTasks[taskId].data[0]++; + break; + case 2: + if (!gPaletteFade.active) + gTasks[taskId].data[0]++; + break; + case 3: + if (sub_814F7E4(gUnknown_3002040->field_00, gUnknown_3002040->field_10, gUnknown_3002040->field_20, gUnknown_3002040->field_61)) + { + FillWindowPixelBuffer(2, 0x00); + for (i = 0; i < 4; i++) + { + ConvertIntToDecimalStringN(gStringVar4, gUnknown_3002040->field_00[i], STR_CONV_MODE_RIGHT_ALIGN, 2); + if (i != 3) + sub_814F65C(2, 3, gStringVar4, 4, 30 * i + 10, 1); + else + sub_814F65C(2, 3, gStringVar4, 4, 100, 2); + } + PutWindowTilemap(2); + CopyWindowToVram(2, 3); + } + if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + gTasks[gUnknown_3002040->field_61].data[15] = 0xFF; + gTasks[taskId].data[0]++; + } + sub_814F364(&gTasks[taskId].data[7], &gTasks[taskId].data[8]); + break; + case 4: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); + gTasks[taskId].data[0]++; + break; + case 5: + if (!gPaletteFade.active) + { + SetMainCallback2(sub_814F32C); + DestroyTask(taskId); + } + break; + } +} + +void sub_814F65C(u8 windowId, u8 fontId, const u8 * str, u8 x, u8 y, u8 palIdx) +{ + struct TextColor textColor; + switch (palIdx) + { + case 0: + textColor.fgColor = 0; + textColor.bgColor = 2; + textColor.shadowColor = 3; + break; + case 1: + textColor.fgColor = 0; + textColor.bgColor = 1; + textColor.shadowColor = 3; + break; + case 2: + textColor.fgColor = 0; + textColor.bgColor = 4; + textColor.shadowColor = 5; + break; + case 3: + textColor.fgColor = 0; + textColor.bgColor = 7; + textColor.shadowColor = 6; + break; + case 4: + textColor.fgColor = 0; + textColor.bgColor = 1; + textColor.shadowColor = 2; + break; + // default: UB + } + AddTextPrinterParameterized4(windowId, fontId,x, y, fontId == 0 ? 0 : 1, 0, &textColor, -1, str); +} + +u32 sub_814F714(struct UnkStruct_x20 * unk20, u32 * arg1) +{ + u32 r8 = unk20->unk.field_0.unk_0a_0; + s32 i, j, k; + + for (i = 0; i < NELEMS(gUnknown_846FAC0); i++) + { + if (r8 == gUnknown_846FAC0[i][0] && unk20->field_1A_0 == 1) + { + if (gUnknown_846FAC0[i][2] == 0) + { + k = 0; + for (j = 0; j < 4; j++) + { + if (unk20->unk.field_0.unk_04[j] != 0) k++; + } + k++; + arg1[gUnknown_846FAC0[i][1]] += k; + } + else + { + arg1[gUnknown_846FAC0[i][1]] += gUnknown_846FAC0[i][2]; + } + } + } + + return r8; +} + +bool32 sub_814F7BC(const u32 * ptr0, const u32 * ptr1) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (ptr0[i] != ptr1[i]) + return TRUE; + } + + return FALSE; +} + +bool32 sub_814F7E4(u32 * a0, u32 * a1, u32 * a2, u8 taskId) +{ + bool32 r8 = FALSE; + u32 sp0[4] = {0, 0, 0, 0}; + struct UnkStruct_Group * group = (void *)gTasks[taskId].data; + s32 i; + + for (i = 0; i < 16; i++) + { + u32 r1 = sub_814F714(&group->field_0->arr[i], sp0); + if (r1 != a2[i]) + { + a2[i] = r1; + r8 = TRUE; + } + } + + if (sub_814F7BC(sp0, a1) == FALSE) + { + if (r8 == TRUE) + return TRUE; + else + return FALSE; + } + + memcpy(a0, sp0, sizeof(sp0)); + memcpy(a1, sp0, sizeof(sp0)); + a0[3] = a0[0] + a0[1] + a0[2]; + return TRUE; +} |