diff options
Diffstat (limited to 'src/battle_records.c')
-rw-r--r-- | src/battle_records.c | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/src/battle_records.c b/src/battle_records.c new file mode 100644 index 000000000..79f29eb8a --- /dev/null +++ b/src/battle_records.c @@ -0,0 +1,576 @@ +#include "global.h" +#include "malloc.h" +#include "main.h" +#include "bg.h" +#include "gpu_regs.h" +#include "event_data.h" +#include "palette.h" +#include "task.h" +#include "text.h" +#include "window.h" +#include "text_window.h" +#include "battle.h" +#include "trainer_tower.h" +#include "trainer_pokemon_sprites.h" +#include "scanline_effect.h" +#include "sound.h" +#include "string_util.h" +#include "link.h" +#include "menu.h" +#include "overworld.h" +#include "strings.h" +#include "trainer_card.h" +#include "constants/battle.h" +#include "constants/songs.h" +#include "constants/maps.h" + +static EWRAM_DATA u16 * sBg3TilemapBuffer_p = NULL; + +static void MainCB2_SetUp(void); +static void VBlankCB(void); +static void MainCB2(void); +static void Task_WaitFadeIn(u8 taskId); +static void Task_WaitButton(u8 taskId); +static void Task_FadeOut(u8 taskId); +static void Task_DestroyAndReturnToField(u8 taskId); +static void ClearWindowCommitAndRemove(u8 winddowId); +static void ResetGpu(void); +static void StopAllRunningTasks(void); +static void EnableDisplay(void); +static void ResetBGPos(void); +static void PrintBattleRecords(void); +static void CommitWindow(u8 windowId); +static void LoadFrameGfxOnBg(u8 bgId); + +static const u16 sTiles[] = INCBIN_U16("graphics/battle_records/bg_tiles.4bpp"); +static const u16 sPalette[] = INCBIN_U16("graphics/battle_records/palette.gbapal"); +static const u16 sTilemap[] = INCBIN_U16("graphics/battle_records/tilemap.bin"); + +static const struct WindowTemplate sWindowTemplates[] = { + { + .bg = 0, + .tilemapLeft = 2, + .tilemapTop = 1, + .width = 27, + .height = 18, + .paletteNum = 0xF, + .baseBlock = 0x014 + }, DUMMY_WIN_TEMPLATE +}; + +static const struct TextColor sTextColor = { + 0, 2, 3 +}; + +static const struct BgTemplate sBgTemplates[2] = { + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, // 4bpp + .priority = 0, + .baseTile = 0x000 + }, { + .bg = 3, + .charBaseIndex = 1, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, // 4bpp + .priority = 3, + .baseTile = 0x000 + } +}; + +static u8 *const sStringVars[3] = { + gStringVar1, + gStringVar2, + gStringVar3 +}; + +void Special_BattleRecords(void) +{ + SetVBlankCallback(NULL); + SetMainCallback2(MainCB2_SetUp); +} + +static void MainCB2_SetUp(void) +{ + switch (gMain.state) + { + case 0: + SetVBlankCallback(NULL); + ResetGpu(); + gMain.state++; + break; + case 1: + StopAllRunningTasks(); + gMain.state++; + break; + case 2: + sBg3TilemapBuffer_p = AllocZeroed(0x800); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sBgTemplates, NELEMS(sBgTemplates)); + SetBgTilemapBuffer(3, sBg3TilemapBuffer_p); + ResetBGPos(); + gMain.state++; + break; + case 3: + LoadFrameGfxOnBg(3); + LoadPalette(stdpal_get(0), 0xF0, 0x20); + gMain.state++; + break; + case 4: + if (IsDma3ManagerBusyWithBgCopy() != TRUE) + { + ShowBg(0); + ShowBg(3); + CopyBgTilemapBufferToVram(3); + gMain.state++; + } + break; + case 5: + InitWindows(sWindowTemplates); + DeactivateAllTextPrinters(); + gMain.state++; + break; + case 6: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB_BLACK); + gMain.state++; + break; + case 7: + EnableDisplay(); + SetVBlankCallback(VBlankCB); + if (gSpecialVar_0x8004) + PrintTrainerTowerRecords(); + else + PrintBattleRecords(); + CreateTask(Task_WaitFadeIn, 8); + SetMainCallback2(MainCB2); + gMain.state = 0; + break; + } +} + +static void VBlankCB(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void MainCB2(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +static void Task_WaitFadeIn(u8 taskId) +{ + if (!gPaletteFade.active) + gTasks[taskId].func = Task_WaitButton; +} + +static void Task_WaitButton(u8 taskId) +{ + struct Task * task = &gTasks[taskId]; + + if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + task->func = Task_FadeOut; + } +} + +static void Task_FadeOut(u8 taskId) +{ + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); + gTasks[taskId].func = Task_DestroyAndReturnToField; +} + +static void Task_DestroyAndReturnToField(u8 taskId) +{ + if (!gPaletteFade.active) + { + SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); + Free(sBg3TilemapBuffer_p); + ClearWindowCommitAndRemove(0); + FreeAllWindowBuffers(); + DestroyTask(taskId); + } +} + +static void ClearWindowCommitAndRemove(u8 windowId) +{ + FillWindowPixelBuffer(windowId, PIXEL_FILL(0)); + ClearWindowTilemap(windowId); + CopyWindowToVram(windowId, 2); + RemoveWindow(windowId); +} + +static void ResetGpu(void) +{ + { + void * dest = (void *)VRAM; + u32 size = VRAM_SIZE; + DmaClearLarge16(3, dest, size, 0x1000); + } + + { + void * dest = (void *)OAM; + u32 size = OAM_SIZE; + DmaClear32(3, dest, size); + } + + { + void * dest = (void *)PLTT; + u32 size = PLTT_SIZE; + DmaClear16(3, dest, size); + } + + SetGpuReg(REG_OFFSET_DISPCNT, 0); + SetGpuReg(REG_OFFSET_BG0CNT, 0); + SetGpuReg(REG_OFFSET_BG0HOFS, 0); + SetGpuReg(REG_OFFSET_BG0VOFS, 0); + SetGpuReg(REG_OFFSET_BG1CNT, 0); + SetGpuReg(REG_OFFSET_BG1HOFS, 0); + SetGpuReg(REG_OFFSET_BG1VOFS, 0); + SetGpuReg(REG_OFFSET_BG2CNT, 0); + SetGpuReg(REG_OFFSET_BG2HOFS, 0); + SetGpuReg(REG_OFFSET_BG2VOFS, 0); + SetGpuReg(REG_OFFSET_BG3CNT, 0); + SetGpuReg(REG_OFFSET_BG3HOFS, 0); + SetGpuReg(REG_OFFSET_BG3VOFS, 0); + SetGpuReg(REG_OFFSET_WIN0H, 0); + SetGpuReg(REG_OFFSET_WIN0V, 0); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); +} + +static void StopAllRunningTasks(void) +{ + ScanlineEffect_Stop(); + ResetTasks(); + ResetSpriteData(); + ResetAllPicSprites(); + ResetPaletteFade(); + FreeAllSpritePalettes(); +} + +static void EnableDisplay(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON | DISPCNT_BG3_ON); +} + +static void ResetBGPos(void) +{ + ChangeBgX(0, 0, 0); + ChangeBgY(0, 0, 0); + ChangeBgX(1, 0, 0); + ChangeBgY(1, 0, 0); + ChangeBgX(2, 0, 0); + ChangeBgY(2, 0, 0); + ChangeBgX(3, 0, 0); + ChangeBgY(3, 0, 0); +} + +static void InitLinkBattleRecord(struct LinkBattleRecord * record) +{ + CpuFill16(0, record, sizeof(*record)); + record->name[0] = EOS; + record->trainerId = 0; + record->wins = 0; + record->losses = 0; + record->draws = 0; +} + +static void InitLinkBattleRecords_(struct LinkBattleRecords * records) +{ + s32 i; + + for (i = 0; i < LINK_B_RECORDS_COUNT; i++) + InitLinkBattleRecord(&records->entries[i]); + SetGameStat(GAME_STAT_LINK_BATTLE_WINS, 0); + SetGameStat(GAME_STAT_LINK_BATTLE_LOSSES, 0); + SetGameStat(GAME_STAT_LINK_BATTLE_DRAWS, 0); +} + +static s32 GetLinkBattleRecordTotalBattles(struct LinkBattleRecord * record) +{ + return record->wins + record->losses + record->draws; +} + +static s32 IndexOfOpponentLinkBattleRecord(struct LinkBattleRecords * records, const u8 * name, u16 trainerId) +{ + s32 i; + + for (i = 0; i < LINK_B_RECORDS_COUNT; i++) + { + if (StringCompareN(records->entries[i].name, name, OT_NAME_LENGTH) == 0 && records->entries[i].trainerId == trainerId) + return i; + } + + return LINK_B_RECORDS_COUNT; +} + +static void SortLinkBattleRecords(struct LinkBattleRecords * records) +{ + struct LinkBattleRecord tmp; + s32 i; + s32 j; + + for (i = LINK_B_RECORDS_COUNT - 1; i > 0; i--) + { + for (j = i - 1; j >= 0; j--) + { + if (GetLinkBattleRecordTotalBattles(&records->entries[i]) > GetLinkBattleRecordTotalBattles(&records->entries[j])) + { + tmp = records->entries[i]; + records->entries[i] = records->entries[j]; + records->entries[j] = tmp; + } + } + } +} + +static void UpdateLinkBattleRecord(struct LinkBattleRecord * record, s32 outcome) +{ + switch (outcome) + { + case B_OUTCOME_WON: + record->wins++; + if (record->wins > 9999) + record->wins = 9999; + break; + case B_OUTCOME_LOST: + record->losses++; + if (record->losses > 9999) + record->losses = 9999; + break; + case B_OUTCOME_DREW: + record->draws++; + if (record->draws > 9999) + record->draws = 9999; + break; + } +} + +static void UpdateLinkBattleGameStats(s32 outcome) +{ + u8 statId; + + switch (outcome) + { + case B_OUTCOME_WON: + statId = GAME_STAT_LINK_BATTLE_WINS; + break; + case B_OUTCOME_LOST: + statId = GAME_STAT_LINK_BATTLE_LOSSES; + break; + case B_OUTCOME_DREW: + statId = GAME_STAT_LINK_BATTLE_DRAWS; + break; + default: + return; + } + + if (GetGameStat(statId) < 9999) + IncrementGameStat(statId); +} + +static void AddOpponentLinkBattleRecord(struct LinkBattleRecords * records, const u8 * name, u16 trainerId, s32 outcome, u32 language) +{ + u8 namebuf[OT_NAME_LENGTH + 1]; + s32 i; + struct LinkBattleRecord * record; + + if (language == LANGUAGE_JAPANESE) + { + namebuf[0] = EXT_CTRL_CODE_BEGIN; + namebuf[1] = EXT_CTRL_CODE_JPN; + StringCopy(&namebuf[2], name); + } + else + StringCopy(namebuf, name); + UpdateLinkBattleGameStats(outcome); + SortLinkBattleRecords(records); + i = IndexOfOpponentLinkBattleRecord(records, namebuf, trainerId); + if (i == LINK_B_RECORDS_COUNT) + { + i = LINK_B_RECORDS_COUNT - 1; + record = &records->entries[LINK_B_RECORDS_COUNT - 1]; + InitLinkBattleRecord(record); + StringCopyN(record->name, namebuf, OT_NAME_LENGTH); + record->trainerId = trainerId; + } + UpdateLinkBattleRecord(&records->entries[i], outcome); + SortLinkBattleRecords(records); +} + +void InitLinkBattleRecords(void) +{ + InitLinkBattleRecords_(&gSaveBlock2Ptr->linkBattleRecords); +} + +static void IncTrainerCardWinCount(s32 battlerId) +{ + u16 *wins = &gTrainerCards[battlerId].linkBattleWins; + (*wins)++; + if (*wins > 9999) + *wins = 9999; +} + +static void IncTrainerCardLossCount(s32 battlerId) +{ + u16 *losses = &gTrainerCards[battlerId].linkBattleLosses; + (*losses)++; + if (*losses > 9999) + *losses = 9999; +} + +static void UpdateBattleOutcomeOnTrainerCards(s32 battlerId) +{ + switch (gBattleOutcome) + { + case B_OUTCOME_WON: + IncTrainerCardWinCount(battlerId ^ 1); + IncTrainerCardLossCount(battlerId); + break; + case B_OUTCOME_LOST: + IncTrainerCardLossCount(battlerId ^ 1); + IncTrainerCardWinCount(battlerId); + break; + } +} + +void TryRecordLinkBattleOutcome(s32 battlerId) +{ + if (gSaveBlock1Ptr->location.mapGroup != MAP_GROUP(UNKNOWN_MAP_00_04) || gSaveBlock1Ptr->location.mapNum != MAP_NUM(UNKNOWN_MAP_00_04)) + { + UpdateBattleOutcomeOnTrainerCards(battlerId); + AddOpponentLinkBattleRecord(&gSaveBlock2Ptr->linkBattleRecords, gTrainerCards[battlerId].playerName, gTrainerCards[battlerId].trainerId, gBattleOutcome, gLinkPlayers[battlerId].language); + } +} + +static void PrintTotalRecord(struct LinkBattleRecords * records) +{ + u32 nwins = GetGameStat(GAME_STAT_LINK_BATTLE_WINS); + u32 nlosses = GetGameStat(GAME_STAT_LINK_BATTLE_LOSSES); + u32 ndraws = GetGameStat(GAME_STAT_LINK_BATTLE_DRAWS); + s32 i; + s32 j; + bool32 foundEnd; + u8 * strvar; + + if (nwins > 9999) + nwins = 9999; + if (nlosses > 9999) + nlosses = 9999; + if (ndraws > 9999) + ndraws = 9999; + + ConvertIntToDecimalStringN(gStringVar1, nwins, STR_CONV_MODE_LEFT_ALIGN, 4); + ConvertIntToDecimalStringN(gStringVar2, nlosses, STR_CONV_MODE_LEFT_ALIGN, 4); + ConvertIntToDecimalStringN(gStringVar3, ndraws, STR_CONV_MODE_LEFT_ALIGN, 4); + + for (i = 0; i < NELEMS(sStringVars); i++) + { + strvar = sStringVars[i]; + foundEnd = FALSE; + for (j = 0; j < 4; j++) + { + if (!foundEnd && *strvar == EOS) + foundEnd = TRUE; + if (foundEnd) + *strvar = CHAR_SPACE; + strvar++; + } + *strvar = 0xFF; + } + + StringExpandPlaceholders(gStringVar4, gString_BattleRecords_TotalRecord); + AddTextPrinterParameterized4(0, 2, 12, 24, 0, 2, &sTextColor, 0, gStringVar4); +} + +static void PrintOpponentBattleRecord(struct LinkBattleRecord * record, u8 y) +{ + u8 i = 0; + s32 x; + + if (record->wins == 0 && record->losses == 0 && record->draws == 0) + { + AddTextPrinterParameterized4(0, 2, 0, y, 0, 2, &sTextColor, 0, gString_BattleRecords_7Dashes); + for (i = 0; i < 3; i++) + { + if (i == 0) + x = 0x54; + else if (i == 1) + x = 0x84; + else + x = 0xB4; + AddTextPrinterParameterized4(0, 2, x, y, 0, 2, &sTextColor, 0, gString_BattleRecords_4Dashes); + } + } + else + { + for (i = 0; i < 4; i++) + { + if (i == 0) + { + x = 0; + StringFillWithTerminator(gStringVar1, OT_NAME_LENGTH + 1); + StringCopyN(gStringVar1, record->name, OT_NAME_LENGTH); + } + else if (i == 1) + { + x = 0x54; + ConvertIntToDecimalStringN(gStringVar1, record->wins, STR_CONV_MODE_RIGHT_ALIGN, 4); + } + else if (i == 2) + { + x = 0x84; + ConvertIntToDecimalStringN(gStringVar1, record->losses, STR_CONV_MODE_RIGHT_ALIGN, 4); + } + else + { + x = 0xB4; + ConvertIntToDecimalStringN(gStringVar1, record->draws, STR_CONV_MODE_RIGHT_ALIGN, 4); + } + AddTextPrinterParameterized4(0, 2, x, y, 0, 2, &sTextColor, 0, gStringVar1); + } + } +} + +static void PrintBattleRecords(void) +{ + u32 left; + s32 i; + + FillWindowPixelRect(0, PIXEL_FILL(0), 0, 0, 0xD8, 0x90); + StringExpandPlaceholders(gStringVar4, gString_BattleRecords_PlayersBattleResults); + left = 0xD0 - GetStringWidth(2, gStringVar4, -1); + AddTextPrinterParameterized4(0, 2, left / 2, 4, 0, 2, &sTextColor, 0, gStringVar4); + PrintTotalRecord(&gSaveBlock2Ptr->linkBattleRecords); + AddTextPrinterParameterized4(0, 2, 0x54, 0x30, 0, 2, &sTextColor, 0, gString_BattleRecords_ColumnHeaders); + for (i = 0; i < LINK_B_RECORDS_COUNT; i++) + PrintOpponentBattleRecord(&gSaveBlock2Ptr->linkBattleRecords.entries[i], 0x3D + 14 * i); + CommitWindow(0); +} + +static void CommitWindow(u8 windowId) +{ + PutWindowTilemap(windowId); + CopyWindowToVram(windowId, 3); +} + +static void LoadFrameGfxOnBg(u8 bg) +{ + LoadBgTiles(bg, sTiles, 0xC0, 0); + CopyToBgTilemapBufferRect(bg, sTilemap, 0, 0, 32, 32); + LoadPalette(sPalette, 0, 0x20); +} |