diff options
author | Diegoisawesome <diego@domoreaweso.me> | 2017-12-22 01:22:16 -0600 |
---|---|---|
committer | Diegoisawesome <diego@domoreaweso.me> | 2017-12-22 01:22:16 -0600 |
commit | 6bd6cfcac7ae76806c8c9d940163dc3ece6a9acf (patch) | |
tree | f71ad889881572488c2a2be299c50fc09393e1a2 /src | |
parent | 0e8d6645f84057a9eaf9e60ac9312bc259f15be1 (diff) | |
parent | 4554b546ef1699d4b3bde9ef27e7477e620d38d9 (diff) |
Merge remote-tracking branch 'pret/master'
Diffstat (limited to 'src')
45 files changed, 7895 insertions, 457 deletions
diff --git a/src/battle_2.c b/src/battle_2.c index 52530f6b3..f8b4113f0 100644 --- a/src/battle_2.c +++ b/src/battle_2.c @@ -17,6 +17,7 @@ #include "item.h" #include "constants/items.h" #include "constants/hold_effects.h" +#include "constants/trainers.h" #include "link.h" #include "bg.h" #include "dma3.h" @@ -38,7 +39,6 @@ #include "pokedex.h" #include "constants/abilities.h" #include "constants/moves.h" -#include "trainer_classes.h" #include "evolution_scene.h" #include "roamer.h" #include "tv.h" @@ -152,7 +152,7 @@ extern u8 gUnknown_020241E9; extern u16 gChosenMove; extern const struct BattleMove gBattleMoves[]; -extern const u16 gUnknown_08C004E0[]; // battle textbox palette +extern const u16 gBattleTextboxPalette[]; // battle textbox palette extern const struct BgTemplate gUnknown_0831AA08[]; extern const struct WindowTemplate * const gUnknown_0831ABA0[]; extern const u8 gUnknown_0831ACE0[]; @@ -185,7 +185,7 @@ extern void sub_80356D0(void); extern void GetFrontierTrainerName(u8* dst, u16 trainerId); // battle tower extern void sub_8166188(void); // battle tower, sets link battle mons level but why? extern void sub_8165B88(u8* dst, u16 trainerId); // battle tower, gets language -extern void sub_81DB4DC(u8* dst, u8 arg2); // +extern void PadNameString(u8* dst, u8 arg2); // extern void sub_81B9150(void); extern void sub_800AC34(void); extern void sub_80B3AF8(u8 taskId); // cable club @@ -415,7 +415,7 @@ static void CB2_InitBattleInternal(void) gBattleTerrain = BattleSetup_GetTerrainId(); if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) - gBattleTerrain = BATTLE_TERRAIN_INSIDE; + gBattleTerrain = BATTLE_TERRAIN_BUILDING; sub_80356D0(); LoadBattleTextboxAndBackground(); @@ -754,7 +754,7 @@ static void CB2_HandleStartBattle(void) ResetBlockReceivedFlags(); sub_8036EB8(2, playerMultiplayerId); SetAllPlayersBerryData(); - taskId = CreateTask(task00_0800F6FC, 0); + taskId = CreateTask(sub_8035D74, 0); gTasks[taskId].data[1] = 0x10E; gTasks[taskId].data[2] = 0x5A; gTasks[taskId].data[5] = 0; @@ -956,7 +956,7 @@ static void CB2_HandleStartMultiPartnerBattle(void) ResetBlockReceivedFlags(); sub_8036EB8(2, playerMultiplayerId); SetAllPlayersBerryData(); - taskId = CreateTask(task00_0800F6FC, 0); + taskId = CreateTask(sub_8035D74, 0); gTasks[taskId].data[1] = 0x10E; gTasks[taskId].data[2] = 0x5A; gTasks[taskId].data[5] = 0; @@ -1140,7 +1140,7 @@ static void sub_80379F8(u8 arrayIdPlus) gUnknown_02022FF8[i].gender = GetMonGender(&gPlayerParty[arrayIdPlus + i]); StripExtCtrlCodes(gUnknown_02022FF8[i].nickname); if (GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_LANGUAGE) != LANGUAGE_JAPANESE) - sub_81DB4DC(gUnknown_02022FF8[i].nickname, 0); + PadNameString(gUnknown_02022FF8[i].nickname, CHAR_SPACE); } memcpy(gUnknown_02023058, gUnknown_02022FF8, sizeof(gUnknown_02022FF8)); } @@ -1342,7 +1342,7 @@ static void CB2_HandleStartMultiBattle(void) sub_8036EB8(4, playerMultiplayerId); SetAllPlayersBerryData(); sub_8068AA4(); - var = CreateTask(task00_0800F6FC, 0); + var = CreateTask(sub_8035D74, 0); gTasks[var].data[1] = 0x10E; gTasks[var].data[2] = 0x5A; gTasks[var].data[5] = 0; @@ -1718,7 +1718,7 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir { const struct TrainerMonNoItemDefaultMoves *partyData = gTrainers[trainerNum].party.NoItemDefaultMoves; - for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++) nameHash += gSpeciesNames[partyData[i].species][j]; personalityValue += nameHash << 8; @@ -1726,11 +1726,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); break; } - case PARTY_FLAG_CUSTOM_MOVES: + case F_TRAINER_PARTY_CUSTOM_MOVESET: { const struct TrainerMonNoItemCustomMoves *partyData = gTrainers[trainerNum].party.NoItemCustomMoves; - for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++) nameHash += gSpeciesNames[partyData[i].species][j]; personalityValue += nameHash << 8; @@ -1744,11 +1744,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir } break; } - case PARTY_FLAG_HAS_ITEM: + case F_TRAINER_PARTY_HELD_ITEM: { const struct TrainerMonItemDefaultMoves *partyData = gTrainers[trainerNum].party.ItemDefaultMoves; - for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++) nameHash += gSpeciesNames[partyData[i].species][j]; personalityValue += nameHash << 8; @@ -1758,11 +1758,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); break; } - case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: + case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: { const struct TrainerMonItemCustomMoves *partyData = gTrainers[trainerNum].party.ItemCustomMoves; - for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++) + for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++) nameHash += gSpeciesNames[partyData[i].species][j]; personalityValue += nameHash << 8; @@ -1978,7 +1978,7 @@ void sub_8038D64(void) gBattle_BG3_Y = 0; sub_80356D0(); - LoadCompressedPalette(gUnknown_08C004E0, 0, 64); + LoadCompressedPalette(gBattleTextboxPalette, 0, 64); ApplyPlayerChosenFrameToBattleMenu(); ResetSpriteData(); ResetTasks(); @@ -1988,7 +1988,7 @@ void sub_8038D64(void) gReservedSpritePaletteCount = 4; SetVBlankCallback(VBlankCB_Battle); - taskId = CreateTask(task00_0800F6FC, 0); + taskId = CreateTask(sub_8035D74, 0); gTasks[taskId].data[1] = 0x10E; gTasks[taskId].data[2] = 0x5A; gTasks[taskId].data[5] = 1; @@ -4749,19 +4749,19 @@ static void HandleEndTurn_BattleWon(void) switch (gTrainers[gTrainerBattleOpponent_A].trainerClass) { - case CLASS_ELITE_FOUR: - case CLASS_CHAMPION: + case TRAINER_CLASS_ELITE_FOUR: + case TRAINER_CLASS_CHAMPION: PlayBGM(BGM_KACHI5); break; - case CLASS_TEAM_AQUA: - case CLASS_TEAM_MAGMA: - case CLASS_AQUA_ADMIN: - case CLASS_AQUA_LEADER: - case CLASS_MAGMA_ADMIN: - case CLASS_MAGMA_LEADER: + case TRAINER_CLASS_TEAM_AQUA: + case TRAINER_CLASS_TEAM_MAGMA: + case TRAINER_CLASS_AQUA_ADMIN: + case TRAINER_CLASS_AQUA_LEADER: + case TRAINER_CLASS_MAGMA_ADMIN: + case TRAINER_CLASS_MAGMA_LEADER: PlayBGM(BGM_KACHI4); break; - case CLASS_LEADER: + case TRAINER_CLASS_LEADER: PlayBGM(BGM_KACHI3); break; default: diff --git a/src/battle_bg.c b/src/battle_bg.c new file mode 100644 index 000000000..82355273b --- /dev/null +++ b/src/battle_bg.c @@ -0,0 +1,754 @@ +#include "global.h" +#include "battle.h" +#include "sprite.h" +#include "constants/trainers.h" +#include "graphics.h" +#include "decompress.h" +#include "bg.h" +#include "palette.h" +#include "main.h" +#include "gpu_regs.h" +#include "link.h" +#include "battle_message.h" +#include "task.h" +#include "trig.h" +#include "sound.h" +#include "songs.h" +#include "strings.h" +#include "window.h" +#include "text_window.h" +#include "new_menu_helpers.h" + +struct BattleBackground +{ + const void *tileset; + const void *tilemap; + const void *entryTileset; + const void *entryTilemap; + const void *palette; +}; + +extern const struct SpriteTemplate gUnknown_0831A9D0; +extern const struct SpriteTemplate gUnknown_0831A9E8; +extern const struct CompressedSpriteSheet gUnknown_0831AA00; +extern const struct BgTemplate gUnknown_0831AA08[4]; +extern const struct WindowTemplate *gUnknown_0831ABA0[]; +extern const struct BattleBackground gBattleTerrainTable[]; + +extern u8 gBattleTerrain; +extern u16 gTrainerBattleOpponent_A; +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; +extern u16 gPartnerTrainerId; + +extern u8 GetCurrentMapBattleScene(void); + +void sub_8035658(void) +{ + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, gUnknown_0831AA08, ARRAY_COUNT(gUnknown_0831AA08)); + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + { + gBattleScripting.field_24 = 1; + SetBgTilemapBuffer(1, gUnknown_02023060); + SetBgTilemapBuffer(2, gUnknown_02023060); + } + else + { + gBattleScripting.field_24 = 0; + } + + InitWindows(gUnknown_0831ABA0[gBattleScripting.field_24]); + DeactivateAllTextPrinters(); +} + +void sub_80356D0(void) +{ + DisableInterrupts(INTR_FLAG_HBLANK); + EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_VCOUNT | INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); + sub_8035658(); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON | DISPCNT_WIN0_ON | DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); +} + +void ApplyPlayerChosenFrameToBattleMenu(void) +{ + sub_809882C(2, 0x12, 0x10); + sub_809882C(2, 0x22, 0x10); + LoadCompressedPalette(gUnknown_08D85600, 0x50, 0x20); + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + { + sub_81978B0(0x70); + copy_textbox_border_tile_patterns_to_vram(0, 0x30, 0x70); + gPlttBufferUnfaded[0x76] = 0; + CpuCopy16(&gPlttBufferUnfaded[0x76], &gPlttBufferFaded[0x76], 2); + } +} + +void DrawMainBattleBackground(void) +{ + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_x2000000)) + { + LZDecompressVram(gBattleTerrainTiles_Building, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Building, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_Frontier, 0x20, 0x60); + } + else if (gBattleTypeFlags & BATTLE_TYPE_GROUDON) + { + LZDecompressVram(gBattleTerrainTiles_Cave, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Cave, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_Groudon, 0x20, 0x60); + } + else if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE) + { + LZDecompressVram(gBattleTerrainTiles_Water, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Water, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_Kyogre, 0x20, 0x60); + } + else if (gBattleTypeFlags & BATTLE_TYPE_RAYQUAZA) + { + LZDecompressVram(gBattleTerrainTiles_Rayquaza, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Rayquaza, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_Rayquaza, 0x20, 0x60); + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + u8 trainerClass = gTrainers[gTrainerBattleOpponent_A].trainerClass; + if (trainerClass == TRAINER_CLASS_LEADER) + { + LZDecompressVram(gBattleTerrainTiles_Building, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Building, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_BuildingLeader, 0x20, 0x60); + return; + } + else if (trainerClass == TRAINER_CLASS_CHAMPION) + { + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_StadiumWallace, 0x20, 0x60); + return; + } + } + + switch (GetCurrentMapBattleScene()) + { + default: + case MAP_BATTLE_SCENE_NORMAL: + LZDecompressVram(gBattleTerrainTable[gBattleTerrain].tileset, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTable[gBattleTerrain].tilemap, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainTable[gBattleTerrain].palette, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_GYM: + LZDecompressVram(gBattleTerrainTiles_Building, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Building, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_BuildingGym, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_MAGMA: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_StadiumMagma, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_AQUA: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_StadiumAqua, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_SIDNEY: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_StadiumSidney, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_PHOEBE: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_StadiumPhoebe, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_GLACIA: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_StadiumGlacia, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_DRAKE: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_StadiumDrake, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_FRONTIER: + LZDecompressVram(gBattleTerrainTiles_Building, (void*)(VRAM + 0x8000)); + LZDecompressVram(gBattleTerrainTilemap_Building, (void*)(VRAM + 0xD000)); + LoadCompressedPalette(gBattleTerrainPalette_Frontier, 0x20, 0x60); + break; + } + } +} + +void LoadBattleTextboxAndBackground(void) +{ + LZDecompressVram(gBattleTextboxTiles, (void*)(VRAM)); + CopyToBgTilemapBuffer(0, gBattleTextboxTilemap, 0, 0); + CopyBgTilemapBufferToVram(0); + LoadCompressedPalette(gBattleTextboxPalette, 0, 0x40); + ApplyPlayerChosenFrameToBattleMenu(); + + DrawMainBattleBackground(); +} + +static void sub_8035AE4(u8 taskId, u8 bank, u8 bgId, u8 destX, u8 destY) +{ + s32 i; + u16 var = 0; + u16 src[6]; + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gTasks[taskId].data[5] != 0) + { + switch (bank) + { + case 0: + var = 0x3F & gTasks[taskId].data[3]; + break; + case 1: + var = (0xFC0 & gTasks[taskId].data[4]) >> 6; + break; + case 2: + var = (0xFC0 & gTasks[taskId].data[3]) >> 6; + break; + case 3: + var = 0x3F & gTasks[taskId].data[4]; + break; + } + } + else + { + switch (bank) + { + case 0: + var = 0x3F & gTasks[taskId].data[3]; + break; + case 1: + var = 0x3F & gTasks[taskId].data[4]; + break; + case 2: + var = (0xFC0 & gTasks[taskId].data[3]) >> 6; + break; + case 3: + var = (0xFC0 & gTasks[taskId].data[4]) >> 6; + break; + } + } + + for (i = 0; i < 3; i++) + { + src[i] = ((var & (3 << (i * 2))) >> (i * 2)) + 0x6001; + } + + CopyToBgTilemapBufferRect_ChangePalette(bgId, src, destX, destY, 3, 1, 0x11); + CopyBgTilemapBufferToVram(bgId); + } + else + { + if (bank == gBattleScripting.multiplayerId) + var = gTasks[taskId].data[3]; + else + var = gTasks[taskId].data[4]; + + for (i = 0; i < 6; i++) + { + src[i] = ((var & (3 << (i * 2))) >> (i * 2)) + 0x6001; + } + + CopyToBgTilemapBufferRect_ChangePalette(bgId, src, destX, destY, 6, 1, 0x11); + CopyBgTilemapBufferToVram(bgId); + } +} + +static void sub_8035C4C(void) +{ + if (gBattleOutcome == BATTLE_DREW) + { + BattleHandleAddTextPrinter(gText_Draw, 0x15); + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleOutcome == BATTLE_WON) + { + switch (gLinkPlayers[gBattleScripting.multiplayerId].lp_field_18) + { + case 0: + BattleHandleAddTextPrinter(gText_Win, 0x16); + BattleHandleAddTextPrinter(gText_Loss, 0x17); + break; + case 1: + BattleHandleAddTextPrinter(gText_Win, 0x17); + BattleHandleAddTextPrinter(gText_Loss, 0x16); + break; + case 2: + BattleHandleAddTextPrinter(gText_Win, 0x16); + BattleHandleAddTextPrinter(gText_Loss, 0x17); + break; + case 3: + BattleHandleAddTextPrinter(gText_Win, 0x17); + BattleHandleAddTextPrinter(gText_Loss, 0x16); + break; + } + } + else + { + switch (gLinkPlayers[gBattleScripting.multiplayerId].lp_field_18) + { + case 0: + BattleHandleAddTextPrinter(gText_Win, 0x17); + BattleHandleAddTextPrinter(gText_Loss, 0x16); + break; + case 1: + BattleHandleAddTextPrinter(gText_Win, 0x16); + BattleHandleAddTextPrinter(gText_Loss, 0x17); + break; + case 2: + BattleHandleAddTextPrinter(gText_Win, 0x17); + BattleHandleAddTextPrinter(gText_Loss, 0x16); + break; + case 3: + BattleHandleAddTextPrinter(gText_Win, 0x16); + BattleHandleAddTextPrinter(gText_Loss, 0x17); + break; + } + } + } + else if (gBattleOutcome == BATTLE_WON) + { + if (gLinkPlayers[gBattleScripting.multiplayerId].lp_field_18 != 0) + { + BattleHandleAddTextPrinter(gText_Win, 0x17); + BattleHandleAddTextPrinter(gText_Loss, 0x16); + } + else + { + BattleHandleAddTextPrinter(gText_Win, 0x16); + BattleHandleAddTextPrinter(gText_Loss, 0x17); + } + } + else + { + if (gLinkPlayers[gBattleScripting.multiplayerId].lp_field_18 != 0) + { + BattleHandleAddTextPrinter(gText_Win, 0x16); + BattleHandleAddTextPrinter(gText_Loss, 0x17); + } + else + { + BattleHandleAddTextPrinter(gText_Win, 0x17); + BattleHandleAddTextPrinter(gText_Loss, 0x16); + } + } +} + +void sub_8035D74(u8 taskId) +{ + struct LinkPlayer *linkPlayer; + u8 *name; + s32 i, palId; + + switch (gTasks[taskId].data[0]) + { + case 0: + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + for (i = 0; i < BATTLE_BANKS_COUNT; i++) + { + name = gLinkPlayers[i].name; + linkPlayer = &gLinkPlayers[i]; + + switch (linkPlayer->lp_field_18) + { + case 0: + BattleHandleAddTextPrinter(name, 0x11); + sub_8035AE4(taskId, linkPlayer->lp_field_18, 1, 2, 4); + break; + case 1: + BattleHandleAddTextPrinter(name, 0x12); + sub_8035AE4(taskId, linkPlayer->lp_field_18, 2, 2, 4); + break; + case 2: + BattleHandleAddTextPrinter(name, 0x13); + sub_8035AE4(taskId, linkPlayer->lp_field_18, 1, 2, 8); + break; + case 3: + BattleHandleAddTextPrinter(name, 0x14); + sub_8035AE4(taskId, linkPlayer->lp_field_18, 2, 2, 8); + break; + } + } + } + else + { + u8 playerId = gBattleScripting.multiplayerId; + u8 opponentId = playerId ^ BIT_SIDE; + u8 opponentId_copy = opponentId; + + if (gLinkPlayers[playerId].lp_field_18 != 0) + opponentId = playerId, playerId = opponentId_copy; + + name = gLinkPlayers[playerId].name; + BattleHandleAddTextPrinter(name, 0xF); + + name = gLinkPlayers[opponentId].name; + BattleHandleAddTextPrinter(name, 0x10); + + sub_8035AE4(taskId, playerId, 1, 2, 7); + sub_8035AE4(taskId, opponentId, 2, 2, 7); + } + gTasks[taskId].data[0]++; + break; + case 1: + palId = AllocSpritePalette(0x2710); + gPlttBufferUnfaded[palId * 16 + 0x10F] = gPlttBufferFaded[palId * 16 + 0x10F] = 0x7FFF; + gBattleStruct->field_7D = CreateSprite(&gUnknown_0831A9D0, 111, 80, 0); + gBattleStruct->field_7E = CreateSprite(&gUnknown_0831A9E8, 129, 80, 0); + gSprites[gBattleStruct->field_7D].invisible = 1; + gSprites[gBattleStruct->field_7E].invisible = 1; + gTasks[taskId].data[0]++; + break; + case 2: + if (gTasks[taskId].data[5] != 0) + { + gBattle_BG1_X = -(20) - (Sin2(gTasks[taskId].data[1]) / 32); + gBattle_BG2_X = -(140) - (Sin2(gTasks[taskId].data[2]) / 32); + gBattle_BG1_Y = -36; + gBattle_BG2_Y = -36; + } + else + { + gBattle_BG1_X = -(20) - (Sin2(gTasks[taskId].data[1]) / 32); + gBattle_BG1_Y = (Cos2(gTasks[taskId].data[1]) / 32) - 164; + gBattle_BG2_X = -(140) - (Sin2(gTasks[taskId].data[2]) / 32); + gBattle_BG2_Y = (Cos2(gTasks[taskId].data[2]) / 32) - 164; + } + + if (gTasks[taskId].data[2] != 0) + { + gTasks[taskId].data[2] -= 2; + gTasks[taskId].data[1] += 2; + } + else + { + if (gTasks[taskId].data[5] != 0) + sub_8035C4C(); + + PlaySE(SE_W231); + DestroyTask(taskId); + gSprites[gBattleStruct->field_7D].invisible = 0; + gSprites[gBattleStruct->field_7E].invisible = 0; + gSprites[gBattleStruct->field_7E].oam.tileNum += 0x40; + gSprites[gBattleStruct->field_7D].data[0] = 0; + gSprites[gBattleStruct->field_7E].data[0] = 1; + gSprites[gBattleStruct->field_7D].data[1] = gSprites[gBattleStruct->field_7D].pos1.x; + gSprites[gBattleStruct->field_7E].data[1] = gSprites[gBattleStruct->field_7E].pos1.x; + gSprites[gBattleStruct->field_7D].data[2] = 0; + gSprites[gBattleStruct->field_7E].data[2] = 0; + } + break; + } +} + +void LoadBattleEntryBackground(void) +{ + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + LZDecompressVram(gUnknown_08D778F0, (void*)(VRAM + 0x4000)); + LZDecompressVram(gUnknown_08D77B0C, (void*)(VRAM + 0x10000)); + LoadCompressedPalette(gUnknown_08D77AE4, 0x60, 0x20); + SetBgAttribute(1, BG_CTRL_ATTR_MAPBASEINDEX, 1); + SetGpuReg(REG_OFFSET_BG1CNT, 0x5C04); + CopyToBgTilemapBuffer(1, gUnknown_08D779D8, 0, 0); + CopyToBgTilemapBuffer(2, gUnknown_08D779D8, 0, 0); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(2); + SetGpuReg(REG_OFFSET_WININ, 0x36); + SetGpuReg(REG_OFFSET_WINOUT, 0x36); + gBattle_BG1_Y = 0xFF5C; + gBattle_BG2_Y = 0xFF5C; + LoadCompressedObjectPicUsingHeap(&gUnknown_0831AA00); + } + else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_EREADER_TRAINER)) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || gPartnerTrainerId == STEVEN_PARTNER_ID) + { + LZDecompressVram(gBattleTerrainAnimTiles_Building, (void*)(VRAM + 0x4000)); + LZDecompressVram(gBattleTerrainAnimTilemap_Building, (void*)(VRAM + 0xE000)); + } + else + { + SetBgAttribute(1, BG_CTRL_ATTR_VISIBLE, 2); + SetBgAttribute(2, BG_CTRL_ATTR_VISIBLE, 2); + CopyToBgTilemapBuffer(1, gUnknown_08D857A8, 0, 0); + CopyToBgTilemapBuffer(2, gUnknown_08D85A1C, 0, 0); + CopyBgTilemapBufferToVram(1); + CopyBgTilemapBufferToVram(2); + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_GROUDON) + { + LZDecompressVram(gBattleTerrainAnimTiles_Cave, (void*)(VRAM + 0x4000)); + LZDecompressVram(gBattleTerrainAnimTilemap_Cave, (void*)(VRAM + 0xE000)); + } + else if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE) + { + LZDecompressVram(gBattleTerrainAnimTiles_Underwater, (void*)(VRAM + 0x4000)); + LZDecompressVram(gBattleTerrainAnimTilemap_Underwater, (void*)(VRAM + 0xE000)); + } + else if (gBattleTypeFlags & BATTLE_TYPE_RAYQUAZA) + { + LZDecompressVram(gBattleTerrainAnimTiles_Rayquaza, (void*)(VRAM + 0x4000)); + LZDecompressVram(gBattleTerrainAnimTilemap_Rayquaza, (void*)(VRAM + 0xE000)); + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + u8 trainerClass = gTrainers[gTrainerBattleOpponent_A].trainerClass; + if (trainerClass == TRAINER_CLASS_LEADER) + { + LZDecompressVram(gBattleTerrainAnimTiles_Building, (void*)(VRAM + 0x4000)); + LZDecompressVram(gBattleTerrainAnimTilemap_Building, (void*)(VRAM + 0xE000)); + return; + } + else if (trainerClass == TRAINER_CLASS_CHAMPION) + { + LZDecompressVram(gBattleTerrainAnimTiles_Building, (void*)(VRAM + 0x4000)); + LZDecompressVram(gBattleTerrainAnimTilemap_Building, (void*)(VRAM + 0xE000)); + return; + } + } + + if (GetCurrentMapBattleScene() == MAP_BATTLE_SCENE_NORMAL) + { + LZDecompressVram(gBattleTerrainTable[gBattleTerrain].entryTileset, (void*)(VRAM + 0x4000)); + LZDecompressVram(gBattleTerrainTable[gBattleTerrain].entryTilemap, (void*)(VRAM + 0xE000)); + } + else + { + LZDecompressVram(gBattleTerrainAnimTiles_Building, (void*)(VRAM + 0x4000)); + LZDecompressVram(gBattleTerrainAnimTilemap_Building, (void*)(VRAM + 0xE000)); + } + } +} + +bool8 LoadChosenBattleElement(u8 caseId) +{ + bool8 ret = FALSE; + + switch (caseId) + { + case 0: + LZDecompressVram(gBattleTextboxTiles, (void*)(VRAM)); + break; + case 1: + CopyToBgTilemapBuffer(0, gBattleTextboxTilemap, 0, 0); + CopyBgTilemapBufferToVram(0); + break; + case 2: + LoadCompressedPalette(gBattleTextboxPalette, 0, 0x40); + break; + case 3: + if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_EREADER_TRAINER)) + { + LZDecompressVram(gBattleTerrainTiles_Building, (void*)(VRAM + 0x8000)); + } + else if (gBattleTypeFlags & BATTLE_TYPE_GROUDON) + { + LZDecompressVram(gBattleTerrainTiles_Cave, (void*)(VRAM + 0x8000)); + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + u8 trainerClass = gTrainers[gTrainerBattleOpponent_A].trainerClass; + if (trainerClass == TRAINER_CLASS_LEADER) + { + LZDecompressVram(gBattleTerrainTiles_Building, (void*)(VRAM + 0x8000)); + break; + } + else if (trainerClass == TRAINER_CLASS_CHAMPION) + { + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + break; + } + } + + switch (GetCurrentMapBattleScene()) + { + default: + case MAP_BATTLE_SCENE_NORMAL: + LZDecompressVram(gBattleTerrainTable[gBattleTerrain].tileset, (void*)(VRAM + 0x8000)); + break; + case MAP_BATTLE_SCENE_GYM: + LZDecompressVram(gBattleTerrainTiles_Building, (void*)(VRAM + 0x8000)); + break; + case MAP_BATTLE_SCENE_MAGMA: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + break; + case MAP_BATTLE_SCENE_AQUA: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + break; + case MAP_BATTLE_SCENE_SIDNEY: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + break; + case MAP_BATTLE_SCENE_PHOEBE: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + break; + case MAP_BATTLE_SCENE_GLACIA: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + break; + case MAP_BATTLE_SCENE_DRAKE: + LZDecompressVram(gBattleTerrainTiles_Stadium, (void*)(VRAM + 0x8000)); + break; + case MAP_BATTLE_SCENE_FRONTIER: + LZDecompressVram(gBattleTerrainTiles_Building, (void*)(VRAM + 0x8000)); + break; + } + } + break; + case 4: + if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_EREADER_TRAINER)) + { + LZDecompressVram(gBattleTerrainTilemap_Building, (void*)(VRAM + 0xD000)); + } + else if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON) + { + if (gGameVersion == VERSION_RUBY) + LZDecompressVram(gBattleTerrainTilemap_Cave, (void*)(VRAM + 0xD000)); + else + LZDecompressVram(gBattleTerrainTilemap_Water, (void*)(VRAM + 0xD000)); + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + u8 trainerClass = gTrainers[gTrainerBattleOpponent_A].trainerClass; + if (trainerClass == TRAINER_CLASS_LEADER) + { + LZDecompressVram(gBattleTerrainTilemap_Building, (void*)(VRAM + 0xD000)); + break; + } + else if (trainerClass == TRAINER_CLASS_CHAMPION) + { + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + break; + } + } + + switch (GetCurrentMapBattleScene()) + { + default: + case MAP_BATTLE_SCENE_NORMAL: + LZDecompressVram(gBattleTerrainTable[gBattleTerrain].tilemap, (void*)(VRAM + 0xD000)); + break; + case MAP_BATTLE_SCENE_GYM: + LZDecompressVram(gBattleTerrainTilemap_Building, (void*)(VRAM + 0xD000)); + break; + case MAP_BATTLE_SCENE_MAGMA: + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + break; + case MAP_BATTLE_SCENE_AQUA: + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + break; + case MAP_BATTLE_SCENE_SIDNEY: + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + break; + case MAP_BATTLE_SCENE_PHOEBE: + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + break; + case MAP_BATTLE_SCENE_GLACIA: + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + break; + case MAP_BATTLE_SCENE_DRAKE: + LZDecompressVram(gBattleTerrainTilemap_Stadium, (void*)(VRAM + 0xD000)); + break; + case MAP_BATTLE_SCENE_FRONTIER: + LZDecompressVram(gBattleTerrainTilemap_Building, (void*)(VRAM + 0xD000)); + break; + } + } + break; + case 5: + if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_EREADER_TRAINER)) + { + LoadCompressedPalette(gBattleTerrainPalette_Frontier, 0x20, 0x60); + } + else if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON) + { + if (gGameVersion == VERSION_RUBY) + LoadCompressedPalette(gBattleTerrainPalette_Groudon, 0x20, 0x60); + else + LoadCompressedPalette(gBattleTerrainPalette_Kyogre, 0x20, 0x60); + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + u8 trainerClass = gTrainers[gTrainerBattleOpponent_A].trainerClass; + if (trainerClass == TRAINER_CLASS_LEADER) + { + LoadCompressedPalette(gBattleTerrainPalette_BuildingLeader, 0x20, 0x60); + break; + } + else if (trainerClass == TRAINER_CLASS_CHAMPION) + { + LoadCompressedPalette(gBattleTerrainPalette_StadiumWallace, 0x20, 0x60); + break; + } + } + + switch (GetCurrentMapBattleScene()) + { + default: + case MAP_BATTLE_SCENE_NORMAL: + LoadCompressedPalette(gBattleTerrainTable[gBattleTerrain].palette, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_GYM: + LoadCompressedPalette(gBattleTerrainPalette_BuildingGym, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_MAGMA: + LoadCompressedPalette(gBattleTerrainPalette_StadiumMagma, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_AQUA: + LoadCompressedPalette(gBattleTerrainPalette_StadiumAqua, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_SIDNEY: + LoadCompressedPalette(gBattleTerrainPalette_StadiumSidney, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_PHOEBE: + LoadCompressedPalette(gBattleTerrainPalette_StadiumPhoebe, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_GLACIA: + LoadCompressedPalette(gBattleTerrainPalette_StadiumGlacia, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_DRAKE: + LoadCompressedPalette(gBattleTerrainPalette_StadiumDrake, 0x20, 0x60); + break; + case MAP_BATTLE_SCENE_FRONTIER: + LoadCompressedPalette(gBattleTerrainPalette_Frontier, 0x20, 0x60); + break; + } + } + break; + case 6: + ApplyPlayerChosenFrameToBattleMenu(); + break; + default: + ret = TRUE; + break; + } + + return ret; +} diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index e497dbfe2..08c666d11 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -234,7 +234,7 @@ static void (*const sPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(void) = static const u8 sTargetIdentities[] = {IDENTITY_PLAYER_MON1, IDENTITY_PLAYER_MON2, IDENTITY_OPPONENT_MON2, IDENTITY_OPPONENT_MON1}; // unknown unused data -static const u8 gUnknown_0831C5FC[] = {0x48, 0x48, 0x20, 0x5a, 0x50, 0x50, 0x50, 0x58}; +static const u8 sUnknown_0831C5FC[] = {0x48, 0x48, 0x20, 0x5a, 0x50, 0x50, 0x50, 0x58}; void nullsub_21(void) { diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index eb57297da..dc4a213cc 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -198,7 +198,7 @@ static void (*const sPlayerPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(void) = }; // unknown unused data -static const u8 gUnknown_08617254[] = +static const u8 sUnknown_08617254[] = { 0x83, 0x4d, 0xf3, 0x5f, 0x6f, 0x4f, 0xeb, 0x3e, 0x67, 0x2e, 0x10, 0x46, 0x8c, 0x3d, 0x28, 0x35, diff --git a/src/battle_controller_safari.c b/src/battle_controller_safari.c index db4670523..64e6a0bc3 100644 --- a/src/battle_controller_safari.c +++ b/src/battle_controller_safari.c @@ -19,6 +19,7 @@ #include "reshow_battle_screen.h" #include "pokeball.h" #include "data2.h" +#include "pokeblock.h" extern u32 gBattleExecBuffer; extern u8 gActiveBank; @@ -291,13 +292,13 @@ static void CompleteOnSpecialAnimDone(void) SafariBufferExecCompleted(); } -static void OpenPokeblockCase(void) +static void SafariOpenPokeblockCase(void) { if (!gPaletteFade.active) { gBattleBankFunc[gActiveBank] = CompleteWhenChosePokeblock; FreeAllWindowBuffers(); - sub_81358F4(); + OpenPokeblockCaseInBattle(); } } @@ -497,7 +498,7 @@ static void SafariHandleChooseItem(void) s32 i; BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); - gBattleBankFunc[gActiveBank] = OpenPokeblockCase; + gBattleBankFunc[gActiveBank] = SafariOpenPokeblockCase; gBankInMenu = gActiveBank; } diff --git a/src/battle_interface.c b/src/battle_interface.c index 95f1a1111..6a6bf00a2 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -177,7 +177,6 @@ extern const u16 gBattleInterface_BallDisplayPal[]; extern const u8 gHealthboxElementsGfxTable[][32]; // functions -extern void AddTextPrinterParametrized2(u8 windowId, u8 fontId, u8 x, u8 y, u8 letterSpacing, u8 lineSpacing, struct TextColor *color, s8 speed, const u8 *str); // menu.h extern void LoadBattleBarGfx(u8 arg0); // this file's functions diff --git a/src/battle_message.c b/src/battle_message.c index ec1cfd626..8a985102d 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -12,6 +12,7 @@ #include "window.h" #include "palette.h" #include "battle_controllers.h" +#include "battle_setup.h" extern u16 gLastUsedItem; extern u8 gLastUsedAbility; @@ -54,8 +55,6 @@ extern void sub_81D5554(u8 *txtPtr, u16 trainerId); // pokenav extern void GetEreaderTrainerName(u8 *txtPtr); extern void sub_81A36D0(u8 arg0, u16 trainerId); // battle_frontier_2 extern void sub_81D572C(u8 arg0, u16 trainerId); // pokenav -extern const u8* GetTrainer1LoseText(void); // battle_setup -extern const u8* GetTrainer2LoseText(void); // battle_setup extern void GetFrontierTrainerName(u8 *dst, u16 trainerId); extern s32 GetStringCenterAlignXOffsetWithLetterSpacing(u8 fontId, const u8 *str, s32 totalWidth, s16 letterSpacing); extern u8 GetTextSpeedInRecordedBattle(void); @@ -1367,7 +1366,7 @@ static const u16 sUnknownMoveTable[] = static const u8 sDummyWeirdStatusString[] = {EOS, EOS, EOS, EOS, EOS, EOS, EOS, EOS, 0, 0}; -static const u8 gUnknown_085CD42C[] = +static const u8 sUnknown_085CD42C[] = { 0xFF, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x1, 0xF, 0x6, 0x0, 0x0, 0xFF, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0xF, 0x6, 0x0, 0x0, 0xEE, 0x1, 0x0, 0x1, 0x0, @@ -1392,7 +1391,7 @@ static const u8 gUnknown_085CD42C[] = 0x6, 0x0, 0x0, 0x0, 0x1, 0xFF, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x6, 0x0, 0x0 }; -static const u8 gUnknown_085CD54C[] = +static const u8 sUnknown_085CD54C[] = { 0xFF, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x1, 0xF, 0x6, 0x0, 0x0, 0xFF, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0xF, 0x6, 0x0, 0x0, 0xEE, 0x1, 0x0, 0x1, 0x0, @@ -1419,7 +1418,7 @@ static const u8 gUnknown_085CD54C[] = static const u8 * const gUnknown_085CD660[] = { - gUnknown_085CD42C, gUnknown_085CD54C + sUnknown_085CD42C, sUnknown_085CD54C }; static const u8 sRecordedBattleTextSpeeds[] = {8, 4, 1, 0}; @@ -2068,7 +2067,7 @@ u32 BattleStringExpandPlaceholders(const u8* src, u8* dst) } else { - toCpy = GetTrainer1LoseText(); + toCpy = GetTrainerALoseText(); } break; case B_TXT_TRAINER1_WIN_TEXT: // trainerA win text @@ -2165,7 +2164,7 @@ u32 BattleStringExpandPlaceholders(const u8* src, u8* dst) } else { - toCpy = GetTrainer2LoseText(); + toCpy = GetTrainerBLoseText(); } break; case B_TXT_TRAINER2_WIN_TEXT: diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 88d583c1f..656f9f43a 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -17,6 +17,7 @@ #include "battle_interface.h" #include "constants/species.h" #include "constants/songs.h" +#include "constants/trainers.h" #include "text.h" #include "sound.h" #include "pokedex.h" @@ -6236,19 +6237,19 @@ static u32 GetTrainerMoneyToGive(u16 trainerId) lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; } break; - case PARTY_FLAG_CUSTOM_MOVES: + case F_TRAINER_PARTY_CUSTOM_MOVESET: { const struct TrainerMonNoItemCustomMoves *party = gTrainers[trainerId].party.NoItemCustomMoves; lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; } break; - case PARTY_FLAG_HAS_ITEM: + case F_TRAINER_PARTY_HELD_ITEM: { const struct TrainerMonItemDefaultMoves *party = gTrainers[trainerId].party.ItemDefaultMoves; lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; } break; - case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: + case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: { const struct TrainerMonItemCustomMoves *party = gTrainers[trainerId].party.ItemCustomMoves; lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; @@ -10334,7 +10335,7 @@ static void atkE4_getsecretpowereffect(void) case BATTLE_TERRAIN_POND: gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SPD_MINUS_1; break; - case BATTLE_TERRAIN_ROCK: + case BATTLE_TERRAIN_MOUNTAIN: gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION; break; case BATTLE_TERRAIN_CAVE: diff --git a/src/battle_setup.c b/src/battle_setup.c new file mode 100644 index 000000000..be23a28c9 --- /dev/null +++ b/src/battle_setup.c @@ -0,0 +1,1881 @@ +#include "global.h" +#include "constants/trainers.h" +#include "battle.h" +#include "battle_setup.h" +#include "battle_transition.h" +#include "main.h" +#include "task.h" +#include "pokemon_3.h" +#include "safari_zone.h" +#include "script.h" +#include "constants/game_stat.h" +#include "event_data.h" +#include "constants/species.h" +#include "songs.h" +#include "metatile_behavior.h" +#include "constants/maps.h" +#include "field_player_avatar.h" +#include "fieldmap.h" +#include "random.h" +#include "starter_choose.h" +#include "script_pokemon_80F8.h" +#include "constants/items.h" +#include "palette.h" +#include "window.h" +#include "field_map_obj.h" +#include "event_scripts.h" +#include "trainer_see.h" +#include "field_message_box.h" +#include "sound.h" +#include "strings.h" +#include "secret_base.h" +#include "string_util.h" + +enum +{ + TRAINER_PARAM_LOAD_VAL_8BIT, + TRAINER_PARAM_LOAD_VAL_16BIT, + TRAINER_PARAM_LOAD_VAL_32BIT, + TRAINER_PARAM_CLEAR_VAL_8BIT, + TRAINER_PARAM_CLEAR_VAL_16BIT, + TRAINER_PARAM_CLEAR_VAL_32BIT, + TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR, +}; + +struct TrainerBattleParameter +{ + void *varPtr; + u8 ptrType; +}; + +extern bool8 InBattlePyramid(void); +extern bool8 InBattlePike(void); +extern bool32 InTrainerHill(void); +extern bool32 FieldPoisonEffectIsRunning(void); +extern void overworld_free_bg_tilemaps(void); +extern void prev_quest_postbuffer_cursor_backup_reset(void); +extern void ResetPoisonStepCounter(void); +extern void sub_81BE72C(void); +extern void FreezeMapObjects(void); +extern void sub_808BCF4(void); +extern void sub_80EECC8(void); +extern void c2_exit_to_overworld_1_continue_scripts_restart_music(void); +extern void c2_exit_to_overworld_2_switch(void); +extern void Overworld_ClearSavedMusic(void); +extern void CB2_WhiteOut(void); +extern void sub_80AF6F0(void); +extern void PlayBattleBGM(void); +extern void sub_81DA57C(void); +extern u8 GetSav1Weather(void); +extern u8 Overworld_GetFlashLevel(void); +extern u16 sub_81A9AA8(u8 localId); +extern u16 sub_81D6180(u8 localId); +extern bool8 GetBattlePyramidTrainerFlag(u8 mapObjId); +extern bool8 GetTrainerHillTrainerFlag(u8 mapObjId); +extern bool8 sub_81D5C18(void); +extern void sub_816306C(u8 a0); +extern void sub_8163048(u8 a0); +extern void sub_81A9B04(void); +extern void sub_81D639C(void); +extern void sub_81D6384(void); +extern void sub_81D61E8(void); +extern void sub_80982B8(void); +extern void sub_81A9EDC(u16 a0); +extern void sub_81D572C(u8 a0, u16 arg1); +extern void IncrementGameStat(u8 statId); +extern u32 GetGameStat(u8 statId); + +extern u32 gBattleTypeFlags; +extern u8 gBattleOutcome; +extern void (*gFieldCallback)(void); + +// this file's functions +static void DoBattlePikeWildBattle(void); +static void DoSafariBattle(void); +static void DoStandardWildBattle(void); +static void CB2_EndWildBattle(void); +static void CB2_EndScriptedWildBattle(void); +static u8 GetWildBattleTransition(void); +static u8 GetTrainerBattleTransition(void); +static void sub_80B1218(void); +static void sub_80B1234(void); +static void CB2_GiveStarter(void); +static void CB2_StartFirstBattle(void); +static void CB2_EndFirstBattle(void); +static void CB2_EndTrainerBattle(void); +static bool32 IsPlayerDefeated(u32 battleOutcome); +static u16 GetRematchTrainerId(u16 trainerId); +static void RegisterTrainerInMatchCall(void); +static void HandleRematchVarsOnBattleEnd(void); +static const u8 *GetIntroSpeechOfApproachingTrainer(void); +static const u8 *GetTrainerCantBattleSpeech(void); + +// ewram vars +EWRAM_DATA static u16 sTrainerBattleMode = 0; +EWRAM_DATA u16 gTrainerBattleOpponent_A = 0; +EWRAM_DATA u16 gTrainerBattleOpponent_B = 0; +EWRAM_DATA u16 gPartnerTrainerId = 0; +EWRAM_DATA static u16 sTrainerMapObjectLocalId = 0; +EWRAM_DATA static u8 *sTrainerAIntroSpeech = NULL; +EWRAM_DATA static u8 *sTrainerBIntroSpeech = NULL; +EWRAM_DATA static u8 *sTrainerADefeatSpeech = NULL; +EWRAM_DATA static u8 *sTrainerBDefeatSpeech = NULL; +EWRAM_DATA static u8 *sTrainerVictorySpeech = NULL; +EWRAM_DATA static u8 *sTrainerCannotBattleSpeech = NULL; +EWRAM_DATA static u8 *sTrainerBattleEndScript = NULL; +EWRAM_DATA static u8 *sTrainerABattleScriptRetAddr = NULL; +EWRAM_DATA static u8 *sTrainerBBattleScriptRetAddr = NULL; +EWRAM_DATA static bool8 sShouldCheckTrainerBScript = FALSE; +EWRAM_DATA static u8 sNoOfPossibleTrainerRetScripts = 0; + +// const rom data + +// The first transition is used if the enemy pokemon are lower level than our pokemon. +// Otherwise, the second transition is used. +static const u8 sBattleTransitionTable_Wild[][2] = +{ + {B_TRANSITION_SLICE, B_TRANSITION_WHITEFADE}, // Normal + {B_TRANSITION_CLOCKWISE_BLACKFADE, B_TRANSITION_GRID_SQUARES}, // Cave + {B_TRANSITION_BLUR, B_TRANSITION_GRID_SQUARES}, // Cave with flash used + {B_TRANSITION_WAVE, B_TRANSITION_RIPPLE}, // Water +}; + +static const u8 sBattleTransitionTable_Trainer[][2] = +{ + {B_TRANSITION_POKEBALLS_TRAIL, B_TRANSITION_SHARDS}, // Normal + {B_TRANSITION_SHUFFLE, B_TRANSITION_BIG_POKEBALL}, // Cave + {B_TRANSITION_BLUR, B_TRANSITION_GRID_SQUARES}, // Cave with flash used + {B_TRANSITION_SWIRL, B_TRANSITION_RIPPLE}, // Water +}; + +static const u8 sUnknown_0854FE98[] = +{ + B_TRANSITION_29, B_TRANSITION_30, B_TRANSITION_31, B_TRANSITION_32, + B_TRANSITION_34, B_TRANSITION_35, B_TRANSITION_36, B_TRANSITION_37, + B_TRANSITION_38, B_TRANSITION_39, B_TRANSITION_40, B_TRANSITION_41 +}; + +static const u8 sUnknown_0854FEA4[] = +{ + B_TRANSITION_31, B_TRANSITION_32, B_TRANSITION_33 +}; + +static const u8 sUnknown_0854FEA7[] = +{ + B_TRANSITION_29, B_TRANSITION_31, B_TRANSITION_32, B_TRANSITION_33 +}; + +static const struct TrainerBattleParameter sOrdinaryBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sContinueScriptBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sDoubleBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sOrdinaryNoIntroBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sContinueScriptDoubleBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerABattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sTrainerBOrdinaryBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_B, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerBIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBDefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBBattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +static const struct TrainerBattleParameter sTrainerBContinueScriptBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&gTrainerBattleOpponent_B, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerMapObjectLocalId, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerBIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBDefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBBattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + +const struct RematchTrainer gRematchTable[REMATCH_TABLE_ENTRIES] = +{ + {{0x0025, 0x0028, 0x0029, 0x002a, 0x002b}, 0x0000, 0x0021}, + {{0x02e1, 0x032c, 0x032d, 0x032e, 0x032f}, 0x0000, 0x0014}, + {{0x002c, 0x002f, 0x0030, 0x0031, 0x0032}, 0x0000, 0x001a}, + {{0x0039, 0x003c, 0x003d, 0x003e, 0x003f}, 0x0000, 0x0018}, + {{0x0040, 0x0043, 0x0044, 0x0045, 0x0046}, 0x0000, 0x0018}, + {{0x02af, 0x02b0, 0x02b1, 0x02b2, 0x02b3}, 0x0000, 0x0027}, + {{0x02ff, 0x033c, 0x033d, 0x033e, 0x033f}, 0x0000, 0x0024}, + {{0x005e, 0x0065, 0x0066, 0x0067, 0x0068}, 0x0000, 0x001a}, + {{0x004e, 0x0054, 0x0055, 0x0056, 0x0057}, 0x0000, 0x001a}, + {{0x006c, 0x006e, 0x006f, 0x0070, 0x0071}, 0x0018, 0x0014}, + {{0x0072, 0x0078, 0x0079, 0x007a, 0x007b}, 0x0000, 0x0013}, + {{0x0090, 0x034c, 0x034d, 0x034e, 0x034f}, 0x0018, 0x0038}, + {{0x007f, 0x0084, 0x0085, 0x0086, 0x0087}, 0x0000, 0x0024}, + {{0x0088, 0x008b, 0x008c, 0x008d, 0x008e}, 0x0000, 0x0013}, + {{0x008f, 0x0093, 0x0094, 0x0095, 0x0096}, 0x0000, 0x001d}, + {{0x009b, 0x00af, 0x00b0, 0x00b1, 0x00b2}, 0x0000, 0x0016}, + {{0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb}, 0x0000, 0x001e}, + {{0x02a0, 0x0338, 0x0339, 0x033a, 0x033b}, 0x0000, 0x002a}, + {{0x00c3, 0x0340, 0x0341, 0x0342, 0x0343}, 0x0000, 0x0026}, + {{0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8}, 0x0000, 0x0021}, + {{0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2}, 0x0000, 0x001d}, + {{0x00d8, 0x00db, 0x00dc, 0x00dd, 0x00de}, 0x0018, 0x000d}, + {{0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad}, 0x0018, 0x0001}, + {{0x00e2, 0x00e4, 0x00e5, 0x00e6, 0x00e7}, 0x0000, 0x0023}, + {{0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2}, 0x0000, 0x0026}, + {{0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd}, 0x0000, 0x0026}, + {{0x00fe, 0x0101, 0x0102, 0x0103, 0x0104}, 0x0000, 0x0024}, + {{0x0118, 0x011a, 0x011b, 0x011c, 0x011d}, 0x0000, 0x001f}, + {{0x0111, 0x0114, 0x0115, 0x0116, 0x0117}, 0x0000, 0x001f}, + {{0x011f, 0x0120, 0x0121, 0x0122, 0x0123}, 0x0000, 0x0020}, + {{0x012e, 0x012f, 0x0130, 0x0131, 0x0132}, 0x0000, 0x0019}, + {{0x0125, 0x0127, 0x0128, 0x0129, 0x012a}, 0x0000, 0x0012}, + {{0x0133, 0x0134, 0x0135, 0x0136, 0x0137}, 0x0000, 0x001e}, + {{0x0139, 0x013a, 0x013b, 0x013c, 0x013d}, 0x0018, 0x000c}, + {{0x013e, 0x0148, 0x0149, 0x014a, 0x014b}, 0x0000, 0x0011}, + {{0x0153, 0x015a, 0x015b, 0x015c, 0x015d}, 0x0000, 0x0015}, + {{0x0178, 0x017b, 0x017c, 0x017d, 0x017e}, 0x0000, 0x002b}, + {{0x0171, 0x0172, 0x0173, 0x0174, 0x0175}, 0x0000, 0x0020}, + {{0x0166, 0x0168, 0x0169, 0x016a, 0x016b}, 0x0000, 0x0019}, + {{0x016c, 0x016d, 0x016e, 0x016f, 0x0170}, 0x0000, 0x0020}, + {{0x0182, 0x0184, 0x0185, 0x0186, 0x0187}, 0x0000, 0x002b}, + {{0x0161, 0x0162, 0x0163, 0x0164, 0x0165}, 0x0000, 0x0019}, + {{0x0179, 0x0334, 0x0335, 0x0336, 0x0337}, 0x0000, 0x0029}, + {{0x0188, 0x0189, 0x018a, 0x018b, 0x018c}, 0x0018, 0x0001}, + {{0x0196, 0x0199, 0x019a, 0x019b, 0x019c}, 0x0000, 0x0023}, + {{0x01a3, 0x01a5, 0x01a6, 0x01a7, 0x01a8}, 0x0000, 0x001c}, + {{0x01ab, 0x01ae, 0x01af, 0x01b0, 0x01b1}, 0x0000, 0x001e}, + {{0x01b2, 0x01b5, 0x01b6, 0x01b7, 0x01b8}, 0x0000, 0x001c}, + {{0x01c1, 0x01d1, 0x01d2, 0x01d3, 0x01d4}, 0x0000, 0x0027}, + {{0x01da, 0x01dd, 0x01de, 0x01df, 0x01e0}, 0x0018, 0x000d}, + {{0x01e1, 0x01e2, 0x01e7, 0x01e8, 0x01e9}, 0x0000, 0x0012}, + {{0x01ec, 0x01f1, 0x01f2, 0x01f3, 0x01f4}, 0x0000, 0x0028}, + {{0x02e4, 0x0330, 0x0331, 0x0332, 0x0333}, 0x0000, 0x0017}, + {{0x0200, 0x0203, 0x0204, 0x0205, 0x0206}, 0x0000, 0x0019}, + {{0x0221, 0x0224, 0x0225, 0x0226, 0x0227}, 0x0000, 0x0020}, + {{0x021a, 0x021d, 0x021e, 0x021f, 0x0220}, 0x0000, 0x0020}, + {{0x0009, 0x0348, 0x0349, 0x034a, 0x034b}, 0x0018, 0x0011}, + {{0x022f, 0x0232, 0x0233, 0x0234, 0x0235}, 0x0000, 0x0022}, + {{0x0228, 0x022b, 0x022c, 0x022d, 0x022e}, 0x0000, 0x0022}, + {{0x025c, 0x025f, 0x0260, 0x0261, 0x0262}, 0x0000, 0x0013}, + {{0x026d, 0x026e, 0x026f, 0x0270, 0x0271}, 0x0018, 0x000b}, + {{0x0273, 0x027c, 0x027d, 0x027e, 0x027f}, 0x0000, 0x001b}, + {{0x0001, 0x0344, 0x0345, 0x0346, 0x0347}, 0x0018, 0x000c}, + {{0x0282, 0x0283, 0x0284, 0x0285, 0x0286}, 0x0018, 0x003e}, + {{0x0291, 0x0292, 0x0293, 0x0294, 0x0294}, 0x0018, 0x002b}, + {{0x0109, 0x0302, 0x0303, 0x0304, 0x0305}, 0x0000, 0x0003}, + {{0x010a, 0x0306, 0x0307, 0x0308, 0x0309}, 0x0000, 0x000b}, + {{0x010b, 0x030a, 0x030b, 0x030c, 0x030d}, 0x0000, 0x0002}, + {{0x010c, 0x030e, 0x030f, 0x0310, 0x0311}, 0x0000, 0x000c}, + {{0x010d, 0x0312, 0x0313, 0x0314, 0x0315}, 0x0000, 0x0000}, + {{0x010e, 0x0316, 0x0317, 0x0318, 0x0319}, 0x0000, 0x0004}, + {{0x010f, 0x031a, 0x031b, 0x031c, 0x031d}, 0x0000, 0x0006}, + {{0x0110, 0x031e, 0x031f, 0x0320, 0x0321}, 0x0000, 0x0007}, + {{0x0105, 0x0105, 0x0105, 0x0105, 0x0105}, 0x0000, 0x0008}, + {{0x0106, 0x0106, 0x0106, 0x0106, 0x0106}, 0x0000, 0x0008}, + {{0x0107, 0x0107, 0x0107, 0x0107, 0x0107}, 0x0000, 0x0008}, + {{0x0108, 0x0108, 0x0108, 0x0108, 0x0108}, 0x0000, 0x0008}, + {{0x014f, 0x014f, 0x014f, 0x014f, 0x014f}, 0x0000, 0x0008}, +}; + +static const u16 sBadgeFlags[8] = +{ + FLAG_BADGE01_GET, FLAG_BADGE02_GET, FLAG_BADGE03_GET, FLAG_BADGE04_GET, + FLAG_BADGE05_GET, FLAG_BADGE06_GET, FLAG_BADGE07_GET, FLAG_BADGE08_GET, +}; + +#define tState data[0] +#define tTransition data[1] + +static void Task_BattleStart(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + switch (tState) + { + case 0: + if (!FieldPoisonEffectIsRunning()) // is poison not active? + { + BattleTransition_StartOnField(tTransition); + sub_81BE72C(); + tState++; // go to case 1. + } + break; + case 1: + if (IsBattleTransitionDone() == TRUE) + { + overworld_free_bg_tilemaps(); + SetMainCallback2(CB2_InitBattle); + prev_quest_postbuffer_cursor_backup_reset(); + ResetPoisonStepCounter(); + DestroyTask(taskId); + } + break; + } +} + +static void CreateBattleStartTask(u8 transition, u16 song) +{ + u8 taskId = CreateTask(Task_BattleStart, 1); + + gTasks[taskId].tTransition = transition; + PlayMapChosenOrBattleBGM(song); +} + +#undef tState +#undef tTransition + +void BattleSetup_StartWildBattle(void) +{ + if (GetSafariZoneFlag()) + DoSafariBattle(); + else + DoStandardWildBattle(); +} + +void BattleSetup_StartBattlePikeWildBattle(void) +{ + DoBattlePikeWildBattle(); +} + +static void DoStandardWildBattle(void) +{ + ScriptContext2_Enable(); + FreezeMapObjects(); + sub_808BCF4(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = 0; + if (InBattlePyramid()) + { + VarSet(VAR_0x400E, 0); + gBattleTypeFlags |= BATTLE_TYPE_PYRAMID; + } + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void BattleSetup_StartRoamerBattle(void) +{ + ScriptContext2_Enable(); + FreezeMapObjects(); + sub_808BCF4(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = BATTLE_TYPE_ROAMER; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +static void DoSafariBattle(void) +{ + ScriptContext2_Enable(); + FreezeMapObjects(); + sub_808BCF4(); + gMain.savedCallback = CB2_EndSafariBattle; + gBattleTypeFlags = BATTLE_TYPE_SAFARI; + CreateBattleStartTask(GetWildBattleTransition(), 0); +} + +static void DoBattlePikeWildBattle(void) +{ + ScriptContext2_Enable(); + FreezeMapObjects(); + sub_808BCF4(); + gMain.savedCallback = CB2_EndWildBattle; + gBattleTypeFlags = BATTLE_TYPE_PIKE; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +static void DoTrainerBattle(void) +{ + CreateBattleStartTask(GetTrainerBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_TRAINER_BATTLES); + sub_80B1234(); +} + +static void sub_80B0828(void) +{ + if (InBattlePyramid()) + CreateBattleStartTask(sub_80B100C(10), 0); + else + CreateBattleStartTask(sub_80B100C(11), 0); + + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_TRAINER_BATTLES); + sub_80B1234(); +} + +// Initiates battle where Wally catches Ralts +void StartWallyTutorialBattle(void) +{ + CreateMaleMon(&gEnemyParty[0], SPECIES_RALTS, 5); + ScriptContext2_Enable(); + gMain.savedCallback = c2_exit_to_overworld_1_continue_scripts_restart_music; + gBattleTypeFlags = BATTLE_TYPE_WALLY_TUTORIAL; + CreateBattleStartTask(B_TRANSITION_SLICE, 0); +} + +void BattleSetup_StartScriptedWildBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = 0; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void BattleSetup_StartLatiBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY; + CreateBattleStartTask(GetWildBattleTransition(), 0); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void BattleSetup_StartLegendaryBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY; + + switch (GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL)) + { + default: + case SPECIES_GROUDON: + gBattleTypeFlags |= BATTLE_TYPE_GROUDON; + CreateBattleStartTask(B_TRANSITION_GROUDON, BGM_BATTLE34); + break; + case SPECIES_KYOGRE: + gBattleTypeFlags |= BATTLE_TYPE_KYOGRE; + CreateBattleStartTask(B_TRANSITION_KYOGRE, BGM_BATTLE34); + break; + case SPECIES_RAYQUAZA: + gBattleTypeFlags |= BATTLE_TYPE_RAYQUAZA; + CreateBattleStartTask(B_TRANSITION_RAYQUAZA, BGM_BATTLE_LEGENDARY); + break; + case SPECIES_DEOXYS: + CreateBattleStartTask(B_TRANSITION_BLUR, BGM_FRLG_BATTLE_DEOXYS); + break; + case SPECIES_LUGIA: + case SPECIES_HO_OH: + CreateBattleStartTask(B_TRANSITION_BLUR, BGM_FRLG_BATTLE_LEGENDARY); + break; + case SPECIES_MEW: + CreateBattleStartTask(B_TRANSITION_GRID_SQUARES, BGM_BATTLE_MEW); + break; + } + + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void StartGroudonKyogreBattle(void) +{ + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_KYOGRE_GROUDON; + + if (gGameVersion == VERSION_RUBY) + CreateBattleStartTask(B_TRANSITION_SHARDS, BGM_BATTLE34); // GROUDON + else + CreateBattleStartTask(B_TRANSITION_RIPPLE, BGM_BATTLE34); // KYOGRE + + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +void StartRegiBattle(void) +{ + u8 transitionId; + u16 species; + + ScriptContext2_Enable(); + gMain.savedCallback = CB2_EndScriptedWildBattle; + gBattleTypeFlags = BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_REGI; + + species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES); + switch (species) + { + case SPECIES_REGIROCK: + transitionId = B_TRANSITION_REGIROCK; + break; + case SPECIES_REGICE: + transitionId = B_TRANSITION_REGICE; + break; + case SPECIES_REGISTEEL: + transitionId = B_TRANSITION_REGISTEEL; + break; + default: + transitionId = B_TRANSITION_GRID_SQUARES; + break; + } + CreateBattleStartTask(transitionId, BGM_BATTLE36); + + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); +} + +static void CB2_EndWildBattle(void) +{ + CpuFill16(0, (void*)(BG_PLTT), BG_PLTT_SIZE); + ResetOamRange(0, 128); + + if (IsPlayerDefeated(gBattleOutcome) == TRUE && !InBattlePyramid() && !InBattlePike()) + { + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(c2_exit_to_overworld_2_switch); + gFieldCallback = sub_80AF6F0; + } +} + +static void CB2_EndScriptedWildBattle(void) +{ + CpuFill16(0, (void*)(BG_PLTT), BG_PLTT_SIZE); + ResetOamRange(0, 128); + + if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + if (InBattlePyramid()) + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + else + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + } +} + +u8 BattleSetup_GetTerrainId(void) +{ + u16 tileBehavior; + s16 x, y; + + PlayerGetDestCoords(&x, &y); + tileBehavior = MapGridGetMetatileBehaviorAt(x, y); + + if (MetatileBehavior_IsTallGrass(tileBehavior)) + return BATTLE_TERRAIN_GRASS; + if (MetatileBehavior_IsLongGrass(tileBehavior)) + return BATTLE_TERRAIN_LONG_GRASS; + if (MetatileBehavior_IsSandOrDeepSand(tileBehavior)) + return BATTLE_TERRAIN_SAND; + + switch (gMapHeader.mapType) + { + case MAP_TYPE_TOWN: + case MAP_TYPE_CITY: + case MAP_TYPE_ROUTE: + break; + case MAP_TYPE_UNDERGROUND: + if (MetatileBehavior_IsMB_0B(tileBehavior)) + return BATTLE_TERRAIN_BUILDING; + if (MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior)) + return BATTLE_TERRAIN_POND; + return BATTLE_TERRAIN_CAVE; + case MAP_TYPE_INDOOR: + case MAP_TYPE_SECRET_BASE: + return BATTLE_TERRAIN_BUILDING; + case MAP_TYPE_UNDERWATER: + return BATTLE_TERRAIN_UNDERWATER; + case MAP_TYPE_6: + if (MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior)) + return BATTLE_TERRAIN_WATER; + return BATTLE_TERRAIN_PLAIN; + } + if (MetatileBehavior_IsDeepOrOceanWater(tileBehavior)) + return BATTLE_TERRAIN_WATER; + if (MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior)) + return BATTLE_TERRAIN_POND; + if (MetatileBehavior_IsMountain(tileBehavior)) + return BATTLE_TERRAIN_MOUNTAIN; + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING)) + { + if (MetatileBehavior_GetBridgeSth(tileBehavior)) + return BATTLE_TERRAIN_POND; + if (MetatileBehavior_IsBridge(tileBehavior) == TRUE) + return BATTLE_TERRAIN_WATER; + } + if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(ROUTE113) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(ROUTE113)) + return BATTLE_TERRAIN_SAND; + if (GetSav1Weather() == 8) + return BATTLE_TERRAIN_SAND; + + return BATTLE_TERRAIN_PLAIN; +} + +static u8 GetBattleTransitionTypeByMap(void) +{ + u16 tileBehavior; + s16 x, y; + + PlayerGetDestCoords(&x, &y); + tileBehavior = MapGridGetMetatileBehaviorAt(x, y); + if (Overworld_GetFlashLevel()) + return B_TRANSITION_SHUFFLE; + if (!MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior)) + { + switch (gMapHeader.mapType) + { + case MAP_TYPE_UNDERGROUND: + return B_TRANSITION_SWIRL; + case MAP_TYPE_UNDERWATER: + return B_TRANSITION_BIG_POKEBALL; + default: + return B_TRANSITION_BLUR; + } + } + return B_TRANSITION_BIG_POKEBALL; +} + +static u16 GetSumOfPlayerPartyLevel(u8 numMons) +{ + u8 sum = 0; + int i; + + for (i = 0; i < PARTY_SIZE; i++) + { + u32 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + + if (species != SPECIES_EGG && species != SPECIES_NONE && GetMonData(&gPlayerParty[i], MON_DATA_HP) != 0) + { + sum += GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); + if (--numMons == 0) + break; + } + } + return sum; +} + +static u8 GetSumOfEnemyPartyLevel(u16 opponentId, u8 numMons) +{ + u8 i; + u8 sum; + u32 count = numMons; + + if (gTrainers[opponentId].partySize < count) + count = gTrainers[opponentId].partySize; + + sum = 0; + + switch (gTrainers[opponentId].partyFlags) + { + case 0: + { + const struct TrainerMonNoItemDefaultMoves *party; + party = gTrainers[opponentId].party.NoItemDefaultMoves; + for (i = 0; i < count; i++) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_CUSTOM_MOVESET: + { + const struct TrainerMonNoItemCustomMoves *party; + party = gTrainers[opponentId].party.NoItemCustomMoves; + for (i = 0; i < count; i++) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_HELD_ITEM: + { + const struct TrainerMonItemDefaultMoves *party; + party = gTrainers[opponentId].party.ItemDefaultMoves; + for (i = 0; i < count; i++) + sum += party[i].lvl; + } + break; + case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: + { + const struct TrainerMonItemCustomMoves *party; + party = gTrainers[opponentId].party.ItemCustomMoves; + for (i = 0; i < count; i++) + sum += party[i].lvl; + } + break; + } + + return sum; +} + +static u8 GetWildBattleTransition(void) +{ + u8 transitionType = GetBattleTransitionTypeByMap(); + u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); + u8 playerLevel = GetSumOfPlayerPartyLevel(1); + + if (enemyLevel < playerLevel) + { + if (InBattlePyramid()) + return B_TRANSITION_BLUR; + else + return sBattleTransitionTable_Wild[transitionType][0]; + } + else + { + if (InBattlePyramid()) + return B_TRANSITION_GRID_SQUARES; + else + return sBattleTransitionTable_Wild[transitionType][1]; + } +} + +static u8 GetTrainerBattleTransition(void) +{ + u8 minPartyCount; + u8 transitionType; + u8 enemyLevel; + u8 playerLevel; + + if (gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) + return B_TRANSITION_CHAMPION; + + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_ELITE_FOUR) + { + if (gTrainerBattleOpponent_A == TRAINER_SIDNEY) + return B_TRANSITION_SYDNEY; + if (gTrainerBattleOpponent_A == TRAINER_PHOEBE) + return B_TRANSITION_PHOEBE; + if (gTrainerBattleOpponent_A == TRAINER_GLACIA) + return B_TRANSITION_GLACIA; + if (gTrainerBattleOpponent_A == TRAINER_DRAKE) + return B_TRANSITION_DRAKE; + return B_TRANSITION_CHAMPION; + } + + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_CHAMPION) + return B_TRANSITION_CHAMPION; + + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_TEAM_MAGMA + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_MAGMA_LEADER + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_MAGMA_ADMIN) + return B_TRANSITION_MAGMA; + + if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_TEAM_AQUA + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_AQUA_LEADER + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_AQUA_ADMIN) + return B_TRANSITION_AQUA; + + if (gTrainers[gTrainerBattleOpponent_A].doubleBattle == TRUE) + minPartyCount = 2; // double battles always at least have 2 pokemon. + else + minPartyCount = 1; + + transitionType = GetBattleTransitionTypeByMap(); + enemyLevel = GetSumOfEnemyPartyLevel(gTrainerBattleOpponent_A, minPartyCount); + playerLevel = GetSumOfPlayerPartyLevel(minPartyCount); + + if (enemyLevel < playerLevel) + return sBattleTransitionTable_Trainer[transitionType][0]; + else + return sBattleTransitionTable_Trainer[transitionType][1]; +} + +u8 sub_80B100C(s32 arg0) +{ + u16 var; + u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); + u8 playerLevel = GetSumOfPlayerPartyLevel(1); + + if (enemyLevel < playerLevel) + { + switch (arg0) + { + case 11: + case 12: + case 13: + return B_TRANSITION_POKEBALLS_TRAIL; + case 10: + return sUnknown_0854FEA4[Random() % ARRAY_COUNT(sUnknown_0854FEA4)]; + case 3: + return sUnknown_0854FEA7[Random() % ARRAY_COUNT(sUnknown_0854FEA7)]; + } + + if (VarGet(VAR_0x40CE) != 3) + return sUnknown_0854FE98[Random() % ARRAY_COUNT(sUnknown_0854FE98)]; + } + else + { + switch (arg0) + { + case 11: + case 12: + case 13: + return B_TRANSITION_BIG_POKEBALL; + case 10: + return sUnknown_0854FEA4[Random() % ARRAY_COUNT(sUnknown_0854FEA4)]; + case 3: + return sUnknown_0854FEA7[Random() % ARRAY_COUNT(sUnknown_0854FEA7)]; + } + + if (VarGet(VAR_0x40CE) != 3) + return sUnknown_0854FE98[Random() % ARRAY_COUNT(sUnknown_0854FE98)]; + } + + var = gSaveBlock2Ptr->field_CB4[gSaveBlock2Ptr->battlePyramidWildHeaderId * 2 + 0] + + gSaveBlock2Ptr->field_CB4[gSaveBlock2Ptr->battlePyramidWildHeaderId * 2 + 1]; + + return sUnknown_0854FE98[var % ARRAY_COUNT(sUnknown_0854FE98)]; +} + +void ChooseStarter(void) +{ + SetMainCallback2(CB2_ChooseStarter); + gMain.savedCallback = CB2_GiveStarter; +} + +static void CB2_GiveStarter(void) +{ + u16 starterMon; + + *GetVarPointer(VAR_FIRST_POKE) = gSpecialVar_Result; + starterMon = GetStarterPokemon(gSpecialVar_Result); + ScriptGiveMon(starterMon, 5, 0, 0, 0, 0); + ResetTasks(); + PlayBattleBGM(); + SetMainCallback2(CB2_StartFirstBattle); + BattleTransition_Start(B_TRANSITION_BLUR); +} + +static void CB2_StartFirstBattle(void) +{ + UpdatePaletteFade(); + RunTasks(); + + if (IsBattleTransitionDone() == TRUE) + { + gBattleTypeFlags = BATTLE_TYPE_FIRST_BATTLE; + gMain.savedCallback = CB2_EndFirstBattle; + FreeAllWindowBuffers(); + SetMainCallback2(CB2_InitBattle); + prev_quest_postbuffer_cursor_backup_reset(); + ResetPoisonStepCounter(); + IncrementGameStat(GAME_STAT_TOTAL_BATTLES); + IncrementGameStat(GAME_STAT_WILD_BATTLES); + sub_80EECC8(); + sub_80B1218(); + } +} + +static void CB2_EndFirstBattle(void) +{ + Overworld_ClearSavedMusic(); + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); +} + +static void sub_80B1218(void) +{ + if (GetGameStat(GAME_STAT_WILD_BATTLES) % 60 == 0) + sub_81DA57C(); +} + +static void sub_80B1234(void) +{ + if (GetGameStat(GAME_STAT_TRAINER_BATTLES) % 20 == 0) + sub_81DA57C(); +} + +// why not just use the macros? maybe its because they didnt want to uncast const every time? +static u32 TrainerBattleLoadArg32(const u8 *ptr) +{ + return T1_READ_32(ptr); +} + +static u16 TrainerBattleLoadArg16(const u8 *ptr) +{ + return T1_READ_16(ptr); +} + +static u8 TrainerBattleLoadArg8(const u8 *ptr) +{ + return T1_READ_8(ptr); +} + +static u16 GetTrainerAFlag(void) +{ + return FLAG_TRAINER_FLAG_START + gTrainerBattleOpponent_A; +} + +static u16 GetTrainerBFlag(void) +{ + return FLAG_TRAINER_FLAG_START + gTrainerBattleOpponent_B; +} + +static bool32 IsPlayerDefeated(u32 battleOutcome) +{ + switch (battleOutcome) + { + case BATTLE_LOST: + case BATTLE_DREW: + return TRUE; + case BATTLE_WON: + case BATTLE_RAN: + case BATTLE_PLAYER_TELEPORTED: + case BATTLE_POKE_FLED: + case BATTLE_CAUGHT: + return FALSE; + default: + return FALSE; + } +} + +void ResetTrainerOpponentIds(void) +{ + gTrainerBattleOpponent_A = 0; + gTrainerBattleOpponent_B = 0; +} + +static void InitTrainerBattleVariables(void) +{ + sTrainerBattleMode = 0; + if (gApproachingTrainerId == 0) + { + sTrainerAIntroSpeech = NULL; + sTrainerADefeatSpeech = NULL; + sTrainerABattleScriptRetAddr = NULL; + } + else + { + sTrainerBIntroSpeech = NULL; + sTrainerBDefeatSpeech = NULL; + sTrainerBBattleScriptRetAddr = NULL; + } + sTrainerMapObjectLocalId = 0; + sTrainerVictorySpeech = NULL; + sTrainerCannotBattleSpeech = NULL; + sTrainerBattleEndScript = NULL; +} + +static inline void SetU8(void *ptr, u8 value) +{ + *(u8*)(ptr) = value; +} + +static inline void SetU16(void *ptr, u16 value) +{ + *(u16*)(ptr) = value; +} + +static inline void SetU32(void *ptr, u32 value) +{ + *(u32*)(ptr) = value; +} + +static inline void SetPtr(const void *ptr, const void* value) +{ + *(const void**)(ptr) = value; +} + +static void TrainerBattleLoadArgs(const struct TrainerBattleParameter *specs, const u8 *data) +{ + while (1) + { + switch (specs->ptrType) + { + case TRAINER_PARAM_LOAD_VAL_8BIT: + SetU8(specs->varPtr, TrainerBattleLoadArg8(data)); + data += 1; + break; + case TRAINER_PARAM_LOAD_VAL_16BIT: + SetU16(specs->varPtr, TrainerBattleLoadArg16(data)); + data += 2; + break; + case TRAINER_PARAM_LOAD_VAL_32BIT: + SetU32(specs->varPtr, TrainerBattleLoadArg32(data)); + data += 4; + break; + case TRAINER_PARAM_CLEAR_VAL_8BIT: + SetU8(specs->varPtr, 0); + break; + case TRAINER_PARAM_CLEAR_VAL_16BIT: + SetU16(specs->varPtr, 0); + break; + case TRAINER_PARAM_CLEAR_VAL_32BIT: + SetU32(specs->varPtr, 0); + break; + case TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR: + SetPtr(specs->varPtr, data); + return; + } + specs++; + } +} + +void SetMapVarsToTrainer(void) +{ + if (sTrainerMapObjectLocalId != 0) + { + gSpecialVar_LastTalked = sTrainerMapObjectLocalId; + gSelectedMapObject = GetFieldObjectIdByLocalIdAndMap(sTrainerMapObjectLocalId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + } +} + +const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data) +{ + InitTrainerBattleVariables(); + sTrainerBattleMode = TrainerBattleLoadArg8(data); + + switch (sTrainerBattleMode) + { + case 3: + TrainerBattleLoadArgs(sOrdinaryNoIntroBattleParams, data); + return EventScript_2713C2; + case 4: + TrainerBattleLoadArgs(sDoubleBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_TryDoDoubleTrainerBattle; + case 2: + if (gApproachingTrainerId == 0) + { + TrainerBattleLoadArgs(sContinueScriptBattleParams, data); + SetMapVarsToTrainer(); + } + else + { + TrainerBattleLoadArgs(sTrainerBContinueScriptBattleParams, data); + } + return EventScript_271362; + case 1: + TrainerBattleLoadArgs(sContinueScriptBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_271362; + case 6: + case 8: + TrainerBattleLoadArgs(sContinueScriptDoubleBattleParams, data); + SetMapVarsToTrainer(); + return EventScript_TryDoDoubleTrainerBattle; + case 7: + TrainerBattleLoadArgs(sDoubleBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = GetRematchTrainerId(gTrainerBattleOpponent_A); + return EventScript_TryDoDoubleRematchBattle; + case 5: + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = GetRematchTrainerId(gTrainerBattleOpponent_A); + return EventScript_2713D1; + case 9: + if (gApproachingTrainerId == 0) + { + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = sub_81A9AA8(gSpecialVar_LastTalked); + } + else + { + TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data); + gTrainerBattleOpponent_B = sub_81A9AA8(gSpecialVar_LastTalked); + } + return EventScript_271362; + case 10: + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + return NULL; + case 11: + TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data); + return NULL; + case 12: + if (gApproachingTrainerId == 0) + { + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + gTrainerBattleOpponent_A = sub_81D6180(gSpecialVar_LastTalked); + } + else + { + TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data); + gTrainerBattleOpponent_B = sub_81D6180(gSpecialVar_LastTalked); + } + return EventScript_271362; + default: + if (gApproachingTrainerId == 0) + { + TrainerBattleLoadArgs(sOrdinaryBattleParams, data); + SetMapVarsToTrainer(); + } + else + { + TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data); + } + return EventScript_271362; + } +} + +void ConfigureAndSetUpOneTrainerBattle(u8 trainerMapObjId, const u8 *trainerScript) +{ + gSelectedMapObject = trainerMapObjId; + gSpecialVar_LastTalked = gMapObjects[trainerMapObjId].localId; + BattleSetup_ConfigureTrainerBattle(trainerScript + 1); + ScriptContext1_SetupScript(EventScript_271354); + ScriptContext2_Enable(); +} + +void ConfigureTwoTrainersBattle(u8 trainerMapObjId, const u8 *trainerScript) +{ + gSelectedMapObject = trainerMapObjId; + gSpecialVar_LastTalked = gMapObjects[trainerMapObjId].localId; + BattleSetup_ConfigureTrainerBattle(trainerScript + 1); +} + +void SetUpTwoTrainersBattle(void) +{ + ScriptContext1_SetupScript(EventScript_271354); + ScriptContext2_Enable(); +} + +bool32 GetTrainerFlagFromScriptPointer(const u8 *data) +{ + u32 flag = TrainerBattleLoadArg16(data + 2); + return FlagGet(FLAG_TRAINER_FLAG_START + flag); +} + +void sub_80B16D8(void) +{ + struct MapObject *mapObject = &gMapObjects[gSelectedMapObject]; + + npc_set_running_behaviour_etc(mapObject, npc_running_behaviour_by_direction(mapObject->mapobj_unk_18)); +} + +u8 GetTrainerBattleMode(void) +{ + return sTrainerBattleMode; +} + +bool8 GetTrainerFlag(void) +{ + if (InBattlePyramid()) + return GetBattlePyramidTrainerFlag(gSelectedMapObject); + else if (InTrainerHill()) + return GetTrainerHillTrainerFlag(gSelectedMapObject); + else + return FlagGet(GetTrainerAFlag()); +} + +static void SetBattledTrainersFlags(void) +{ + if (gTrainerBattleOpponent_B != 0) + FlagSet(GetTrainerBFlag()); + FlagSet(GetTrainerAFlag()); +} + +static void SetBattledTrainerFlag(void) +{ + FlagSet(GetTrainerAFlag()); +} + +bool8 HasTrainerBeenFought(u16 trainerId) +{ + return FlagGet(FLAG_TRAINER_FLAG_START + trainerId); +} + +void SetTrainerFlag(u16 trainerId) +{ + FlagSet(FLAG_TRAINER_FLAG_START + trainerId); +} + +void ClearTrainerFlag(u16 trainerId) +{ + FlagClear(FLAG_TRAINER_FLAG_START + trainerId); +} + +void BattleSetup_StartTrainerBattle(void) +{ + if (gNoOfApproachingTrainers == 2) + gBattleTypeFlags = (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_TRAINER); + else + gBattleTypeFlags = (BATTLE_TYPE_TRAINER); + + if (InBattlePyramid()) + { + VarSet(VAR_0x400E, 0); + gBattleTypeFlags |= BATTLE_TYPE_PYRAMID; + + if (gNoOfApproachingTrainers == 2) + { + sub_816306C(1); + ZeroMonData(&gEnemyParty[1]); + ZeroMonData(&gEnemyParty[2]); + ZeroMonData(&gEnemyParty[4]); + ZeroMonData(&gEnemyParty[5]); + } + else + { + sub_8163048(1); + ZeroMonData(&gEnemyParty[1]); + ZeroMonData(&gEnemyParty[2]); + } + + sub_81A9B04(); + } + else if (sub_81D5C18()) + { + gBattleTypeFlags |= BATTLE_TYPE_x4000000; + + if (gNoOfApproachingTrainers == 2) + sub_81D639C(); + else + sub_81D6384(); + + sub_81D61E8(); + } + + sNoOfPossibleTrainerRetScripts = gNoOfApproachingTrainers; + gNoOfApproachingTrainers = 0; + sShouldCheckTrainerBScript = FALSE; + gUnknown_03006080 = 0; + gMain.savedCallback = CB2_EndTrainerBattle; + + if (InBattlePyramid() || sub_81D5C18()) + sub_80B0828(); + else + DoTrainerBattle(); + + ScriptContext1_Stop(); +} + +static void CB2_EndTrainerBattle(void) +{ + if (gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + } + else if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + if (InBattlePyramid() || sub_81D5C18()) + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + else + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + if (!InBattlePyramid() && !sub_81D5C18()) + { + RegisterTrainerInMatchCall(); + SetBattledTrainersFlags(); + } + } +} + +static void CB2_EndRematchBattle(void) +{ + if (gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + } + else if (IsPlayerDefeated(gBattleOutcome) == TRUE) + { + SetMainCallback2(CB2_WhiteOut); + } + else + { + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); + RegisterTrainerInMatchCall(); + SetBattledTrainersFlags(); + HandleRematchVarsOnBattleEnd(); + } +} + +void BattleSetup_StartRematchBattle(void) +{ + gBattleTypeFlags = BATTLE_TYPE_TRAINER; + gMain.savedCallback = CB2_EndRematchBattle; + DoTrainerBattle(); + ScriptContext1_Stop(); +} + +void ShowTrainerIntroSpeech(void) +{ + if (InBattlePyramid()) + { + if (gNoOfApproachingTrainers == 0 || gNoOfApproachingTrainers == 1) + sub_81A9EDC(sub_81A9AA8(gSpecialVar_LastTalked)); + else + sub_81A9EDC(sub_81A9AA8(gMapObjects[gApproachingTrainers[gApproachingTrainerId].mapObjectId].localId)); + + sub_80982B8(); + } + else if (sub_81D5C18()) + { + if (gNoOfApproachingTrainers == 0 || gNoOfApproachingTrainers == 1) + sub_81D572C(2, sub_81D6180(gSpecialVar_LastTalked)); + else + sub_81D572C(2, sub_81D6180(gMapObjects[gApproachingTrainers[gApproachingTrainerId].mapObjectId].localId)); + + sub_80982B8(); + } + else + { + ShowFieldMessage(GetIntroSpeechOfApproachingTrainer()); + } +} + +const u8 *BattleSetup_GetScriptAddrAfterBattle(void) +{ + if (sTrainerBattleEndScript != NULL) + return sTrainerBattleEndScript; + else + return EventScript_TestSignpostMsg; +} + +const u8 *BattleSetup_GetTrainerPostBattleScript(void) +{ + if (sShouldCheckTrainerBScript) + { + sShouldCheckTrainerBScript = FALSE; + if (sTrainerBBattleScriptRetAddr != NULL) + { + gUnknown_03006080 = 1; + return sTrainerBBattleScriptRetAddr; + } + } + else + { + if (sTrainerABattleScriptRetAddr != NULL) + { + gUnknown_03006080 = 0; + return sTrainerABattleScriptRetAddr; + } + } + + return EventScript_TryGetTrainerScript; +} + +void ShowTrainerCantBattleSpeech(void) +{ + ShowFieldMessage(GetTrainerCantBattleSpeech()); +} + +void SetUpTrainerEncounterMusic(void) +{ + u16 trainerId; + u16 music; + + if (gApproachingTrainerId == 0) + trainerId = gTrainerBattleOpponent_A; + else + trainerId = gTrainerBattleOpponent_B; + + if (sTrainerBattleMode != TRAINER_BATTLE_CONTINUE_SCRIPT_NO_MUSIC + && sTrainerBattleMode != TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE_NO_MUSIC) + { + switch (GetTrainerEncounterMusicId(trainerId)) + { + case TRAINER_ENCOUNTER_MUSIC_MALE: + music = BGM_BOYEYE; + break; + case TRAINER_ENCOUNTER_MUSIC_FEMALE: + music = BGM_GIRLEYE; + break; + case TRAINER_ENCOUNTER_MUSIC_GIRL: + music = BGM_SYOUJOEYE; + break; + case TRAINER_ENCOUNTER_MUSIC_INTENSE: + music = BGM_HAGESHII; + break; + case TRAINER_ENCOUNTER_MUSIC_COOL: + music = BGM_KAKKOII; + break; + case TRAINER_ENCOUNTER_MUSIC_AQUA: + music = BGM_AQA_0; + break; + case TRAINER_ENCOUNTER_MUSIC_MAGMA: + music = BGM_MGM0; + break; + case TRAINER_ENCOUNTER_MUSIC_SWIMMER: + music = BGM_SWIMEYE; + break; + case TRAINER_ENCOUNTER_MUSIC_TWINS: + music = BGM_HUTAGO; + break; + case TRAINER_ENCOUNTER_MUSIC_ELITE_FOUR: + music = BGM_SITENNOU; + break; + case TRAINER_ENCOUNTER_MUSIC_HIKER: + music = BGM_YAMA_EYE; + break; + case TRAINER_ENCOUNTER_MUSIC_INTERVIEWER: + music = BGM_INTER_V; + break; + case TRAINER_ENCOUNTER_MUSIC_RICH: + music = BGM_TEST; + break; + default: + music = BGM_AYASII; + } + PlayNewMapMusic(music); + } +} + +static const u8 *ReturnEmptyStringIfNull(const u8 *string) +{ + if (string == NULL) + return gText_EmptyString2; + else + return string; +} + +static const u8 *GetIntroSpeechOfApproachingTrainer(void) +{ + if (gApproachingTrainerId == 0) + return ReturnEmptyStringIfNull(sTrainerAIntroSpeech); + else + return ReturnEmptyStringIfNull(sTrainerBIntroSpeech); +} + +const u8 *GetTrainerALoseText(void) +{ + const u8 *string; + + if (gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) + string = GetSecretBaseTrainerLoseText(); + else + string = sTrainerADefeatSpeech; + + StringExpandPlaceholders(gStringVar4, ReturnEmptyStringIfNull(string)); + return gStringVar4; +} + +const u8 *GetTrainerBLoseText(void) +{ + StringExpandPlaceholders(gStringVar4, ReturnEmptyStringIfNull(sTrainerBDefeatSpeech)); + return gStringVar4; +} + +const u8 *GetTrainerWonSpeech(void) +{ + return ReturnEmptyStringIfNull(sTrainerVictorySpeech); +} + +static const u8 *GetTrainerCantBattleSpeech(void) +{ + return ReturnEmptyStringIfNull(sTrainerCannotBattleSpeech); +} + +static s32 FirstBattleTrainerIdToRematchTableId(const struct RematchTrainer *table, u16 trainerId) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (table[i].trainerIds[0] == trainerId) + return i; + } + + return -1; +} + +static s32 TrainerIdToRematchTableId(const struct RematchTrainer *table, u16 trainerId) +{ + s32 i, j; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + for (j = 0; j < REMATCHES_COUNT; j++) + { + if (table[i].trainerIds[j] == 0) + break; + if (table[i].trainerIds[j] == trainerId) + return i; + } + } + + return -1; +} + +static bool32 sub_80B1D94(s32 rematchTableId) +{ + if (rematchTableId >= REMATCH_ELITE_FOUR_ENTRIES) + return TRUE; + else if (rematchTableId == REMATCH_WALLY_ENTRY) + return (FlagGet(FLAG_0x07E) == FALSE); + else + return FALSE; +} + +static void SetRematchIdForTrainer(const struct RematchTrainer *table, u32 tableId) +{ + s32 i; + + for (i = 1; i < REMATCHES_COUNT; i++) + { + u16 trainerId = table[tableId].trainerIds[i]; + + if (trainerId == 0) + break; + if (!HasTrainerBeenFought(trainerId)) + break; + } + + gSaveBlock1Ptr->trainerRematches[tableId] = i; +} + +static bool32 UpdateRandomTrainerRematches(const struct RematchTrainer *table, u16 mapGroup, u16 mapNum) +{ + s32 i; + bool32 ret = FALSE; + + for (i = 0; i <= REMATCH_WALLY_ENTRY; i++) + { + if (table[i].mapGroup == mapGroup && table[i].mapNum == mapNum && !sub_80B1D94(i)) + { + if (gSaveBlock1Ptr->trainerRematches[i] != 0) + { + // Trainer already wants a rematch. Don't bother updating it + ret = TRUE; + } + else if (FlagGet(FLAG_MATCH_CALL_REGISTERED + i) + && (Random() % 100) <= 30) // 31% chance of getting a rematch + { + SetRematchIdForTrainer(table, i); + ret = TRUE; + } + } + } + + return ret; +} + +void UpdateRematchIfDefeated(s32 rematchTableId) +{ + if (HasTrainerBeenFought(gRematchTable[rematchTableId].trainerIds[0]) == TRUE) + SetRematchIdForTrainer(gRematchTable, rematchTableId); +} + +static bool32 DoesSomeoneWantRematchIn_(const struct RematchTrainer *table, u16 mapGroup, u16 mapNum) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (table[i].mapGroup == mapGroup && table[i].mapNum == mapNum && gSaveBlock1Ptr->trainerRematches[i] != 0) + return TRUE; + } + + return FALSE; +} + +static bool32 IsRematchTrainerIn_(const struct RematchTrainer *table, u16 mapGroup, u16 mapNum) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (table[i].mapGroup == mapGroup && table[i].mapNum == mapNum) + return TRUE; + } + + return FALSE; +} + +static bool8 IsFirstTrainerIdReadyForRematch(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + s32 tableId = FirstBattleTrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId == -1) + return FALSE; + if (tableId >= 100) + return FALSE; + if (gSaveBlock1Ptr->trainerRematches[tableId] == 0) + return FALSE; + + return TRUE; +} + +static bool8 IsTrainerReadyForRematch_(const struct RematchTrainer *table, u16 trainerId) +{ + s32 tableId = TrainerIdToRematchTableId(table, trainerId); + + if (tableId == -1) + return FALSE; + if (tableId >= 100) + return FALSE; + if (gSaveBlock1Ptr->trainerRematches[tableId] == 0) + return FALSE; + + return TRUE; +} + +static u16 GetRematchTrainerIdFromTable(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + const struct RematchTrainer *trainerEntry; + s32 i; + s32 tableId = FirstBattleTrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId == -1) + return FALSE; + + trainerEntry = &table[tableId]; + for (i = 1; i < REMATCHES_COUNT; i++) + { + if (trainerEntry->trainerIds[i] == 0) // previous entry was this trainer's last one + return trainerEntry->trainerIds[i - 1]; + if (!HasTrainerBeenFought(trainerEntry->trainerIds[i])) + return trainerEntry->trainerIds[i]; + } + + return trainerEntry->trainerIds[REMATCHES_COUNT - 1]; // already beaten at max stage +} + +static u16 GetLastBeatenRematchTrainerIdFromTable(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + const struct RematchTrainer *trainerEntry; + s32 i; + s32 tableId = FirstBattleTrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId == -1) + return FALSE; + + trainerEntry = &table[tableId]; + for (i = 1; i < REMATCHES_COUNT; i++) + { + if (trainerEntry->trainerIds[i] == 0) // previous entry was this trainer's last one + return trainerEntry->trainerIds[i - 1]; + if (!HasTrainerBeenFought(trainerEntry->trainerIds[i])) + return trainerEntry->trainerIds[i - 1]; + } + + return trainerEntry->trainerIds[REMATCHES_COUNT - 1]; // already beaten at max stage +} + +static void ClearTrainerWantRematchState(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + s32 tableId = TrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId != -1) + gSaveBlock1Ptr->trainerRematches[tableId] = 0; +} + +static u32 GetTrainerMatchCallFlag(u32 trainerId) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (gRematchTable[i].trainerIds[0] == trainerId) + return FLAG_MATCH_CALL_REGISTERED + i; + } + + return 0xFFFF; +} + +static void RegisterTrainerInMatchCall(void) +{ + if (FlagGet(FLAG_HAS_MATCH_CALL)) + { + u32 matchCallFlagId = GetTrainerMatchCallFlag(gTrainerBattleOpponent_A); + if (matchCallFlagId != 0xFFFF) + FlagSet(matchCallFlagId); + } +} + +static bool8 WasSecondRematchWon(const struct RematchTrainer *table, u16 firstBattleTrainerId) +{ + s32 tableId = FirstBattleTrainerIdToRematchTableId(table, firstBattleTrainerId); + + if (tableId == -1) + return FALSE; + if (!HasTrainerBeenFought(table[tableId].trainerIds[1])) + return FALSE; + + return TRUE; +} + +static bool32 HasAtLeastFiveBadges(void) +{ + s32 i, count; + + for (count = 0, i = 0; i < ARRAY_COUNT(sBadgeFlags); i++) + { + if (FlagGet(sBadgeFlags[i]) == TRUE) + { + if (++count >= 5) + return TRUE; + } + } + + return FALSE; +} + +#define STEP_COUNTER_MAX 255 + +void IncrementRematchStepCounter(void) +{ + if (HasAtLeastFiveBadges()) + { + if (gSaveBlock1Ptr->trainerRematchStepCounter >= STEP_COUNTER_MAX) + gSaveBlock1Ptr->trainerRematchStepCounter = STEP_COUNTER_MAX; + else + gSaveBlock1Ptr->trainerRematchStepCounter++; + } +} + +static bool32 IsRematchStepCounterMaxed(void) +{ + if (HasAtLeastFiveBadges() && gSaveBlock1Ptr->trainerRematchStepCounter >= STEP_COUNTER_MAX) + return TRUE; + else + return FALSE; +} + +void TryUpdateRandomTrainerRematches(u16 mapGroup, u16 mapNum) +{ + if (IsRematchStepCounterMaxed() && UpdateRandomTrainerRematches(gRematchTable, mapGroup, mapNum) == TRUE) + gSaveBlock1Ptr->trainerRematchStepCounter = 0; +} + +bool32 DoesSomeoneWantRematchIn(u16 mapGroup, u16 mapNum) +{ + return DoesSomeoneWantRematchIn_(gRematchTable, mapGroup, mapNum); +} + +bool32 IsRematchTrainerIn(u16 mapGroup, u16 mapNum) +{ + return IsRematchTrainerIn_(gRematchTable, mapGroup, mapNum); +} + +static u16 GetRematchTrainerId(u16 trainerId) +{ + return GetRematchTrainerIdFromTable(gRematchTable, trainerId); +} + +u16 GetLastBeatenRematchTrainerId(u16 trainerId) +{ + return GetLastBeatenRematchTrainerIdFromTable(gRematchTable, trainerId); +} + +bool8 ShouldTryRematchBattle(void) +{ + if (IsFirstTrainerIdReadyForRematch(gRematchTable, gTrainerBattleOpponent_A)) + return TRUE; + + return WasSecondRematchWon(gRematchTable, gTrainerBattleOpponent_A); +} + +bool8 IsTrainerReadyForRematch(void) +{ + return IsTrainerReadyForRematch_(gRematchTable, gTrainerBattleOpponent_A); +} + +static void HandleRematchVarsOnBattleEnd(void) +{ + ClearTrainerWantRematchState(gRematchTable, gTrainerBattleOpponent_A); + SetBattledTrainersFlags(); +} + +void ShouldTryGetTrainerScript(void) +{ + if (sNoOfPossibleTrainerRetScripts > 1) + { + sNoOfPossibleTrainerRetScripts = 0; + sShouldCheckTrainerBScript = TRUE; + gSpecialVar_Result = TRUE; + } + else + { + sShouldCheckTrainerBScript = FALSE; + gSpecialVar_Result = FALSE; + } +} + +u16 CountBattledRematchTeams(u16 trainerId) +{ + s32 i; + + if (HasTrainerBeenFought(gRematchTable[trainerId].trainerIds[0]) != TRUE) + return 0; + + for (i = 1; i < REMATCHES_COUNT; i++) + { + if (gRematchTable[trainerId].trainerIds[i] == 0) + break; + if (!HasTrainerBeenFought(gRematchTable[trainerId].trainerIds[i])) + break; + } + + return i; +} diff --git a/src/berry_blender.c b/src/berry_blender.c index b1d36e2d9..810162746 100644 --- a/src/berry_blender.c +++ b/src/berry_blender.c @@ -134,8 +134,6 @@ extern u8 gInGameOpponentsNo; extern u8 gUnknown_020322D5; extern u8 gResultsWindowId; -extern const u8 * const gPokeblockNames[]; - // graphics extern const u8 gBerryBlenderArrowTiles[]; extern const u8 gBerryBlenderStartTiles[]; @@ -2444,7 +2442,7 @@ static void CB2_HandleBlenderEndGame(void) sBerryBlenderData->gameEndState++; break; case 10: - switch (sub_8198C58()) + switch (ProcessMenuInputNoWrap_()) { case 1: case -1: diff --git a/src/berry_fix_program.c b/src/berry_fix_program.c index bba39c3eb..195490543 100644 --- a/src/berry_fix_program.c +++ b/src/berry_fix_program.c @@ -35,9 +35,9 @@ static void berry_fix_bg_hide(void); // .rodata -static const u8 gUnknown_08617E78[] = _("Berry Program Update"); -static const u8 gUnknown_08617E8D[] = _("Ruby/Sapphire"); -static const u8 gUnknown_08617E9B[] = _("Emerald"); +static const u8 sUnknown_08617E78[] = _("Berry Program Update"); +static const u8 sUnknown_08617E8D[] = _("Ruby/Sapphire"); +static const u8 sUnknown_08617E9B[] = _("Emerald"); static const u8 Unknown_08617EA3[] = _("The Berry Program on your POKéMON\nRuby/Sapphire Game Pak will be updated.\n{COLOR RED}{SHADOW LIGHT_RED}Press the A Button."); static const u8 Unknown_08617F07[] = _("Please ensure the connection of your\nGame Boy Advance system matches this.\n{COLOR RED}{SHADOW LIGHT_RED}YES: Press the A Button.\nNO: Turn off the power and try again."); @@ -62,15 +62,15 @@ static const struct WindowTemplate gUnknown_08618110[] = { {-1} }; -static const u16 gUnknown_08618138[] = { +static const u16 sUnknown_08618138[] = { 0x7fff, 0x7fff, 0x318c, 0x675a, 0x043c, 0x3aff, 0x0664, 0x4bd2, 0x6546, 0x7b14, 0x7fff, 0x318c, 0x675a, 0x0000, 0x0000, 0x0000 }; -static const u8 gUnknown_08618158[] = {10, 11, 12}; -static const u8 gUnknown_0861815B[] = { 0, 10, 13}; +static const u8 sUnknown_08618158[] = {10, 11, 12}; +static const u8 sUnknown_0861815B[] = { 0, 10, 13}; static const u8 *const gUnknown_08618160[] = { Unknown_08617F07, @@ -243,21 +243,21 @@ static void berry_fix_gpu_set(void) InitWindows(gUnknown_08618110); DeactivateAllTextPrinters(); - DmaCopy32(3, gUnknown_08618138, BG_PLTT + 0x1E0, 0x20); + DmaCopy32(3, sUnknown_08618138, BG_PLTT + 0x1E0, 0x20); SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP); FillWindowPixelBuffer(2, 0); FillWindowPixelBuffer(3, 0); FillWindowPixelBuffer(0, 0xAA); // This block is a meme among memes - width = (0x78 - GetStringWidth(0, gUnknown_08617E9B, 0)) / 2; - box_print(2, 0, width, 3, gUnknown_0861815B, -1, gUnknown_08617E9B); - width = (s32)(0x78 - GetStringWidth(0, gUnknown_08617E9B, 0)) / 2 + 0x78; - box_print(2, 0, width, 3, gUnknown_0861815B, -1, gUnknown_08617E8D); - width = (0x70 - GetStringWidth(0, gUnknown_08617E8D, 0)) / 2; - box_print(3, 0, width, 0, gUnknown_0861815B, -1, gUnknown_08617E8D); - width = (0xd0 - GetStringWidth(1, gUnknown_08617E78, 0)) / 2; - box_print(0, 1, width, 2, gUnknown_08618158, -1, gUnknown_08617E78); + width = (0x78 - GetStringWidth(0, sUnknown_08617E9B, 0)) / 2; + box_print(2, 0, width, 3, sUnknown_0861815B, -1, sUnknown_08617E9B); + width = (s32)(0x78 - GetStringWidth(0, sUnknown_08617E9B, 0)) / 2 + 0x78; + box_print(2, 0, width, 3, sUnknown_0861815B, -1, sUnknown_08617E8D); + width = (0x70 - GetStringWidth(0, sUnknown_08617E8D, 0)) / 2; + box_print(3, 0, width, 0, sUnknown_0861815B, -1, sUnknown_08617E8D); + width = (0xd0 - GetStringWidth(1, sUnknown_08617E78, 0)) / 2; + box_print(0, 1, width, 2, sUnknown_08618158, -1, sUnknown_08617E78); CopyWindowToVram(2, 2); CopyWindowToVram(3, 2); @@ -346,7 +346,7 @@ __attribute__((naked)) static void berry_fix_gpu_set(void) "\tldr r0, =gUnknown_08618110\n" "\tbl InitWindows\n" "\tbl DeactivateAllTextPrinters\n" - "\tldr r0, =gUnknown_08618138\n" + "\tldr r0, =sUnknown_08618138\n" "\tstr r0, [r4]\n" "\tldr r0, =0x050001e0\n" "\tstr r0, [r4, 0x4]\n" @@ -365,7 +365,7 @@ __attribute__((naked)) static void berry_fix_gpu_set(void) "\tmovs r0, 0\n" "\tmovs r1, 0xAA\n" "\tbl FillWindowPixelBuffer\n" - "\tldr r5, =gUnknown_08617E9B\n" + "\tldr r5, =sUnknown_08617E9B\n" "\tmovs r0, 0\n" "\tadds r1, r5, 0\n" "\tmovs r2, 0\n" @@ -378,7 +378,7 @@ __attribute__((naked)) static void berry_fix_gpu_set(void) "\tasrs r0, 1\n" "\tlsls r2, r0, 24\n" "\tlsrs r2, 24\n" - "\tldr r6, =gUnknown_0861815B\n" + "\tldr r6, =sUnknown_0861815B\n" "\tstr r6, [sp]\n" "\tmovs r0, 0x1\n" "\tnegs r0, r0\n" @@ -389,7 +389,7 @@ __attribute__((naked)) static void berry_fix_gpu_set(void) "\tmovs r1, 0\n" "\tmovs r3, 0x3\n" "\tbl box_print\n" - "\tldr r5, =gUnknown_08617E8D\n" + "\tldr r5, =sUnknown_08617E8D\n" "\tmovs r0, 0\n" "\tadds r1, r5, 0\n" "\tmovs r2, 0\n" @@ -431,7 +431,7 @@ __attribute__((naked)) static void berry_fix_gpu_set(void) "\tmovs r1, 0\n" "\tmovs r3, 0\n" "\tbl box_print\n" - "\tldr r4, =gUnknown_08617E78\n" + "\tldr r4, =sUnknown_08617E78\n" "\tmovs r0, 0x1\n" "\tadds r1, r4, 0\n" "\tmovs r2, 0\n" @@ -444,7 +444,7 @@ __attribute__((naked)) static void berry_fix_gpu_set(void) "\tasrs r0, 1\n" "\tlsls r2, r0, 24\n" "\tlsrs r2, 24\n" - "\tldr r0, =gUnknown_08618158\n" + "\tldr r0, =sUnknown_08618158\n" "\tstr r0, [sp]\n" "\tmov r0, r8\n" "\tstr r0, [sp, 0x4]\n" @@ -496,7 +496,7 @@ static void berry_fix_text_print(int scene) { FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 32, 32); FillWindowPixelBuffer(1, 0xAA); - box_print(1, 1, 0, 0, gUnknown_08618158, -1, gUnknown_08618160[scene]); + box_print(1, 1, 0, 0, sUnknown_08618158, -1, gUnknown_08618160[scene]); PutWindowTilemap(1); CopyWindowToVram(1, 2); switch (scene) diff --git a/src/clear_save_data_screen.c b/src/clear_save_data_screen.c index d00944ac1..6d6a1545b 100755 --- a/src/clear_save_data_screen.c +++ b/src/clear_save_data_screen.c @@ -88,7 +88,7 @@ static void Task_DoClearSaveDataScreenYesNo(u8 taskId) static void Task_ClearSaveDataScreenYesNoChoice(u8 taskId) { - switch(sub_8198C58()) + switch(ProcessMenuInputNoWrap_()) { case 0: FillWindowPixelBuffer(0, 17); diff --git a/src/clock.c b/src/clock.c new file mode 100644 index 000000000..7cea30166 --- /dev/null +++ b/src/clock.c @@ -0,0 +1,93 @@ +#include "global.h" +#include "rom6.h" +#include "event_data.h" +#include "rtc.h" +#include "lottery_corner.h" +#include "dewford_trend.h" +#include "tv.h" +#include "field_screen.h" +#include "berry.h" +#include "main.h" +#include "overworld.h" +#include "wallclock.h" + +// static types + +// static declarations + +static void UpdatePerDay(struct Time *localTime); +static void UpdatePerMinute(struct Time *localTime); + +// rodata + +// text + +static void InitTimeBasedEvents(void) +{ + FlagSet(FLAG_SYS_CLOCK_SET); + RtcCalcLocalTime(); + gSaveBlock2Ptr->lastBerryTreeUpdate = gLocalTime; + VarSet(VAR_DAYS, gLocalTime.days); +} + +void DoTimeBasedEvents(void) +{ + if (FlagGet(FLAG_SYS_CLOCK_SET) && !sub_813B9C0()) + { + RtcCalcLocalTime(); + UpdatePerDay(&gLocalTime); + UpdatePerMinute(&gLocalTime); + } +} + +static void UpdatePerDay(struct Time *localTime) +{ + u16 *days = GetVarPointer(VAR_DAYS); + u16 daysSince; + + if (*days != localTime->days && *days <= localTime->days) + { + daysSince = localTime->days - *days; + ClearUpperFlags(); + UpdateDewfordTrendPerDay(daysSince); + UpdateTVShowsPerDay(daysSince); + UpdateWeatherPerDay(daysSince); + UpdatePartyPokerusTime(daysSince); + UpdateMirageRnd(daysSince); + UpdateBirchState(daysSince); + UpdateFrontierManiac(daysSince); + UpdateFrontierGambler(daysSince); + SetShoalItemFlag(daysSince); + SetRandomLotteryNumber(daysSince); + *days = localTime->days; + } +} + +static void UpdatePerMinute(struct Time *localTime) +{ + struct Time difference; + int minutes; + + CalcTimeDifference(&difference, &gSaveBlock2Ptr->lastBerryTreeUpdate, localTime); + minutes = 24 * 60 * difference.days + 60 * difference.hours + difference.minutes; + if (minutes != 0) + { + if (minutes >= 0) + { + BerryTreeTimeUpdate(minutes); + gSaveBlock2Ptr->lastBerryTreeUpdate = *localTime; + } + } +} + +static void ReturnFromStartWallClock(void) +{ + InitTimeBasedEvents(); + SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music); +} + +void StartWallClock(void) +{ + SetMainCallback2(Cb2_StartWallClock); + gMain.savedCallback = ReturnFromStartWallClock; +} diff --git a/src/daycare.c b/src/daycare.c index ce9952531..59ee562bd 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -40,7 +40,7 @@ extern const u8 gDaycareText_PlayOther[]; extern u8 GetCursorSelectionMonId(void); extern u16 ItemIdToBattleMoveId(u16); -extern s32 ListMenuHandleInput(u8); +extern s32 ListMenuHandleInputGetItemId(u8); extern void sub_81AE6C8(u8, u16*, u16*); extern void sub_819746C(u8, bool8); extern void sub_81973FC(u8, bool8); @@ -75,7 +75,7 @@ static const struct ListMenuItem sLevelMenuItems[] = static const struct ListMenuTemplate sDaycareListMenuLevelTemplate = { .items = sLevelMenuItems, - .unk_04 = sub_81AF078, + .moveCursorFunc = sub_81AF078, .unk_08 = DaycarePrintMonInfo, .totalItems = 3, .maxShowed = 3, @@ -90,7 +90,8 @@ static const struct ListMenuTemplate sDaycareListMenuLevelTemplate = .unk_16_0 = TRUE, .spaceBetweenItems = 0, .unk_16_7 = FALSE, - .unk_17_0 = 1 + .unk_17_0 = 1, + .cursorKind = 0 }; static const u8 *const sCompatibilityMessages[] = @@ -1256,7 +1257,7 @@ static void DaycarePrintMonInfo(u8 windowId, s32 daycareSlotId, u8 y) static void Task_HandleDaycareLevelMenuInput(u8 taskId) { - u32 var = ListMenuHandleInput(gTasks[taskId].tMenuListTaskId); + u32 var = ListMenuHandleInputGetItemId(gTasks[taskId].tMenuListTaskId); if (gMain.newKeys & A_BUTTON) { diff --git a/src/decoration.c b/src/decoration.c index 987e628c5..faef779b7 100644 --- a/src/decoration.c +++ b/src/decoration.c @@ -792,17 +792,17 @@ void sub_8127330(u8 taskId) for (i = 0; i < sDecorPCBuffer->unk_520 - 1; i ++) { sub_8127454(sDecorPCBuffer->names[i], gCurDecorInventoryItems[i]); - sDecorPCBuffer->items[i].unk_00 = sDecorPCBuffer->names[i]; - sDecorPCBuffer->items[i].unk_04 = i; + sDecorPCBuffer->items[i].name = sDecorPCBuffer->names[i]; + sDecorPCBuffer->items[i].id = i; } StringCopy(sDecorPCBuffer->names[i], gText_Cancel); - sDecorPCBuffer->items[i].unk_00 = sDecorPCBuffer->names[i]; - sDecorPCBuffer->items[i].unk_04 = -2; - gUnknown_03006310 = gUnknown_085A6BD0; - gUnknown_03006310.unk_10 = sDecorMenuWindowIndices[1]; - gUnknown_03006310.totalItems = sDecorPCBuffer->unk_520; - gUnknown_03006310.items = sDecorPCBuffer->items; - gUnknown_03006310.maxShowed = sDecorPCBuffer->unk_521; + sDecorPCBuffer->items[i].name = sDecorPCBuffer->names[i]; + sDecorPCBuffer->items[i].id = -2; + gMultiuseListMenuTemplate = gUnknown_085A6BD0; + gMultiuseListMenuTemplate.unk_10 = sDecorMenuWindowIndices[1]; + gMultiuseListMenuTemplate.totalItems = sDecorPCBuffer->unk_520; + gMultiuseListMenuTemplate.items = sDecorPCBuffer->items; + gMultiuseListMenuTemplate.maxShowed = sDecorPCBuffer->unk_521; } void sub_8127454(u8 *dest, u16 decorId) @@ -871,7 +871,7 @@ void sub_812759C(u8 taskId) sub_81272C8(); sub_81272F8(); sub_8127330(taskId); - data[13] = ListMenuInit(&gUnknown_03006310, sSecretBasePCSelectDecorPageNo, sSecretBasePCSelectDecorLineNo); + data[13] = ListMenuInit(&gMultiuseListMenuTemplate, sSecretBasePCSelectDecorPageNo, sSecretBasePCSelectDecorLineNo); sub_8127500(); } @@ -889,8 +889,8 @@ void sub_812764C(u8 taskId) data = gTasks[taskId].data; if (!gPaletteFade.active) { - input = ListMenuHandleInput(data[13]); - get_coro_args_x18_x1A(data[13], &sSecretBasePCSelectDecorPageNo, &sSecretBasePCSelectDecorLineNo); + input = ListMenuHandleInputGetItemId(data[13]); + sub_81AE860(data[13], &sSecretBasePCSelectDecorPageNo, &sSecretBasePCSelectDecorLineNo); switch (input) { case -1: diff --git a/src/egg_hatch.c b/src/egg_hatch.c index 032607806..721ba4a4f 100644 --- a/src/egg_hatch.c +++ b/src/egg_hatch.c @@ -48,9 +48,9 @@ extern struct SpriteTemplate gUnknown_0202499C; extern void (*gFieldCallback)(void); extern const struct CompressedSpriteSheet gMonFrontPicTable[]; -extern const u8 gUnknown_08C00000[]; -extern const u8 gUnknown_08C00524[]; -extern const u8 gUnknown_08C004E0[]; +extern const u8 gBattleTextboxTiles[]; +extern const u8 gBattleTextboxTilemap[]; +extern const u8 gBattleTextboxPalette[]; extern const u16 gUnknown_08DD7300[]; // palette, gameboy advance extern const u32 gUnknown_08DD7360[]; // tileset gameboy advance extern const u32 gUnknown_08331F60[]; // tilemap gameboy circle @@ -58,7 +58,7 @@ extern const u8 gText_HatchedFromEgg[]; extern const u8 gText_NickHatchPrompt[]; extern u8 sav1_map_get_name(void); -extern s8 sub_8198C58(void); +extern s8 ProcessMenuInputNoWrap_(void); extern void TVShowConvertInternationalString(u8* str1, u8* str2, u8); extern void sub_806A068(u16, u8); extern void fade_screen(u8, u8); @@ -91,7 +91,7 @@ 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; +static IWRAM_DATA struct EggHatchData *sEggHatchData; // rom data static const u16 sEggPalette[] = INCBIN_U16("graphics/pokemon/palettes/egg_palette.gbapal"); @@ -522,9 +522,9 @@ static void CB2_EggHatch_0(void) gMain.state++; break; case 2: - copy_decompressed_tile_data_to_vram_autofree(0, gUnknown_08C00000, 0, 0, 0); - CopyToBgTilemapBuffer(0, gUnknown_08C00524, 0, 0); - LoadCompressedPalette(gUnknown_08C004E0, 0, 0x20); + copy_decompressed_tile_data_to_vram_autofree(0, gBattleTextboxTiles, 0, 0, 0); + CopyToBgTilemapBuffer(0, gBattleTextboxTilemap, 0, 0); + LoadCompressedPalette(gBattleTextboxPalette, 0, 0x20); gMain.state++; break; case 3: @@ -669,7 +669,7 @@ static void CB2_EggHatch_1(void) } break; case 10: - switch (sub_8198C58()) + switch (ProcessMenuInputNoWrap_()) { case 0: GetMonNick(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar3); diff --git a/src/evolution_scene.c b/src/evolution_scene.c index c17921b74..2b88fec3a 100644 --- a/src/evolution_scene.c +++ b/src/evolution_scene.c @@ -1168,7 +1168,7 @@ static void Task_TradeEvolutionScene(u8 taskID) } break; case 4: - switch (sub_8198C58()) + switch (ProcessMenuInputNoWrap_()) { case 0: sEvoCursorPos = 0; diff --git a/src/field_map_obj.c b/src/field_map_obj.c index 6a99890a4..fc23a6e37 100755 --- a/src/field_map_obj.c +++ b/src/field_map_obj.c @@ -1174,11 +1174,11 @@ void npc_by_local_id_and_map_set_field_1_bit_x20(u8 localId, u8 mapNum, u8 mapGr } } -void FieldObjectGetLocalIdAndMap(struct MapObject *mapObject, u8 *localId, u8 *mapNum, u8 *mapGroup) +void FieldObjectGetLocalIdAndMap(struct MapObject *mapObject, void *localId, void *mapNum, void *mapGroup) { - *localId = mapObject->localId; - *mapNum = mapObject->mapNum; - *mapGroup = mapObject->mapGroup; + *(u8*)(localId) = mapObject->localId; + *(u8*)(mapNum) = mapObject->mapNum; + *(u8*)(mapGroup) = mapObject->mapGroup; } void sub_808E75C(s16 x, s16 y) @@ -3426,7 +3426,7 @@ void FieldObjectCB_TreeDisguise(struct Sprite *sprite) mapObject = &gMapObjects[sprite->data[0]]; if (mapObject->mapobj_unk_21 == 0 || (mapObject->mapobj_unk_21 == 1 && !sprite->data[7])) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); + FieldObjectGetLocalIdAndMap(mapObject, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]); mapObject->mapobj_unk_1A = FieldEffectStart(FLDEFF_TREE_DISGUISE); mapObject->mapobj_unk_21 = 1; sprite->data[7] ++; @@ -3447,7 +3447,7 @@ void FieldObjectCB_MountainDisguise(struct Sprite *sprite) mapObject = &gMapObjects[sprite->data[0]]; if (mapObject->mapobj_unk_21 == 0 || (mapObject->mapobj_unk_21 == 1 && !sprite->data[7])) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); + FieldObjectGetLocalIdAndMap(mapObject, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]); mapObject->mapobj_unk_1A = FieldEffectStart(FLDEFF_MOUNTAIN_DISGUISE); mapObject->mapobj_unk_21 = 1; sprite->data[7] ++; @@ -4694,7 +4694,7 @@ bool8 sub_80954CC(struct MapObject *mapObject, struct Sprite *sprite) bool8 do_exclamation_mark_bubble_1(struct MapObject *mapObject, struct Sprite *sprite) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); + FieldObjectGetLocalIdAndMap(mapObject, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]); FieldEffectStart(FLDEFF_EXCLAMATION_MARK_ICON_1); sprite->data[2] = 1; return TRUE; @@ -4702,7 +4702,7 @@ bool8 do_exclamation_mark_bubble_1(struct MapObject *mapObject, struct Sprite *s bool8 do_exclamation_mark_bubble_2(struct MapObject *mapObject, struct Sprite *sprite) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); + FieldObjectGetLocalIdAndMap(mapObject, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]); FieldEffectStart(FLDEFF_EXCLAMATION_MARK_ICON_2); sprite->data[2] = 1; return TRUE; @@ -4710,7 +4710,7 @@ bool8 do_exclamation_mark_bubble_2(struct MapObject *mapObject, struct Sprite *s bool8 do_heart_bubble(struct MapObject *mapObject, struct Sprite *sprite) { - FieldObjectGetLocalIdAndMap(mapObject, (u8 *)&gFieldEffectArguments[0], (u8 *)&gFieldEffectArguments[1], (u8 *)&gFieldEffectArguments[2]); + FieldObjectGetLocalIdAndMap(mapObject, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]); FieldEffectStart(FLDEFF_HEART_ICON); sprite->data[2] = 1; return TRUE; diff --git a/src/hall_of_fame.c b/src/hall_of_fame.c index 52babe346..239c5d690 100644 --- a/src/hall_of_fame.c +++ b/src/hall_of_fame.c @@ -187,9 +187,9 @@ static const struct BgTemplate sHof_BgTemplates[] = static const struct WindowTemplate sHof_WindowTemplate = {0, 2, 2, 0xE, 6, 0xE, 1}; -static const u8 gUnknown_085E5388[] = {0, 1, 2, 0}; +static const u8 sUnknown_085E5388[] = {0, 1, 2, 0}; -static const u8 gUnknown_085E538C[] = {0, 2, 3, 0, 4, 5, 0, 0}; +static const u8 sUnknown_085E538C[] = {0, 2, 3, 0, 4, 5, 0, 0}; static const struct CompressedSpriteSheet sHallOfFame_ConfettiSpriteSheet = { @@ -1137,7 +1137,7 @@ static void HallOfFame_PrintWelcomeText(u8 unusedPossiblyWindowId, u8 unused2) { FillWindowPixelBuffer(0, 0); PutWindowTilemap(0); - box_print(0, 1, GetStringCenterAlignXOffset(1, gText_WelcomeToHOF, 0xD0), 1, gUnknown_085E5388, 0, gText_WelcomeToHOF); + box_print(0, 1, GetStringCenterAlignXOffset(1, gText_WelcomeToHOF, 0xD0), 1, sUnknown_085E5388, 0, gText_WelcomeToHOF); CopyWindowToVram(0, 3); } @@ -1173,7 +1173,7 @@ static void HallOfFame_PrintMonInfo(struct HallofFameMon* currMon, u8 unused1, u *(stringPtr)++ = CHAR_QUESTION_MARK; } stringPtr[0] = EOS; - box_print(0, 1, 0x10, 1, gUnknown_085E5388, -1, text); + box_print(0, 1, 0x10, 1, sUnknown_085E5388, -1, text); } // nick, species names, gender and level @@ -1182,13 +1182,13 @@ static void HallOfFame_PrintMonInfo(struct HallofFameMon* currMon, u8 unused1, u if (currMon->species == SPECIES_EGG) { width = GetStringCenterAlignXOffset(1, text, 0xD0); - box_print(0, 1, width, 1, gUnknown_085E5388, -1, text); + box_print(0, 1, width, 1, sUnknown_085E5388, -1, text); CopyWindowToVram(0, 3); } else { width = GetStringRightAlignXOffset(1, text, 0x80); - box_print(0, 1, width, 1, gUnknown_085E5388, -1, text); + box_print(0, 1, width, 1, sUnknown_085E5388, -1, text); text[0] = CHAR_SLASH; stringPtr = StringCopy(text + 1, gSpeciesNames[currMon->species]); @@ -1209,15 +1209,15 @@ static void HallOfFame_PrintMonInfo(struct HallofFameMon* currMon, u8 unused1, u } stringPtr[0] = EOS; - box_print(0, 1, 0x80, 1, gUnknown_085E5388, -1, text); + box_print(0, 1, 0x80, 1, sUnknown_085E5388, -1, text); stringPtr = StringCopy(text, gText_Level); ConvertIntToDecimalStringN(stringPtr, currMon->lvl, STR_CONV_MODE_LEFT_ALIGN, 3); - box_print(0, 1, 0x24, 0x11, gUnknown_085E5388, -1, text); + box_print(0, 1, 0x24, 0x11, sUnknown_085E5388, -1, text); stringPtr = StringCopy(text, gText_IDNumber); ConvertIntToDecimalStringN(stringPtr, (u16)(currMon->tid), STR_CONV_MODE_LEADING_ZEROS, 5); - box_print(0, 1, 0x68, 0x11, gUnknown_085E5388, -1, text); + box_print(0, 1, 0x68, 0x11, sUnknown_085E5388, -1, text); CopyWindowToVram(0, 3); } @@ -1232,13 +1232,13 @@ static void HallOfFame_PrintPlayerInfo(u8 unused1, u8 unused2) FillWindowPixelBuffer(1, 0x11); PutWindowTilemap(1); SetWindowBorderStyle(1, FALSE, 0x21D, 0xD); - box_print(1, 1, 0, 1, gUnknown_085E538C, -1, gText_Name); + box_print(1, 1, 0, 1, sUnknown_085E538C, -1, gText_Name); width = GetStringRightAlignXOffset(1, gSaveBlock2Ptr->playerName, 0x70); - box_print(1, 1, width, 1, gUnknown_085E538C, -1, gSaveBlock2Ptr->playerName); + box_print(1, 1, width, 1, sUnknown_085E538C, -1, gSaveBlock2Ptr->playerName); trainerId = (gSaveBlock2Ptr->playerTrainerId[0]) | (gSaveBlock2Ptr->playerTrainerId[1] << 8); - box_print(1, 1, 0, 0x11, gUnknown_085E538C, 0, gText_IDNumber); + box_print(1, 1, 0, 0x11, sUnknown_085E538C, 0, gText_IDNumber); text[0] = (trainerId % 100000) / 10000 + CHAR_0; text[1] = (trainerId % 10000) / 1000 + CHAR_0; text[2] = (trainerId % 1000) / 100 + CHAR_0; @@ -1246,9 +1246,9 @@ static void HallOfFame_PrintPlayerInfo(u8 unused1, u8 unused2) text[4] = (trainerId % 10) / 1 + CHAR_0; text[5] = EOS; width = GetStringRightAlignXOffset(1, text, 0x70); - box_print(1, 1, width, 0x11, gUnknown_085E538C, -1, text); + box_print(1, 1, width, 0x11, sUnknown_085E538C, -1, text); - box_print(1, 1, 0, 0x21, gUnknown_085E538C, -1, gText_MainMenuTime); + box_print(1, 1, 0, 0x21, sUnknown_085E538C, -1, gText_MainMenuTime); text[0] = (gSaveBlock2Ptr->playTimeHours / 100) + CHAR_0; text[1] = (gSaveBlock2Ptr->playTimeHours % 100) / 10 + CHAR_0; text[2] = (gSaveBlock2Ptr->playTimeHours % 10) + CHAR_0; @@ -1264,7 +1264,7 @@ static void HallOfFame_PrintPlayerInfo(u8 unused1, u8 unused2) text[6] = EOS; width = GetStringRightAlignXOffset(1, text, 0x70); - box_print(1, 1, width, 0x21, gUnknown_085E538C, -1, text); + box_print(1, 1, width, 0x21, sUnknown_085E538C, -1, text); CopyWindowToVram(1, 3); } diff --git a/src/lilycove_lady.c b/src/lilycove_lady.c index 95270974a..927b87c72 100644 --- a/src/lilycove_lady.c +++ b/src/lilycove_lady.c @@ -29,10 +29,10 @@ static u8 sub_818E258(const u8 *); extern const u8 gText_Lady2[]; -static const u16 gUnknown_0860B074[] = { +static const u16 sUnknown_0860B074[] = { 0x62, 0xcb, 0xdc, 0xcc, 0xd1 }; -static const u16 gUnknown_0860B07E[] = { +static const u16 sUnknown_0860B07E[] = { 0x1a, 0x14, 0x0a }; @@ -119,11 +119,11 @@ static const u16 *const gUnknown_0860B1A4[] = { Unknown_0860B192 }; -static const u16 gUnknown_0860B1E4[] = { +static const u16 sUnknown_0860B1E4[] = { 0x0210, 0x0400, 0x0212, 0x1a26, 0x0208, 0x045d, 0x040a, 0x0411, 0x0464, 0x020e, 0x1a25, 0x181b, 0x1a24, 0x0420, 0x0410, 0x0400 }; -static const u16 gUnknown_0860B204[] = { +static const u16 sUnknown_0860B204[] = { 0x007b, 0x007f, 0x0081, 0x0023, 0x0023, 0x0023, 0x00a5, 0x00a7, 0x00a6, 0x000b, 0x012f, 0x006b, 0x006d, 0x0044, 0x0044, 0x000c }; @@ -176,7 +176,7 @@ static const u16 *const gUnknown_0860B2EC[] = { Unknown_0860B2D6 }; -static const u16 gUnknown_0860B304[] = { +static const u16 sUnknown_0860B304[] = { 0x0b, 0x6e, 0x40, 0x6f, 0x44, 0x47 }; @@ -218,7 +218,7 @@ static const u8 *const gUnknown_0860B338[] = { gUnknown_085EADE7 }; -static const u16 gUnknown_0860B34C[] = { +static const u16 sUnknown_0860B34C[] = { 0x0120, 0x013b, 0x011e, 0x013d, 0x0019 }; @@ -237,11 +237,11 @@ void sub_818D9C0(void) { LilycoveLady *lilycoveLady; - VarSet(VAR_0x4010, gUnknown_0860B07E[GetLilycoveLadyId()]); + VarSet(VAR_0x4010, sUnknown_0860B07E[GetLilycoveLadyId()]); if (GetLilycoveLadyId() == LILYCOVE_LADY_CONTEST) { lilycoveLady = &gSaveBlock1Ptr->lilycoveLady; - VarSet(VAR_0x4011, gUnknown_0860B074[lilycoveLady->contest.category]); + VarSet(VAR_0x4011, sUnknown_0860B074[lilycoveLady->contest.category]); gSpecialVar_Result = TRUE; } else @@ -481,7 +481,7 @@ u16 sub_818DEA0(void) u16 itemId; gUnknown_0203CD64 = &gSaveBlock1Ptr->lilycoveLady.favour; - itemId = gUnknown_0860B304[gUnknown_0203CD64->unk_00c]; + itemId = sUnknown_0860B304[gUnknown_0203CD64->unk_00c]; sub_818DE88(itemId); gUnknown_0203CD64->phase = 2; return itemId; @@ -508,8 +508,8 @@ static void sub_818DF00(void) { gUnknown_0203CD68->unk_002[i] = gUnknown_0860B1A4[v0][i]; } - gUnknown_0203CD68->unk_014 = gUnknown_0860B1E4[v0]; - gUnknown_0203CD68->itemId = gUnknown_0860B204[v0]; + gUnknown_0203CD68->unk_014 = sUnknown_0860B1E4[v0]; + gUnknown_0203CD68->itemId = sUnknown_0860B204[v0]; gUnknown_0203CD68->unk_02b = v0; gUnknown_0203CD68->playerName[0] = EOS; } @@ -581,13 +581,13 @@ u8 sub_818E06C(void) { i = 0; } - } while (sub_811F8D8(gUnknown_0860B1E4[i]) == 0); + } while (sub_811F8D8(sUnknown_0860B1E4[i]) == 0); for (j = 0; j < 9; j ++) { quiz->unk_002[j] = gUnknown_0860B1A4[i][j]; } - quiz->unk_014 = gUnknown_0860B1E4[i]; - quiz->itemId = gUnknown_0860B204[i]; + quiz->unk_014 = sUnknown_0860B1E4[i]; + quiz->itemId = sUnknown_0860B204[i]; quiz->unk_02b = i; quiz->playerName[0] = EOS; } @@ -943,7 +943,7 @@ static void sub_818E6B0(u8 sheen) } } -bool8 sub_818E704(struct Pokeblock *pokeblock) +bool8 GivePokeblockToContestLady(struct Pokeblock *pokeblock) { u8 sheen; bool8 response; @@ -1079,7 +1079,7 @@ void sub_818E914(void) void sub_818E92C(void) { - sub_81357FC(3, c2_exit_to_overworld_2_switch); + OpenPokeblockCase(3, c2_exit_to_overworld_2_switch); } void sub_818E940(void) @@ -1091,7 +1091,7 @@ void sub_818E940(void) void sub_818E960(void) { gUnknown_0203CD6C = &gSaveBlock1Ptr->lilycoveLady.contest; - gSpecialVar_0x8005 = gUnknown_0860B34C[gUnknown_0203CD6C->category]; + gSpecialVar_0x8005 = sUnknown_0860B34C[gUnknown_0203CD6C->category]; } u8 sub_818E990(void) diff --git a/src/load_save.c b/src/load_save.c index 2b40f2e92..e0106c0a8 100644 --- a/src/load_save.c +++ b/src/load_save.c @@ -1,4 +1,4 @@ -#include "global.h" +#include "global.h" #include "gba/flash_internal.h" #include "load_save.h" #include "main.h" @@ -28,7 +28,7 @@ struct LoadedSaveData /*0x00F0*/ struct ItemSlot pokeBalls[16]; /*0x0130*/ struct ItemSlot TMsHMs[64]; /*0x0230*/ struct ItemSlot berries[46]; - /*0x02E8*/ struct MailStruct mail[16]; + /*0x02E8*/ struct MailStruct mail[MAIL_COUNT]; }; EWRAM_DATA struct SaveBlock2 gSaveblock2 = {0}; @@ -330,7 +330,7 @@ void LoadSerializedGame(void) void copy_bags_and_unk_data_from_save_blocks(void) { int i; - + // load player items. for (i = 0; i < 30; i++) gLoadedSaveData.items[i] = gSaveBlock1Ptr->bagPocket_Items[i]; diff --git a/src/mail.c b/src/mail.c index 877035fb6..ec7ff2ce2 100644 --- a/src/mail.c +++ b/src/mail.c @@ -1,4 +1,5 @@ #include "global.h" +#include "mail.h" #include "constants/items.h" #include "main.h" #include "overworld.h" @@ -18,8 +19,43 @@ #include "constants/species.h" #include "malloc.h" #include "easy_chat.h" -#include "mail_data.h" -#include "mail.h" + +extern const u16 gUnknown_08DBE818[]; +extern const u16 gUnknown_08DBE838[]; +extern const u16 gUnknown_08DBE858[]; +extern const u16 gUnknown_08DBE878[]; +extern const u16 gUnknown_08DBE898[]; +extern const u16 gUnknown_08DBE8B8[]; +extern const u16 gUnknown_08DBE8D8[]; +extern const u16 gUnknown_08DBE8F8[]; +extern const u16 gUnknown_08DBE918[]; +extern const u16 gUnknown_08DBE938[]; +extern const u16 gUnknown_08DBE958[]; +extern const u16 gUnknown_08DBE978[]; +extern const u8 gUnknown_08DBE998[]; +extern const u8 gUnknown_08DBFBA4[]; +extern const u8 gUnknown_08DBEB38[]; +extern const u8 gUnknown_08DBFC7C[]; +extern const u8 gUnknown_08DBEC74[]; +extern const u8 gUnknown_08DBFD5C[]; +extern const u8 gUnknown_08DBEE84[]; +extern const u8 gUnknown_08DBFE68[]; +extern const u8 gUnknown_08DBEF5C[]; +extern const u8 gUnknown_08DBFF44[]; +extern const u8 gUnknown_08DBF154[]; +extern const u8 gUnknown_08DC0034[]; +extern const u8 gUnknown_08DBF2D4[]; +extern const u8 gUnknown_08DC0114[]; +extern const u8 gUnknown_08DBF37C[]; +extern const u8 gUnknown_08DC01F4[]; +extern const u8 gUnknown_08DBF50C[]; +extern const u8 gUnknown_08DC0300[]; +extern const u8 gUnknown_08DBF64C[]; +extern const u8 gUnknown_08DC03F0[]; +extern const u8 gUnknown_08DBF7B4[]; +extern const u8 gUnknown_08DC04E8[]; +extern const u8 gUnknown_08DBF904[]; +extern const u8 gUnknown_08DC0600[]; // Static type declarations @@ -51,9 +87,7 @@ struct MailGraphics u16 color12; }; -// Static RAM declarations - -static EWRAM_DATA struct +struct MailRead { /*0x0000*/ u8 strbuf[8][64]; /*0x0200*/ u8 playerName[12]; @@ -72,22 +106,26 @@ static EWRAM_DATA struct /*0x0228*/ const struct MailLayout *layout; /*0x022c*/ u8 bg1TilemapBuffer[0x1000]; /*0x122c*/ u8 bg2TilemapBuffer[0x1000]; -} *gUnknown_0203A134 = NULL; +}; + +// Static RAM declarations + +static EWRAM_DATA struct MailRead *sMailRead = NULL; // Static ROM declarations -void sub_81219F0(void); -void sub_8121A1C(void); -void sub_8121B1C(void); -void sub_8121C50(void); -void sub_8121C64(void); -void sub_8121C98(void); -void sub_8121CC0(void); -void sub_8121D00(void); +static void CB2_InitMailRead(void); +static void sub_8121A1C(void); +static void sub_8121B1C(void); +static void VBlankCB_MailRead(void); +static void CB2_MailRead(void); +static void CB2_WaitForPaletteExitOnKeyPress(void); +static void CB2_ExitOnKeyPress(void); +static void CB2_ExitMailReadFreeVars(void); // .rodata -const struct BgTemplate gUnknown_0859F290[] = { +static const struct BgTemplate sUnknown_0859F290[] = { { .bg = 0, .charBaseIndex = 2, @@ -106,7 +144,7 @@ const struct BgTemplate gUnknown_0859F290[] = { } }; -const struct WindowTemplate gUnknown_0859F29C[] = { +static const struct WindowTemplate sUnknown_0859F29C[] = { { .priority = 0, .tilemapLeft = 2, @@ -119,55 +157,18 @@ const struct WindowTemplate gUnknown_0859F29C[] = { DUMMY_WIN_TEMPLATE }; -const u8 gUnknown_0859F2AC[] = { +static const u8 sUnknown_0859F2AC[] = { 0, 10, 11 }; -const u16 gUnknown_0859F2B0[][2] = { +static const u16 sUnknown_0859F2B0[][2] = { { 0x6ACD, 0x51A5 }, { 0x45FC, 0x38D4 } }; -extern const u16 gUnknown_08DBE818[]; -extern const u16 gUnknown_08DBE838[]; -extern const u16 gUnknown_08DBE858[]; -extern const u16 gUnknown_08DBE878[]; -extern const u16 gUnknown_08DBE898[]; -extern const u16 gUnknown_08DBE8B8[]; -extern const u16 gUnknown_08DBE8D8[]; -extern const u16 gUnknown_08DBE8F8[]; -extern const u16 gUnknown_08DBE918[]; -extern const u16 gUnknown_08DBE938[]; -extern const u16 gUnknown_08DBE958[]; -extern const u16 gUnknown_08DBE978[]; -extern const u8 gUnknown_08DBE998[]; -extern const u8 gUnknown_08DBFBA4[]; -extern const u8 gUnknown_08DBEB38[]; -extern const u8 gUnknown_08DBFC7C[]; -extern const u8 gUnknown_08DBEC74[]; -extern const u8 gUnknown_08DBFD5C[]; -extern const u8 gUnknown_08DBEE84[]; -extern const u8 gUnknown_08DBFE68[]; -extern const u8 gUnknown_08DBEF5C[]; -extern const u8 gUnknown_08DBFF44[]; -extern const u8 gUnknown_08DBF154[]; -extern const u8 gUnknown_08DC0034[]; -extern const u8 gUnknown_08DBF2D4[]; -extern const u8 gUnknown_08DC0114[]; -extern const u8 gUnknown_08DBF37C[]; -extern const u8 gUnknown_08DC01F4[]; -extern const u8 gUnknown_08DBF50C[]; -extern const u8 gUnknown_08DC0300[]; -extern const u8 gUnknown_08DBF64C[]; -extern const u8 gUnknown_08DC03F0[]; -extern const u8 gUnknown_08DBF7B4[]; -extern const u8 gUnknown_08DC04E8[]; -extern const u8 gUnknown_08DBF904[]; -extern const u8 gUnknown_08DC0600[]; - -const struct MailGraphics gUnknown_0859F2B8[] = { +static const struct MailGraphics sUnknown_0859F2B8[] = { { gUnknown_08DBE818, gUnknown_08DBE998, gUnknown_08DBFBA4, 0x02c0, 0x0000, 0x294a, 0x6739 }, { @@ -195,13 +196,13 @@ const struct MailGraphics gUnknown_0859F2B8[] = { } }; -const struct UnkMailStruct Unknown_0859F3A8[] = { +static const struct UnkMailStruct Unknown_0859F3A8[] = { { .numEasyChatWords = 3, .lineHeight = 16 }, { .numEasyChatWords = 3, .lineHeight = 16 }, { .numEasyChatWords = 3, .lineHeight = 16 } }; -const struct MailLayout gUnknown_0859F3B4[] = { +static const struct MailLayout sUnknown_0859F3B4[] = { { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, { 0x03, 0x00, 0x00, 0x02, 0x04, Unknown_0859F3A8 }, @@ -216,7 +217,7 @@ const struct MailLayout gUnknown_0859F3B4[] = { { 0x03, 0x00, 0x00, 0x02, 0x00, Unknown_0859F3A8 } }; -const struct UnkMailStruct Unknown_0859F444[] = { +static const struct UnkMailStruct Unknown_0859F444[] = { { .numEasyChatWords = 2, .lineHeight = 16 }, { .numEasyChatWords = 2, .lineHeight = 16 }, { .numEasyChatWords = 2, .lineHeight = 16 }, @@ -224,7 +225,7 @@ const struct UnkMailStruct Unknown_0859F444[] = { { .numEasyChatWords = 1, .lineHeight = 16 } }; -const struct MailLayout gUnknown_0859F458[] = { +static const struct MailLayout sUnknown_0859F458[] = { { 0x05, 0x07, 0x58, 0x0b, 0x1e, Unknown_0859F444 }, { 0x05, 0x0a, 0x60, 0x09, 0x1e, Unknown_0859F444 }, { 0x05, 0x0c, 0x68, 0x05, 0x1e, Unknown_0859F444 }, @@ -241,23 +242,23 @@ const struct MailLayout gUnknown_0859F458[] = { // What the heck are these meant to be? Call them u16 for now. -const u16 Unknown_0859F4E8[] = { +static const u16 Unknown_0859F4E8[] = { 0x00, 0x4000, 0x00, 0x00 }; -const u16 Unknown_0859F4F0[] = { +static const u16 Unknown_0859F4F0[] = { 0x00, 0x00, -1, 0x00 }; -const u16 Unknown_0859F4F8[] = { +static const u16 Unknown_0859F4F8[] = { 0x04, 0x00, -1, 0x00 }; -const u16 Unknown_0859F500[] = { +static const u16 Unknown_0859F500[] = { 0x00, 0x40, -1, 0x00 }; -const u16 *const gUnknown_0859F508[] = { +static const u16 *const sUnknown_0859F508[] = { Unknown_0859F4F0, Unknown_0859F4F8, Unknown_0859F500 @@ -265,60 +266,62 @@ const u16 *const gUnknown_0859F508[] = { // .text -void sub_8121478(struct MailStruct *mail, MainCallback callback, bool8 flag) { +void ReadMail(struct MailStruct *mail, void (*callback)(void), bool8 flag) +{ u16 buffer[2]; u16 species; - gUnknown_0203A134 = calloc(1, sizeof(*gUnknown_0203A134)); - gUnknown_0203A134->language = LANGUAGE_ENGLISH; - gUnknown_0203A134->playerIsSender = TRUE; - gUnknown_0203A134->parserSingle = CopyEasyChatWord; - gUnknown_0203A134->parserMultiple = ConvertEasyChatWordsToString; - if (mail->itemId >= ITEM_ORANGE_MAIL && mail->itemId <= ITEM_RETRO_MAIL) { - gUnknown_0203A134->mailType = mail->itemId - ITEM_ORANGE_MAIL; + sMailRead = calloc(1, sizeof(*sMailRead)); + sMailRead->language = LANGUAGE_ENGLISH; + sMailRead->playerIsSender = TRUE; + sMailRead->parserSingle = CopyEasyChatWord; + sMailRead->parserMultiple = ConvertEasyChatWordsToString; + if (IS_ITEM_MAIL(mail->itemId)) + { + sMailRead->mailType = mail->itemId - ITEM_ORANGE_MAIL; } else { - gUnknown_0203A134->mailType = 0; + sMailRead->mailType = 0; flag = FALSE; } - switch (gUnknown_0203A134->playerIsSender) + switch (sMailRead->playerIsSender) { case FALSE: default: - gUnknown_0203A134->layout = &gUnknown_0859F3B4[gUnknown_0203A134->mailType]; + sMailRead->layout = &sUnknown_0859F3B4[sMailRead->mailType]; break; case TRUE: - gUnknown_0203A134->layout = &gUnknown_0859F458[gUnknown_0203A134->mailType]; + sMailRead->layout = &sUnknown_0859F458[sMailRead->mailType]; break; } - species = sub_80D45E8(mail->species, buffer); + species = MailSpeciesToSpecies(mail->species, buffer); if (species >= SPECIES_BULBASAUR && species < NUM_SPECIES) { - switch (gUnknown_0203A134->mailType) + switch (sMailRead->mailType) { default: - gUnknown_0203A134->animsActive = 0; + sMailRead->animsActive = 0; break; case ITEM_BEAD_MAIL - ITEM_ORANGE_MAIL: - gUnknown_0203A134->animsActive = 1; + sMailRead->animsActive = 1; break; case ITEM_DREAM_MAIL - ITEM_ORANGE_MAIL: - gUnknown_0203A134->animsActive = 2; + sMailRead->animsActive = 2; break; } } else { - gUnknown_0203A134->animsActive = 0; + sMailRead->animsActive = 0; } - gUnknown_0203A134->mail = mail; - gUnknown_0203A134->callback = callback; - gUnknown_0203A134->flag = flag; - SetMainCallback2(sub_81219F0); + sMailRead->mail = mail; + sMailRead->callback = callback; + sMailRead->flag = flag; + SetMainCallback2(CB2_InitMailRead); } -bool8 sub_81215EC(void) +static bool8 MailReadBuildGraphics(void) { u16 icon; @@ -352,21 +355,21 @@ bool8 sub_81215EC(void) SetGpuReg(REG_OFFSET_BG2HOFS, 0x0000); SetGpuReg(REG_OFFSET_BG3HOFS, 0x0000); SetGpuReg(REG_OFFSET_BG3VOFS, 0x0000); - SetGpuReg(REG_OFFSET_BLDCNT, 0x0000); + SetGpuReg(REG_OFFSET_BLDCNT, 0x0000); SetGpuReg(REG_OFFSET_BLDALPHA, 0x0000); break; case 6: ResetBgsAndClearDma3BusyFlags(0); - InitBgsFromTemplates(0, gUnknown_0859F290, 3); - SetBgTilemapBuffer(1, gUnknown_0203A134->bg1TilemapBuffer); - SetBgTilemapBuffer(2, gUnknown_0203A134->bg2TilemapBuffer); + InitBgsFromTemplates(0, sUnknown_0859F290, 3); + SetBgTilemapBuffer(1, sMailRead->bg1TilemapBuffer); + SetBgTilemapBuffer(2, sMailRead->bg2TilemapBuffer); break; case 7: - InitWindows(gUnknown_0859F29C); + InitWindows(sUnknown_0859F29C); DeactivateAllTextPrinters(); break; case 8: - decompress_and_copy_tile_data_to_vram(1, gUnknown_0859F2B8[gUnknown_0203A134->mailType].tiles, 0, 0, 0); + decompress_and_copy_tile_data_to_vram(1, sUnknown_0859F2B8[sMailRead->mailType].tiles, 0, 0, 0); break; case 9: if (free_temp_tile_data_buffers_if_possible()) @@ -377,7 +380,7 @@ bool8 sub_81215EC(void) case 10: FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 30, 20); FillBgTilemapBufferRect_Palette0(2, 1, 0, 0, 30, 20); - CopyToBgTilemapBuffer(1, gUnknown_0859F2B8[gUnknown_0203A134->mailType].tileMap, 0, 0); + CopyToBgTilemapBuffer(1, sUnknown_0859F2B8[sMailRead->mailType].tileMap, 0, 0); break; case 11: CopyBgTilemapBufferToVram(0); @@ -386,24 +389,24 @@ bool8 sub_81215EC(void) break; case 12: LoadPalette(GetOverworldTextboxPalettePtr(), 240, 32); - gPlttBufferUnfaded[250] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color10; - gPlttBufferFaded[250] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color10; - gPlttBufferUnfaded[251] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color12; - gPlttBufferFaded[251] = gUnknown_0859F2B8[gUnknown_0203A134->mailType].color12; - LoadPalette(gUnknown_0859F2B8[gUnknown_0203A134->mailType].palette, 0, 32); - gPlttBufferUnfaded[10] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; - gPlttBufferFaded[10] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; - gPlttBufferUnfaded[11] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; - gPlttBufferFaded[11] = gUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; + gPlttBufferUnfaded[250] = sUnknown_0859F2B8[sMailRead->mailType].color10; + gPlttBufferFaded[250] = sUnknown_0859F2B8[sMailRead->mailType].color10; + gPlttBufferUnfaded[251] = sUnknown_0859F2B8[sMailRead->mailType].color12; + gPlttBufferFaded[251] = sUnknown_0859F2B8[sMailRead->mailType].color12; + LoadPalette(sUnknown_0859F2B8[sMailRead->mailType].palette, 0, 32); + gPlttBufferUnfaded[10] = sUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; + gPlttBufferFaded[10] = sUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][0]; + gPlttBufferUnfaded[11] = sUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; + gPlttBufferFaded[11] = sUnknown_0859F2B0[gSaveBlock2Ptr->playerGender][1]; break; case 13: - if (gUnknown_0203A134->flag) + if (sMailRead->flag) { sub_8121A1C(); } break; case 14: - if (gUnknown_0203A134->flag) + if (sMailRead->flag) { sub_8121B1C(); RunTextPrinters(); @@ -416,20 +419,20 @@ bool8 sub_81215EC(void) } break; case 16: - SetVBlankCallback(sub_8121C50); + SetVBlankCallback(VBlankCB_MailRead); gPaletteFade.bufferTransferDisabled = TRUE; break; case 17: - icon = sub_80D2E84(gUnknown_0203A134->mail->species); - switch (gUnknown_0203A134->animsActive) + icon = sub_80D2E84(sMailRead->mail->species); + switch (sMailRead->animsActive) { case 1: sub_80D2F68(icon); - gUnknown_0203A134->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x60, 0x80, 0, 0); + sMailRead->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x60, 0x80, 0, 0); break; case 2: sub_80D2F68(icon); - gUnknown_0203A134->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x28, 0x80, 0, 0); + sMailRead->monIconSprite = sub_80D2D78(icon, SpriteCallbackDummy, 0x28, 0x80, 0, 0); break; } break; @@ -440,53 +443,53 @@ bool8 sub_81215EC(void) ShowBg(2); BeginNormalPaletteFade(-1, 0, 16, 0, 0); gPaletteFade.bufferTransferDisabled = FALSE; - gUnknown_0203A134->callback2 = sub_8121C98; + sMailRead->callback2 = CB2_WaitForPaletteExitOnKeyPress; return TRUE; default: return FALSE; } - gMain.state ++; + gMain.state++; return FALSE; } -void sub_81219F0(void) +static void CB2_InitMailRead(void) { do { - if (sub_81215EC() == TRUE) + if (MailReadBuildGraphics() == TRUE) { - SetMainCallback2(sub_8121C64); + SetMainCallback2(CB2_MailRead); break; } } while (sub_81221AC() != TRUE); } -void sub_8121A1C(void) +static void sub_8121A1C(void) { u16 i; u8 total; u8 *ptr; total = 0; - for (i = 0; i < gUnknown_0203A134->layout->numSubStructs; i ++) + for (i = 0; i < sMailRead->layout->numSubStructs; i ++) { - ConvertEasyChatWordsToString(gUnknown_0203A134->strbuf[i], &gUnknown_0203A134->mail->words[total], gUnknown_0203A134->layout->var8[i].numEasyChatWords, 1); - total += gUnknown_0203A134->layout->var8[i].numEasyChatWords; + ConvertEasyChatWordsToString(sMailRead->strbuf[i], &sMailRead->mail->words[total], sMailRead->layout->var8[i].numEasyChatWords, 1); + total += sMailRead->layout->var8[i].numEasyChatWords; } - ptr = StringCopy(gUnknown_0203A134->playerName, gUnknown_0203A134->mail->playerName); - if (!gUnknown_0203A134->playerIsSender) + ptr = StringCopy(sMailRead->playerName, sMailRead->mail->playerName); + if (!sMailRead->playerIsSender) { StringCopy(ptr, gText_FromSpace); - gUnknown_0203A134->signatureWidth = gUnknown_0203A134->layout->signatureWidth - (StringLength(gUnknown_0203A134->playerName) * 8 - 0x60); + sMailRead->signatureWidth = sMailRead->layout->signatureWidth - (StringLength(sMailRead->playerName) * 8 - 0x60); } else { - sub_81DB52C(gUnknown_0203A134->playerName); - gUnknown_0203A134->signatureWidth = gUnknown_0203A134->layout->signatureWidth; + sub_81DB52C(sMailRead->playerName); + sMailRead->signatureWidth = sMailRead->layout->signatureWidth; } } -void sub_8121B1C(void) +static void sub_8121B1C(void) { u16 i; u8 strbuf[0x20]; @@ -500,77 +503,76 @@ void sub_8121B1C(void) PutWindowTilemap(1); FillWindowPixelBuffer(0, 0); FillWindowPixelBuffer(1, 0); - for (i = 0; i < gUnknown_0203A134->layout->numSubStructs; i ++) + for (i = 0; i < sMailRead->layout->numSubStructs; i ++) { - if (gUnknown_0203A134->strbuf[i][0] == EOS || gUnknown_0203A134->strbuf[i][0] == CHAR_SPACE) + if (sMailRead->strbuf[i][0] == EOS || sMailRead->strbuf[i][0] == CHAR_SPACE) { continue; } - box_print(0, 1, gUnknown_0203A134->layout->var8[i].xOffset + gUnknown_0203A134->layout->wordsYPos, y + gUnknown_0203A134->layout->wordsXPos, gUnknown_0859F2AC, 0, gUnknown_0203A134->strbuf[i]); - y += gUnknown_0203A134->layout->var8[i].lineHeight; + box_print(0, 1, sMailRead->layout->var8[i].xOffset + sMailRead->layout->wordsYPos, y + sMailRead->layout->wordsXPos, sUnknown_0859F2AC, 0, sMailRead->strbuf[i]); + y += sMailRead->layout->var8[i].lineHeight; } bufptr = StringCopy(strbuf, gText_FromSpace); - StringCopy(bufptr, gUnknown_0203A134->playerName); - box_x = GetStringCenterAlignXOffset(1, strbuf, gUnknown_0203A134->signatureWidth) + 0x68; - box_y = gUnknown_0203A134->layout->signatureYPos + 0x58; - box_print(0, 1, box_x, box_y, gUnknown_0859F2AC, 0, strbuf); + StringCopy(bufptr, sMailRead->playerName); + box_x = GetStringCenterAlignXOffset(1, strbuf, sMailRead->signatureWidth) + 0x68; + box_y = sMailRead->layout->signatureYPos + 0x58; + box_print(0, 1, box_x, box_y, sUnknown_0859F2AC, 0, strbuf); CopyWindowToVram(0, 3); CopyWindowToVram(1, 3); } -void sub_8121C50(void) +static void VBlankCB_MailRead(void) { LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); } -void sub_8121C64(void) +static void CB2_MailRead(void) { - if (gUnknown_0203A134->animsActive != 0) + if (sMailRead->animsActive != 0) { AnimateSprites(); BuildOamBuffer(); } - gUnknown_0203A134->callback2(); + sMailRead->callback2(); } -void sub_8121C98(void) +static void CB2_WaitForPaletteExitOnKeyPress(void) { if (!UpdatePaletteFade()) { - gUnknown_0203A134->callback2 = sub_8121CC0; + sMailRead->callback2 = CB2_ExitOnKeyPress; } } -void sub_8121CC0(void) +static void CB2_ExitOnKeyPress(void) { if (gMain.newKeys & (A_BUTTON | B_BUTTON)) { BeginNormalPaletteFade(-1, 0, 0, 16, 0); - gUnknown_0203A134->callback2 = sub_8121D00; + sMailRead->callback2 = CB2_ExitMailReadFreeVars; } } -void sub_8121D00(void) +static void CB2_ExitMailReadFreeVars(void) { if (!UpdatePaletteFade()) { - SetMainCallback2(gUnknown_0203A134->callback); - switch (gUnknown_0203A134->animsActive) + SetMainCallback2(sMailRead->callback); + switch (sMailRead->animsActive) { case 1: case 2: - sub_80D2FF0(sub_80D2E84(gUnknown_0203A134->mail->species)); - sub_80D2EF8(&gSprites[gUnknown_0203A134->monIconSprite]); + sub_80D2FF0(sub_80D2E84(sMailRead->mail->species)); + sub_80D2EF8(&gSprites[sMailRead->monIconSprite]); } - memset(gUnknown_0203A134, 0, sizeof(*gUnknown_0203A134)); + memset(sMailRead, 0, sizeof(*sMailRead)); ResetPaletteFade(); UnsetBgTilemapBuffer(0); UnsetBgTilemapBuffer(1); ResetBgsAndClearDma3BusyFlags(0); FreeAllWindowBuffers(); - free(gUnknown_0203A134); - gUnknown_0203A134 = NULL; + FREE_AND_SET_NULL(sMailRead); } } diff --git a/src/mail_data.c b/src/mail_data.c new file mode 100644 index 000000000..ebb49febf --- /dev/null +++ b/src/mail_data.c @@ -0,0 +1,203 @@ +#include "global.h" +#include "mail.h" +#include "constants/items.h" +#include "pokemon.h" +#include "pokemon_icon.h" +#include "constants/species.h" +#include "text.h" +#include "international_string_util.h" + +void ClearMailData(void) +{ + u8 i; + + for (i = 0; i < MAIL_COUNT; i++) + ClearMailStruct(&gSaveBlock1Ptr->mail[i]); +} + +void ClearMailStruct(struct MailStruct *mail) +{ + s32 i; + + for (i = 0; i < MAIL_WORDS_COUNT; i++) + mail->words[i] = 0xFFFF; + + for (i = 0; i < PLAYER_NAME_LENGTH; i++) + mail->playerName[i] = EOS; + + for (i = 0; i < 4; i++) + mail->trainerId[i] = 0; + + mail->species = SPECIES_BULBASAUR; + mail->itemId = ITEM_NONE; +} + +bool8 MonHasMail(struct Pokemon *mon) +{ + u16 heldItem = GetMonData(mon, MON_DATA_HELD_ITEM); + if (ItemIsMail(heldItem) && GetMonData(mon, MON_DATA_MAIL) != 0xFF) + return TRUE; + else + return FALSE; +} + +u8 GiveMailToMon(struct Pokemon *mon, u16 itemId) +{ + u8 heldItem[2]; + u8 id, i; + u16 species; + u32 personality; + + heldItem[0] = itemId; + heldItem[1] = itemId >> 8; + + for (id = 0; id < PARTY_SIZE; id++) + { + if (gSaveBlock1Ptr->mail[id].itemId == 0) + { + for (i = 0; i < MAIL_WORDS_COUNT; i++) + gSaveBlock1Ptr->mail[id].words[i] = 0xFFFF; + + for (i = 0; i < PLAYER_NAME_LENGTH - 1; i++) + gSaveBlock1Ptr->mail[id].playerName[i] = gSaveBlock2Ptr->playerName[i]; + gSaveBlock1Ptr->mail[id].playerName[i] = EOS; + PadNameString(gSaveBlock1Ptr->mail[id].playerName, CHAR_SPACE); + + for (i = 0; i < 4; i++) + gSaveBlock1Ptr->mail[id].trainerId[i] = gSaveBlock2Ptr->playerTrainerId[i]; + + species = GetBoxMonData(&mon->box, MON_DATA_SPECIES); + personality = GetBoxMonData(&mon->box, MON_DATA_PERSONALITY); + gSaveBlock1Ptr->mail[id].species = SpeciesToMailSpecies(species, personality); + gSaveBlock1Ptr->mail[id].itemId = itemId; + SetMonData(mon, MON_DATA_MAIL, &id); + SetMonData(mon, MON_DATA_HELD_ITEM, heldItem); + return id; + } + } + + return 0xFF; +} + +u16 SpeciesToMailSpecies(u16 species, u32 personality) +{ + if (species == SPECIES_UNOWN) + { + u32 species = GetUnownLetterByPersonality(personality) + 30000; + return species; + } + + return species; +} + +u16 MailSpeciesToSpecies(u16 mailSpecies, u16 *buffer) +{ + u16 result; + + if (mailSpecies >= 30000 && mailSpecies < (30000 + UNOWN_FORM_COUNT)) + { + result = SPECIES_UNOWN; + *buffer = mailSpecies - 30000; + } + else + { + result = mailSpecies; + } + + return result; +} + +u8 GiveMailToMon2(struct Pokemon *mon, struct MailStruct *mail) +{ + u8 heldItem[2]; + u16 itemId = mail->itemId; + u8 mailId = GiveMailToMon(mon, itemId); + + if (mailId == 0xFF) + return 0xFF; + + gSaveBlock1Ptr->mail[mailId] = *mail; + + SetMonData(mon, MON_DATA_MAIL, &mailId); + + heldItem[0] = itemId; + heldItem[1] = itemId >> 8; + + SetMonData(mon, MON_DATA_HELD_ITEM, heldItem); + + return mailId; +} + +static bool32 DummyMailFunc(void) +{ + return FALSE; +} + +void TakeMailFromMon(struct Pokemon *mon) +{ + u8 heldItem[2]; + u8 mailId; + + if (MonHasMail(mon)) + { + mailId = GetMonData(mon, MON_DATA_MAIL); + gSaveBlock1Ptr->mail[mailId].itemId = ITEM_NONE; + mailId = 0xFF; + heldItem[0] = ITEM_NONE; + heldItem[1] = ITEM_NONE << 8; + SetMonData(mon, MON_DATA_MAIL, &mailId); + SetMonData(mon, MON_DATA_HELD_ITEM, heldItem); + } +} + +void ClearMailItemId(u8 mailId) +{ + gSaveBlock1Ptr->mail[mailId].itemId = ITEM_NONE; +} + +u8 TakeMailFromMon2(struct Pokemon *mon) +{ + u8 i; + u8 newHeldItem[2]; + u8 newMailId; + + newHeldItem[0] = ITEM_NONE; + newHeldItem[1] = ITEM_NONE << 8; + newMailId = 0xFF; + + for (i = PARTY_SIZE; i < MAIL_COUNT; i++) + { + if (gSaveBlock1Ptr->mail[i].itemId == ITEM_NONE) + { + memcpy(&gSaveBlock1Ptr->mail[i], &gSaveBlock1Ptr->mail[GetMonData(mon, MON_DATA_MAIL)], sizeof(struct MailStruct)); + gSaveBlock1Ptr->mail[GetMonData(mon, MON_DATA_MAIL)].itemId = ITEM_NONE; + SetMonData(mon, MON_DATA_MAIL, &newMailId); + SetMonData(mon, MON_DATA_HELD_ITEM, newHeldItem); + return i; + } + } + + return 0xFF; +} + +bool8 ItemIsMail(u16 itemId) +{ + switch (itemId) + { + case ITEM_ORANGE_MAIL: + case ITEM_HARBOR_MAIL: + case ITEM_GLITTER_MAIL: + case ITEM_MECH_MAIL: + case ITEM_WOOD_MAIL: + case ITEM_WAVE_MAIL: + case ITEM_BEAD_MAIL: + case ITEM_SHADOW_MAIL: + case ITEM_TROPIC_MAIL: + case ITEM_DREAM_MAIL: + case ITEM_FAB_MAIL: + case ITEM_RETRO_MAIL: + return TRUE; + default: + return FALSE; + } +} diff --git a/src/new_game.c b/src/new_game.c index 12873fec9..89771e92b 100644 --- a/src/new_game.c +++ b/src/new_game.c @@ -33,7 +33,6 @@ extern void Overworld_SetWarpDestination(s8 mapBank, s8 mapNo, s8 warpNo, s8 xPo extern void warp_in(void); extern void sub_80BB358(void); extern void ResetBagScrollPositions(void); -extern void sub_813624C(void); // clears something pokeblock related extern void ResetPokedex(void); extern void sub_8084400(void); extern void ClearMailData(void); @@ -148,7 +147,7 @@ void sub_808447C(void) ZeroPlayerPartyMons(); ZeroEnemyPartyMons(); ResetBagScrollPositions(); - sub_813624C(); + ResetPokeblockScrollPositions(); } void NewGameInitData(void) diff --git a/src/palette.c b/src/palette.c index 8528a3fdc..d7b6ad479 100644 --- a/src/palette.c +++ b/src/palette.c @@ -850,13 +850,13 @@ void TintPalette_GrayScale(u16 *palette, u16 count) r = *palette & 0x1F; g = (*palette >> 5) & 0x1F; b = (*palette >> 10) & 0x1F; - + r = r * Q_8_8(0.2969); r += g * Q_8_8(0.5899); r += b * Q_8_8(0.1133); - + gray = r >> 8; - + *palette++ = gray << 10 | gray << 5 | gray; } } @@ -874,18 +874,18 @@ void TintPalette_GrayScale2(u16 *palette, u16 count) r = *palette & 0x1F; g = (*palette >> 5) & 0x1F; b = (*palette >> 10) & 0x1F; - + r = r * Q_8_8(0.2969); r += g * Q_8_8(0.5899); r += b * Q_8_8(0.1133); - + gray = r >> 8; - + if (gray > 0x1F) gray = 0x1F; - + gray = sRoundedDownGrayscaleMap[gray]; - + *palette++ = gray << 10 | gray << 5 | gray; } } @@ -897,32 +897,35 @@ void TintPalette_SepiaTone(u16 *palette, u16 count) int green; int blue; u32 gray; - u8 r2; - u8 g2; - u8 b2; - + u32 sepia; + s8 r2; + s8 g2; + s8 b2; + int i; for (i = 0; i < count; i++) { - red = *palette & 0x1F; - green = (*palette >> 5) & 0x1F; - blue = (*palette >> 10) & 0x1F; - - gray = red * Q_8_8(0.2969); - gray += green * Q_8_8(0.5899); - gray += blue * Q_8_8(0.1133); - - gray = gray / 256; - - r2 = (gray * 0x133) / 256; - + r = *palette & 0x1F; + g = (*palette >> 5) & 0x1F; + b = (*palette >> 10) & 0x1F; + + r *= 0x4C; + r += g * 0x97; + r += b * 0x1D; + + gray = (s32)(r >> 8); + + sepia = (gray * 0x133); + + r2 = (u16)sepia >> 8; + g2 = gray; - - b2 = (gray * 0xF); - + + b2 = (gray * 15); + if (r2 > 0x1F) r2 = 0x1F; - + *palette++ = b2 << 10 | g2 << 5 | r2; } } @@ -1006,28 +1009,28 @@ void TintPalette_CustomTone(u16 *palette, u16 count, u16 a3, u16 a4, u16 a5) r = *palette & 0x1F; g = (*palette >> 5) & 0x1F; b = (*palette >> 10) & 0x1F; - + r *= 0x4C; r += g * 0x97; r += b * 0x1D; - + gray = r >> 8; - + r2 = (u16)(gray * a3) >> 8; - + g2 = (u16)(gray * a4) >> 8; - + b2 = (u16)(gray * a5) >> 8; - + if (r2 > 0x1F) r2 = 0x1F; - + if (g2 > 0x1F) g2 = 0x1F; - + if (b2 > 0x1F) b2 = 0x1F; - + *palette++ = b2 << 10 | g2 << 5 | r2; } return; diff --git a/src/pokeblock.c b/src/pokeblock.c new file mode 100644 index 000000000..8716e827f --- /dev/null +++ b/src/pokeblock.c @@ -0,0 +1,1337 @@ +#include "global.h" +#include "pokeblock.h" +#include "bg.h" +#include "strings.h" +#include "text.h" +#include "menu.h" +#include "task.h" +#include "menu_helpers.h" +#include "new_menu_helpers.h" +#include "pokemon.h" +#include "graphics.h" +#include "malloc.h" +#include "main.h" +#include "battle.h" +#include "battle_controllers.h" +#include "palette.h" +#include "unknown_task.h" +#include "list_menu.h" +#include "gpu_regs.h" +#include "decompress.h" +#include "international_string_util.h" +#include "item.h" +#include "constants/items.h" +#include "string_util.h" +#include "songs.h" +#include "sound.h" +#include "berry.h" +#include "menu_indicators.h" +#include "event_data.h" +#include "battle_message.h" +#include "safari_zone.h" +#include "lilycove_lady.h" + +#define POKEBLOCK_MAX_FEEL 99 +#define FIELD_E75_COUNT 7 + +struct PokeblockMenuStruct +{ + u8 tilemap[0x800]; + void (*callbackOnUse)(void); + const u8 *pokeblockOptionsIds; + u8 optionsNo; + u8 caseId; + u8 itemsNo; + u8 maxShowed; + struct ListMenuItem items[POKEBLOCKS_COUNT + 1]; + u8 menuItemsStrings[POKEBLOCKS_COUNT + 1][0x20]; // + 1 because of STOW CASE item + u8 pokeblockCaseSpriteId; + u8 field_E75[FIELD_E75_COUNT]; + u8 unkTaskId; + bool8 isSwapping; + s16 gfxState; + u8 unused[8]; +}; + +struct PokeblockSavedData +{ + void (*callback)(void); + u16 lastItemPos; + u16 lastItemPage; +}; + +enum +{ + PKBL_USE_ON_FIELD, + PKBL_TOSS, + PKBL_CANCEL, + PKBL_USE_IN_BATTLE, + PKBL_USE_ON_FEEDER, + PKBL_GIVE_TO_LADY +}; + +extern u16 gSpecialVar_ItemId; +extern void (*gFieldCallback)(void); + +extern const u16 gUnknown_0860F074[]; + +extern void c2_exit_to_overworld_2_switch(void); +extern bool8 sub_81221EC(void); +extern void sub_809882C(u8, u16, u8); +extern void copy_textbox_border_tile_patterns_to_vram(u8, u16, u8); +extern void sub_80AF168(void); + +// this file's functions +static void CB2_InitPokeblockMenu(void); +static bool8 InitPokeblockMenu(void); +static bool8 LoadPokeblockMenuGfx(void); +static void HandleInitBackgrounds(void); +static void HandleInitWindows(void); +static void SetMenuItemsCountAndMaxShowed(void); +static void sub_81362E0(void); +static void sub_8136344(void); +static void HandlePokeblockListMenuItems(void); +static void sub_81363BC(void); +static void MovePokeblockMenuCursor(u32 pkblId, bool8 arg1, struct ListMenu *arg2); +static void PutPokeblockInfoText(void); +static void HandlePokeblockMenuCursor(u16 cursorPos, u16 arg1); +static void PutPokeblockListMenuString(u8 *dst, u16 pkblId); +static void Task_HandlePokeblockMenuInput(u8 taskId); +static void PokeblockAction_UseOnField(u8 taskId); +static void PokeblockAction_Toss(u8 taskId); +static void PokeblockAction_Cancel(u8 taskId); +static void PokeblockAction_UseInBattle(u8 taskId); +static void PokeblockAction_UseOnPokeblockFeeder(u8 taskId); +static void PokeblockAction_GiveToContestLady(u8 taskId); +static void TossPokeblockChoice_Yes(u8 taskId); +static void TossPokeblockChoice_No(u8 taskId); +static void Task_FreeDataAndExitPokeblockCase(u8 taskId); +static void Task_HandlePokeblockOptionsInput(u8 taskId); +static void PutPokeblockOptionsWindow(u8 taskId); +static void Task_HandlePokeblocksSwapInput(u8 taskId); +static void sub_8136470(struct Sprite *sprite); +static void sub_8135FCC(s32 pkblId); +static void HandlePokeblocksSwap(u8 taskId, bool8 noSwap); +static void UsePokeblockOnField(void); +static void ReturnToPokeblockCaseOnField(void); +static void CreateTossPokeblockYesNoMenu(u8 taskId); +static void HandleErasePokeblock(u8 taskId); + +// ram variables +EWRAM_DATA static struct PokeblockSavedData sSavedPokeblockData = {0}; +EWRAM_DATA static struct PokeblockMenuStruct *sPokeblockMenu = NULL; + +// const rom data +const s8 gPokeblockFlavorCompatibilityTable[] = +{ + // Cool, Beauty, Cute, Smart, Tough + 0, 0, 0, 0, 0, // Hardy + 1, 0, 0, 0, -1, // Lonely + 1, 0, -1, 0, 0, // Brave + 1, -1, 0, 0, 0, // Adamant + 1, 0, 0, -1, 0, // Naughty + -1, 0, 0, 0, 1, // Bold + 0, 0, 0, 0, 0, // Docile + 0, 0, -1, 0, 1, // Relaxed + 0, -1, 0, 0, 1, // Impish + 0, 0, 0, -1, 1, // Lax + -1, 0, 1, 0, 0, // Timid + 0, 0, 1, 0, -1, // Hasty + 0, 0, 0, 0, 0, // Serious + 0, -1, 1, 0, 0, // Jolly + 0, 0, 1, -1, 0, // Naive + -1, 1, 0, 0, 0, // Modest + 0, 1, 0, 0, -1, // Mild + 0, 1, -1, 0, 0, // Quiet + 0, 0, 0, 0, 0, // Bashful + 0, 1, 0, -1, 0, // Rash + -1, 0, 0, 1, 0, // Calm + 0, 0, 0, 1, -1, // Gentle + 0, 0, -1, 1, 0, // Sassy + 0, -1, 0, 1, 0, // Careful + 0, 0, 0, 0, 0 // Quirky +}; + +static const struct BgTemplate sBgTemplatesForPokeblockMenu[] = +{ + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0 + }, + { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0 + }, + { + .bg = 2, + .charBaseIndex = 3, + .mapBaseIndex = 29, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0 + } +}; + +const u8 *const gPokeblockNames[] = +{ + NULL, + gText_RedPokeblock, + gText_BluePokeblock, + gText_PinkPokeblock, + gText_GreenPokeblock, + gText_YellowPokeblock, + gText_PurplePokeblock, + gText_IndigoPokeblock, + gText_BrownPokeblock, + gText_LiteBluePokeblock, + gText_OlivePokeblock, + gText_GrayPokeblock, + gText_BlackPokeblock, + gText_WhitePokeblock, + gText_GoldPokeblock +}; + +static const struct MenuAction sPokeblockMenuActions[] = +{ + {gMenuText_Use, PokeblockAction_UseOnField}, + {gMenuText_Toss, PokeblockAction_Toss}, + {gText_Cancel2, PokeblockAction_Cancel}, + {gMenuText_Use, PokeblockAction_UseInBattle}, + {gMenuText_Use, PokeblockAction_UseOnPokeblockFeeder}, + {gMenuText_Give2, PokeblockAction_GiveToContestLady}, +}; + +static const u8 sActionsOnField[] = {PKBL_USE_ON_FIELD, PKBL_TOSS, PKBL_CANCEL}; +static const u8 sActionsInBattle[] = {PKBL_USE_IN_BATTLE, PKBL_CANCEL}; +static const u8 sActionsOnPokeblockFeeder[] = {PKBL_USE_ON_FEEDER, PKBL_CANCEL}; +static const u8 sActionsWhenGivingToLady[] = {PKBL_GIVE_TO_LADY, PKBL_CANCEL}; + +static const struct YesNoFuncTable sTossYesNoFuncTable = {TossPokeblockChoice_Yes, TossPokeblockChoice_No}; + +static const u8 sContestStatsMonData[] = {MON_DATA_COOL, MON_DATA_BEAUTY, MON_DATA_CUTE, MON_DATA_SMART, MON_DATA_TOUGH}; + +static const struct OamData sOamData_PokeblockCase = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 0, + .x = 0, + .matrixNum = 0, + .size = 3, + .tileNum = 0, + .priority = 2, + .paletteNum = 0, + .affineParam = 0, +}; + +static const union AnimCmd sSpriteAnim_PokeblockCase[] = +{ + ANIMCMD_FRAME(0, 0), + ANIMCMD_END +}; + +static const union AnimCmd *const sSpriteAnimTable_PokeblockCase[] = +{ + sSpriteAnim_PokeblockCase +}; + +static const union AffineAnimCmd sSpriteAffineAnim_85B26C8[] = +{ + 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 sSpriteAffineAnimTable_85B26F0[] = +{ + sSpriteAffineAnim_85B26C8 +}; + +const struct CompressedSpriteSheet gPokeblockCase_SpriteSheet = +{ + gMenuPokeblockDevice_Gfx, 0x800, GFX_TAG_POKEBLOCK_CASE +}; + +const struct CompressedSpritePalette gPokeblockCase_SpritePal = +{ + gMenuPokeblockDevice_Pal, GFX_TAG_POKEBLOCK_CASE +}; + +static const struct SpriteTemplate sSpriteTemplate_PokeblockCase = +{ + GFX_TAG_POKEBLOCK_CASE, + GFX_TAG_POKEBLOCK_CASE, + &sOamData_PokeblockCase, + sSpriteAnimTable_PokeblockCase, + NULL, + gDummySpriteAffineAnimTable, + SpriteCallbackDummy +}; + +static const struct TextColor sTextColorInPokeblockMenu = {0, 2, 3}; + +static const struct Pokeblock sFavoritePokeblocksTable[] = +{ + { PBLOCK_CLR_RED, 20, 0, 0, 0, 0, 20}, + { PBLOCK_CLR_BLUE, 0, 20, 0, 0, 0, 20}, + { PBLOCK_CLR_PINK, 0, 0, 20, 0, 0, 20}, + { PBLOCK_CLR_GREEN, 0, 0, 0, 20, 0, 20}, + { PBLOCK_CLR_YELLOW, 0, 0, 0, 0, 20, 20} +}; + +static const struct WindowTemplate sWindowTemplatesForPokeblockMenu[] = +{ + {0, 2, 1, 9, 2, 0xF, 0x1E}, + {0, 0xF, 1, 0xE, 0x12, 0xF, 0x30}, + {0, 2, 0xD, 5, 2, 0xF, 0x12C}, + {0, 2, 0xF, 5, 2, 0xF, 0x136}, + {0, 2, 0x11, 5, 2, 0xF, 0x140}, + {0, 8, 0xD, 5, 2, 0xF, 0x14A}, + {0, 8, 0xF, 5, 2, 0xF, 0x154}, + {0, 0xB, 0x11, 2, 2, 0xF, 0x15E}, + {1, 7, 5, 6, 6, 0xF, 0x162}, + {1, 7, 7, 6, 4, 0xF, 0x186}, + {1, 2, 0xF, 0x1B, 4, 0xF, 0x19E}, + DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate sTossPkblockWindowTemplate = {1, 0x15, 9, 5, 4, 0xF, 0x20A}; + +static const struct ListMenuTemplate sPokeblockListMenuTemplate = +{ + .items = NULL, + .moveCursorFunc = MovePokeblockMenuCursor, + .unk_08 = NULL, + .totalItems = 0, + .maxShowed = 0, + .unk_10 = 1, + .unk_11 = 0, + .unk_12 = 1, + .cursor_Y = 0, + .upText_Y = 1, + .cursorColor = 2, + .fillColor = 0, + .cursorShadowColor = 3, + .unk_16_0 = FALSE, + .spaceBetweenItems = 32, + .unk_16_7 = FALSE, + .unk_17_0 = 1, + .cursorKind = 1 +}; + +// code +void OpenPokeblockCase(u8 caseId, void (*callback)(void)) +{ + sPokeblockMenu = Alloc(sizeof(*sPokeblockMenu)); + sPokeblockMenu->caseId = caseId; + sPokeblockMenu->callbackOnUse = NULL; + sPokeblockMenu->unkTaskId = 0xFF; + sPokeblockMenu->isSwapping = FALSE; + sSavedPokeblockData.callback = callback; + + switch (sPokeblockMenu->caseId) + { + case PBLOCK_CASE_BATTLE: + sPokeblockMenu->pokeblockOptionsIds = sActionsInBattle; + sPokeblockMenu->optionsNo = ARRAY_COUNT(sActionsInBattle); + break; + case PBLOCK_CASE_FEEDER: + sPokeblockMenu->pokeblockOptionsIds = sActionsOnPokeblockFeeder; + sPokeblockMenu->optionsNo = ARRAY_COUNT(sActionsOnPokeblockFeeder); + break; + case PBLOCK_CASE_GIVE: + sPokeblockMenu->pokeblockOptionsIds = sActionsWhenGivingToLady; + sPokeblockMenu->optionsNo = ARRAY_COUNT(sActionsWhenGivingToLady); + break; + default: + sPokeblockMenu->pokeblockOptionsIds = sActionsOnField; + sPokeblockMenu->optionsNo = ARRAY_COUNT(sActionsOnField); + break; + } + + SetMainCallback2(CB2_InitPokeblockMenu); +} + +void OpenPokeblockCaseInBattle(void) +{ + OpenPokeblockCase(PBLOCK_CASE_BATTLE, SetCB2ToReshowScreenAfterMenu2); +} + +void OpenPokeblockCaseOnFeeder(void) +{ + OpenPokeblockCase(PBLOCK_CASE_FEEDER, c2_exit_to_overworld_2_switch); +} + +static void CB2_PokeblockMenu(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +static void VBlankCB_PokeblockMenu(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void CB2_InitPokeblockMenu(void) +{ + while (1) + { + if (sub_81221EC() == TRUE) + break; + if (InitPokeblockMenu() == TRUE) + break; + if (sub_81221AC() == TRUE) + break; + } +} + +static bool8 InitPokeblockMenu(void) +{ + u8 taskId; + + switch (gMain.state) + { + case 0: + SetVBlankHBlankCallbacksToNull(); + clear_scheduled_bg_copies_to_vram(); + gMain.state++; + break; + case 1: + remove_some_task(); + gMain.state++; + break; + case 2: + FreeAllSpritePalettes(); + gMain.state++; + break; + case 3: + ResetPaletteFade(); + gPaletteFade.bufferTransferDisabled = 1; + gMain.state++; + break; + case 4: + ResetSpriteData(); + gMain.state++; + break; + case 5: + if (sPokeblockMenu->caseId != PBLOCK_CASE_BATTLE) + ResetTasks(); + gMain.state++; + break; + case 6: + HandleInitBackgrounds(); + sPokeblockMenu->gfxState = 0; + gMain.state++; + break; + case 7: + if (!LoadPokeblockMenuGfx()) + return FALSE; + gMain.state++; + break; + case 8: + SetMenuItemsCountAndMaxShowed(); + sub_81362E0(); + sub_8136344(); + gMain.state++; + break; + case 9: + sPokeblockMenu->pokeblockCaseSpriteId = CreatePokeblockCaseSprite(56, 64, 0); + gMain.state++; + break; + case 10: + sub_8122344(&sPokeblockMenu->field_E75, FIELD_E75_COUNT); + gMain.state++; + break; + case 11: + HandlePokeblockMenuCursor(sSavedPokeblockData.lastItemPos, 0x1005); + gMain.state++; + break; + case 12: + HandleInitWindows(); + gMain.state++; + break; + case 13: + HandlePokeblockListMenuItems(); + gMain.state++; + break; + case 14: + sub_81363BC(); + gMain.state++; + break; + case 15: + taskId = CreateTask(Task_HandlePokeblockMenuInput, 0); + gTasks[taskId].data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sSavedPokeblockData.lastItemPage, sSavedPokeblockData.lastItemPos); + gMain.state++; + break; + case 16: + PutPokeblockInfoText(); + gMain.state++; + break; + case 17: + BlendPalettes(-1, 0x10, 0); + gMain.state++; + break; + case 18: + BeginNormalPaletteFade(-1, 0, 0x10, 0, 0); + gPaletteFade.bufferTransferDisabled = 0; + gMain.state++; + break; + default: + SetVBlankCallback(VBlankCB_PokeblockMenu); + SetMainCallback2(CB2_PokeblockMenu); + return TRUE; + } + + return FALSE; +} + +static void HandleInitBackgrounds(void) +{ + ResetVramOamAndBgCntRegs(); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBgTemplatesForPokeblockMenu, ARRAY_COUNT(sBgTemplatesForPokeblockMenu)); + SetBgTilemapBuffer(2, sPokeblockMenu->tilemap); + ResetAllBgsCoordinates(); + schedule_bg_copy_tilemap_to_vram(2); + + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + + ShowBg(0); + ShowBg(1); + ShowBg(2); + + SetGpuReg(REG_OFFSET_BLDCNT, 0); +} + +static bool8 LoadPokeblockMenuGfx(void) +{ + switch (sPokeblockMenu->gfxState) + { + case 0: + reset_temp_tile_data_buffers(); + decompress_and_copy_tile_data_to_vram(2, gMenuPokeblock_Gfx, 0, 0, 0); + sPokeblockMenu->gfxState++; + break; + case 1: + if (free_temp_tile_data_buffers_if_possible() != TRUE) + { + LZDecompressWram(gMenuPokeblock_Tilemap, sPokeblockMenu->tilemap); + sPokeblockMenu->gfxState++; + } + break; + case 2: + LoadCompressedPalette(gMenuPokeblock_Pal, 0, 0xC0); + sPokeblockMenu->gfxState++; + break; + case 3: + LoadCompressedObjectPic(&gPokeblockCase_SpriteSheet); + sPokeblockMenu->gfxState++; + break; + case 4: + LoadCompressedObjectPalette(&gPokeblockCase_SpritePal); + sPokeblockMenu->gfxState++; + break; + case 5: + LoadListMenuArrowsGfx(); + sPokeblockMenu->gfxState = 0; + return TRUE; + } + + return FALSE; +} + +static void HandleInitWindows(void) +{ + u8 i; + + InitWindows(sWindowTemplatesForPokeblockMenu); + DeactivateAllTextPrinters(); + sub_809882C(0, 1, 0xE0); + copy_textbox_border_tile_patterns_to_vram(0, 0xA, 0xD0); + LoadPalette(gUnknown_0860F074, 0xF0, 0x20); + + for (i = 0; i < ARRAY_COUNT(sWindowTemplatesForPokeblockMenu) - 1; i++) + { + FillWindowPixelBuffer(i, 0); + } + + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); +} + +static void PrintOnPokeblockWindow(u8 windowId, const u8 *string, s32 x) +{ + AddTextPrinterParametrized2(windowId, 1, x, 1, 0, 0, &sTextColorInPokeblockMenu, 0, string); +} + +static void PutPokeblockInfoText(void) +{ + u8 i; + + const u8 *itemName = ItemId_GetItem(ITEM_POKEBLOCK_CASE)->name; + PrintOnPokeblockWindow(0, itemName, GetStringCenterAlignXOffset(1, itemName, 0x48)); + + PrintOnPokeblockWindow(2, gText_Spicy, 0); + PrintOnPokeblockWindow(3, gText_Dry, 0); + PrintOnPokeblockWindow(4, gText_Sweet, 0); + PrintOnPokeblockWindow(5, gText_Bitter, 0); + PrintOnPokeblockWindow(6, gText_Sour, 0); + + for (i = 0; i < 8; i++) + { + PutWindowTilemap(i); + } +} + +static void HandlePokeblockListMenuItems(void) +{ + u16 i; + + for (i = 0; i < sPokeblockMenu->itemsNo - 1; i++) + { + PutPokeblockListMenuString(sPokeblockMenu->menuItemsStrings[i], i); + sPokeblockMenu->items[i].name = sPokeblockMenu->menuItemsStrings[i]; + sPokeblockMenu->items[i].id = i; + } + + StringCopy(sPokeblockMenu->menuItemsStrings[i], gText_StowCase); + sPokeblockMenu->items[i].name = sPokeblockMenu->menuItemsStrings[i]; + sPokeblockMenu->items[i].id = LIST_B_PRESSED; + + gMultiuseListMenuTemplate = sPokeblockListMenuTemplate; + gMultiuseListMenuTemplate.unk_17_0 = 7; + gMultiuseListMenuTemplate.totalItems = sPokeblockMenu->itemsNo; + gMultiuseListMenuTemplate.items = sPokeblockMenu->items; + gMultiuseListMenuTemplate.maxShowed = sPokeblockMenu->maxShowed; +} + +static void PutPokeblockListMenuString(u8 *dst, u16 pkblId) +{ + struct Pokeblock *pkblock = &gSaveBlock1Ptr->pokeblocks[pkblId]; + u8 *txtPtr = StringCopy(dst, gPokeblockNames[pkblock->color]); + + *(txtPtr++) = EXT_CTRL_CODE_BEGIN; + *(txtPtr++) = 0x12; + *(txtPtr++) = 0x57; + + ConvertIntToDecimalStringN(gStringVar1, GetHighestPokeblocksFlavorLevel(pkblock), STR_CONV_MODE_LEFT_ALIGN, 3); + StringExpandPlaceholders(txtPtr, gText_LvVar1); +} + +static void MovePokeblockMenuCursor(u32 pkblId, bool8 arg1, struct ListMenu *arg2) +{ + if (arg1 != TRUE) + { + PlaySE(SE_SELECT); + gSprites[sPokeblockMenu->pokeblockCaseSpriteId].callback = sub_8136470; + } + + if (!sPokeblockMenu->isSwapping) + sub_8135FCC(pkblId); +} + +static void sub_8135FCC(s32 pkblId) +{ + u8 i; + struct Pokeblock *pokeblock; + u16 rectTilemapSrc[2]; + + FillWindowPixelBuffer(7, 0); + + if (pkblId != LIST_B_PRESSED) + { + pokeblock = &gSaveBlock1Ptr->pokeblocks[pkblId]; + rectTilemapSrc[0] = 0x17; + rectTilemapSrc[1] = 0x18; + for (i = 0; i < FLAVOR_COUNT; i++) + { + if (GetPokeblockData(pokeblock, PBLOCK_SPICY + i) > 0) + { + rectTilemapSrc[0] = (i << 0xC) + 0x17; + rectTilemapSrc[1] = (i << 0xC) + 0x18; + } + else + { + rectTilemapSrc[0] = 0xF; + rectTilemapSrc[1] = 0xF; + } + CopyToBgTilemapBufferRect(2, rectTilemapSrc, (i / 3 * 6) + 1, (i % 3 * 2) + 13, 1, 2); + } + ConvertIntToDecimalStringN(gStringVar1, GetPokeblocksFeel(pokeblock), STR_CONV_MODE_RIGHT_ALIGN, 2); + PrintOnPokeblockWindow(7, gStringVar1, 4); + } + else + { + rectTilemapSrc[0] = 0xF; + rectTilemapSrc[1] = 0xF; + + for (i = 0; i < FLAVOR_COUNT; i++) + { + CopyToBgTilemapBufferRect(2, rectTilemapSrc, (i / 3 * 6) + 1, (i % 3 * 2) + 13, 1, 2); + } + CopyWindowToVram(7, 2); + } + + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(2); +} + +static void HandlePokeblockMenuCursor(u16 cursorPos, u16 arg1) +{ + FillBgTilemapBufferRect_Palette0(2, arg1, 0xF, (cursorPos * 2) + 1, 0xE, 2); + schedule_bg_copy_tilemap_to_vram(2); +} + +static void CompactPokeblockSlots(void) +{ + u16 i, j; + + for (i = 0; i < POKEBLOCKS_COUNT - 1; i++) + { + for (j = i + 1; j < POKEBLOCKS_COUNT; j++) + { + if (gSaveBlock1Ptr->pokeblocks[i].color == 0) + { + struct Pokeblock temp = gSaveBlock1Ptr->pokeblocks[i]; + gSaveBlock1Ptr->pokeblocks[i] = gSaveBlock1Ptr->pokeblocks[j]; + gSaveBlock1Ptr->pokeblocks[j] = temp; + } + } + } +} + +static void SwapSortPokeblocksInternalData(u32 id1, u32 id2) +{ + s16 i, count; + struct Pokeblock *pokeblocks = gSaveBlock1Ptr->pokeblocks; + struct Pokeblock *copyPokeblock1; + + if (id1 == id2) + return; + + copyPokeblock1 = Alloc(sizeof(struct Pokeblock)); + *copyPokeblock1 = pokeblocks[id1]; + + if (id2 > id1) + { + id2--; + for (count = id2, i = id1; i < count; i++) + pokeblocks[i] = pokeblocks[i + 1]; + } + else + { + for (count = id2, i = id1; i > count; i--) + pokeblocks[i] = pokeblocks[i - 1]; + } + + pokeblocks[id2] = *copyPokeblock1; + Free(copyPokeblock1); +} + +void ResetPokeblockScrollPositions(void) +{ + sSavedPokeblockData.lastItemPos = 0; + sSavedPokeblockData.lastItemPage = 0; +} + +static void SetMenuItemsCountAndMaxShowed(void) +{ + u16 i; + + CompactPokeblockSlots(); + + for (sPokeblockMenu->itemsNo = 0, i = 0; i < POKEBLOCKS_COUNT; i++) + { + if (gSaveBlock1Ptr->pokeblocks[i].color != 0) + sPokeblockMenu->itemsNo++; + } + + sPokeblockMenu->itemsNo++; // STOW CASE menu item + + if (sPokeblockMenu->itemsNo > 9) + sPokeblockMenu->maxShowed = 9; + else + sPokeblockMenu->maxShowed = sPokeblockMenu->itemsNo; +} + +static void sub_81362E0(void) +{ + if (sSavedPokeblockData.lastItemPage != 0) + { + if (sSavedPokeblockData.lastItemPage + sPokeblockMenu->maxShowed > sPokeblockMenu->itemsNo) + sSavedPokeblockData.lastItemPage = sPokeblockMenu->itemsNo - sPokeblockMenu->maxShowed; + } + + if (sSavedPokeblockData.lastItemPage + sSavedPokeblockData.lastItemPos >= sPokeblockMenu->itemsNo) + { + if (sPokeblockMenu->itemsNo == 0) + sSavedPokeblockData.lastItemPos = 0; + else + sSavedPokeblockData.lastItemPos = sPokeblockMenu->itemsNo - 1; + } +} + +static void sub_8136344(void) +{ + if (sSavedPokeblockData.lastItemPos > 4) + { + u8 i; + + for (i = 0; + (i < sSavedPokeblockData.lastItemPos - 4) && (sSavedPokeblockData.lastItemPage + sPokeblockMenu->maxShowed != sPokeblockMenu->itemsNo); + sSavedPokeblockData.lastItemPos--, sSavedPokeblockData.lastItemPage++, i++); + } +} + +static void sub_81363BC(void) +{ + if (sPokeblockMenu->unkTaskId == 0xFF) + { + sPokeblockMenu->unkTaskId = AddScrollIndicatorArrowPairParametrized(2, 0xB0, 8, 0x98, sPokeblockMenu->itemsNo - sPokeblockMenu->maxShowed, + 0x456, 0x456, &sSavedPokeblockData.lastItemPage); + } +} + +static void sub_8136418(void) +{ + if (sPokeblockMenu->unkTaskId != 0xFF) + { + RemoveScrollIndicatorArrowPair(sPokeblockMenu->unkTaskId); + sPokeblockMenu->unkTaskId = 0xFF; + } +} + +u8 CreatePokeblockCaseSprite(s16 x, s16 y, u8 subpriority) +{ + return CreateSprite(&sSpriteTemplate_PokeblockCase, x, y, subpriority); +} + +static void sub_8136470(struct Sprite *sprite) +{ + if (sprite->data[0] > 1) + sprite->data[0] = 0; + + switch (sprite->data[0]) + { + case 0: + sprite->oam.affineMode = 1; + sprite->affineAnims = sSpriteAffineAnimTable_85B26F0; + InitSpriteAffineAnim(sprite); + sprite->data[0] = 1; + sprite->data[1] = 0; + break; + case 1: + if (++sprite->data[1] > 11) + { + sprite->oam.affineMode = 0; + sprite->data[0] = 0; + sprite->data[1] = 0; + FreeOamMatrix(sprite->oam.matrixNum); + sprite->callback = SpriteCallbackDummy; + } + break; + } +} + +static void FadePaletteAndSetTaskToClosePokeblockCase(u8 taskId) +{ + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gTasks[taskId].func = Task_FreeDataAndExitPokeblockCase; +} + +static void Task_FreeDataAndExitPokeblockCase(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (!gPaletteFade.active) + { + if (sPokeblockMenu->caseId == PBLOCK_CASE_FEEDER || sPokeblockMenu->caseId == PBLOCK_CASE_GIVE) + gFieldCallback = sub_80AF168; + + sub_81AE6C8(data[0], &sSavedPokeblockData.lastItemPage, &sSavedPokeblockData.lastItemPos); + sub_8136418(); + ResetSpriteData(); + FreeAllSpritePalettes(); + + if (sPokeblockMenu->callbackOnUse != NULL) + SetMainCallback2(sPokeblockMenu->callbackOnUse); + else + SetMainCallback2(sSavedPokeblockData.callback); + + FreeAllWindowBuffers(); + Free(sPokeblockMenu); + DestroyTask(taskId); + } +} + +static void Task_HandlePokeblockMenuInput(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (!gPaletteFade.active && sub_81221EC() != TRUE) + { + if (gMain.newKeys & SELECT_BUTTON) + { + sub_81AE860(data[0], &sSavedPokeblockData.lastItemPage, &sSavedPokeblockData.lastItemPos); + if (sSavedPokeblockData.lastItemPage + sSavedPokeblockData.lastItemPos != sPokeblockMenu->itemsNo - 1) + { + PlaySE(SE_SELECT); + HandlePokeblockMenuCursor(sSavedPokeblockData.lastItemPos, 0x2005); + data[2] = sSavedPokeblockData.lastItemPage + sSavedPokeblockData.lastItemPos; + sPokeblockMenu->isSwapping = TRUE; + gTasks[taskId].func = Task_HandlePokeblocksSwapInput; + } + } + else + { + u16 oldPosition = sSavedPokeblockData.lastItemPos; + s32 itemId = ListMenuHandleInputGetItemId(data[0]); + + sub_81AE860(data[0], &sSavedPokeblockData.lastItemPage, &sSavedPokeblockData.lastItemPos); + if (oldPosition != sSavedPokeblockData.lastItemPos) + { + HandlePokeblockMenuCursor(oldPosition, 5); + HandlePokeblockMenuCursor(sSavedPokeblockData.lastItemPos, 0x1005); + } + + switch (itemId) + { + case LIST_NOTHING_CHOSEN: + break; + case LIST_B_PRESSED: + PlaySE(SE_SELECT); + gSpecialVar_Result = 0xFFFF; + gSpecialVar_ItemId = 0; + FadePaletteAndSetTaskToClosePokeblockCase(taskId); + break; + default: + PlaySE(SE_SELECT); + gSpecialVar_ItemId = itemId; + PutPokeblockOptionsWindow(taskId); + break; + } + } + } +} + +static void Task_HandlePokeblocksSwapInput(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (sub_81221EC() == TRUE) + return; + + if (gMain.newKeys & SELECT_BUTTON) + { + PlaySE(SE_SELECT); + sub_81AE860(data[0], &sSavedPokeblockData.lastItemPage, &sSavedPokeblockData.lastItemPos); + HandlePokeblocksSwap(taskId, FALSE); + } + else + { + u16 i = sSavedPokeblockData.lastItemPage; + u16 var = sSavedPokeblockData.lastItemPos; + s32 itemId = ListMenuHandleInputGetItemId(data[0]); + + sub_81AE860(data[0], &sSavedPokeblockData.lastItemPage, &sSavedPokeblockData.lastItemPos); + if (i != sSavedPokeblockData.lastItemPage || var != sSavedPokeblockData.lastItemPos) + { + for (i = 0; i < 9; i++) + { + var = i + sSavedPokeblockData.lastItemPage; + if (var == data[2]) + HandlePokeblockMenuCursor(i, 0x2005); + else + HandlePokeblockMenuCursor(i, 5); + } + } + + sub_81223FC(sPokeblockMenu->field_E75, FIELD_E75_COUNT, 0); + sub_8122448(sPokeblockMenu->field_E75, FIELD_E75_COUNT, 0x80, (sSavedPokeblockData.lastItemPos * 16) + 8); + + switch (itemId) + { + case LIST_NOTHING_CHOSEN: + break; + case LIST_B_PRESSED: // same id as STOW CASE field + PlaySE(SE_SELECT); + if (gMain.newKeys & A_BUTTON) + HandlePokeblocksSwap(taskId, FALSE); + else + HandlePokeblocksSwap(taskId, TRUE); + break; + default: + PlaySE(SE_SELECT); + HandlePokeblocksSwap(taskId, FALSE); + break; + } + } +} + +static void HandlePokeblocksSwap(u8 taskId, bool8 noSwap) +{ + u8 i; + s16 *data = gTasks[taskId].data; + u16 swappedFromId = sSavedPokeblockData.lastItemPage + sSavedPokeblockData.lastItemPos; + + sPokeblockMenu->isSwapping = FALSE; + sub_81AE6C8(data[0], &sSavedPokeblockData.lastItemPage, &sSavedPokeblockData.lastItemPos); + + if (!noSwap && data[2] != swappedFromId && data[2] != swappedFromId - 1) + { + SwapSortPokeblocksInternalData(data[2], swappedFromId); + HandlePokeblockListMenuItems(); + } + + if (data[2] < swappedFromId) + sSavedPokeblockData.lastItemPos--; + + data[0] = ListMenuInit(&gMultiuseListMenuTemplate, sSavedPokeblockData.lastItemPage, sSavedPokeblockData.lastItemPos); + schedule_bg_copy_tilemap_to_vram(0); + sub_81223FC(sPokeblockMenu->field_E75, FIELD_E75_COUNT, 1); + + for (i = 0; i < 9; i++) + HandlePokeblockMenuCursor(i, 5); + + HandlePokeblockMenuCursor(sSavedPokeblockData.lastItemPos, 0x1005); + gTasks[taskId].func = Task_HandlePokeblockMenuInput; +} + +static void PutPokeblockOptionsWindow(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (sPokeblockMenu->optionsNo == 3) + data[1] = 8; + else + data[1] = 9; + + sub_8136418(); + SetWindowBorderStyle(data[1], 0, 1, 0xE); + sub_81995E4(data[1], sPokeblockMenu->optionsNo, sPokeblockMenuActions, sPokeblockMenu->pokeblockOptionsIds); + InitMenuInUpperLeftCornerPlaySoundWhenAPressed(data[1], sPokeblockMenu->optionsNo, 0); + PutWindowTilemap(data[1]); + schedule_bg_copy_tilemap_to_vram(1); + + gTasks[taskId].func = Task_HandlePokeblockOptionsInput; +} + +static void Task_HandlePokeblockOptionsInput(u8 taskId) +{ + s8 itemId; + + if (sub_81221EC() == TRUE) + return; + + itemId = ProcessMenuInputNoWrapAround(); + if (itemId == MENU_NOTHING_CHOSEN) + { + return; + } + else if (itemId == MENU_B_PRESSED) + { + PlaySE(SE_SELECT); + PokeblockAction_Cancel(taskId); + } + else + { + PlaySE(SE_SELECT); + sPokeblockMenuActions[sPokeblockMenu->pokeblockOptionsIds[itemId]].func.void_u8(taskId); + } +} + +static void PokeblockAction_UseOnField(u8 taskId) +{ + sPokeblockMenu->callbackOnUse = UsePokeblockOnField; + FadePaletteAndSetTaskToClosePokeblockCase(taskId); +} + +static void UsePokeblockOnField(void) +{ + ChooseMonToGivePokeblock(&gSaveBlock1Ptr->pokeblocks[gSpecialVar_ItemId], ReturnToPokeblockCaseOnField); +} + +static void ReturnToPokeblockCaseOnField(void) +{ + OpenPokeblockCase(PBLOCK_CASE_FIELD, sSavedPokeblockData.callback); +} + +static void PokeblockAction_Toss(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + sub_8198070(data[1], FALSE); + StringCopy(gStringVar1, gPokeblockNames[gSaveBlock1Ptr->pokeblocks[gSpecialVar_ItemId].color]); + StringExpandPlaceholders(gStringVar4, gText_ThrowAwayVar1); + DisplayMessageAndContinueTask(taskId, 10, 10, 13, 1, GetPlayerTextSpeed(), gStringVar4, CreateTossPokeblockYesNoMenu); +} + +static void CreateTossPokeblockYesNoMenu(u8 taskId) +{ + CreateYesNoMenuWithCallbacks(taskId, &sTossPkblockWindowTemplate, 1, 0, 2, 1, 0xE, &sTossYesNoFuncTable); +} + +static void TossPokeblockChoice_Yes(u8 taskId) +{ + StringExpandPlaceholders(gStringVar4, gText_Var1ThrownAway); + DisplayMessageAndContinueTask(taskId, 10, 10, 13, 1, GetPlayerTextSpeed(), gStringVar4, HandleErasePokeblock); +} + +static void HandleErasePokeblock(u8 taskId) +{ + if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + s16 *data; + u16 *lastPage, *lastPos; + + TryClearPokeblock(gSpecialVar_ItemId); + PlaySE(SE_SELECT); + + lastPage = &sSavedPokeblockData.lastItemPage; + lastPos = &sSavedPokeblockData.lastItemPos; + data = gTasks[taskId].data; + + sub_81AE6C8(data[0], lastPage, lastPos); + HandlePokeblockMenuCursor(*lastPos, 5); + SetMenuItemsCountAndMaxShowed(); + sub_81362E0(); + HandlePokeblockListMenuItems(); + data[0] = ListMenuInit(&gMultiuseListMenuTemplate, *lastPage, *lastPos); + HandlePokeblockMenuCursor(*lastPos, 0x1005); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + TossPokeblockChoice_No(taskId); + } +} + +static void TossPokeblockChoice_No(u8 taskId) +{ + sub_8197DF8(10, FALSE); + schedule_bg_copy_tilemap_to_vram(1); + sub_81363BC(); + gTasks[taskId].func = Task_HandlePokeblockMenuInput; +} + +static void PokeblockAction_UseInBattle(u8 taskId) +{ + u8 nature = GetNature(&gEnemyParty[0]); + s16 gain = PokeblockGetGain(nature, &gSaveBlock1Ptr->pokeblocks[gSpecialVar_ItemId]); + StringCopy(gBattleTextBuff1, gPokeblockNames[gSaveBlock1Ptr->pokeblocks[gSpecialVar_ItemId].color]); + TryClearPokeblock(gSpecialVar_ItemId); + + gSpecialVar_ItemId = gSaveBlock1Ptr->pokeblocks[gSpecialVar_ItemId].color << 8; + if (gain == 0) + gSpecialVar_ItemId += 1; + else if (gain > 0) + gSpecialVar_ItemId += 2; + else + gSpecialVar_ItemId += 3; + + FadePaletteAndSetTaskToClosePokeblockCase(taskId); +} + +static void PokeblockAction_UseOnPokeblockFeeder(u8 taskId) +{ + SafariZoneActivatePokeblockFeeder(gSpecialVar_ItemId); + StringCopy(gStringVar1, gPokeblockNames[gSaveBlock1Ptr->pokeblocks[gSpecialVar_ItemId].color]); + gSpecialVar_Result = gSpecialVar_ItemId; + TryClearPokeblock(gSpecialVar_ItemId); + gSpecialVar_ItemId = 0; + FadePaletteAndSetTaskToClosePokeblockCase(taskId); +} + +static void PokeblockAction_GiveToContestLady(u8 taskId) +{ + gSpecialVar_0x8004 = GivePokeblockToContestLady(&gSaveBlock1Ptr->pokeblocks[gSpecialVar_ItemId]); + gSpecialVar_Result = gSpecialVar_ItemId; + TryClearPokeblock(gSpecialVar_ItemId); + gSpecialVar_ItemId = 0; + FadePaletteAndSetTaskToClosePokeblockCase(taskId); +} + +static void PokeblockAction_Cancel(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + sub_8198070(data[1], FALSE); + schedule_bg_copy_tilemap_to_vram(1); + sub_81363BC(); + gTasks[taskId].func = Task_HandlePokeblockMenuInput; +} + +static void ClearPokeblock(u8 pkblId) +{ + gSaveBlock1Ptr->pokeblocks[pkblId].color = 0; + gSaveBlock1Ptr->pokeblocks[pkblId].spicy = 0; + gSaveBlock1Ptr->pokeblocks[pkblId].dry = 0; + gSaveBlock1Ptr->pokeblocks[pkblId].sweet = 0; + gSaveBlock1Ptr->pokeblocks[pkblId].bitter = 0; + gSaveBlock1Ptr->pokeblocks[pkblId].sour = 0; + gSaveBlock1Ptr->pokeblocks[pkblId].feel = 0; +} + +void ClearPokeblocks(void) +{ + u8 i; + + for (i = 0; i < POKEBLOCKS_COUNT; i++) + ClearPokeblock(i); +} + +u8 GetHighestPokeblocksFlavorLevel(const struct Pokeblock *pokeblock) +{ + u8 i; + u8 maxFlavor = GetPokeblockData(pokeblock, PBLOCK_SPICY); + + for (i = PBLOCK_SPICY; i < FLAVOR_COUNT; i++) + { + u8 currFlavor = GetPokeblockData(pokeblock, PBLOCK_SPICY + i); + if (maxFlavor < currFlavor) + maxFlavor = currFlavor; + } + + return maxFlavor; +} + +u8 GetPokeblocksFeel(const struct Pokeblock *pokeblock) +{ + u8 feel = GetPokeblockData(pokeblock, PBLOCK_FEEL); + if (feel > POKEBLOCK_MAX_FEEL) + feel = POKEBLOCK_MAX_FEEL; + + return feel; +} + +s8 GetFirstFreePokeblockSlot(void) +{ + u8 i; + + for (i = 0; i < POKEBLOCKS_COUNT; i++) + { + if (gSaveBlock1Ptr->pokeblocks[i].color == 0) + return i; + } + + return -1; +} + +bool32 AddPokeblock(const struct Pokeblock *pokeblock) +{ + s8 slot = GetFirstFreePokeblockSlot(); + + if (slot == -1) + { + return FALSE; + } + else + { + gSaveBlock1Ptr->pokeblocks[slot] = *pokeblock; + return TRUE; + } +} + +bool32 TryClearPokeblock(u8 pkblId) +{ + if (gSaveBlock1Ptr->pokeblocks[pkblId].color == 0) + { + return FALSE; + } + else + { + ClearPokeblock(pkblId); + return TRUE; + } +} + +s16 GetPokeblockData(const struct Pokeblock *pokeblock, u8 field) +{ + if (field == PBLOCK_COLOR) + return pokeblock->color; + if (field == PBLOCK_SPICY) + return pokeblock->spicy; + if (field == PBLOCK_DRY) + return pokeblock->dry; + if (field == PBLOCK_SWEET) + return pokeblock->sweet; + if (field == PBLOCK_BITTER) + return pokeblock->bitter; + if (field == PBLOCK_SOUR) + return pokeblock->sour; + if (field == PBLOCK_FEEL) + return pokeblock->feel; + + return 0; +} + +s16 PokeblockGetGain(u8 nature, const struct Pokeblock *pokeblock) +{ + u8 flavor; + s16 curGain, totalGain = 0; + + for (flavor = 0; flavor < FLAVOR_COUNT; flavor++) + { + curGain = GetPokeblockData(pokeblock, flavor + PBLOCK_SPICY); + if (curGain > 0) + totalGain += curGain * gPokeblockFlavorCompatibilityTable[5 * nature + flavor]; + } + + return totalGain; +} + +void PokeblockCopyName(const struct Pokeblock *pokeblock, u8 *dest) +{ + u8 color = GetPokeblockData(pokeblock, PBLOCK_COLOR); + StringCopy(dest, gPokeblockNames[color]); +} + +bool8 CopyMonFavoritePokeblockName(u8 nature, u8 *dest) +{ + u8 i; + + for (i = 0; i < FLAVOR_COUNT; i++) + { + if (PokeblockGetGain(nature, &sFavoritePokeblocksTable[i]) > 0) + { + StringCopy(dest, gPokeblockNames[i + 1]); + return TRUE; + } + } + + return FALSE; +} + +u8 GetPokeblocksFlavor(const struct Pokeblock *pokeblock) +{ + s16 bestFlavor = 0; + s16 i; + + for (i = 0; i < FLAVOR_COUNT; i++) + { + if (GetPokeblockData(pokeblock, bestFlavor + 1) < GetPokeblockData(pokeblock, i + 1)) + bestFlavor = i; + } + + return bestFlavor; +} diff --git a/src/pokeblock_feed.c b/src/pokeblock_feed.c new file mode 100644 index 000000000..1bf40bbe5 --- /dev/null +++ b/src/pokeblock_feed.c @@ -0,0 +1,1108 @@ +#include "global.h" +#include "pokeblock.h" +#include "sprite.h" +#include "task.h" +#include "palette.h" +#include "menu.h" +#include "malloc.h" +#include "pokemon.h" +#include "blend_palette.h" +#include "main.h" +#include "menu_helpers.h" +#include "bg.h" +#include "gpu_regs.h" +#include "data2.h" +#include "decompress.h" +#include "event_data.h" +#include "strings.h" +#include "string_util.h" +#include "new_menu_helpers.h" +#include "party_menu.h" +#include "m4a.h" +#include "sound.h" +#include "trig.h" +#include "graphics.h" +#include "battle.h" // to get rid of once gMonSpritesGfxPtr is put elsewhere + +struct PokeblockFeedStruct +{ + struct Sprite *monSpritePtr; + struct Sprite savedMonSprite; + u8 tilemapBuffer[0x808]; + s16 field_850[0x200]; + s16 field_C50[0x200]; + u8 field_1050; + u8 animId; + u8 field_1052; + bool8 noMonFlip; + u16 species; + u16 field_1056; + u16 field_1058; + u8 nature; + u8 monSpriteId_; + u8 field_105C; + u8 monSpriteId; + u8 pokeblockCaseSpriteId; + u8 pokeblockSpriteId; + s16 field_1060[15]; + s16 loadGfxState; + u8 unused; +}; + +extern u16 gSpecialVar_ItemId; +extern struct MusicPlayerInfo gMPlay_BGM; +extern struct SpriteTemplate gUnknown_0202499C; + +extern const u8 gBattleTerrainPalette_Frontier[]; +extern const u8 gBattleTerrainTiles_Building[]; +extern const u8 gUnknown_08D9BA44[]; +extern const struct CompressedSpriteSheet gMonFrontPicTable[]; +extern const u16 gUnknown_0860F074[]; + +extern bool8 sub_81221EC(void); +extern void sub_806A068(u16, u8); +extern void sub_809882C(u8, u16, u8); + +// this file's functions +static void HandleInitBackgrounds(void); +static void HandleInitWindows(void); +static void LaunchPokeblockFeedTask(void); +static void SetPokeblockSpritePal(u8 pokeblockCaseId); +static void sub_817A5CC(void); +static void sub_8148108(u8 spriteId, bool8 a1); +static void DoPokeblockCaseThrowEffect(u8 spriteId, bool8 arg1); +static void PrepareMonToMoveToPokeblock(u8 spriteId); +static void Task_HandleMonAtePokeblock(u8 taskId); +static void Task_PaletteFadeToReturn(u8 taskId); +static void sub_817A634(void); +static void sub_817A468(struct Sprite *sprite); +static void sub_817AB68(void); +static void sub_817AA54(void); +static bool8 sub_817A91C(void); +static bool8 FreeMonSpriteOamMatrix(void); +static bool8 sub_817A9E4(void); +static bool8 LoadMonAndSceneGfx(struct Pokemon *mon); +static u8 CreatePokeblockSprite(void); +static u8 CreatePokeblockCaseSpriteForFeeding(void); +static u8 CreateMonSprite(struct Pokemon *mon); +static void SpriteCB_ThrownPokeblock(struct Sprite* sprite); + +// ram variables +EWRAM_DATA static struct PokeblockFeedStruct *sPokeblockFeed = NULL; +EWRAM_DATA static struct CompressedSpritePalette sPokeblockSpritePal = {0}; + +// const rom data +static const u8 sNatureToMonPokeblockAnim[][2] = +{ + { 0, 0 }, // HARDY + { 3, 0 }, // LONELY + { 4, 1 }, // BRAVE + { 5, 0 }, // ADAMANT + { 10, 0 }, // NAUGHTY + { 13, 0 }, // BOLD + { 15, 0 }, // DOCILE + { 16, 2 }, // RELAXED + { 18, 0 }, // IMPISH + { 19, 0 }, // LAX + { 20, 0 }, // TIMID + { 25, 0 }, // HASTY + { 27, 3 }, // SERIOUS + { 28, 0 }, // JOLLY + { 29, 0 }, // NAIVE + { 33, 4 }, // MODEST + { 36, 0 }, // MILD + { 37, 0 }, // QUIET + { 39, 0 }, // BASHFUL + { 42, 0 }, // RASH + { 45, 0 }, // CALM + { 46, 5 }, // GENTLE + { 47, 6 }, // SASSY + { 48, 0 }, // CAREFUL + { 53, 0 }, // QUIRKY +}; + +static const s16 sMonPokeblockAnims[][10] = +{ + // HARDY + { 0, 4, 0, 8, 24, 0, 0, 0, 12, 0}, + { 0, 4, 0, 16, 24, 0, 0, 0, 12, 0}, + { 0, 4, 0, 32, 32, 0, 0, 0, 16, 1}, + + // LONELY + { 0, 3, 6, 0, 48, 0, 0, 0, 24, 1}, + + // BRAVE + { 64, 16, -24, 0, 32, 0, 0, 0, 0, 1}, + + // ADAMANT + { 0, 4, 8, 0, 16, 0, -8, 0, 0, 0}, + { 0, 0, 0, 0, 16, 0, 0, 0, 0, 0}, + { 0, 4, 8, 0, 16, 0, -8, 0, 0, 0}, + { 0, 0, 0, 0, 16, 0, 0, 0, 0, 0}, + { 0, 4, -16, 0, 4, 0, 16, 0, 0, 1}, + + // NAUGHTY + { 0, 3, 6, 0, 12, 0, 0, 0, 6, 0}, + { 0, 3, -6, 0, 12, 0, 0, 0, 6, 0}, + { 0, 16, 16, 0, 45, 1, 0, 0, 0, 1}, + + // BOLD + { 0, 16, 0, 24, 32, 0, 0, 0, 16, 0}, + { 0, 16, 0, 23, 32, 0, 0, 0, 16, 1}, + + // DOCILE + { 0, 0, 0, 0, 80, 0, 0, 0, 0, 1}, + + // RELAXED + { 0, 2, 8, 0, 32, 0, 0, 0, 0, 0}, + { 0, 2, -8, 0, 32, 0, 0, 0, 0, 1}, + + // IMPISH + { 0, 32, 2, 1, 48, 1, 0, 0, 24, 1}, + + // LAX + { 0, 2, 16, 16, 128, 0, 0, 0, 0, 1}, + + // TIMID + { 0, 2, -8, 0, 48, 0, -24, 0, 0, 0}, + { 0, 0, 0, 0, 8, 0, 0, 0, 0, 0}, + { 64, 32, 2, 0, 36, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 8, 0, 0, 0, 0, 0}, + { 0, 2, 8, 0, 48, 0, 24, 0, 0, 1}, + + // HASTY + { 64, 24, 16, 0, 32, 0, 0, 0, 0, 0}, + { 0, 28, 2, 1, 32, 1, 0, 0, 16, 1}, + + // SERIOUS + { 0, 0, 0, 0, 32, 0, 0, 0, 0, 1}, + + // JOLLY + { 64, 16, -16, 2, 48, 0, 0, 0, 32, 1}, + + // NAIVE + { 0, 12, -8, 4, 24, 0, 8, 0, 12, 0}, + { 0, 12, 8, 8, 24, 0, -16, 0, 12, 0}, + { 0, 12, -8, 16, 24, 0, 16, 0, 12, 0}, + { 0, 12, 8, 28, 24, 0, -8, 0, 12, 1}, + + // MODEST + { 0, 0, 0, 0, 8, 0, 0, 0, 0, 0}, + { 64, 16, -4, 0, 32, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 8, 0, 0, 0, 0, 1}, + + // MILD + { 128, 4, 0, 8, 64, 0, 0, 0, 0, 1}, + + // QUIET + { 0, 2, 16, 0, 48, 0, 0, 0, 0, 0}, + { 128, 2, 16, 0, 48, 0, 0, 0, 0, 1}, + + // BASHFUL + { 0, 2, -4, 0, 48, 0, -48, 0, 0, 0}, + { 0, 0, 0, 0, 80, 0, 0, 0, 0, 0}, + { 0, 2, 8, 0, 24, 0, 48, 0, 0, 1}, + + // RASH + { 64, 4, 64, 58, 52, 0, -88, 0, 0, 0}, + { 0, 0, 0, 0, 80, 0, 0, 0, 0, 0}, + { 0, 24, 80, 0, 32, 0, 88, 0, 0, 1}, + + // CALM + { 0, 2, 16, 4, 64, 0, 0, 0, 0, 1}, + + // GENTLE + { 0, 0, 0, 0, 32, 0, 0, 0, 0, 1}, + + // SASSY + { 0, 0, 0, 0, 42, 0, 0, 0, 0, 1}, + + // CAREFUL + { 0, 4, 0, 8, 24, 0, 0, 0, 12, 0}, + { 0, 0, 0, 0, 12, 0, 0, 0, 0, 0}, + { 0, 4, 0, 12, 24, 0, 0, 0, 12, 0}, + { 0, 0, 0, 0, 12, 0, 0, 0, 0, 0}, + { 0, 4, 0, 4, 24, 0, 0, 0, 12, 1}, + + // QUIRKY + { 0, 4, 16, 12, 64, 0, 0, 0, 0, 0}, + { 0, -4, 16, 12, 64, 0, 0, 0, 0, 1}, +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411E90[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411EA0[] = +{ + AFFINEANIMCMD_FRAME(0, 0, 12, 1), + AFFINEANIMCMD_FRAME(0, 0, 0, 30), + AFFINEANIMCMD_FRAME(0, 0, -12, 1), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411EC0[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0, 0, 12, 1), + AFFINEANIMCMD_FRAME(0, 0, 0, 28), + AFFINEANIMCMD_FRAME(0, 0, -4, 3), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411EE8[] = +{ + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 16), + AFFINEANIMCMD_FRAME(0x0, 0x0, -1, 32), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 16), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411F08[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 16), + AFFINEANIMCMD_FRAME(0x0, 0x0, -1, 32), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 16), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411F30[] = +{ + AFFINEANIMCMD_FRAME(0x0, 0x0, -1, 8), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 16), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 8), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411F50[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0x0, 0x0, -1, 8), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 16), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 8), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411F78[] = +{ + AFFINEANIMCMD_FRAME(0x0, 0x0, -1, 8), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 32), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 8), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411F98[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0x0, 0x0, -1, 8), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 32), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 8), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411FC0[] = +{ + AFFINEANIMCMD_FRAME(0x0, 0x0, -1, 4), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 24), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 4), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8411FE0[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0x0, 0x0, -1, 4), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 24), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 4), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8412008[] = +{ + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 24), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 16), + AFFINEANIMCMD_FRAME(0x0, 0x0, -12, 2), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8412028[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0x0, 0x0, 1, 24), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 16), + AFFINEANIMCMD_FRAME(0x0, 0x0, -12, 2), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd *const sSpriteAffineAnimTable_85F04FC[] = +{ + sSpriteAffineAnim_8411E90, + sSpriteAffineAnim_8411EA0, + sSpriteAffineAnim_8411EE8, + sSpriteAffineAnim_8411F30, + sSpriteAffineAnim_8411F78, + sSpriteAffineAnim_8411FC0, + sSpriteAffineAnim_8412008, + sSpriteAffineAnim_8411E90, + sSpriteAffineAnim_8411E90, + sSpriteAffineAnim_8411E90, + sSpriteAffineAnim_8411E90, + sSpriteAffineAnim_8411EC0, + sSpriteAffineAnim_8411F08, + sSpriteAffineAnim_8411F50, + sSpriteAffineAnim_8411F98, + sSpriteAffineAnim_8411FE0, + sSpriteAffineAnim_8412028, + sSpriteAffineAnim_8411E90, + sSpriteAffineAnim_8411E90, + sSpriteAffineAnim_8411E90, + sSpriteAffineAnim_8411E90, +}; + +static const struct BgTemplate sBackgroundTemplates[] = +{ + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0 + }, + { + .bg = 1, + .charBaseIndex = 2, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0 + } +}; + +static const struct WindowTemplate sWindowTemplates[] = +{ + {0, 1, 0xF, 0x1C, 4, 0xF, 0xA}, + DUMMY_WIN_TEMPLATE +}; + +static const u8* const sPokeblocksPals[] = +{ + gPokeblockRed_Pal, + gPokeblockBlue_Pal, + gPokeblockPink_Pal, + gPokeblockGreen_Pal, + gPokeblockYellow_Pal, + gPokeblockPurple_Pal, + gPokeblockIndigo_Pal, + gPokeblockBrown_Pal, + gPokeblockLiteBlue_Pal, + gPokeblockOlive_Pal, + gPokeblockGray_Pal, + gPokeblockBlack_Pal, + gPokeblockWhite_Pal, + gPokeblockGold_Pal +}; + +static const union AffineAnimCmd sSpriteAffineAnim_84120DC[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd *const sSpriteAffineAnimTable_MonNoFlip[] = +{ + sSpriteAffineAnim_84120DC +}; + +static const union AffineAnimCmd sSpriteAffineAnim_84120F0[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0x0, 0x0, -8, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, -8, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, -8, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, -8, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 8), + AFFINEANIMCMD_FRAME(0x0, 0x0, 16, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, 16, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, 16, 1), + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sSpriteAffineAnim_8412148[] = +{ + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0x0, 0x0, 8, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, 8, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, 8, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, 8, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 8), + AFFINEANIMCMD_FRAME(0x0, 0x0, -16, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, -16, 1), + AFFINEANIMCMD_FRAME(0x0, 0x0, -16, 1), + AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd *const sSpriteAffineAnimTable_85F0664[] = +{ + sSpriteAffineAnim_84120DC +}; + +static const union AffineAnimCmd *const sSpriteAffineAnimTable_85F0668[] = +{ + sSpriteAffineAnim_84120F0 +}; + +static const union AffineAnimCmd *const sSpriteAffineAnimTable_85F066C[] = +{ + sSpriteAffineAnim_8412148 +}; + +static const struct OamData sThrownPokeblockOamData = +{ + .y = 0, + .affineMode = 3, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 0, + .x = 0, + .matrixNum = 0, + .size = 0, + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, +}; + +static const union AnimCmd sThrownPokeblockSpriteAnim[] = +{ + ANIMCMD_FRAME(0, 0), + ANIMCMD_END +}; + +static const union AnimCmd *const sThrownPokeblockAnimTable[] = +{ + sThrownPokeblockSpriteAnim, +}; + +static const union AffineAnimCmd sSpriteAffineAnim_84121C0[] = +{ + AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(-8, -8, 0, 1), + AFFINEANIMCMD_JUMP(1) +}; + +static const union AffineAnimCmd *const sThrownPokeblockAffineAnimTable[] = +{ + sSpriteAffineAnim_84121C0 +}; + +static const struct CompressedSpriteSheet sPokeblock_SpriteSheet = +{ + gPokeblock_Gfx, 0x20, GFX_TAG_POKEBLOCK +}; + +static const struct SpriteTemplate sThrownPokeblockSpriteTemplate = +{ + .tileTag = GFX_TAG_POKEBLOCK, + .paletteTag = GFX_TAG_POKEBLOCK, + .oam = &sThrownPokeblockOamData, + .anims = sThrownPokeblockAnimTable, + .images = NULL, + .affineAnims = sThrownPokeblockAffineAnimTable, + .callback = SpriteCB_ThrownPokeblock +}; + +// code +static void CB2_PokeblockFeed(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +static void VBlankCB_PokeblockFeed(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static bool8 TransitionToPokeblockFeedScene(void) +{ + switch (gMain.state) + { + case 0: + sPokeblockFeed = AllocZeroed(sizeof(*sPokeblockFeed)); + SetVBlankHBlankCallbacksToNull(); + clear_scheduled_bg_copies_to_vram(); + gMain.state++; + break; + case 1: + ResetPaletteFade(); + gPaletteFade.bufferTransferDisabled = 1; + gMain.state++; + break; + case 2: + ResetSpriteData(); + gMain.state++; + break; + case 3: + FreeAllSpritePalettes(); + gMain.state++; + break; + case 4: + AllocateMonSpritesGfx(); + gMain.state++; + break; + case 5: + HandleInitBackgrounds(); + gMain.state++; + break; + case 6: + HandleInitWindows(); + gMain.state++; + break; + case 7: + if (LoadMonAndSceneGfx(&gPlayerParty[gPokeblockMonId])) + { + gMain.state++; + } + break; + case 8: + sPokeblockFeed->pokeblockCaseSpriteId = CreatePokeblockCaseSpriteForFeeding(); + gMain.state++; + break; + case 9: + sPokeblockFeed->monSpriteId = CreateMonSprite(&gPlayerParty[gPokeblockMonId]); + gMain.state++; + break; + case 10: + SetWindowBorderStyle(0, 1, 1, 14); + gMain.state++; + break; + case 11: + LaunchPokeblockFeedTask(); + gMain.state++; + break; + case 12: + BlendPalettes(-1, 0x10, 0); + gMain.state++; + break; + case 13: + BeginNormalPaletteFade(-1, 0, 0x10, 0, 0); + gPaletteFade.bufferTransferDisabled = 0; + gMain.state++; + break; + default: + SetVBlankCallback(VBlankCB_PokeblockFeed); + SetMainCallback2(CB2_PokeblockFeed); + return TRUE; + } + return FALSE; +} + +void CB2_PreparePokeblockFeedScene(void) +{ + while (1) + { + if (sub_81221EC() == TRUE) + break; + if (TransitionToPokeblockFeedScene() == TRUE) + break; + if (sub_81221AC() == TRUE) + break; + } +} + +static void HandleInitBackgrounds(void) +{ + ResetVramOamAndBgCntRegs(); + + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBackgroundTemplates, ARRAY_COUNT(sBackgroundTemplates)); + SetBgTilemapBuffer(1, sPokeblockFeed->tilemapBuffer); + ResetAllBgsCoordinates(); + schedule_bg_copy_tilemap_to_vram(1); + + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + + ShowBg(0); + ShowBg(1); + + SetGpuReg(REG_OFFSET_BLDCNT, 0); +} + +static bool8 LoadMonAndSceneGfx(struct Pokemon *mon) +{ + u16 species; + u32 personality, trainerId; + const struct CompressedSpritePalette *palette; + + switch (sPokeblockFeed->loadGfxState) + { + case 0: + species = GetMonData(mon, MON_DATA_SPECIES2); + personality = GetMonData(mon, MON_DATA_PERSONALITY); + HandleLoadSpecialPokePic_2(&gMonFrontPicTable[species], gMonSpritesGfxPtr->sprites[1], species, personality); + sPokeblockFeed->loadGfxState++; + break; + case 1: + species = GetMonData(mon, MON_DATA_SPECIES2); + personality = GetMonData(mon, MON_DATA_PERSONALITY); + trainerId = GetMonData(mon, MON_DATA_OT_ID); + palette = GetMonSpritePalStructFromOtIdPersonality(species, trainerId, personality); + + LoadCompressedObjectPalette(palette); + sub_806A068(palette->tag, 1); + sPokeblockFeed->loadGfxState++; + break; + case 2: + LoadCompressedObjectPic(&gPokeblockCase_SpriteSheet); + sPokeblockFeed->loadGfxState++; + break; + case 3: + LoadCompressedObjectPalette(&gPokeblockCase_SpritePal); + sPokeblockFeed->loadGfxState++; + break; + case 4: + LoadCompressedObjectPic(&sPokeblock_SpriteSheet); + sPokeblockFeed->loadGfxState++; + break; + case 5: + SetPokeblockSpritePal(gSpecialVar_ItemId); + LoadCompressedObjectPalette(&sPokeblockSpritePal); + sPokeblockFeed->loadGfxState++; + break; + case 6: + reset_temp_tile_data_buffers(); + decompress_and_copy_tile_data_to_vram(1, gBattleTerrainTiles_Building, 0, 0, 0); + sPokeblockFeed->loadGfxState++; + break; + case 7: + if (free_temp_tile_data_buffers_if_possible() != TRUE) + { + LZDecompressWram(gUnknown_08D9BA44, sPokeblockFeed->tilemapBuffer); + sPokeblockFeed->loadGfxState++; + } + break; + case 8: + LoadCompressedPalette(gBattleTerrainPalette_Frontier, 0x20, 0x60); + sPokeblockFeed->loadGfxState = 0; + return TRUE; + } + + return FALSE; +} + +static void HandleInitWindows(void) +{ + InitWindows(sWindowTemplates); + DeactivateAllTextPrinters(); + sub_809882C(0, 1, 0xE0); + LoadPalette(gUnknown_0860F074, 0xF0, 0x20); + FillWindowPixelBuffer(0, 0); + PutWindowTilemap(0); + schedule_bg_copy_tilemap_to_vram(0); +} + +static void SetPokeblockSpritePal(u8 pokeblockCaseId) +{ + u8 colorId = GetPokeblockData(&gSaveBlock1Ptr->pokeblocks[pokeblockCaseId], PBLOCK_COLOR); + sPokeblockSpritePal.data = sPokeblocksPals[colorId - 1]; + sPokeblockSpritePal.tag = GFX_TAG_POKEBLOCK; +} + +// defines for task data fields + +#define tFrames data[0] +#define tData1 data[1] + +static void Task_HandlePokeblockFeed(u8 taskId) +{ + if (!gPaletteFade.active) + { + switch (gTasks[taskId].tFrames) + { + case 0: + sPokeblockFeed->field_1050 = 0; + sPokeblockFeed->field_1058 = 0; + sub_817A5CC(); + break; + case 255: + DoPokeblockCaseThrowEffect(sPokeblockFeed->pokeblockCaseSpriteId, gTasks[taskId].tData1); + break; + case 269: + sPokeblockFeed->pokeblockSpriteId = CreatePokeblockSprite(); + break; + case 281: + PrepareMonToMoveToPokeblock(sPokeblockFeed->monSpriteId); + break; + case 297: + gTasks[taskId].func = Task_HandleMonAtePokeblock; + return; + } + + if (sPokeblockFeed->field_1058 < sPokeblockFeed->field_1056) + sub_817A634(); + else if (sPokeblockFeed->field_1058 == sPokeblockFeed->field_1056) + gTasks[taskId].tFrames = 254; + + sPokeblockFeed->field_1058++; + gTasks[taskId].tFrames++; + } +} + +static void LaunchPokeblockFeedTask(void) +{ + u8 taskId = CreateTask(Task_HandlePokeblockFeed, 0); + gTasks[taskId].tFrames = 0; + gTasks[taskId].tData1 = 1; +} + +static void Task_WaitForAtePokeblockText(u8 taskId) +{ + if (RunTextPrintersRetIsActive(0) != TRUE) + gTasks[taskId].func = Task_PaletteFadeToReturn; +} + +static void Task_HandleMonAtePokeblock(u8 taskId) +{ + struct Pokemon *mon = &gPlayerParty[gPokeblockMonId]; + struct Pokeblock *pokeblock = &gSaveBlock1Ptr->pokeblocks[gSpecialVar_ItemId]; + + gPokeblockGain = PokeblockGetGain(GetNature(mon), pokeblock); + GetMonNickname(mon, gStringVar1); + PokeblockCopyName(pokeblock, gStringVar2); + + if (gPokeblockGain == 0) + StringExpandPlaceholders(gStringVar4, gText_Var1AteTheVar2); + else if (gPokeblockGain > 0) + StringExpandPlaceholders(gStringVar4, gText_Var1HappilyAteVar2); + else + StringExpandPlaceholders(gStringVar4, gText_Var1DisdainfullyAteVar2); + + gTextFlags.flag_0 = 1; + AddTextPrinterParametrized(0, 1, gStringVar4, GetPlayerTextSpeed(), NULL, 2, 1, 3); + gTasks[taskId].func = Task_WaitForAtePokeblockText; +} + +static void Task_ReturnAfterPaletteFade(u8 taskId) +{ + if (!gPaletteFade.active) + { + ResetSpriteData(); + FreeAllSpritePalettes(); + m4aMPlayVolumeControl(&gMPlay_BGM, -1, 0x100); + SetMainCallback2(gMain.savedCallback); + DestroyTask(taskId); + FreeAllWindowBuffers(); + Free(sPokeblockFeed); + FreeMonSpritesGfx(); + } +} + +static void Task_PaletteFadeToReturn(u8 taskId) +{ + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gTasks[taskId].func = Task_ReturnAfterPaletteFade; +} + +#undef tFrames +#undef tData1 + +// defines for mon sprite data fields + +#define tDelta data[0] +#define tDeltaMod data[1] +#define tSpecies data[2] + +static u8 CreateMonSprite(struct Pokemon* mon) +{ + u16 species = GetMonData(mon, MON_DATA_SPECIES2); + u8 spriteId = CreateSprite(&gUnknown_0202499C, 48, 80, 2); + + sPokeblockFeed->species = species; + sPokeblockFeed->monSpriteId_ = spriteId; + sPokeblockFeed->nature = GetNature(mon); + gSprites[spriteId].tSpecies = species; + gSprites[spriteId].callback = SpriteCallbackDummy; + + sPokeblockFeed->noMonFlip = TRUE; + if (!IsPokeSpriteNotFlipped(species)) + { + gSprites[spriteId].affineAnims = sSpriteAffineAnimTable_MonNoFlip; + gSprites[spriteId].oam.affineMode = 3; + CalcCenterToCornerVec(&gSprites[spriteId], gSprites[spriteId].oam.shape, gSprites[spriteId].oam.size, gSprites[spriteId].oam.affineMode); + sPokeblockFeed->noMonFlip = FALSE; + } + + return spriteId; +} + +static void PrepareMonToMoveToPokeblock(u8 spriteId) +{ + gSprites[spriteId].pos1.x = 48; + gSprites[spriteId].pos1.y = 80; + gSprites[spriteId].tDelta = -8; + gSprites[spriteId].tDeltaMod = 1; + gSprites[spriteId].callback = sub_817A468; +} + +static void sub_817A468(struct Sprite* sprite) +{ + sprite->pos1.x += 4; + sprite->pos1.y += sprite->tDelta; + sprite->tDelta += sprite->tDeltaMod; + + if (sprite->tDelta == 0) + PlayCry1(sprite->tSpecies, 0); + if (sprite->tDelta == 9) + sprite->callback = SpriteCallbackDummy; +} + +#undef tDelta +#undef tDeltaMod +#undef tSpecies + +static u8 CreatePokeblockCaseSpriteForFeeding(void) +{ + u8 spriteId = CreatePokeblockCaseSprite(188, 100, 2); + gSprites[spriteId].oam.affineMode = 1; + gSprites[spriteId].affineAnims = sSpriteAffineAnimTable_85F0664; + gSprites[spriteId].callback = SpriteCallbackDummy; + InitSpriteAffineAnim(&gSprites[spriteId]); + return spriteId; +} + +static void DoPokeblockCaseThrowEffect(u8 spriteId, bool8 a1) +{ + FreeOamMatrix(gSprites[spriteId].oam.matrixNum); + gSprites[spriteId].oam.affineMode = 3; + + if (!a1) + gSprites[spriteId].affineAnims = sSpriteAffineAnimTable_85F0668; + else + gSprites[spriteId].affineAnims = sSpriteAffineAnimTable_85F066C; + + InitSpriteAffineAnim(&gSprites[spriteId]); +} + +// defines for the pokeblock sprite data fields +#define tDelta data[0] +#define tDeltaMod data[1] + +static u8 CreatePokeblockSprite(void) +{ + u8 spriteId = CreateSprite(&sThrownPokeblockSpriteTemplate, 174, 84, 1); + gSprites[spriteId].tDelta = -12; + gSprites[spriteId].tDeltaMod = 1; + return spriteId; +} + +static void SpriteCB_ThrownPokeblock(struct Sprite* sprite) +{ + sprite->pos1.x -= 4; + sprite->pos1.y += sprite->tDelta; + sprite->tDelta += sprite->tDeltaMod; + if (sprite->tDelta == 10) + DestroySprite(sprite); +} + +#undef tDelta +#undef tDeltaMod + +static void sub_817A5CC(void) +{ + u8 animId, i; + struct PokeblockFeedStruct *pokeblockFeed; + + pokeblockFeed = sPokeblockFeed; + pokeblockFeed->field_1056 = 1; + animId = sNatureToMonPokeblockAnim[pokeblockFeed->nature][0]; + for (i = 0; i < 8; i++, animId++) + { + pokeblockFeed->field_1056 += sMonPokeblockAnims[animId][4]; + if (sMonPokeblockAnims[animId][9] == 1) + break; + } +} + +static void sub_817A634(void) +{ + struct PokeblockFeedStruct *pokeblockFeed = sPokeblockFeed; + + switch (pokeblockFeed->field_1050) + { + case 0: + pokeblockFeed->animId = sNatureToMonPokeblockAnim[pokeblockFeed->nature][0]; + pokeblockFeed->monSpritePtr = &gSprites[pokeblockFeed->monSpriteId_]; + pokeblockFeed->savedMonSprite = *pokeblockFeed->monSpritePtr; + pokeblockFeed->field_1050 = 10; + break; + case 1 ... 9: + break; + case 10: + sub_817A91C(); + if (sNatureToMonPokeblockAnim[pokeblockFeed->nature][1] != 0) + { + pokeblockFeed->monSpritePtr->oam.affineMode = 3; + pokeblockFeed->monSpritePtr->oam.matrixNum = 0; + pokeblockFeed->monSpritePtr->affineAnims = sSpriteAffineAnimTable_85F04FC; + InitSpriteAffineAnim(pokeblockFeed->monSpritePtr); + } + pokeblockFeed->field_1050 = 50; + case 50: + if (sNatureToMonPokeblockAnim[pokeblockFeed->nature][1] != 0) + { + if (!pokeblockFeed->noMonFlip) // double negation, so mon's sprite is flipped + StartSpriteAffineAnim(pokeblockFeed->monSpritePtr, sNatureToMonPokeblockAnim[pokeblockFeed->nature][1] + 10); + else + StartSpriteAffineAnim(pokeblockFeed->monSpritePtr, sNatureToMonPokeblockAnim[pokeblockFeed->nature][1]); + } + pokeblockFeed->field_1050 = 60; + break; + case 60: + if (sub_817A9E4() == TRUE) + { + if (pokeblockFeed->field_1060[9] == 0) + { + pokeblockFeed->animId++; + sub_817A91C(); + pokeblockFeed->field_1050 = 60; + } + else + { + FreeOamMatrix(pokeblockFeed->monSpritePtr->oam.matrixNum); + pokeblockFeed->field_1050 = 70; + } + } + break; + case 70: + FreeMonSpriteOamMatrix(); + pokeblockFeed->animId = 0; + pokeblockFeed->field_1050 = 0; + break; + case 71 ... 90: + break; + } +} + +static bool8 sub_817A91C(void) +{ + struct PokeblockFeedStruct *pokeblockFeed = sPokeblockFeed; + u8 i; + + for (i = 0; i < 10; i++) + pokeblockFeed->field_1060[i] = sMonPokeblockAnims[pokeblockFeed->animId][i]; + + if (pokeblockFeed->field_1060[4] == 0) + { + return TRUE; + } + else + { + pokeblockFeed->field_1060[10] = Sin(pokeblockFeed->field_1060[0], pokeblockFeed->field_1060[2]); + pokeblockFeed->field_1060[11] = Cos(pokeblockFeed->field_1060[0], pokeblockFeed->field_1060[3]); + pokeblockFeed->field_1060[12] = pokeblockFeed->field_1060[4]; + pokeblockFeed->field_1060[13] = pokeblockFeed->monSpritePtr->pos2.x; + pokeblockFeed->field_1060[14] = pokeblockFeed->monSpritePtr->pos2.y; + sub_817AB68(); + pokeblockFeed->field_1060[4] = pokeblockFeed->field_1060[12]; + sub_817AA54(); + pokeblockFeed->field_1060[4] = pokeblockFeed->field_1060[12]; + return FALSE; + } +} + +static bool8 sub_817A9E4(void) +{ + u16 var = sPokeblockFeed->field_1060[12] - sPokeblockFeed->field_1060[4]; + + sPokeblockFeed->monSpritePtr->pos2.x = sPokeblockFeed->field_850[var]; + sPokeblockFeed->monSpritePtr->pos2.y = sPokeblockFeed->field_C50[var]; + + if (--sPokeblockFeed->field_1060[4] == 0) + return TRUE; + else + return FALSE; +} + +static bool8 FreeMonSpriteOamMatrix(void) +{ + FreeSpriteOamMatrix(sPokeblockFeed->monSpritePtr); + return FALSE; +} + +static void sub_817AA54(void) +{ + struct PokeblockFeedStruct *pokeblockFeed = sPokeblockFeed; + u16 i; + u16 r8 = pokeblockFeed->field_1060[8]; + u16 r7 = pokeblockFeed->field_1060[12] - r8; + s16 var3 = pokeblockFeed->field_1060[13] + pokeblockFeed->field_1060[6]; + s16 r9 = pokeblockFeed->field_1060[14] + pokeblockFeed->field_1060[7]; + + for (i = 0; i < r7 - 1; i++) + { + s16 r1 = pokeblockFeed->field_850[r8 + i] - (var3); + s16 r4 = pokeblockFeed->field_C50[r8 + i] - r9; + + pokeblockFeed->field_850[r8 + i] -= r1 * (i + 1) / r7; + pokeblockFeed->field_C50[r8 + i] -= r4 * (i + 1) / r7; + } + + pokeblockFeed->field_850[(r8 + r7) - 1] = var3; + pokeblockFeed->field_C50[(r8 + r7) - 1] = r9; +} + +static void sub_817AB68(void) +{ + struct PokeblockFeedStruct *pokeblockFeed = sPokeblockFeed; + bool8 var_24 = FALSE; + s16 r8 = pokeblockFeed->field_1060[13] - pokeblockFeed->field_1060[10]; + s16 r7 = pokeblockFeed->field_1060[14] - pokeblockFeed->field_1060[11]; + + while (1) + { + u16 r5; + u16 r4; + u16 var; + + var = abs(pokeblockFeed->field_1060[5]); + r5 = var + pokeblockFeed->field_1060[3]; + pokeblockFeed->field_1060[3] = r5; + + if (pokeblockFeed->field_1060[2] < 0) + var_24 = TRUE; + + r4 = pokeblockFeed->field_1060[12] - pokeblockFeed->field_1060[4]; + + if (pokeblockFeed->field_1060[4] == 0) + break; + + if (!var_24) + { + pokeblockFeed->field_850[r4] = Sin(pokeblockFeed->field_1060[0], pokeblockFeed->field_1060[2] + r5 / 0x100) + r8; + pokeblockFeed->field_C50[r4] = Cos(pokeblockFeed->field_1060[0], pokeblockFeed->field_1060[3] + r5 / 0x100) + r7; + } + else + { + pokeblockFeed->field_850[r4] = Sin(pokeblockFeed->field_1060[0], pokeblockFeed->field_1060[2] - r5 / 0x100) + r8; + pokeblockFeed->field_C50[r4] = Cos(pokeblockFeed->field_1060[0], pokeblockFeed->field_1060[3] - r5 / 0x100) + r7; + } + + pokeblockFeed->field_1060[0] += pokeblockFeed->field_1060[1]; + pokeblockFeed->field_1060[0] &= 0xFF; + pokeblockFeed->field_1060[4]--; + } +} diff --git a/src/pokemon_2.c b/src/pokemon_2.c index a4d00112b..db176e025 100644 --- a/src/pokemon_2.c +++ b/src/pokemon_2.c @@ -1155,7 +1155,7 @@ u8 GetMonsStateToDoubles_2(void) s32 aliveCount = 0; s32 i; - for (i = 0; i < 6; i++) + for (i = 0; i < PARTY_SIZE; i++) { u32 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2, NULL); if (species != SPECIES_EGG && species != SPECIES_NONE diff --git a/src/pokemon_3.c b/src/pokemon_3.c index a419dd46e..1a44a4410 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -11,8 +11,7 @@ #include "link.h" #include "constants/hold_effects.h" #include "random.h" -#include "trainer_classes.h" -#include "trainer_ids.h" +#include "constants/trainers.h" #include "constants/songs.h" #include "sound.h" #include "m4a.h" @@ -22,6 +21,7 @@ #include "constants/abilities.h" #include "pokemon_animation.h" #include "pokedex.h" +#include "pokeblock.h" extern struct BattlePokemon gBattleMons[4]; extern struct BattleEnigmaBerry gEnigmaBerries[4]; @@ -59,7 +59,6 @@ extern const u8 gText_PkmnsXPreventsSwitching[]; extern const struct CompressedSpritePalette gMonPaletteTable[]; extern const struct CompressedSpritePalette gMonShinyPaletteTable[]; extern const u16 gHMMoves[]; -extern const s8 gPokeblockFlavorCompatibilityTable[]; extern const u8 gMonAnimationDelayTable[]; extern const u8 gMonFrontAnimIdsTable[]; @@ -692,9 +691,9 @@ void AdjustFriendship(struct Pokemon *mon, u8 event) if ((event != 5 || !(Random() & 1)) && (event != 3 || ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) - && (gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_ELITE_FOUR - || gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_LEADER - || gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_CHAMPION)))) + && (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_ELITE_FOUR + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_LEADER + || gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_CHAMPION)))) { s8 mod = gUnknown_08329ECE[event][friendshipLevel]; if (mod > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) @@ -1146,55 +1145,57 @@ void ClearBattleMonForms(void) u16 GetBattleBGM(void) { if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON) - return 0x1E0; + return BGM_BATTLE34; if (gBattleTypeFlags & BATTLE_TYPE_REGI) - return 0x1DF; + return BGM_BATTLE36; if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) - return 0x1DC; + return BGM_BATTLE20; if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { u8 trainerClass; + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) trainerClass = GetFrontierOpponentClass(gTrainerBattleOpponent_A); else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) - trainerClass = CLASS_EXPERT; + trainerClass = TRAINER_CLASS_EXPERT; else trainerClass = gTrainers[gTrainerBattleOpponent_A].trainerClass; + switch (trainerClass) { - case CLASS_AQUA_LEADER: - case CLASS_MAGMA_LEADER: - return 0x1E3; - case CLASS_TEAM_AQUA: - case CLASS_TEAM_MAGMA: - case CLASS_AQUA_ADMIN: - case CLASS_MAGMA_ADMIN: - return 0x1DB; - case CLASS_LEADER: - return 0x1DD; - case CLASS_CHAMPION: - return 0x1DE; - case CLASS_PKMN_TRAINER_RIVAL: + case TRAINER_CLASS_AQUA_LEADER: + case TRAINER_CLASS_MAGMA_LEADER: + return BGM_BATTLE30; + case TRAINER_CLASS_TEAM_AQUA: + case TRAINER_CLASS_TEAM_MAGMA: + case TRAINER_CLASS_AQUA_ADMIN: + case TRAINER_CLASS_MAGMA_ADMIN: + return BGM_BATTLE31; + case TRAINER_CLASS_LEADER: + return BGM_BATTLE32; + case TRAINER_CLASS_CHAMPION: + return BGM_BATTLE33; + case TRAINER_CLASS_PKMN_TRAINER_3: if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) - return 0x1E1; + return BGM_BATTLE35; if (!StringCompare(gTrainers[gTrainerBattleOpponent_A].trainerName, gText_BattleWallyName)) - return 0x1DC; - return 0x1E1; - case CLASS_ELITE_FOUR: - return 0x1E2; - case CLASS_SALON_MAIDEN: - case CLASS_DOME_ACE: - case CLASS_PALACE_MAVEN: - case CLASS_ARENA_TYCOON: - case CLASS_FACTORY_HEAD: - case CLASS_PIKE_QUEEN: - case CLASS_PYRAMID_KING: - return 0x1D7; + return BGM_BATTLE20; + return BGM_BATTLE35; + case TRAINER_CLASS_ELITE_FOUR: + return BGM_BATTLE38; + case TRAINER_CLASS_SALON_MAIDEN: + case TRAINER_CLASS_DOME_ACE: + case TRAINER_CLASS_PALACE_MAVEN: + case TRAINER_CLASS_ARENA_TYCOON: + case TRAINER_CLASS_FACTORY_HEAD: + case TRAINER_CLASS_PIKE_QUEEN: + case TRAINER_CLASS_PYRAMID_KING: + return BGM_BATTLE_FRONTIER_BRAIN; default: - return 0x1DC; + return BGM_BATTLE20; } } - return 0x1DA; + return BGM_BATTLE27; } void PlayBattleBGM(void) @@ -1297,21 +1298,21 @@ bool8 IsPokeSpriteNotFlipped(u16 species) return gBaseStats[species].noFlip; } -s8 GetMonFlavorRelation(struct Pokemon *mon, u8 a2) +s8 GetMonFlavorRelation(struct Pokemon *mon, u8 flavor) { u8 nature = GetNature(mon); - return gPokeblockFlavorCompatibilityTable[nature * 5 + a2]; + return gPokeblockFlavorCompatibilityTable[nature * 5 + flavor]; } -s8 GetFlavorRelationByPersonality(u32 personality, u8 a2) +s8 GetFlavorRelationByPersonality(u32 personality, u8 flavor) { u8 nature = GetNatureFromPersonality(personality); - return gPokeblockFlavorCompatibilityTable[nature * 5 + a2]; + return gPokeblockFlavorCompatibilityTable[nature * 5 + flavor]; } bool8 IsTradedMon(struct Pokemon *mon) { - u8 otName[8]; + u8 otName[OT_NAME_LENGTH + 1]; u32 otId; GetMonData(mon, MON_DATA_OT_NAME, otName); otId = GetMonData(mon, MON_DATA_OT_ID, 0); @@ -1396,7 +1397,7 @@ static s32 GetWildMonTableIdInAlteringCave(u16 species) void SetWildMonHeldItem(void) { - if (!(gBattleTypeFlags & (BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_TRAINER | BATTLE_TYPE_PYRAMID | BATTLE_TYPE_x100000))) + if (!(gBattleTypeFlags & (BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_TRAINER | BATTLE_TYPE_PYRAMID | BATTLE_TYPE_PIKE))) { u16 rnd = Random() % 100; u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, 0); @@ -1462,12 +1463,14 @@ bool8 IsShinyOtIdPersonality(u32 otId, u32 personality) return retVal; } -const u8* GetTrainerPartnerName(void) +const u8 *GetTrainerPartnerName(void) { if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { if (gPartnerTrainerId == STEVEN_PARTNER_ID) - return gTrainers[TRAINER_ID_STEVEN].trainerName; + { + return gTrainers[TRAINER_STEVEN].trainerName; + } else { GetFrontierTrainerName(gStringVar1, gPartnerTrainerId); @@ -1682,14 +1685,14 @@ void HandleSetPokedexFlag(u16 nationalNum, u8 caseId, u32 personality) } } -const u8* GetTrainerClassNameFromId(u16 trainerId) +const u8 *GetTrainerClassNameFromId(u16 trainerId) { if (trainerId > NO_OF_TRAINERS) trainerId = 0; return gTrainerClassNames[gTrainers[trainerId].trainerClass]; } -const u8* GetTrainerNameFromId(u16 trainerId) +const u8 *GetTrainerNameFromId(u16 trainerId) { if (trainerId > NO_OF_TRAINERS) trainerId = 0; diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index b00979945..ba0c4dde7 100755 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -73,7 +73,7 @@ extern void do_scheduled_bg_tilemap_copies_to_vram(void); extern u8 sub_81221EC(); extern u8 sub_81221AC(); extern void SetVBlankHBlankCallbacksToNull(); -extern void sub_8121DA0(); +extern void ResetVramOamAndBgCntRegs(); extern void clear_scheduled_bg_copies_to_vram(); extern void remove_some_task(); extern void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable); @@ -193,7 +193,7 @@ void sub_81C4A88(); void sub_81C4280(); void sub_81C0510(u8 taskId); void sub_81C171C(u8 taskId); -void sub_8121E10(); +void ResetAllBgsCoordinates(); u8 sub_81B205C(struct Pokemon* a); void sub_81C1DA4(u16 a, s16 b); void sub_81C1EFC(u16 a, s16 b, u16 c); @@ -450,7 +450,7 @@ bool8 sub_81BFB10(void) { case 0: SetVBlankHBlankCallbacksToNull(); - sub_8121DA0(); + ResetVramOamAndBgCntRegs(); clear_scheduled_bg_copies_to_vram(); gMain.state++; break; @@ -578,7 +578,7 @@ void sub_81BFE24() SetBgTilemapBuffer(1, &gUnknown_0203CF1C->unkTilemap2); SetBgTilemapBuffer(2, &gUnknown_0203CF1C->unkTilemap1); SetBgTilemapBuffer(3, &gUnknown_0203CF1C->unkTilemap0); - sub_8121E10(); + ResetAllBgsCoordinates(); schedule_bg_copy_tilemap_to_vram(1); schedule_bg_copy_tilemap_to_vram(2); schedule_bg_copy_tilemap_to_vram(3); diff --git a/src/recorded_battle.c b/src/recorded_battle.c index 4f3fe4ab9..c88229c61 100644 --- a/src/recorded_battle.c +++ b/src/recorded_battle.c @@ -19,7 +19,7 @@ | BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_ROAMER | BATTLE_TYPE_EREADER_TRAINER \ | BATTLE_TYPE_KYOGRE_GROUDON | BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_REGI \ | BATTLE_TYPE_RECORDED | BATTLE_TYPE_x4000000 | BATTLE_TYPE_SECRET_BASE \ - | BATTLE_TYPE_GROUDON | BATTLE_TYPE_KYORGE | BATTLE_TYPE_RAYQUAZA)) + | BATTLE_TYPE_GROUDON | BATTLE_TYPE_KYOGRE | BATTLE_TYPE_RAYQUAZA)) extern u32 gBattleTypeFlags; extern u16 gTrainerBattleOpponent_A; diff --git a/src/region_map.c b/src/region_map.c index b7fc625ca..f28f07d52 100644 --- a/src/region_map.c +++ b/src/region_map.c @@ -239,9 +239,9 @@ static const u8 sRegionMapFrameTilemapLZ[] = INCBIN_U8("graphics/pokenav/map_fra static const u16 Unknown_085A1D48[] = INCBIN_U16("graphics/pokenav/fly_target_icons.gbapal"); -static const u8 gUnknown_085A1D68[] = INCBIN_U8("graphics/pokenav/fly_target_icons.4bpp.lz"); +static const u8 sUnknown_085A1D68[] = INCBIN_U8("graphics/pokenav/fly_target_icons.4bpp.lz"); -static const u8 gUnknown_085A1E3C[][3] = { +static const u8 sUnknown_085A1E3C[][3] = { {MAP_GROUP(LITTLEROOT_TOWN), MAP_NUM(LITTLEROOT_TOWN), 1}, {MAP_GROUP(OLDALE_TOWN), MAP_NUM(OLDALE_TOWN), 14}, {MAP_GROUP(DEWFORD_TOWN), MAP_NUM(DEWFORD_TOWN), 15}, @@ -326,7 +326,7 @@ static const struct SpritePalette gUnknown_085A1F10 = { Unknown_085A1D48, 2 }; -static const u16 gUnknown_085A1F18[][2] = { +static const u16 sUnknown_085A1F18[][2] = { {FLAG_UNLOCK_BATTLE_FRONTIER, MAPSEC_BATTLE_FRONTIER}, {-1, MAPSEC_NONE} }; @@ -1738,7 +1738,7 @@ static void sub_8124A70(void) { struct SpriteSheet sheet; - LZ77UnCompWram(gUnknown_085A1D68, gUnknown_0203A148->unk_88c); + LZ77UnCompWram(sUnknown_085A1D68, gUnknown_0203A148->unk_88c); sheet.data = gUnknown_0203A148->unk_88c; sheet.size = 0x1c0; sheet.tag = 2; @@ -1806,11 +1806,11 @@ static void sub_8124BE4(void) u16 mapSecId; u8 spriteId; - for (i = 0; gUnknown_085A1F18[i][1] != MAPSEC_NONE; i++) + for (i = 0; sUnknown_085A1F18[i][1] != MAPSEC_NONE; i++) { - if (FlagGet(gUnknown_085A1F18[i][0])) + if (FlagGet(sUnknown_085A1F18[i][0])) { - mapSecId = gUnknown_085A1F18[i][1]; + mapSecId = sUnknown_085A1F18[i][1]; sub_8124630(mapSecId, &x, &y, &width, &height); x = (x + MAPCURSOR_X_MIN) * 8; y = (y + MAPCURSOR_Y_MIN) * 8; @@ -1919,13 +1919,13 @@ static void sub_8124E0C(void) sub_8084CCC(FlagGet(FLAG_SYS_POKEMON_LEAGUE_FLY) && gUnknown_0203A148->regionMap.posWithinMapSec == 0 ? 0x14 : 0x0B); break; default: - if (gUnknown_085A1E3C[gUnknown_0203A148->regionMap.mapSecId][2] != 0) + if (sUnknown_085A1E3C[gUnknown_0203A148->regionMap.mapSecId][2] != 0) { - sub_8084CCC(gUnknown_085A1E3C[gUnknown_0203A148->regionMap.mapSecId][2]); + sub_8084CCC(sUnknown_085A1E3C[gUnknown_0203A148->regionMap.mapSecId][2]); } else { - warp1_set_2(gUnknown_085A1E3C[gUnknown_0203A148->regionMap.mapSecId][0], gUnknown_085A1E3C[gUnknown_0203A148->regionMap.mapSecId][1], -1); + warp1_set_2(sUnknown_085A1E3C[gUnknown_0203A148->regionMap.mapSecId][0], sUnknown_085A1E3C[gUnknown_0203A148->regionMap.mapSecId][1], -1); } break; } diff --git a/src/reshow_battle_screen.c b/src/reshow_battle_screen.c index a034ca089..3df2ff151 100644 --- a/src/reshow_battle_screen.c +++ b/src/reshow_battle_screen.c @@ -35,7 +35,7 @@ extern struct SpriteTemplate gUnknown_0202499C; extern const union AnimCmd * const * const gMonAnimationsSpriteAnimsPtrTable[]; extern void dp12_8087EA4(void); -extern void trs_config(void); +extern void sub_8035658(void); extern bool8 IsDoubleBattle(void); extern u8 GetSubstituteSpriteDefault_Y(u8 bank); extern u8 GetBankSpriteDefault_Y(u8 bank); @@ -73,7 +73,7 @@ static void CB2_ReshowBattleScreenAfterMenu(void) { case 0: dp12_8087EA4(); - trs_config(); + sub_8035658(); SetBgAttribute(1, BG_CTRL_ATTR_VISIBLE, 0); SetBgAttribute(2, BG_CTRL_ATTR_VISIBLE, 0); ShowBg(0); diff --git a/src/battle_1.c b/src/rom_8034C54.c index 5e4ef5583..4d4492524 100644 --- a/src/battle_1.c +++ b/src/rom_8034C54.c @@ -1,17 +1,5 @@ - -// Includes #include "global.h" -// Static type declarations - -// Static RAM declarations - IWRAM_DATA u32 gUnknown_03000DD4; IWRAM_DATA u32 gUnknown_03000DD8; IWRAM_DATA u32 gUnknown_03000DDC; - -// Static ROM declarations - -// .rodata - -// .text diff --git a/src/safari_zone.c b/src/safari_zone.c index 19a26dad9..ce1eb65bc 100644 --- a/src/safari_zone.c +++ b/src/safari_zone.c @@ -5,6 +5,7 @@ #include "main.h" #include "battle.h" #include "string_util.h" +#include "pokeblock.h" struct PokeblockFeeder { @@ -24,7 +25,6 @@ extern u8 EventScript_2A4B8A[]; extern u8 EventScript_2A4B6F[]; extern u8 EventScript_2A4B4C[]; extern u8 EventScript_2A4B9B[]; -extern const u8* const gPokeblockNames[]; extern void sub_80EE44C(u8, u8); extern void IncrementGameStat(u8 index); @@ -105,7 +105,7 @@ void SafariZoneRetirePrompt(void) ScriptContext1_SetupScript(EventScript_2A4B6F); } -void sub_80FC190(void) +void CB2_EndSafariBattle(void) { sSafariZoneFleedMons += gBattleResults.field_1F; if (gBattleOutcome == BATTLE_CAUGHT) diff --git a/src/save_failed_screen.c b/src/save_failed_screen.c index ef01f0293..218ef68d7 100755 --- a/src/save_failed_screen.c +++ b/src/save_failed_screen.c @@ -154,8 +154,8 @@ static const u8 sClockFrames[8][3] = { 5, 1, 0 }, }; -static const u8 gSaveFailedClockPal[] = INCBIN_U8("graphics/misc/clock_small.gbapal"); -static const u8 gSaveFailedClockGfx[] = INCBIN_U8("graphics/misc/clock_small.4bpp.lz"); +static const u8 sSaveFailedClockPal[] = INCBIN_U8("graphics/misc/clock_small.gbapal"); +static const u8 sSaveFailedClockGfx[] = INCBIN_U8("graphics/misc/clock_small.4bpp.lz"); static void CB2_SaveFailedScreen(void); static void CB2_WipeSave(void); @@ -221,7 +221,7 @@ static void CB2_SaveFailedScreen(void) LZ77UnCompVram(gBirchHelpGfx, (void *)VRAM); LZ77UnCompVram(gBirchBagTilemap, (void *)(VRAM + 0x7000)); LZ77UnCompVram(gBirchGrassTilemap, (void *)(VRAM + 0x7800)); - LZ77UnCompVram(gSaveFailedClockGfx, (void *)(VRAM + 0x10020)); + LZ77UnCompVram(sSaveFailedClockGfx, (void *)(VRAM + 0x10020)); ResetBgsAndClearDma3BusyFlags(0); InitBgsFromTemplates(0, gUnknown_085EFD88, 3); SetBgTilemapBuffer(0, (void *)&gDecompressionBuffer[0x2000]); @@ -238,7 +238,7 @@ static void CB2_SaveFailedScreen(void) ResetTasks(); ResetPaletteFade(); LoadPalette(gBirchBagGrassPal, 0, 0x40); - LoadPalette(gSaveFailedClockPal, 0x100, 0x20); + LoadPalette(sSaveFailedClockPal, 0x100, 0x20); LoadPalette(gUnknown_0850FEFC, 0xE0, 0x20); LoadPalette(gUnknown_0860F074, 0xF0, 0x20); SetWindowBorderStyle(gSaveFailedWindowIds[TEXT_WIN_ID], FALSE, 0x214, 0xE); diff --git a/src/scrcmd.c b/src/scrcmd.c index 504d001ea..0557cd95e 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -656,7 +656,7 @@ bool8 ScrCmd_fadescreenspeed(struct ScriptContext *ctx) bool8 ScrCmd_fadescreenswapbuffers(struct ScriptContext *ctx) { u8 mode = ScriptReadByte(ctx); - + switch (mode) { case 1: @@ -1445,7 +1445,7 @@ bool8 ScrCmd_drawboxtext(struct ScriptContext *ctx) u8 top = ScriptReadByte(ctx); u8 multichoiceId = ScriptReadByte(ctx); u8 ignoreBPress = ScriptReadByte(ctx); - + /*if (Multichoice(left, top, multichoiceId, ignoreBPress) == TRUE) { ScriptContext1_Stop(); @@ -1501,31 +1501,31 @@ bool8 ScrCmd_braillemessage(struct ScriptContext *ctx) u8 y; StringExpandPlaceholders(gStringVar4, ptr + 6); - + width = GetStringWidth(6, gStringVar4, -1) / 8; - + if (width > 0x1C) width = 0x1C; - + for (i = 0, height = 4; gStringVar4[i] != 0xFF;) { if (gStringVar4[i++] == 0xFE) height += 3; } - + if (height > 0x12) height = 0x12; - + x = width + 2; temp1 = (0x1E - x) / 2; x = temp1 + 1; temp1 = ((x - temp1 - 1) * 8 + 3); - + y = height + 2; temp2 = (0x14 - y) / 2; y = temp2 + 2; temp2 = ((y - temp2 - 1) * 8); - + sub_8198A50(&template1, 0, x, y, width, height, 0xF, 0x1); template2 = template1; gUnknown_03000F30 = AddWindow(&template2); @@ -1924,7 +1924,7 @@ bool8 ScrCmd_hidemoneybox(struct ScriptContext *ctx) { /*u8 x = ScriptReadByte(ctx); u8 y = ScriptReadByte(ctx);*/ - + HideMoneyBox(); return FALSE; } @@ -1979,13 +1979,13 @@ bool8 ScrCmd_dotrainerbattle(struct ScriptContext *ctx) return TRUE; } -bool8 ScrCmd_ontrainerbattleend(struct ScriptContext *ctx) +bool8 ScrCmd_gotopostbattlescript(struct ScriptContext *ctx) { ctx->scriptPtr = BattleSetup_GetScriptAddrAfterBattle(); return FALSE; } -bool8 ScrCmd_ontrainerbattleendgoto(struct ScriptContext *ctx) +bool8 ScrCmd_gotobeatenscript(struct ScriptContext *ctx) { ctx->scriptPtr = BattleSetup_GetTrainerPostBattleScript(); return FALSE; @@ -1995,7 +1995,7 @@ bool8 ScrCmd_checktrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); - ctx->comparisonResult = HasTrainerAlreadyBeenFought(index); + ctx->comparisonResult = HasTrainerBeenFought(index); return FALSE; } @@ -2003,7 +2003,7 @@ bool8 ScrCmd_settrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); - trainer_flag_set(index); + SetTrainerFlag(index); return FALSE; } @@ -2011,7 +2011,7 @@ bool8 ScrCmd_cleartrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); - trainer_flag_clear(index); + ClearTrainerFlag(index); return FALSE; } @@ -2089,7 +2089,7 @@ bool8 ScrCmd_getpricereduction(struct ScriptContext *ctx) return FALSE; } -bool8 ScrCmd_choosecontestpkmn(struct ScriptContext *ctx) +bool8 ScrCmd_choosecontestmon(struct ScriptContext *ctx) { sub_81B9404(); ScriptContext1_Stop(); @@ -2332,7 +2332,7 @@ bool8 ScrCmd_mossdeepgym4(struct ScriptContext *ctx) bool8 ScrCmd_cmdD8(struct ScriptContext *ctx) { - gSelectedMapObject = sub_80B47BC(); + gSelectedMapObject = GetCurrentApproachingTrainerMapObjectId(); return FALSE; } @@ -2374,7 +2374,7 @@ bool8 ScrCmd_checkmonobedience(struct ScriptContext *ctx) bool8 ScrCmd_cmdCF(struct ScriptContext *ctx) { const u8* v1 = sub_8099244(); - + if (v1) { ((u8*)gUnknown_020375C0) = ctx->scriptPtr; diff --git a/src/secret_base.c b/src/secret_base.c index 6d66e6576..bf6bec1f8 100644 --- a/src/secret_base.c +++ b/src/secret_base.c @@ -1082,13 +1082,13 @@ void game_continue(u8 taskId) if (sub_80E9878(i)) { sub_80E9780(gUnknown_0203A020->names[count], i); - gUnknown_0203A020->items[count].unk_00 = gUnknown_0203A020->names[count]; - gUnknown_0203A020->items[count].unk_04 = i; + gUnknown_0203A020->items[count].name = gUnknown_0203A020->names[count]; + gUnknown_0203A020->items[count].id = i; count ++; } } - gUnknown_0203A020->items[count].unk_00 = gText_Cancel; - gUnknown_0203A020->items[count].unk_04 = -2; + gUnknown_0203A020->items[count].name = gText_Cancel; + gUnknown_0203A020->items[count].id = -2; data[0] = count + 1; if (data[0] < 8) { @@ -1098,11 +1098,11 @@ void game_continue(u8 taskId) { data[3] = 8; } - gUnknown_03006310 = gUnknown_0858D07C; - gUnknown_03006310.unk_10 = data[6]; - gUnknown_03006310.totalItems = data[0]; - gUnknown_03006310.items = gUnknown_0203A020->items; - gUnknown_03006310.maxShowed = data[3]; + gMultiuseListMenuTemplate = gUnknown_0858D07C; + gMultiuseListMenuTemplate.unk_10 = data[6]; + gMultiuseListMenuTemplate.totalItems = data[0]; + gMultiuseListMenuTemplate.items = gUnknown_0203A020->items; + gMultiuseListMenuTemplate.maxShowed = data[3]; } void sub_80E9DEC(u32 a0, bool8 flag, struct ListMenu *menu) @@ -1119,7 +1119,7 @@ void sub_80E9E00(u8 taskId) data = gTasks[taskId].data; SetStandardWindowBorderStyle(data[6], 0); - data[5] = ListMenuInit(&gUnknown_03006310, data[2], data[1]); + data[5] = ListMenuInit(&gMultiuseListMenuTemplate, data[2], data[1]); sub_80E9E44(taskId); schedule_bg_copy_tilemap_to_vram(0); } @@ -1138,8 +1138,8 @@ void sub_80E9E90(u8 taskId) s32 input; data = gTasks[taskId].data; - input = ListMenuHandleInput(data[5]); - get_coro_args_x18_x1A(data[5], &data[2], &data[1]); + input = ListMenuHandleInputGetItemId(data[5]); + sub_81AE860(data[5], &data[2], &data[1]); switch (input) { case -1: @@ -1283,7 +1283,7 @@ u8 sub_80EA20C(u8 secretBaseRecordId) return (gSaveBlock1Ptr->secretBases[secretBaseRecordId].trainerId[0] % 5) + (gSaveBlock1Ptr->secretBases[secretBaseRecordId].gender * 5); } -const u8 *sub_80EA250(void) +const u8 *GetSecretBaseTrainerLoseText(void) { u8 param; diff --git a/src/sprite.c b/src/sprite.c index 9db61d2e9..6d76b9854 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -240,7 +240,7 @@ static const AffineAnimCmdFunc sAffineAnimCmdFuncs[] = AffineAnimCmd_frame, }; -static const s32 gUnknown_082EC6F4[24] = +static const s32 sUnknown_082EC6F4[24] = { 8, 8, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x10, 8, 0x20, 8, @@ -1214,14 +1214,14 @@ void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2) u8 matrixNum = sprite->oam.matrixNum; if (a1 != 0x800) { - var0 = gUnknown_082EC6F4[sprite->oam.size * 8 + sprite->oam.shape * 32]; + var0 = sUnknown_082EC6F4[sprite->oam.size * 8 + sprite->oam.shape * 32]; var1 = var0 << 8; var2 = (var0 << 16) / gOamMatrices[matrixNum].a; sprite->pos2.x = sub_8007E28(var1, var2, a1); } if (a2 != 0x800) { - var0 = gUnknown_082EC6F4[4 + (sprite->oam.size * 8 + sprite->oam.shape * 32)]; + var0 = sUnknown_082EC6F4[4 + (sprite->oam.size * 8 + sprite->oam.shape * 32)]; var1 = var0 << 8; var2 = (var0 << 16) / gOamMatrices[matrixNum].d; sprite->pos2.y = sub_8007E28(var1, var2, a2); @@ -1247,7 +1247,7 @@ void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2) mov r9, r0\n\ cmp r6, r9\n\ beq _08007EA2\n\ - ldr r2, =gUnknown_082EC6F4\n\ + ldr r2, =sUnknown_082EC6F4\n\ lsrs r1, 6\n\ lsls r1, 3\n\ ldrb r0, [r5, 0x1]\n\ @@ -1272,7 +1272,7 @@ void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2) _08007EA2:\n\ cmp r8, r9\n\ beq _08007EDA\n\ - ldr r2, =gUnknown_082EC6F4\n\ + ldr r2, =sUnknown_082EC6F4\n\ ldrb r1, [r5, 0x3]\n\ lsrs r1, 6\n\ lsls r1, 3\n\ diff --git a/src/starter_choose.c b/src/starter_choose.c index 82f8f75f6..2d78af8fb 100644 --- a/src/starter_choose.c +++ b/src/starter_choose.c @@ -265,7 +265,7 @@ static void Task_StarterChoose5(u8 taskId) { u8 spriteId; - switch (sub_8198C58()) + switch (ProcessMenuInputNoWrap_()) { case 0: // YES // Return the starter choice and exit. diff --git a/src/trainer_see.c b/src/trainer_see.c new file mode 100644 index 000000000..53bc5cbbb --- /dev/null +++ b/src/trainer_see.c @@ -0,0 +1,781 @@ +#include "global.h" +#include "trainer_see.h" +#include "battle_setup.h" +#include "pokemon.h" +#include "sprite.h" +#include "field_effect.h" +#include "field_map_obj.h" +#include "field_player_avatar.h" +#include "map_obj_8097404.h" +#include "pokenav.h" +#include "task.h" +#include "util.h" +#include "script.h" +#include "event_data.h" +#include "script_movement.h" + +extern bool8 InBattlePyramid(void); +extern bool32 InTrainerHill(void); +extern bool8 GetBattlePyramidTrainerFlag(u8 mapObjectId); +extern bool8 GetTrainerHillTrainerFlag(u8 mapObjectId); +extern void sub_809BE48(u16 npcId); + +// this file's functions +static u8 CheckTrainer(u8 mapObjectId); +static u8 GetTrainerApproachDistance(struct MapObject *trainerObj); +static u8 CheckPathBetweenTrainerAndPlayer(struct MapObject *trainerObj, u8 approachDistance, u8 direction); +static void TrainerApproachPlayer(struct MapObject *trainerObj, u8 range); +static void Task_RunTrainerSeeFuncList(u8 taskId); +static void Task_DestroyTrainerApproachTask(u8 taskId); +static void SetIconSpriteData(struct Sprite *sprite, u16 fldEffId, u8 spriteAnimNum); + +static u8 GetTrainerApproachDistanceSouth(struct MapObject *trainerObj, s16 range, s16 x, s16 y); +static u8 GetTrainerApproachDistanceNorth(struct MapObject *trainerObj, s16 range, s16 x, s16 y); +static u8 GetTrainerApproachDistanceWest(struct MapObject *trainerObj, s16 range, s16 x, s16 y); +static u8 GetTrainerApproachDistanceEast(struct MapObject *trainerObj, s16 range, s16 x, s16 y); + +static bool8 sub_80B4178(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B417C(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B41C0(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B4200(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B425C(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B4318(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B435C(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B4390(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B43AC(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B43E0(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B4438(u8 taskId, struct Task *task, struct MapObject *trainerObj); +static bool8 sub_80B44AC(u8 taskId, struct Task *task, struct MapObject *trainerObj); + +static void SpriteCB_TrainerIcons(struct Sprite *sprite); + +// IWRAM common +u16 gUnknown_03006080; +u8 gUnknown_03006084[4]; +struct ApproachingTrainer gApproachingTrainers[2]; +u8 gNoOfApproachingTrainers; +u8 gUnknown_030060AC; + +// EWRAM +EWRAM_DATA u8 gApproachingTrainerId = 0; + +// const rom data +static const u8 sEmotion_ExclamationMarkGfx[] = INCBIN_U8("graphics/misc/emotion_exclamation.4bpp"); +static const u8 sEmotion_QuestionMarkGfx[] = INCBIN_U8("graphics/misc/emotion_question.4bpp"); +static const u8 sEmotion_HeartGfx[] = INCBIN_U8("graphics/misc/emotion_heart.4bpp"); + +static u8 (*const sDirectionalApproachDistanceFuncs[])(struct MapObject *trainerObj, s16 range, s16 x, s16 y) = +{ + GetTrainerApproachDistanceSouth, + GetTrainerApproachDistanceNorth, + GetTrainerApproachDistanceWest, + GetTrainerApproachDistanceEast, +}; + +static bool8 (*const sTrainerSeeFuncList[])(u8 taskId, struct Task *task, struct MapObject *trainerObj) = +{ + sub_80B4178, + sub_80B417C, + sub_80B41C0, + sub_80B4200, + sub_80B425C, + sub_80B4318, + sub_80B435C, + sub_80B4390, + sub_80B43AC, + sub_80B43E0, + sub_80B4438, + sub_80B44AC +}; + +static bool8 (*const sTrainerSeeFuncList2[])(u8 taskId, struct Task *task, struct MapObject *trainerObj) = +{ + sub_80B43AC, + sub_80B43E0, + sub_80B4438, + sub_80B44AC, +}; + +static const struct OamData sOamData_Icons = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 0, + .x = 0, + .matrixNum = 0, + .size = 1, + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, +}; + +static const struct SpriteFrameImage sSpriteImageTable_ExclamationQuestionMark[] = +{ + {sEmotion_ExclamationMarkGfx, 0x80}, + {sEmotion_QuestionMarkGfx, 0x80} +}; + +static const struct SpriteFrameImage sSpriteImageTable_HeartIcon[] = +{ + {sEmotion_HeartGfx, 0x80} +}; + +static const union AnimCmd sSpriteAnim_Icons1[] = +{ + ANIMCMD_FRAME(0, 60), + ANIMCMD_END +}; + +static const union AnimCmd sSpriteAnim_Icons2[] = +{ + ANIMCMD_FRAME(1, 60), + ANIMCMD_END +}; + +static const union AnimCmd *const sSpriteAnimTable_Icons[] = +{ + sSpriteAnim_Icons1, + sSpriteAnim_Icons2 +}; + +static const struct SpriteTemplate sSpriteTemplate_ExclamationQuestionMark = +{ + .tileTag = 0xffff, + .paletteTag = 0xffff, + .oam = &sOamData_Icons, + .anims = sSpriteAnimTable_Icons, + .images = sSpriteImageTable_ExclamationQuestionMark, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_TrainerIcons +}; + +static const struct SpriteTemplate sSpriteTemplate_HeartIcon = +{ + .tileTag = 0xffff, + .paletteTag = 0x1004, + .oam = &sOamData_Icons, + .anims = sSpriteAnimTable_Icons, + .images = sSpriteImageTable_HeartIcon, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_TrainerIcons +}; + +// code +bool8 CheckForTrainersWantingBattle(void) +{ + u8 i; + + gNoOfApproachingTrainers = 0; + gApproachingTrainerId = 0; + + for (i = 0; i < MAP_OBJECTS_COUNT; i++) + { + u8 retVal; + + if (!gMapObjects[i].active) + continue; + if (gMapObjects[i].trainerType != 1 && gMapObjects[i].trainerType != 3) + continue; + + retVal = CheckTrainer(i); + if (retVal == 2) + break; // two trainers have been found + + if (retVal == 0) // no trainers + continue; + + if (gNoOfApproachingTrainers > 1) + break; + if (GetMonsStateToDoubles_2() != 0) // one trainer found and cant have a double battle + break; + } + + if (gNoOfApproachingTrainers == 1) + { + ResetTrainerOpponentIds(); + ConfigureAndSetUpOneTrainerBattle(gApproachingTrainers[gNoOfApproachingTrainers - 1].mapObjectId, + gApproachingTrainers[gNoOfApproachingTrainers - 1].trainerScriptPtr); + gUnknown_030060AC = 1; + return TRUE; + } + else if (gNoOfApproachingTrainers == 2) + { + ResetTrainerOpponentIds(); + for (i = 0; i < gNoOfApproachingTrainers; i++, gApproachingTrainerId++) + { + ConfigureTwoTrainersBattle(gApproachingTrainers[i].mapObjectId, + gApproachingTrainers[i].trainerScriptPtr); + } + SetUpTwoTrainersBattle(); + gApproachingTrainerId = 0; + gUnknown_030060AC = 1; + return TRUE; + } + else + { + gUnknown_030060AC = 0; + return FALSE; + } +} + +static u8 CheckTrainer(u8 mapObjectId) +{ + const u8 *scriptPtr; + u8 ret = 1; + u8 approachDistance; + + if (InTrainerHill() == TRUE) + scriptPtr = sub_81D62AC(); + else + scriptPtr = GetFieldObjectScriptPointerByFieldObjectId(mapObjectId); + + if (InBattlePyramid()) + { + if (GetBattlePyramidTrainerFlag(mapObjectId)) + return 0; + } + else if (InTrainerHill() == TRUE) + { + if (GetTrainerHillTrainerFlag(mapObjectId)) + return 0; + } + else + { + if (GetTrainerFlagFromScriptPointer(scriptPtr)) + return 0; + } + + approachDistance = GetTrainerApproachDistance(&gMapObjects[mapObjectId]); + + if (approachDistance != 0) + { + if (scriptPtr[1] == TRAINER_BATTLE_DOUBLE + || scriptPtr[1] == TRAINER_BATTLE_REMATCH_DOUBLE + || scriptPtr[1] == TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE) + { + if (GetMonsStateToDoubles_2() != 0) + return 0; + + ret = 2; + } + + gApproachingTrainers[gNoOfApproachingTrainers].mapObjectId = mapObjectId; + gApproachingTrainers[gNoOfApproachingTrainers].trainerScriptPtr = scriptPtr; + gApproachingTrainers[gNoOfApproachingTrainers].radius = approachDistance; + TrainerApproachPlayer(&gMapObjects[mapObjectId], approachDistance - 1); + gNoOfApproachingTrainers++; + + return ret; + } + + return 0; +} + +static u8 GetTrainerApproachDistance(struct MapObject *trainerObj) +{ + s16 x, y; + u8 i; + u8 approachDistance; + + PlayerGetDestCoords(&x, &y); + if (trainerObj->trainerType == 1) // can only see in one direction + { + approachDistance = sDirectionalApproachDistanceFuncs[trainerObj->mapobj_unk_18 - 1](trainerObj, trainerObj->trainerRange_berryTreeId, x, y); + return CheckPathBetweenTrainerAndPlayer(trainerObj, approachDistance, trainerObj->mapobj_unk_18); + } + else // can see in all directions + { + for (i = 0; i < 4; i++) + { + approachDistance = sDirectionalApproachDistanceFuncs[i](trainerObj, trainerObj->trainerRange_berryTreeId, x, y); + if (CheckPathBetweenTrainerAndPlayer(trainerObj, approachDistance, i + 1)) // directions are 1-4 instead of 0-3. south north west east + return approachDistance; + } + } + + return 0; +} + +// Returns how far south the player is from trainer. 0 if out of trainer's sight. +static u8 GetTrainerApproachDistanceSouth(struct MapObject *trainerObj, s16 range, s16 x, s16 y) +{ + if (trainerObj->coords2.x == x + && y > trainerObj->coords2.y + && y <= trainerObj->coords2.y + range) + return (y - trainerObj->coords2.y); + else + return 0; +} + +// Returns how far north the player is from trainer. 0 if out of trainer's sight. +static u8 GetTrainerApproachDistanceNorth(struct MapObject *trainerObj, s16 range, s16 x, s16 y) +{ + if (trainerObj->coords2.x == x + && y < trainerObj->coords2.y + && y >= trainerObj->coords2.y - range) + return (trainerObj->coords2.y - y); + else + return 0; +} + +// Returns how far west the player is from trainer. 0 if out of trainer's sight. +static u8 GetTrainerApproachDistanceWest(struct MapObject *trainerObj, s16 range, s16 x, s16 y) +{ + if (trainerObj->coords2.y == y + && x < trainerObj->coords2.x + && x >= trainerObj->coords2.x - range) + return (trainerObj->coords2.x - x); + else + return 0; +} + +// Returns how far east the player is from trainer. 0 if out of trainer's sight. +static u8 GetTrainerApproachDistanceEast(struct MapObject *trainerObj, s16 range, s16 x, s16 y) +{ + if (trainerObj->coords2.y == y + && x > trainerObj->coords2.x + && x <= trainerObj->coords2.x + range) + return (x - trainerObj->coords2.x); + else + return 0; +} + +#define COLLISION_MASK (~1) + +static u8 CheckPathBetweenTrainerAndPlayer(struct MapObject *trainerObj, u8 approachDistance, u8 direction) +{ + s16 x, y; + u8 unk19_temp; + u8 unk19b_temp; + u8 i; + u8 collision; + + if (approachDistance == 0) + return 0; + + x = trainerObj->coords2.x; + y = trainerObj->coords2.y; + + MoveCoords(direction, &x, &y); + for (i = 0; i < approachDistance - 1; i++, MoveCoords(direction, &x, &y)) + { + collision = sub_8092C8C(trainerObj, x, y, direction); + if (collision != 0 && (collision & COLLISION_MASK)) + return 0; + } + + // preserve mapobj_unk_19 before clearing. + unk19_temp = trainerObj->range.as_nybbles.x; + unk19b_temp = trainerObj->range.as_nybbles.y; + trainerObj->range.as_nybbles.x = 0; + trainerObj->range.as_nybbles.y = 0; + + collision = npc_block_way(trainerObj, x, y, direction); + + trainerObj->range.as_nybbles.x = unk19_temp; + trainerObj->range.as_nybbles.y = unk19b_temp; + if (collision == 4) + return approachDistance; + + return 0; +} + +#define tFuncId data[0] +#define tTrainerRange data[3] +#define tOutOfAshSpriteId data[4] +#define tTrainerMapObjectId data[7] + +static void TrainerApproachPlayer(struct MapObject *trainerObj, u8 range) +{ + struct Task *task; + + gApproachingTrainers[gNoOfApproachingTrainers].taskId = CreateTask(Task_RunTrainerSeeFuncList, 0x50); + task = &gTasks[gApproachingTrainers[gNoOfApproachingTrainers].taskId]; + task->tTrainerRange = range; + task->tTrainerMapObjectId = gApproachingTrainers[gNoOfApproachingTrainers].mapObjectId; +} + +static void sub_80B40C8(TaskFunc followupFunc) +{ + u8 taskId; + TaskFunc taskFunc; + + if (gApproachingTrainerId == 0) + taskId = gApproachingTrainers[0].taskId; + else + taskId = gApproachingTrainers[1].taskId; + + taskFunc = Task_RunTrainerSeeFuncList; + SetTaskFuncWithFollowupFunc(taskId, taskFunc, followupFunc); + gTasks[taskId].tFuncId = 1; + taskFunc(taskId); +} + +static void Task_RunTrainerSeeFuncList(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + struct MapObject *trainerObj = &gMapObjects[task->tTrainerMapObjectId]; + + if (!trainerObj->active) + { + SwitchTaskToFollowupFunc(taskId); + } + else + { + while (sTrainerSeeFuncList[task->tFuncId](taskId, task, trainerObj)); + } +} + +static bool8 sub_80B4178(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + return FALSE; +} + +static bool8 sub_80B417C(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + u8 direction; + + FieldObjectGetLocalIdAndMap(trainerObj, &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]); + FieldEffectStart(FLDEFF_EXCLAMATION_MARK_ICON_1); + direction = GetFaceDirectionAnimId(trainerObj->mapobj_unk_18); + FieldObjectSetSpecialAnim(trainerObj, direction); + task->tFuncId++; + return TRUE; +} + +static bool8 sub_80B41C0(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + if (FieldEffectActiveListContains(FLDEFF_EXCLAMATION_MARK_ICON_1)) + { + return FALSE; + } + else + { + task->tFuncId++; + if (trainerObj->animPattern == 57 || trainerObj->animPattern == 58) + task->tFuncId = 6; + if (trainerObj->animPattern == 63) + task->tFuncId = 8; + return TRUE; + } +} + +static bool8 sub_80B4200(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + if (!(FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(trainerObj)) || FieldObjectClearAnimIfSpecialAnimFinished(trainerObj)) + { + if (task->tTrainerRange) + { + FieldObjectSetSpecialAnim(trainerObj, GetGoSpeed0AnimId(trainerObj->mapobj_unk_18)); + task->tTrainerRange--; + } + else + { + FieldObjectSetSpecialAnim(trainerObj, 0x3E); + task->tFuncId++; + } + } + return FALSE; +} + +static bool8 sub_80B425C(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + struct MapObject *playerObj; + + if (FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(trainerObj) && !FieldObjectClearAnimIfSpecialAnimFinished(trainerObj)) + return FALSE; + + npc_set_running_behaviour_etc(trainerObj, npc_running_behaviour_by_direction(trainerObj->mapobj_unk_18)); + sub_808F23C(trainerObj, npc_running_behaviour_by_direction(trainerObj->mapobj_unk_18)); + sub_808F208(trainerObj); + + playerObj = &gMapObjects[gPlayerAvatar.mapObjectId]; + if (FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(playerObj) && !FieldObjectClearAnimIfSpecialAnimFinished(playerObj)) + return FALSE; + + sub_808BCE8(); + FieldObjectSetSpecialAnim(&gMapObjects[gPlayerAvatar.mapObjectId], GetFaceDirectionAnimId(GetOppositeDirection(trainerObj->mapobj_unk_18))); + task->tFuncId++; + return FALSE; +} + +static bool8 sub_80B4318(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + struct MapObject *playerObj = &gMapObjects[gPlayerAvatar.mapObjectId]; + + if (!FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(playerObj) + || FieldObjectClearAnimIfSpecialAnimFinished(playerObj)) + SwitchTaskToFollowupFunc(taskId); + return FALSE; +} + +static bool8 sub_80B435C(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + if (!FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(trainerObj) + || FieldObjectClearAnimIfSpecialAnimFinished(trainerObj)) + { + FieldObjectSetSpecialAnim(trainerObj, 0x59); + task->tFuncId++; + } + return FALSE; +} + +static bool8 sub_80B4390(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + if (FieldObjectClearAnimIfSpecialAnimFinished(trainerObj)) + task->tFuncId = 3; + + return FALSE; +} + +static bool8 sub_80B43AC(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + if (!FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(trainerObj) + || FieldObjectClearAnimIfSpecialAnimFinished(trainerObj)) + { + FieldObjectSetSpecialAnim(trainerObj, 0x3E); + task->tFuncId++; + } + return FALSE; +} + +static bool8 sub_80B43E0(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + if (FieldObjectCheckIfSpecialAnimFinishedOrInactive(trainerObj)) + { + gFieldEffectArguments[0] = trainerObj->coords2.x; + gFieldEffectArguments[1] = trainerObj->coords2.y; + gFieldEffectArguments[2] = gSprites[trainerObj->spriteId].subpriority - 1; + gFieldEffectArguments[3] = 2; + task->tOutOfAshSpriteId = FieldEffectStart(FLDEFF_POP_OUT_OF_ASH); + task->tFuncId++; + } + return FALSE; +} + +static bool8 sub_80B4438(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + struct Sprite *sprite; + + if (gSprites[task->tOutOfAshSpriteId].animCmdIndex == 2) + { + trainerObj->mapobj_bit_26 = 0; + trainerObj->mapobj_bit_2 = 1; + + sprite = &gSprites[trainerObj->spriteId]; + sprite->oam.priority = 2; + FieldObjectClearAnimIfSpecialAnimFinished(trainerObj); + FieldObjectSetSpecialAnim(trainerObj, sub_80934BC(trainerObj->mapobj_unk_18)); + task->tFuncId++; + } + + return FALSE; +} + +static bool8 sub_80B44AC(u8 taskId, struct Task *task, struct MapObject *trainerObj) +{ + if (!FieldEffectActiveListContains(FLDEFF_POP_OUT_OF_ASH)) + task->tFuncId = 3; + + return FALSE; +} + +#undef tFuncId +#undef tTrainerRange +#undef tOutOfAshSpriteId +#undef tTrainerMapObjectId + +static void sub_80B44C8(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + struct MapObject *mapObj; + + // another mapObj loaded into by loadword? + LoadWordFromTwoHalfwords(&task->data[1], (u32 *)&mapObj); + if (!task->data[7]) + { + FieldObjectClearAnim(mapObj); + task->data[7]++; + } + sTrainerSeeFuncList2[task->data[0]](taskId, task, mapObj); + if (task->data[0] == 3 && !FieldEffectActiveListContains(FLDEFF_POP_OUT_OF_ASH)) + { + npc_set_running_behaviour_etc(mapObj, npc_running_behaviour_by_direction(mapObj->mapobj_unk_18)); + sub_808F23C(mapObj, npc_running_behaviour_by_direction(mapObj->mapobj_unk_18)); + DestroyTask(taskId); + } + else + { + mapObj->mapobj_bit_7 = 0; + } +} + +void sub_80B4578(struct MapObject *var) +{ + StoreWordInTwoHalfwords(&gTasks[CreateTask(sub_80B44C8, 0)].data[1], (u32)var); +} + +void EndTrainerApproach(void) +{ + sub_80B40C8(Task_DestroyTrainerApproachTask); +} + +static void Task_DestroyTrainerApproachTask(u8 taskId) +{ + DestroyTask(taskId); + EnableBothScriptContexts(); +} + +void sub_80B45D0(void) +{ + if (gNoOfApproachingTrainers == 2) + { + if (gApproachingTrainerId == 0) + { + gApproachingTrainerId++; + gSpecialVar_Result = 1; + UnfreezeMapObjects(); + sub_80974D0(gApproachingTrainers[1].mapObjectId); + } + else + { + gApproachingTrainerId = 0; + gSpecialVar_Result = 0; + } + } + else + { + gSpecialVar_Result = 0; + } +} + +#define sLocalId data[0] +#define sMapNum data[1] +#define sMapGroup data[2] +#define sData3 data[3] +#define sData4 data[4] +#define sFldEffId data[7] + +u8 FldEff_ExclamationMarkIcon1(void) +{ + u8 spriteId = CreateSpriteAtEnd(&sSpriteTemplate_ExclamationQuestionMark, 0, 0, 0x53); + + if (spriteId != MAX_SPRITES) + SetIconSpriteData(&gSprites[spriteId], FLDEFF_EXCLAMATION_MARK_ICON_1, 0); + + return 0; +} + +u8 FldEff_ExclamationMarkIcon2(void) +{ + u8 spriteId = CreateSpriteAtEnd(&sSpriteTemplate_ExclamationQuestionMark, 0, 0, 0x52); + + if (spriteId != MAX_SPRITES) + SetIconSpriteData(&gSprites[spriteId], FLDEFF_EXCLAMATION_MARK_ICON_2, 1); + + return 0; +} + +u8 FldEff_HeartIcon(void) +{ + u8 spriteId = CreateSpriteAtEnd(&sSpriteTemplate_HeartIcon, 0, 0, 0x52); + + if (spriteId != MAX_SPRITES) + { + struct Sprite *sprite = &gSprites[spriteId]; + + SetIconSpriteData(sprite, FLDEFF_HEART_ICON, 0); + sprite->oam.paletteNum = 2; + } + + return 0; +} + +static void SetIconSpriteData(struct Sprite *sprite, u16 fldEffId, u8 spriteAnimNum) +{ + sprite->oam.priority = 1; + sprite->coordOffsetEnabled = 1; + + sprite->sLocalId = gFieldEffectArguments[0]; + sprite->sMapNum = gFieldEffectArguments[1]; + sprite->sMapGroup = gFieldEffectArguments[2]; + sprite->sData3 = -5; + sprite->sFldEffId = fldEffId; + + StartSpriteAnim(sprite, spriteAnimNum); +} + +static void SpriteCB_TrainerIcons(struct Sprite *sprite) +{ + u8 mapObjId; + + if (TryGetFieldObjectIdByLocalIdAndMap(sprite->sLocalId, sprite->sMapNum, sprite->sMapGroup, &mapObjId) + || sprite->animEnded) + { + FieldEffectStop(sprite, sprite->sFldEffId); + } + else + { + struct Sprite *mapObjSprite = &gSprites[gMapObjects[mapObjId].spriteId]; + sprite->sData4 += sprite->sData3; + sprite->pos1.x = mapObjSprite->pos1.x; + sprite->pos1.y = mapObjSprite->pos1.y - 16; + sprite->pos2.x = mapObjSprite->pos2.x; + sprite->pos2.y = mapObjSprite->pos2.y + sprite->sData4; + if (sprite->sData4) + sprite->sData3++; + else + sprite->sData3 = 0; + } +} + +#undef sLocalId +#undef sMapNum +#undef sMapGroup +#undef sData3 +#undef sData4 +#undef sFldEffId + +u8 GetCurrentApproachingTrainerMapObjectId(void) +{ + if (gApproachingTrainerId == 0) + return gApproachingTrainers[0].mapObjectId; + else + return gApproachingTrainers[1].mapObjectId; +} + +u8 GetChosenApproachingTrainerMapObjectId(u8 arrayId) +{ + if (arrayId >= ARRAY_COUNT(gApproachingTrainers)) + return 0; + else if (arrayId == 0) + return gApproachingTrainers[0].mapObjectId; + else + return gApproachingTrainers[1].mapObjectId; +} + +void sub_80B4808(void) +{ + struct MapObject *trainerObj; + + if (gUnknown_030060AC == 1) + { + trainerObj = &gMapObjects[gApproachingTrainers[gUnknown_03006080].mapObjectId]; + gUnknown_03006084[0] = GetFaceDirectionAnimId(GetOppositeDirection(trainerObj->mapobj_unk_18)); + gUnknown_03006084[1] = 0xFE; + ScriptMovement_StartObjectMovementScript(0xFF, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, gUnknown_03006084); + } + else + { + trainerObj = &gMapObjects[gPlayerAvatar.mapObjectId]; + gUnknown_03006084[0] = GetFaceDirectionAnimId(trainerObj->mapobj_unk_18); + gUnknown_03006084[1] = 0xFE; + ScriptMovement_StartObjectMovementScript(0xFF, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, gUnknown_03006084); + } + + sub_809BE48(0xFF); +} @@ -1793,7 +1793,7 @@ void EndMassOutbreak(void) gSaveBlock1Ptr->outbreakDaysLeft = 0; } -void sub_80ED888(u16 days) +void UpdateTVShowsPerDay(u16 days) { sub_80ED8B4(days); diff --git a/src/unk_text_util_2.c b/src/unk_text_util_2.c index d88af611f..8eaab32b6 100644 --- a/src/unk_text_util_2.c +++ b/src/unk_text_util_2.c @@ -4,8 +4,8 @@ #include "text.h" #include "sound.h" -static const u8 gUnknown_08616124[] = {1, 2, 4}; -static const u16 gFont6BrailleGlyphs[] = INCBIN_U16("data/graphics/fonts/font6.fwjpnfont"); +static const u8 sUnknown_08616124[] = {1, 2, 4}; +static const u16 sFont6BrailleGlyphs[] = INCBIN_U16("data/graphics/fonts/font6.fwjpnfont"); static void DecompressGlyphFont6(u16); @@ -13,7 +13,7 @@ u16 Font6Func(struct TextPrinter *textPrinter) { u16 char_; struct TextPrinterSubStruct *sub; - + sub = &textPrinter->sub_union.sub; switch (textPrinter->state) { @@ -163,15 +163,15 @@ u16 Font6Func(struct TextPrinter *textPrinter) case 4: if (textPrinter->scrollDistance) { - if (textPrinter->scrollDistance < gUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed]) + if (textPrinter->scrollDistance < sUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed]) { ScrollWindow(textPrinter->subPrinter.windowId, 0, textPrinter->scrollDistance, textPrinter->subPrinter.bgColor | (textPrinter->subPrinter.bgColor << 4)); textPrinter->scrollDistance = 0; } else { - ScrollWindow(textPrinter->subPrinter.windowId, 0, gUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed], textPrinter->subPrinter.bgColor | (textPrinter->subPrinter.bgColor << 4)); - textPrinter->scrollDistance -= gUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed]; + ScrollWindow(textPrinter->subPrinter.windowId, 0, sUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed], textPrinter->subPrinter.bgColor | (textPrinter->subPrinter.bgColor << 4)); + textPrinter->scrollDistance -= sUnknown_08616124[gSaveBlock2Ptr->optionsTextSpeed]; } CopyWindowToVram(textPrinter->subPrinter.windowId, 2); } @@ -204,7 +204,7 @@ static void DecompressGlyphFont6(u16 glyph) { const u16 *glyphs; - glyphs = gFont6BrailleGlyphs + 0x100 * (glyph / 8) + 0x10 * (glyph % 8); + glyphs = sFont6BrailleGlyphs + 0x100 * (glyph / 8) + 0x10 * (glyph % 8); DecompressGlyphTile(glyphs, (u16 *)gUnknown_03002F90); DecompressGlyphTile(glyphs + 0x8, (u16 *)(gUnknown_03002F90 + 0x20)); DecompressGlyphTile(glyphs + 0x80, (u16 *)(gUnknown_03002F90 + 0x40)); diff --git a/src/use_pokeblock.c b/src/use_pokeblock.c new file mode 100644 index 000000000..12f475c93 --- /dev/null +++ b/src/use_pokeblock.c @@ -0,0 +1,230 @@ +#include "global.h" +#include "main.h" +#include "pokeblock.h" +#include "malloc.h" +#include "palette.h" +#include "pokenav.h" +#include "unknown_task.h" +#include "text.h" +#include "bg.h" +#include "window.h" +#include "text_window.h" + +struct UsePokeblockSubStruct +{ + void (*field_0)(void); + void (*callback)(void); + struct Pokeblock *pokeblock; + struct Pokemon *pokemon; + u8 stringBuffer[0x40]; + u8 field_50; + u8 field_51; + u8 field_52; + u8 field_53; + u8 field_54; + u8 field_55; + u8 field_56; + u8 field_57[5]; + u8 field_5c[5]; + u8 field_61[5]; + s16 field_66[5]; +}; + +struct UsePokeblockStruct +{ + u8 field_0[0x7C58]; + u8 field_7C58[0x378]; + struct UsePokeblockSubStruct info; +}; + +extern u16 gKeyRepeatStartDelay; + +// this file's functions +void sub_816636C(void (*func)(void)); +void sub_8166380(void); +void sub_816631C(void); +void sub_81662C0(void); +void sub_8166564(void); +void sub_8166304(void); +void sub_81668F8(void); +void sub_8167420(void); +void sub_8167760(void); +u8 sub_81672E4(u8 arg0); +bool8 sub_8168328(void); +bool8 sub_8167930(void); +void sub_8167608(u8 arg0); +void sub_8167BA0(u16 arg0, u8 copyToVramMode); + +extern const struct BgTemplate gUnknown_085DFCCC[4]; +extern const struct WindowTemplate gUnknown_085DFCDC[]; + +// ram variables +EWRAM_DATA struct UsePokeblockSubStruct *gUnknown_0203BC90 = NULL; +EWRAM_DATA void (*gUnknown_0203BC94)(void) = NULL; +EWRAM_DATA struct Pokeblock *gUnknown_0203BC98 = NULL; +EWRAM_DATA u8 gPokeblockMonId = 0; +EWRAM_DATA s16 gPokeblockGain = 0; +EWRAM_DATA void *gUnknown_0203BCA0 = NULL; +EWRAM_DATA void *gUnknown_0203BCA4 = NULL; +EWRAM_DATA void *gUnknown_0203BCA8 = NULL; +EWRAM_DATA struct UsePokeblockStruct *gUnknown_0203BCAC = NULL; + +// const rom data +// todo: make it static once the file is decompiled + +// code +void ChooseMonToGivePokeblock(struct Pokeblock *pokeblock, void (*callback)(void)) +{ + gUnknown_0203BCAC = AllocZeroed(0x806C); + gUnknown_0203BC90 = &gUnknown_0203BCAC->info; + gUnknown_0203BC90->pokeblock = pokeblock; + gUnknown_0203BC90->callback = callback; + sub_816636C(sub_8166380); + SetMainCallback2(sub_816631C); +} + +void CB2_ReturnAndChooseMonToGivePokeblock(void) +{ + gUnknown_0203BCAC = AllocZeroed(0x806C); + gUnknown_0203BC90 = &gUnknown_0203BCAC->info; + gUnknown_0203BC90->pokeblock = gUnknown_0203BC98; + gUnknown_0203BC90->callback = gUnknown_0203BC94; + gPokeblockMonId = sub_81672E4(gPokeblockMonId); + gUnknown_0203BC90->field_56 = gPokeblockMonId < 4 ? 0 : 1; + sub_816636C(sub_8166380); + SetMainCallback2(sub_81662C0); +} + +void sub_81662C0(void) +{ + gUnknown_0203BC90->field_0(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); + if (gUnknown_0203BC90->field_0 == sub_8166564) + { + gUnknown_0203BC90->field_50 = 0; + SetMainCallback2(sub_8166304); + } +} + +void sub_8166304(void) +{ + sub_81668F8(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +void sub_816631C(void) +{ + gUnknown_0203BC90->field_0(); + AnimateSprites(); + BuildOamBuffer(); + RunTextPrinters(); + UpdatePaletteFade(); +} + +void sub_8166340(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); + sub_81D2108(gUnknown_0203BCAC->field_7C58); + sub_80BA0A8(); +} + +void sub_816636C(void (*func)(void)) +{ + gUnknown_0203BC90->field_0 = func; + gUnknown_0203BC90->field_50 = 0; +} + +void sub_8166380(void) +{ + switch (gUnknown_0203BC90->field_50) + { + case 0: + gUnknown_0203BCAC->field_0[0x7B10] = 0xFF; + sub_81D1ED4(gUnknown_0203BCAC->field_7C58); + gUnknown_0203BC90->field_50++; + break; + case 1: + ResetSpriteData(); + FreeAllSpritePalettes(); + gUnknown_0203BC90->field_50++; + break; + case 2: + SetVBlankCallback(NULL); + CpuFill32(0, (void*)(VRAM), VRAM_SIZE); + gUnknown_0203BC90->field_50++; + break; + case 3: + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, gUnknown_085DFCCC, ARRAY_COUNT(gUnknown_085DFCCC)); + InitWindows(gUnknown_085DFCDC); + DeactivateAllTextPrinters(); + sub_809882C(0, 0x97, 0xE0); + gUnknown_0203BC90->field_50++; + break; + case 4: + gUnknown_0203BC90->field_50++; + break; + case 5: + if (!sub_8168328()) + { + gUnknown_0203BC90->field_50++; + } + break; + case 6: + gKeyRepeatStartDelay = 20; + sub_8167420(); + gUnknown_0203BC90->field_50++; + break; + case 7: + if (!sub_8167930()) + { + gUnknown_0203BC90->field_50++; + } + break; + case 8: + sub_8167608(0); + sub_8167760(); + gUnknown_0203BC90->field_50++; + break; + case 9: + if (!sub_81D312C(&gUnknown_0203BCAC->field_0[0x7B0E])) + { + gUnknown_0203BC90->field_50++; + } + break; + case 10: + gUnknown_0203BC90->field_50++; + break; + case 11: + sub_81D2754(gUnknown_0203BCAC->field_7C58, &gUnknown_0203BCAC->field_0[0x7C6C]); + sub_81D20AC(gUnknown_0203BCAC->field_7C58); + gUnknown_0203BC90->field_50++; + break; + case 12: + if (!sub_81D20BC(gUnknown_0203BCAC->field_7C58)) + { + sub_81D1F84(gUnknown_0203BCAC->field_7C58, &gUnknown_0203BCAC->field_7C58[0x14], &gUnknown_0203BCAC->field_7C58[0x14]); + gUnknown_0203BC90->field_50++; + } + break; + case 13: + sub_81D2230(gUnknown_0203BCAC->field_7C58); + gUnknown_0203BC90->field_50++; + break; + case 14: + PutWindowTilemap(0); + PutWindowTilemap(1); + sub_8167BA0(0, 1); + gUnknown_0203BC90->field_50++; + break; + case 15: + sub_816636C(sub_8166564); + break; + } +} diff --git a/src/wallclock.c b/src/wallclock.c new file mode 100644 index 000000000..cd85de230 --- /dev/null +++ b/src/wallclock.c @@ -0,0 +1,1057 @@ +#include "global.h" +#include "main.h" +#include "palette.h" +#include "gpu_regs.h" +#include "bg.h" +#include "rtc.h" +#include "clock.h" +#include "wallclock.h" +#include "event_data.h" +#include "graphics.h" +#include "text.h" +#include "window.h" +#include "text_window.h" +#include "menu.h" +#include "unknown_task.h" +#include "task.h" +#include "strings.h" +#include "sound.h" +#include "songs.h" +#include "trig.h" +#include "decompress.h" + +// static types + +#define tMinuteHandAngle data[0] +#define tHourHandAngle data[1] +#define tHours data[2] +#define tMinutes data[3] +#define tMvmtDir data[4] +#define tPeriod data[5] +#define tMvmtSpeed data[6] + +#define TAG_GFX_WALL_CLOCK_HAND 0x1000 +#define TAG_PAL_WALL_CLOCK_HAND 0x1000 + +// static declarations + +static void WallClockMainCallback(void); +static void Task_SetClock1(u8 taskId); +static void Task_SetClock2(u8 taskId); +static void Task_SetClock3(u8 taskId); +static void Task_SetClock4(u8 taskId); +static void Task_SetClock5(u8 taskId); +static void Task_SetClock6(u8 taskId); +static void Task_ViewClock1(u8 taskId); +static void Task_ViewClock2(u8 taskId); +static void Task_ViewClock3(u8 taskId); +static void Task_ViewClock4(u8 taskId); +static u16 CalcNewMinHandAngle(u16 a0, u8 command, u8 a2); +static bool32 AdvanceClock(u8 taskId, u8 command); +static void UpdateClockPeriod(u8 taskId, u8 command); +static void InitClockWithRtc(u8 taskId); +static void SpriteCB_MinuteHand(struct Sprite *sprite); +static void SpriteCB_HourHand(struct Sprite *sprite); +static void SpriteCB_AMIndicator(struct Sprite *sprite); +static void SpriteCB_PMIndicator(struct Sprite *sprite); + +// rodata + +static const u8 sUnknown_085B1F58[] = INCBIN_U8("graphics/wallclock/graphics_85b1f58.4bpp.lz"); +static const u16 sUnknown_085B21D4[] = INCBIN_U16("graphics/wallclock/palette_85b21d4.gbapal"); +static const struct WindowTemplate gUnknown_085B21DC[] = { + { 0x00, 0x03, 0x11, 0x18, 0x02, 0x0e, 0x200 }, + { 0x02, 0x18, 0x10, 0x06, 0x02, 0x0c, 0x230 }, + DUMMY_WIN_TEMPLATE +}; +static const struct WindowTemplate gUnknown_085B21F4 = { + 0x00, 0x18, 0x09, 0x05, 0x04, 0x0e, 0x23c +}; +static const struct BgTemplate gUnknown_085B21FC[] = { + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 31, + .priority = 0 + }, + { + .bg = 2, + .charBaseIndex = 1, + .mapBaseIndex = 8, + .priority = 1 + }, + { + .bg = 3, + .charBaseIndex = 0, + .mapBaseIndex = 7, + .priority = 2 + } +}; +static const struct CompressedSpriteSheet gUnknown_085B2208 = { + sUnknown_085B1F58, 0x2000, TAG_GFX_WALL_CLOCK_HAND +}; +static const u32 filler_85B2210[2] = {}; +static const struct SpritePalette gUnknown_085B2218[] = { + { gUnknown_08DCC01C, TAG_PAL_WALL_CLOCK_HAND }, + { gUnknown_08DCC03C, 0x1001 }, + {} +}; +static const struct OamData Unknown_085B2230 = { + .y = 0xa0, + .size = 3, + .priority = 1 +}; +static const union AnimCmd Unknown_085B2238[] = { + ANIMCMD_FRAME(0, 30), + ANIMCMD_END +}; +static const union AnimCmd Unknown_085B2240[] = { + ANIMCMD_FRAME(64, 30), + ANIMCMD_END +}; +static const union AnimCmd *const gUnknown_085B2248[] = { + Unknown_085B2238 +}; +static const union AnimCmd *const gUnknown_085B224C[] = { + Unknown_085B2240 +}; +static const struct SpriteTemplate gUnknown_085B2250 = { + TAG_GFX_WALL_CLOCK_HAND, + TAG_PAL_WALL_CLOCK_HAND, + &Unknown_085B2230, + gUnknown_085B2248, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_MinuteHand +}; +static const struct SpriteTemplate gUnknown_085B2268 = { + TAG_GFX_WALL_CLOCK_HAND, + TAG_PAL_WALL_CLOCK_HAND, + &Unknown_085B2230, + gUnknown_085B224C, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_HourHand +}; +static const struct OamData Unknown_085B2280 = { + .y = 0xa0, + .size = 1, + .priority = 3 +}; +static const union AnimCmd Unknown_085B2288[] = { + ANIMCMD_FRAME(0x84, 30), + ANIMCMD_END +}; +static const union AnimCmd Unknown_085B2290[] = { + ANIMCMD_FRAME(0x80, 30), + ANIMCMD_END +}; +static const union AnimCmd *const gUnknown_085B2298[] = { + Unknown_085B2288 +}; +static const union AnimCmd *const gUnknown_085B229C[] = { + Unknown_085B2290 +}; +static const struct SpriteTemplate gUnknown_085B22A0 = { + TAG_GFX_WALL_CLOCK_HAND, + TAG_PAL_WALL_CLOCK_HAND, + &Unknown_085B2280, + gUnknown_085B2298, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_AMIndicator +}; +static const struct SpriteTemplate gUnknown_085B22B8 = { + TAG_GFX_WALL_CLOCK_HAND, + TAG_PAL_WALL_CLOCK_HAND, + &Unknown_085B2280, + gUnknown_085B229C, + NULL, + gDummySpriteAffineAnimTable, + SpriteCB_PMIndicator +}; +static const s8 sClockHandCoords[][2] = { + { 0x00, -0x18}, + { 0x01, -0x19}, + { 0x01, -0x19}, + { 0x02, -0x19}, + { 0x02, -0x19}, + { 0x02, -0x19}, + { 0x03, -0x18}, + { 0x03, -0x19}, + { 0x04, -0x19}, + { 0x04, -0x19}, + { 0x04, -0x19}, + { 0x05, -0x19}, + { 0x05, -0x19}, + { 0x06, -0x18}, + { 0x06, -0x18}, + { 0x06, -0x18}, + { 0x07, -0x18}, + { 0x07, -0x18}, + { 0x07, -0x18}, + { 0x08, -0x18}, + { 0x08, -0x18}, + { 0x09, -0x18}, + { 0x09, -0x18}, + { 0x0a, -0x17}, + { 0x0a, -0x17}, + { 0x0b, -0x16}, + { 0x0b, -0x16}, + { 0x0b, -0x16}, + { 0x0c, -0x16}, + { 0x0c, -0x15}, + { 0x0d, -0x15}, + { 0x0d, -0x15}, + { 0x0d, -0x15}, + { 0x0e, -0x15}, + { 0x0e, -0x15}, + { 0x0e, -0x14}, + { 0x0e, -0x14}, + { 0x0f, -0x14}, + { 0x0f, -0x13}, + { 0x10, -0x13}, + { 0x10, -0x13}, + { 0x10, -0x13}, + { 0x10, -0x12}, + { 0x10, -0x12}, + { 0x11, -0x12}, + { 0x11, -0x11}, + { 0x11, -0x11}, + { 0x12, -0x11}, + { 0x12, -0x11}, + { 0x12, -0x10}, + { 0x12, -0x10}, + { 0x13, -0x10}, + { 0x13, -0x0f}, + { 0x13, -0x0f}, + { 0x14, -0x0f}, + { 0x14, -0x0e}, + { 0x14, -0x0e}, + { 0x14, -0x0d}, + { 0x14, -0x0d}, + { 0x15, -0x0d}, + { 0x15, -0x0d}, + { 0x15, -0x0c}, + { 0x16, -0x0c}, + { 0x16, -0x0c}, + { 0x16, -0x0b}, + { 0x16, -0x0b}, + { 0x16, -0x0a}, + { 0x17, -0x0a}, + { 0x17, -0x09}, + { 0x17, -0x09}, + { 0x17, -0x09}, + { 0x17, -0x09}, + { 0x17, -0x08}, + { 0x17, -0x08}, + { 0x17, -0x07}, + { 0x17, -0x07}, + { 0x17, -0x06}, + { 0x18, -0x06}, + { 0x18, -0x06}, + { 0x19, -0x05}, + { 0x19, -0x05}, + { 0x18, -0x04}, + { 0x19, -0x04}, + { 0x18, -0x03}, + { 0x19, -0x03}, + { 0x19, -0x03}, + { 0x19, -0x02}, + { 0x19, -0x02}, + { 0x18, -0x01}, + { 0x19, -0x01}, + { 0x18, 0x00}, + { 0x18, 0x00}, + { 0x18, 0x00}, + { 0x18, 0x01}, + { 0x18, 0x01}, + { 0x19, 0x02}, + { 0x18, 0x02}, + { 0x19, 0x02}, + { 0x18, 0x03}, + { 0x18, 0x03}, + { 0x19, 0x04}, + { 0x18, 0x04}, + { 0x18, 0x05}, + { 0x18, 0x05}, + { 0x18, 0x05}, + { 0x18, 0x06}, + { 0x17, 0x06}, + { 0x17, 0x06}, + { 0x17, 0x07}, + { 0x17, 0x08}, + { 0x17, 0x08}, + { 0x17, 0x08}, + { 0x17, 0x09}, + { 0x17, 0x09}, + { 0x17, 0x0a}, + { 0x16, 0x0a}, + { 0x16, 0x0a}, + { 0x16, 0x0b}, + { 0x16, 0x0b}, + { 0x16, 0x0b}, + { 0x16, 0x0c}, + { 0x15, 0x0c}, + { 0x15, 0x0c}, + { 0x15, 0x0d}, + { 0x14, 0x0d}, + { 0x14, 0x0d}, + { 0x13, 0x0d}, + { 0x13, 0x0d}, + { 0x13, 0x0e}, + { 0x13, 0x0e}, + { 0x13, 0x0f}, + { 0x13, 0x0f}, + { 0x12, 0x0f}, + { 0x12, 0x10}, + { 0x11, 0x10}, + { 0x11, 0x10}, + { 0x11, 0x11}, + { 0x11, 0x11}, + { 0x10, 0x11}, + { 0x10, 0x12}, + { 0x10, 0x12}, + { 0x0f, 0x12}, + { 0x0e, 0x12}, + { 0x0f, 0x13}, + { 0x0e, 0x13}, + { 0x0e, 0x13}, + { 0x0d, 0x13}, + { 0x0d, 0x14}, + { 0x0d, 0x14}, + { 0x0d, 0x14}, + { 0x0c, 0x14}, + { 0x0c, 0x14}, + { 0x0c, 0x15}, + { 0x0b, 0x15}, + { 0x0b, 0x15}, + { 0x0b, 0x15}, + { 0x0a, 0x15}, + { 0x0a, 0x16}, + { 0x0a, 0x16}, + { 0x09, 0x16}, + { 0x09, 0x16}, + { 0x08, 0x16}, + { 0x07, 0x16}, + { 0x07, 0x17}, + { 0x07, 0x17}, + { 0x06, 0x17}, + { 0x06, 0x17}, + { 0x05, 0x17}, + { 0x05, 0x17}, + { 0x05, 0x18}, + { 0x04, 0x18}, + { 0x04, 0x18}, + { 0x04, 0x18}, + { 0x03, 0x18}, + { 0x02, 0x18}, + { 0x02, 0x18}, + { 0x01, 0x18}, + { 0x01, 0x18}, + { 0x00, 0x18}, + { 0x00, 0x18}, + {-0x01, 0x17}, + { 0x00, 0x18}, + { 0x00, 0x18}, + {-0x01, 0x18}, + {-0x01, 0x18}, + {-0x02, 0x18}, + {-0x02, 0x18}, + {-0x03, 0x18}, + {-0x03, 0x18}, + {-0x04, 0x18}, + {-0x04, 0x18}, + {-0x05, 0x18}, + {-0x05, 0x17}, + {-0x05, 0x17}, + {-0x06, 0x17}, + {-0x06, 0x17}, + {-0x07, 0x17}, + {-0x07, 0x17}, + {-0x07, 0x17}, + {-0x08, 0x17}, + {-0x08, 0x16}, + {-0x09, 0x16}, + {-0x09, 0x16}, + {-0x0a, 0x16}, + {-0x0a, 0x16}, + {-0x0a, 0x15}, + {-0x0b, 0x15}, + {-0x0b, 0x15}, + {-0x0b, 0x15}, + {-0x0b, 0x14}, + {-0x0c, 0x14}, + {-0x0c, 0x14}, + {-0x0d, 0x14}, + {-0x0d, 0x14}, + {-0x0d, 0x13}, + {-0x0e, 0x13}, + {-0x0e, 0x13}, + {-0x0e, 0x13}, + {-0x0e, 0x12}, + {-0x0f, 0x12}, + {-0x0f, 0x12}, + {-0x0f, 0x11}, + {-0x10, 0x11}, + {-0x10, 0x11}, + {-0x11, 0x11}, + {-0x11, 0x10}, + {-0x11, 0x10}, + {-0x12, 0x10}, + {-0x11, 0x0f}, + {-0x12, 0x0f}, + {-0x12, 0x0f}, + {-0x13, 0x0f}, + {-0x13, 0x0e}, + {-0x13, 0x0e}, + {-0x13, 0x0d}, + {-0x13, 0x0d}, + {-0x14, 0x0d}, + {-0x14, 0x0c}, + {-0x14, 0x0c}, + {-0x15, 0x0c}, + {-0x15, 0x0c}, + {-0x15, 0x0b}, + {-0x15, 0x0b}, + {-0x15, 0x0a}, + {-0x15, 0x0a}, + {-0x15, 0x09}, + {-0x16, 0x09}, + {-0x16, 0x09}, + {-0x16, 0x08}, + {-0x16, 0x08}, + {-0x16, 0x07}, + {-0x17, 0x07}, + {-0x17, 0x07}, + {-0x17, 0x06}, + {-0x17, 0x06}, + {-0x17, 0x05}, + {-0x18, 0x05}, + {-0x17, 0x04}, + {-0x17, 0x04}, + {-0x18, 0x04}, + {-0x18, 0x04}, + {-0x18, 0x03}, + {-0x18, 0x03}, + {-0x18, 0x02}, + {-0x18, 0x02}, + {-0x18, 0x01}, + {-0x18, 0x01}, + {-0x18, 0x01}, + {-0x18, 0x00}, + {-0x19, 0x00}, + {-0x18, -0x01}, + {-0x19, -0x01}, + {-0x18, -0x01}, + {-0x18, -0x02}, + {-0x18, -0x02}, + {-0x18, -0x03}, + {-0x18, -0x03}, + {-0x18, -0x04}, + {-0x18, -0x04}, + {-0x18, -0x04}, + {-0x18, -0x05}, + {-0x18, -0x05}, + {-0x18, -0x06}, + {-0x18, -0x06}, + {-0x17, -0x06}, + {-0x17, -0x07}, + {-0x17, -0x07}, + {-0x17, -0x08}, + {-0x17, -0x08}, + {-0x17, -0x09}, + {-0x17, -0x09}, + {-0x16, -0x09}, + {-0x16, -0x09}, + {-0x16, -0x0a}, + {-0x16, -0x0a}, + {-0x15, -0x0a}, + {-0x15, -0x0b}, + {-0x16, -0x0b}, + {-0x16, -0x0c}, + {-0x15, -0x0c}, + {-0x15, -0x0d}, + {-0x15, -0x0d}, + {-0x14, -0x0d}, + {-0x15, -0x0e}, + {-0x14, -0x0e}, + {-0x14, -0x0e}, + {-0x13, -0x0e}, + {-0x13, -0x0f}, + {-0x13, -0x0f}, + {-0x12, -0x10}, + {-0x12, -0x10}, + {-0x12, -0x10}, + {-0x12, -0x11}, + {-0x12, -0x11}, + {-0x11, -0x11}, + {-0x11, -0x12}, + {-0x11, -0x12}, + {-0x10, -0x12}, + {-0x10, -0x12}, + {-0x10, -0x13}, + {-0x10, -0x13}, + {-0x0f, -0x13}, + {-0x0f, -0x13}, + {-0x0f, -0x14}, + {-0x0e, -0x14}, + {-0x0e, -0x14}, + {-0x0e, -0x15}, + {-0x0d, -0x15}, + {-0x0d, -0x15}, + {-0x0d, -0x15}, + {-0x0c, -0x15}, + {-0x0c, -0x16}, + {-0x0b, -0x16}, + {-0x0b, -0x16}, + {-0x0b, -0x16}, + {-0x0a, -0x16}, + {-0x0a, -0x16}, + {-0x09, -0x16}, + {-0x09, -0x17}, + {-0x09, -0x17}, + {-0x08, -0x17}, + {-0x08, -0x17}, + {-0x07, -0x17}, + {-0x07, -0x17}, + {-0x07, -0x18}, + {-0x06, -0x18}, + {-0x06, -0x18}, + {-0x05, -0x18}, + {-0x05, -0x18}, + {-0x04, -0x18}, + {-0x04, -0x18}, + {-0x04, -0x18}, + {-0x04, -0x19}, + {-0x03, -0x19}, + {-0x02, -0x19}, + {-0x02, -0x18}, + {-0x02, -0x18}, + {-0x01, -0x19}, + {-0x01, -0x19}, + { 0x00, -0x19} +}; + +// text + +static void WallClockVblankCallback(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void LoadWallClockGraphics(void) +{ + SetVBlankCallback(NULL); + SetGpuReg(REG_OFFSET_DISPCNT, 0x0000); + SetGpuReg(REG_OFFSET_BG3CNT, 0x0000); + SetGpuReg(REG_OFFSET_BG2CNT, 0x0000); + SetGpuReg(REG_OFFSET_BG1CNT, 0x0000); + SetGpuReg(REG_OFFSET_BG0CNT, 0x0000); + 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); + DmaFillLarge16(3, 0, (void *)VRAM, VRAM_SIZE, 0x1000); + DmaClear32(3, (void *)OAM, OAM_SIZE); + DmaClear16(3, (void *)PLTT, PLTT_SIZE); + LZ77UnCompVram(gUnknown_08DCC05C, (void *)VRAM); + if (gSpecialVar_0x8004 == 0) + { + LoadPalette(gUnknown_08DCC01C, 0x00, 0x20); + } + else + { + LoadPalette(gUnknown_08DCC03C, 0x00, 0x20); + } + LoadPalette(GetOverworldTextboxPalettePtr(), 0xe0, 0x20); + LoadPalette(sUnknown_085B21D4, 0xc0, 0x08); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, gUnknown_085B21FC, 3); + InitWindows(gUnknown_085B21DC); + DeactivateAllTextPrinters(); + sub_809882C(0, 0x250, 0xd0); + clear_scheduled_bg_copies_to_vram(); + remove_some_task(); + ResetTasks(); + ResetSpriteData(); + ResetPaletteFade(); + FreeAllSpritePalettes(); + LoadCompressedObjectPic(&gUnknown_085B2208); + LoadSpritePalettes(gUnknown_085B2218); +} + +static void WallClockInit(void) +{ + BeginNormalPaletteFade(-1, 0, 16, 0, 0); + EnableInterrupts(INTR_FLAG_VBLANK); + SetVBlankCallback(WallClockVblankCallback); + SetMainCallback2(WallClockMainCallback); + SetGpuReg(REG_OFFSET_BLDCNT, 0x0000); + SetGpuReg(REG_OFFSET_BLDALPHA, 0x0000); + SetGpuReg(REG_OFFSET_BLDY, 0x0000); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); + ShowBg(0); + ShowBg(2); + ShowBg(3); +} + +void Cb2_StartWallClock(void) +{ + u8 taskId; + u8 spriteId; + + LoadWallClockGraphics(); + LZ77UnCompVram(gUnknown_08DCC648, (u16 *)BG_SCREEN_ADDR(7)); + + taskId = CreateTask(Task_SetClock1, 0); + gTasks[taskId].tHours = 10; + gTasks[taskId].tMinutes = 0; + gTasks[taskId].tMvmtDir = 0; + gTasks[taskId].tPeriod = 0; + gTasks[taskId].tMvmtSpeed = 0; + gTasks[taskId].tMinuteHandAngle = 0; + gTasks[taskId].tHourHandAngle = 300; + + spriteId = CreateSprite(&gUnknown_085B2250, 0x78, 0x50, 1); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[spriteId].oam.matrixNum = 0; + + spriteId = CreateSprite(&gUnknown_085B2268, 0x78, 0x50, 0); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[spriteId].oam.matrixNum = 1; + + spriteId = CreateSprite(&gUnknown_085B22A0, 0x78, 0x50, 2); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].data[1] = 45; + + spriteId = CreateSprite(&gUnknown_085B22B8, 0x78, 0x50, 2); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].data[1] = 90; + + WallClockInit(); + + PrintTextOnWindow(1, 1, gText_Confirm3, 0, 1, 0, NULL); + PutWindowTilemap(1); + schedule_bg_copy_tilemap_to_vram(2); +} + +void Cb2_ViewWallClock(void) +{ + u8 taskId; + u8 spriteId; + u8 angle1; + u8 angle2; + + LoadWallClockGraphics(); + LZ77UnCompVram(gUnknown_08DCC908, (u16 *)BG_SCREEN_ADDR(7)); + + taskId = CreateTask(Task_ViewClock1, 0); + InitClockWithRtc(taskId); + if (gTasks[taskId].tPeriod == 0) + { + angle1 = 45; + angle2 = 90; + } + else + { + angle1 = 90; + angle2 = 135; + } + + spriteId = CreateSprite(&gUnknown_085B2250, 0x78, 0x50, 1); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[spriteId].oam.matrixNum = 0; + + spriteId = CreateSprite(&gUnknown_085B2268, 0x78, 0x50, 0); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[spriteId].oam.matrixNum = 1; + + spriteId = CreateSprite(&gUnknown_085B22A0, 0x78, 0x50, 2); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].data[1] = angle1; + + spriteId = CreateSprite(&gUnknown_085B22B8, 0x78, 0x50, 2); + gSprites[spriteId].data[0] = taskId; + gSprites[spriteId].data[1] = angle2; + + WallClockInit(); + + PrintTextOnWindow(1, 1, gText_Cancel4, 0, 1, 0, NULL); + PutWindowTilemap(1); + schedule_bg_copy_tilemap_to_vram(2); +} + +static void WallClockMainCallback(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +static void Task_SetClock1(u8 taskId) +{ + if (!gPaletteFade.active) + { + gTasks[taskId].func = Task_SetClock2; + } +} + +static void Task_SetClock2(u8 taskId) +{ + if (gTasks[taskId].tMinuteHandAngle % 6) + { + gTasks[taskId].tMinuteHandAngle = CalcNewMinHandAngle(gTasks[taskId].tMinuteHandAngle, gTasks[taskId].tMvmtDir, gTasks[taskId].tMvmtSpeed); + } + else + { + gTasks[taskId].tMinuteHandAngle = gTasks[taskId].tMinutes * 6; + gTasks[taskId].tHourHandAngle = (gTasks[taskId].tHours % 12) * 30 + (gTasks[taskId].tMinutes / 10) * 5; + if (gMain.newKeys & A_BUTTON) + { + gTasks[taskId].func = Task_SetClock3; + } + else + { + gTasks[taskId].tMvmtDir = 0; + if (gMain.heldKeys & DPAD_LEFT) + { + gTasks[taskId].tMvmtDir = 1; + } + if (gMain.heldKeys & DPAD_RIGHT) + { + gTasks[taskId].tMvmtDir = 2; + } + if (gTasks[taskId].tMvmtDir != 0) + { + if (gTasks[taskId].tMvmtSpeed < 0xFF) + { + gTasks[taskId].tMvmtSpeed++; + } + gTasks[taskId].tMinuteHandAngle = CalcNewMinHandAngle(gTasks[taskId].tMinuteHandAngle, gTasks[taskId].tMvmtDir, gTasks[taskId].tMvmtSpeed); + AdvanceClock(taskId, gTasks[taskId].tMvmtDir); + } + else + { + gTasks[taskId].tMvmtSpeed = 0; + } + } + } +} + +static void Task_SetClock3(u8 taskId) +{ + SetWindowBorderStyle(0, FALSE, 0x250, 0x0d); + PrintTextOnWindow(0, 1, gText_IsThisTheCorrectTime, 0, 1, 0, NULL); + PutWindowTilemap(0); + schedule_bg_copy_tilemap_to_vram(0); + CreateYesNoMenu(&gUnknown_085B21F4, 0x250, 0x0d, 1); + gTasks[taskId].func = Task_SetClock4; +} + +static void Task_SetClock4(u8 taskId) +{ + switch (ProcessMenuInputNoWrap_()) + { + case 0: + PlaySE(SE_SELECT); + gTasks[taskId].func = Task_SetClock5; + break; + case 1: + case -1: + PlaySE(SE_SELECT); + sub_8198070(0, FALSE); + ClearWindowTilemap(0); + gTasks[taskId].func = Task_SetClock2; + break; + } +} + +static void Task_SetClock5(u8 taskId) +{ + RtcInitLocalTimeOffset(gTasks[taskId].tHours, gTasks[taskId].tMinutes); + BeginNormalPaletteFade(-1, 0, 0, 16, 0); + gTasks[taskId].func = Task_SetClock6; +} + +static void Task_SetClock6(u8 taskId) +{ + if (!gPaletteFade.active) + { + FreeAllWindowBuffers(); + SetMainCallback2(gMain.savedCallback); + } +} + +static void Task_ViewClock1(u8 taskId) +{ + if (!gPaletteFade.active) + { + gTasks[taskId].func = Task_ViewClock2; + } +} + +static void Task_ViewClock2(u8 taskId) +{ + InitClockWithRtc(taskId); + if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + gTasks[taskId].func = Task_ViewClock3; + } +} + +static void Task_ViewClock3(u8 taskId) +{ + BeginNormalPaletteFade(-1, 0, 0, 16, 0); + gTasks[taskId].func = Task_ViewClock4; +} + +static void Task_ViewClock4(u8 taskId) +{ + if (!gPaletteFade.active) + { + SetMainCallback2(gMain.savedCallback); + } +} + +static u8 CalcMinHandDelta(u16 a0) +{ + if (a0 > 60) + { + return 6; + } + if (a0 > 30) + { + return 3; + } + if (a0 > 10) + { + return 2; + } + return 1; +} + +static u16 CalcNewMinHandAngle(u16 a0, u8 command, u8 a2) +{ + u8 r1 = CalcMinHandDelta(a2); + switch (command) + { + case 1: + if (a0) a0 -= r1; + else a0 = 360 - r1; + break; + case 2: + if (a0 < 360 - r1) a0 += r1; + else a0 = 0; + break; + } + return a0; +} + +static bool32 AdvanceClock(u8 taskId, u8 command) +{ + switch (command) + { + case 1: + if (gTasks[taskId].tMinutes > 0) + { + gTasks[taskId].tMinutes--; + } + else + { + gTasks[taskId].tMinutes = 59; + if (gTasks[taskId].tHours > 0) + { + gTasks[taskId].tHours--; + } + else + { + gTasks[taskId].tHours = 23; + } + UpdateClockPeriod(taskId, command); + } + break; + case 2: + if (gTasks[taskId].tMinutes < 59) + { + gTasks[taskId].tMinutes++; + } + else + { + gTasks[taskId].tMinutes = 0; + if (gTasks[taskId].tHours < 23) + { + gTasks[taskId].tHours++; + } + else + { + gTasks[taskId].tHours = 0; + } + UpdateClockPeriod(taskId, command); + } + break; + } + return FALSE; +} + +static void UpdateClockPeriod(u8 taskId, u8 command) +{ + u8 hours = gTasks[taskId].tHours; + switch (command) + { + case 1: + switch (hours) + { + case 11: + gTasks[taskId].tPeriod = FALSE; + break; + case 23: + gTasks[taskId].tPeriod = TRUE; + break; + } + break; + case 2: + switch (hours) + { + case 0: + gTasks[taskId].tPeriod = FALSE; + break; + case 12: + gTasks[taskId].tPeriod = TRUE; + break; + } + break; + } +} + +static void InitClockWithRtc(u8 taskId) +{ + RtcCalcLocalTime(); + gTasks[taskId].tHours = gLocalTime.hours; + gTasks[taskId].tMinutes = gLocalTime.minutes; + gTasks[taskId].tMinuteHandAngle = gTasks[taskId].tMinutes * 6; + gTasks[taskId].tHourHandAngle = (gTasks[taskId].tHours % 12) * 30 + (gTasks[taskId].tMinutes / 10) * 5; + if (gLocalTime.hours < 12) + { + gTasks[taskId].tPeriod = FALSE; + } + else + { + gTasks[taskId].tPeriod = TRUE; + } +} + +static void SpriteCB_MinuteHand(struct Sprite *sprite) +{ + u16 angle = gTasks[sprite->data[0]].tMinuteHandAngle; + s16 sin = Sin2(angle) / 16; + s16 cos = Cos2(angle) / 16; + u16 xhat; + u16 yhat; + + SetOamMatrix(0, cos, sin, -sin, cos); + xhat = sClockHandCoords[angle][0]; + yhat = sClockHandCoords[angle][1]; + + if (xhat > 0x80) + { + xhat |= 0xff00; + } + if (yhat > 0x80) + { + yhat |= 0xff00; + } + sprite->pos2.x = xhat; + sprite->pos2.y = yhat; +} + +static void SpriteCB_HourHand(struct Sprite *sprite) +{ + u16 angle = gTasks[sprite->data[0]].tHourHandAngle; + s16 sin = Sin2(angle) / 16; + s16 cos = Cos2(angle) / 16; + u16 xhat; + u16 yhat; + + SetOamMatrix(1, cos, sin, -sin, cos); + xhat = sClockHandCoords[angle][0]; + yhat = sClockHandCoords[angle][1]; + if (xhat > 0x80) + { + xhat |= 0xff00; + } + if (yhat > 0x80) + { + yhat |= 0xff00; + } + sprite->pos2.x = xhat; + sprite->pos2.y = yhat; +} + +static void SpriteCB_AMIndicator(struct Sprite *sprite) +{ + if (gTasks[sprite->data[0]].tPeriod) + { + if (sprite->data[1] >= 60 && sprite->data[1] < 90) + { + sprite->data[1] += 5; + } + if (sprite->data[1] < 60) + { + sprite->data[1]++; + } + } + else + { + if (sprite->data[1] >= 46 && sprite->data[1] < 76) + { + sprite->data[1] -= 5; + } + if (sprite->data[1] > 75) + { + sprite->data[1]--; + } + } + sprite->pos2.x = Cos2(sprite->data[1]) * 30 / 0x1000; + sprite->pos2.y = Sin2(sprite->data[1]) * 30 / 0x1000; +} + +static void SpriteCB_PMIndicator(struct Sprite *sprite) +{ + if (gTasks[sprite->data[0]].tPeriod) + { + if (sprite->data[1] >= 105 && sprite->data[1] < 135) + { + sprite->data[1] += 5; + } + if (sprite->data[1] < 105) + { + sprite->data[1]++; + } + } + else + { + if (sprite->data[1] >= 91 && sprite->data[1] < 121) + { + sprite->data[1] -= 5; + } + if (sprite->data[1] > 120) + { + sprite->data[1]--; + } + } + sprite->pos2.x = Cos2(sprite->data[1]) * 30 / 0x1000; + sprite->pos2.y = Sin2(sprite->data[1]) * 30 / 0x1000; +} |