diff options
author | Evan <eroelke@gmail.com> | 2019-12-05 18:47:01 -0700 |
---|---|---|
committer | Evan <eroelke@gmail.com> | 2019-12-05 18:47:01 -0700 |
commit | af24633bf3f00e47a9d52e0ae6f1914e0f1cfa3d (patch) | |
tree | ac17b69d8ad09e56007f2396e747a4db1106c556 /src | |
parent | 67f48e5f28b1773d3570630540a082e99f7cab4e (diff) |
init branch
Diffstat (limited to 'src')
-rw-r--r-- | src/trainer_card.c | 1852 |
1 files changed, 1852 insertions, 0 deletions
diff --git a/src/trainer_card.c b/src/trainer_card.c new file mode 100644 index 000000000..095a21685 --- /dev/null +++ b/src/trainer_card.c @@ -0,0 +1,1852 @@ +#include "global.h" +#include "scanline_effect.h" +#include "palette.h" +#include "task.h" +#include "main.h" +#include "window.h" +#include "malloc.h" +#include "link.h" +#include "bg.h" +#include "sound.h" +#include "frontier_pass.h" +#include "overworld.h" +#include "menu.h" +#include "text.h" +#include "event_data.h" +#include "easy_chat.h" +#include "money.h" +#include "strings.h" +#include "string_util.h" +#include "trainer_card.h" +#include "gpu_regs.h" +#include "international_string_util.h" +#include "pokedex.h" +#include "pokemon_icon.h" +#include "graphics.h" +#include "pokemon_icon.h" +#include "trainer_pokemon_sprites.h" +#include "script_pokemon_util_80F87D8.h" +#include "constants/songs.h" +#include "constants/flags.h" +#include "constants/game_stat.h" +#include "constants/battle_frontier.h" +#include "constants/rgb.h" + +enum +{ + CARD_TYPE_FRLG, + CARD_TYPE_RS, + CARD_TYPE_EMERALD, +}; + +struct TrainerCardData +{ + u8 var_0; + u8 printState; + u8 gfxLoadState; + u8 bgPalLoadState; + u8 var_4; + bool8 isLink; + u8 var_6; + u8 var_7; + u8 var_8; + bool8 allowDMACopy; + bool8 hasPokedex; + bool8 hasHofResult; + bool8 hasLinkResults; + bool8 hasBattleTowerWins; + u8 var_E; + u8 var_F; + bool8 hasTrades; + u8 badgeCount[8]; + u8 var_19[4][0xD]; + u8 var_4D[0x46]; + u8 var_93[0x46]; + u8 var_D9[0x8C]; + u8 var_165[0x46]; + u8 var_1AB[0x8C]; + u8 var_237[0x8C]; + u8 var_2C3[0x8C]; + u8 var_34F[0x46]; + u8 var_395[0x46]; + u8 var_3DB[0x46]; + u8 var_421[0x46]; + u16 var_468[0x60]; + s8 var_528; + u8 var_529; + u8 cardType; + bool8 isHoenn; + u16 var_52C; + void (*callback2)(void); + struct TrainerCard trainerCard; + u16 var_598[0x4B0 / 2]; + u16 var_A48[0x4B0 / 2]; + u16 var_EF8[0x4B0 / 2]; + u8 var_13A8[0x400]; + u8 var_17A8[0x200]; + u8 var_19A8[0x2300]; + u16 var_3CA8[0x2000 / 2]; + u16 var_5CA8[0x2000 / 2]; + u16 var_7CA8; + u8 language; +}; + +EWRAM_DATA struct TrainerCard gTrainerCards[4] = {0}; +EWRAM_DATA static struct TrainerCardData *sTrainerCardDataPtr = NULL; + +// Function Declaration +static void VblankCb_TrainerCard(void); +static void HblankCb_TrainerCard(void); +static void sub_80C48C8(void); +static void CB2_TrainerCard(void); +static void CloseTrainerCard(u8 task); +static bool8 PrintAllOnCardPage1(void); +static void sub_80C438C(u8); +static void sub_80C4FF0(void); +static void sub_80C4550(u16*); +static void sub_80C45C0(u16*); +static void TrainerCard_PrintStarsAndBadgesOnCard(void); +static void PrintTimeOnCard(void); +static void sub_80C4918(void); +static bool8 sub_80C4940(void); +static bool8 LoadCardGfx(void); +static void CB2_InitTrainerCard(void); +static u32 GetCappedGameStat(u8 statId, u32 maxValue); +static bool8 HasAllFrontierSymbols(void); +static u8 GetRubyTrainerStars(struct TrainerCard*); +static u16 GetCaughtMonsCount(void); +static void SetPlayerCardData(struct TrainerCard*, u8); +static void TrainerCard_GenerateCardForLinkPlayer(struct TrainerCard*); +static u8 VersionToCardType(u8); +static void SetDataFromTrainerCard(void); +static void HandleGpuRegs(void); +static void ResetGpuRegs(void); +static void InitBgsAndWindows(void); +static void SetTrainerCardCb2(void); +static void sub_80C3414(void); +static void sub_80C4EE4(void); +static u8 GetSetCardType(void); +static void PrintNameOnCard(void); +static void PrintIdOnCard(void); +static void PrintMoneyOnCard(void); +static void PrintPokedexOnCard(void); +static void PrintProfilePhraseOnCard(void); +static bool8 PrintStringsOnCardPage2(void); +static void sub_80C3B50(void); +static void PrintHofDebutStringOnCard(void); +static void PrintWinsLossesStringOnCard(void); +static void PrintTradesStringOnCard(void); +static void PrintBerryCrushStringOnCard(void); +static void PrintPokeblockStringOnCard(void); +static void PrintUnionStringOnCard(void); +static void PrintContestStringOnCard(void); +static void TrainerCard_PrintPokemonIconsOnCard(void); +static void PrintBattleFacilityStringOnCard(void); +static void sub_80C42A4(void); +static void PrintAllVariableNumsOnCardPage2(void); +static void PrintNameOnCard2(void); +static void PrintHofTimeOnCard(void); +static void PrintLinkResultsNumsOnCard(void); +static void PrintTradesNumOnCard(void); +static void PrintBerryCrushNumOnCard(void); +static void PrintUnionNumOnCard(void); +static void PrintPokeblocksNumOnCard(void); +static void PrintContestNumOnCard(void); +static void PrintBattleFacilityNumsOnCard(void); +static void PrintString(u8 top, const u8* str1, u8* str2, const u8* color); +static void sub_80C4330(void); +static u8 SetCardBgsAndPals(void); +static void sub_80C474C(void); +static void sub_80C4960(u8); +static bool8 sub_80C4998(struct Task* task); +static bool8 sub_80C49D8(struct Task* task); +static bool8 sub_80C4B08(struct Task* task); +static bool8 sub_80C4C1C(struct Task* task); +static bool8 sub_80C4C84(struct Task* task); +static bool8 sub_80C4DB0(struct Task* task); +static void sub_80C32EC(u16); +static void sub_80C41D8(void); + +// const rom data +static const u32 gUnknown_0856F018[] = INCBIN_U32("graphics/trainer_card/stickers_fr.4bpp.lz"); +static const u16 gUnknown_0856F18C[] = INCBIN_U16("graphics/trainer_card/unknown_56F18C.gbapal"); +static const u16 gEmeraldTrainerCard1Star_Pal[] = INCBIN_U16("graphics/trainer_card/one_star.gbapal"); +static const u16 gFireRedTrainerCard1Star_Pal[] = INCBIN_U16("graphics/trainer_card/one_star_fr.gbapal"); +static const u16 gEmeraldTrainerCard2Star_Pal[] = INCBIN_U16("graphics/trainer_card/two_stars.gbapal"); +static const u16 gFireRedTrainerCard2Star_Pal[] = INCBIN_U16("graphics/trainer_card/two_stars_fr.gbapal"); +static const u16 gEmeraldTrainerCard3Star_Pal[] = INCBIN_U16("graphics/trainer_card/three_stars.gbapal"); +static const u16 gFireRedTrainerCard3Star_Pal[] = INCBIN_U16("graphics/trainer_card/three_stars_fr.gbapal"); +static const u16 gEmeraldTrainerCard4Star_Pal[] = INCBIN_U16("graphics/trainer_card/four_stars.gbapal"); +static const u16 gFireRedTrainerCard4Star_Pal[] = INCBIN_U16("graphics/trainer_card/four_stars_fr.gbapal"); +static const u16 sEmeraldTrainerCardFemaleBackground_Pal[] = INCBIN_U16("graphics/trainer_card/female_bg.gbapal"); +static const u16 sFireRedTrainerCardFemaleBackground_Pal[] = INCBIN_U16("graphics/trainer_card/female_bg_fr.gbapal"); +static const u16 sEmeraldTrainerCardBadges_Pal[] = INCBIN_U16("graphics/trainer_card/badges.gbapal"); +static const u16 sFireRedTrainerCardBadges_Pal[] = INCBIN_U16("graphics/trainer_card/badges_fr.gbapal"); +static const u16 gUnknown_0856F52C[] = INCBIN_U16("graphics/trainer_card/gold.gbapal"); +static const u16 gUnknown_0856F54C[] = INCBIN_U16("graphics/trainer_card/stickers_fr1.gbapal"); +static const u16 gUnknown_0856F56C[] = INCBIN_U16("graphics/trainer_card/stickers_fr2.gbapal"); +static const u16 gUnknown_0856F58C[] = INCBIN_U16("graphics/trainer_card/stickers_fr3.gbapal"); +static const u16 gUnknown_0856F5AC[] = INCBIN_U16("graphics/trainer_card/stickers_fr4.gbapal"); +static const u32 sEmeraldTrainerCardBadges_Tile[] = INCBIN_U32("graphics/trainer_card/badges.4bpp.lz"); +static const u32 sFireRedTrainerCardBadges_Tile[] = INCBIN_U32("graphics/trainer_card/badges_fr.4bpp.lz"); + +static const struct BgTemplate gUnknown_0856FAB4[4] = +{ + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 27, + .screenSize = 2, + .paletteMode = 0, + .priority = 2, + .baseTile = 0 + }, + { + .bg = 1, + .charBaseIndex = 2, + .mapBaseIndex = 29, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0 + }, + { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0 + }, + { + .bg = 3, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 192 + }, +}; + +static const struct WindowTemplate gUnknown_0856FAC4[] = +{ + { + .bg = 1, + .tilemapLeft = 2, + .tilemapTop = 15, + .width = 27, + .height = 4, + .paletteNum = 15, + .baseBlock = 0x253, + }, + { + .bg = 1, + .tilemapLeft = 1, + .tilemapTop = 1, + .width = 28, + .height = 18, + .paletteNum = 15, + .baseBlock = 0x1, + }, + { + .bg = 3, + .tilemapLeft = 19, + .tilemapTop = 5, + .width = 9, + .height = 10, + .paletteNum = 8, + .baseBlock = 0x150, + }, + DUMMY_WIN_TEMPLATE +}; + +static const u16 *const gEmeraldTrainerCardStarPals[] = +{ + gEmeraldTrainerCard0Star_Pal, + gEmeraldTrainerCard1Star_Pal, + gEmeraldTrainerCard2Star_Pal, + gEmeraldTrainerCard3Star_Pal, + gEmeraldTrainerCard4Star_Pal, +}; + +static const u16 *const gFireRedTrainerCardStarPals[] = +{ + gFireRedTrainerCard0Star_Pal, + gFireRedTrainerCard1Star_Pal, + gFireRedTrainerCard2Star_Pal, + gFireRedTrainerCard3Star_Pal, + gFireRedTrainerCard4Star_Pal, +}; + +static const u8 gUnknown_0856FB0C[] = {0, 2, 3}; +static const u8 gUnknown_0856FB0F[] = {0, 4, 5}; +static const u8 gUnknown_0856FB12[6] = {0}; + +static const u8 gUnknown_0856FB18[][2][2] = +{ + {{0xD, 4}, {0xD, 4}}, + {{1, 0}, {1, 0}}, +}; + +static const u8 gUnknown_0856FB20[][2] = {{0x4E, 0x4F}, {0x50, 0x51}, {0x3C, 0x3F}}; + +static bool8 (*const gUnknown_0856FB28[])(struct Task *) = +{ + sub_80C4998, + sub_80C49D8, + sub_80C4B08, + sub_80C4C1C, + sub_80C4C84, + sub_80C4DB0, +}; + +// Functions +static void VblankCb_TrainerCard(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); + sub_80C48C8(); + if (sTrainerCardDataPtr->allowDMACopy) + DmaCopy16(3, &gScanlineEffectRegBuffers[0], &gScanlineEffectRegBuffers[1], 0x140); +} + +static void HblankCb_TrainerCard(void) +{ + u16 backup; + u16 bgVOffset; + + backup = REG_IME; + REG_IME = 0; + bgVOffset = gScanlineEffectRegBuffers[1][REG_VCOUNT & 0xFF]; + REG_BG0VOFS = bgVOffset; + REG_IME = backup; +} + +static void CB2_TrainerCard(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +static void CloseTrainerCard(u8 taskId) +{ + SetMainCallback2(sTrainerCardDataPtr->callback2); + FreeAllWindowBuffers(); + FREE_AND_SET_NULL(sTrainerCardDataPtr); + DestroyTask(taskId); +} + +static void Task_TrainerCard(u8 taskId) +{ + switch (sTrainerCardDataPtr->var_0) + { + case 0: + if (!IsDma3ManagerBusyWithBgCopy()) + { + FillWindowPixelBuffer(1, PIXEL_FILL(0)); + sTrainerCardDataPtr->var_0++; + } + break; + case 1: + if (PrintAllOnCardPage1()) + sTrainerCardDataPtr->var_0++; + break; + case 2: + sub_80C438C(1); + sTrainerCardDataPtr->var_0++; + break; + case 3: + FillWindowPixelBuffer(2, PIXEL_FILL(0)); + sub_80C4FF0(); + sub_80C438C(2); + sTrainerCardDataPtr->var_0++; + break; + case 4: + sub_80C4550(sTrainerCardDataPtr->var_EF8); + sTrainerCardDataPtr->var_0++; + break; + case 5: + sub_80C45C0(sTrainerCardDataPtr->var_598); + sTrainerCardDataPtr->var_0++; + break; + case 6: + TrainerCard_PrintStarsAndBadgesOnCard(); + sTrainerCardDataPtr->var_0++; + break; + case 7: + if (gWirelessCommType == 1 && gReceivedRemoteLinkPlayers == TRUE) + { + LoadWirelessStatusIndicatorSpriteGfx(); + CreateWirelessStatusIndicatorSprite(230, 150); + } + BlendPalettes(0xFFFFFFFF, 16, sTrainerCardDataPtr->var_52C); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, sTrainerCardDataPtr->var_52C); + SetVBlankCallback(VblankCb_TrainerCard); + sTrainerCardDataPtr->var_0++; + break; + case 8: + if (!UpdatePaletteFade() && !IsDma3ManagerBusyWithBgCopy()) + { + PlaySE(SE_RG_CARD3); + sTrainerCardDataPtr->var_0 = 10; + } + break; + case 9: + if (!IsSEPlaying()) + sTrainerCardDataPtr->var_0++; + break; + case 10: + if (!gReceivedRemoteLinkPlayers && sTrainerCardDataPtr->var_529) + { + PrintTimeOnCard(); + sub_80C438C(1); + sTrainerCardDataPtr->var_529 = 0; + } + if (gMain.newKeys & A_BUTTON) + { + sub_80C4918(); + PlaySE(SE_RG_CARD1); + sTrainerCardDataPtr->var_0 = 12; + } + else if (gMain.newKeys & B_BUTTON) + { + if (gReceivedRemoteLinkPlayers && sTrainerCardDataPtr->isLink && InUnionRoom() == TRUE) + { + sTrainerCardDataPtr->var_0 = 15; + } + else + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, sTrainerCardDataPtr->var_52C); + sTrainerCardDataPtr->var_0 = 14; + } + } + break; + case 12: + if (sub_80C4940() && sub_8087598() != TRUE) + { + PlaySE(SE_RG_CARD3); + sTrainerCardDataPtr->var_0 = 11; + } + break; + case 11: + if (gMain.newKeys & B_BUTTON) + { + if (gReceivedRemoteLinkPlayers && sTrainerCardDataPtr->isLink && InUnionRoom() == TRUE) + { + sTrainerCardDataPtr->var_0 = 15; + } + else if (gReceivedRemoteLinkPlayers) + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, sTrainerCardDataPtr->var_52C); + sTrainerCardDataPtr->var_0 = 14; + } + else + { + sub_80C4918(); + sTrainerCardDataPtr->var_0 = 13; + PlaySE(SE_RG_CARD1); + } + } + else if (gMain.newKeys & A_BUTTON) + { + if (gReceivedRemoteLinkPlayers && sTrainerCardDataPtr->isLink && InUnionRoom() == TRUE) + { + sTrainerCardDataPtr->var_0 = 15; + } + else + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, sTrainerCardDataPtr->var_52C); + sTrainerCardDataPtr->var_0 = 14; + } + } + break; + case 15: + sub_800AC34(); + DrawDialogueFrame(0, 1); + AddTextPrinterParameterized(0, 1, gText_WaitingTrainerFinishReading, 0, 1, 255, 0); + CopyWindowToVram(0, 3); + sTrainerCardDataPtr->var_0 = 16; + break; + case 16: + if (!gReceivedRemoteLinkPlayers) + { + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, sTrainerCardDataPtr->var_52C); + sTrainerCardDataPtr->var_0 = 14; + } + break; + case 14: + if (!UpdatePaletteFade()) + CloseTrainerCard(taskId); + break; + case 13: + if (sub_80C4940() && sub_8087598() != TRUE) + { + sTrainerCardDataPtr->var_0 = 10; + PlaySE(SE_RG_CARD3); + } + break; + } +} + +static bool8 LoadCardGfx(void) +{ + switch (sTrainerCardDataPtr->gfxLoadState) + { + case 0: + if (sTrainerCardDataPtr->cardType == CARD_TYPE_RS) + LZ77UnCompWram(gUnknown_83CCE30, sTrainerCardDataPtr->unk_E1C); + else + LZ77UnCompWram(gUnknown_83CCEC8, sTrainerCardDataPtr->unk_E1C); + break; + case 1: + if (sTrainerCardDataPtr->cardType == CARD_TYPE_RS) + LZ77UnCompWram(gUnknown_83CC8A8, sTrainerCardDataPtr->unk_96C); + else + LZ77UnCompWram(gUnknown_83CC984, sTrainerCardDataPtr->unk_96C); + break; + case 2: + if (!sTrainerCardDataPtr->isLink) + { + if (sTrainerCardDataPtr->cardType == CARD_TYPE_RS) + LZ77UnCompWram(gUnknown_83CC4DC, sTrainerCardDataPtr->unk_4BC); + else + LZ77UnCompWram(gUnknown_83CC6F0, sTrainerCardDataPtr->unk_4BC); + } + else + { + if (sTrainerCardDataPtr->cardType == CARD_TYPE_RS) + LZ77UnCompWram(gUnknown_83CCAB0, sTrainerCardDataPtr->unk_4BC); + else + LZ77UnCompWram(gUnknown_83CCCA4, sTrainerCardDataPtr->unk_4BC); + } + break; + case 3: + LZ77UnCompWram(sTrainerCardBadges_Tile, sTrainerCardDataPtr->var_12CC); + break; + case 4: + if (sTrainerCardDataPtr->cardType == CARD_TYPE_RS) + LZ77UnCompWram(gEmeraldTrainerCard_Gfx, sTrainerCardDataPtr->var_18CC); + else + LZ77UnCompWram(gFireRedTrainerCard_Gfx, sTrainerCardDataPtr->var_18CC); + break; + case 5: + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG) + LZ77UnCompWram(gTrainerCardIcons, sTrainerCardDataPtr->var_16CC); + break; + default: + sTrainerCardDataPtr->gfxLoadState = 0; + return TRUE; + } + sTrainerCardDataPtr->gfxLoadState++; + return FALSE; +} + +static void CB2_InitTrainerCard(void) +{ + switch (gMain.state) + { + case 0: + ResetGpuRegs(); + sub_80C3414(); + gMain.state++; + break; + case 1: + DmaClear32(3, (void *)OAM, OAM_SIZE); + gMain.state++; + break; + case 2: + if (!sTrainerCardDataPtr->var_52C) + DmaClear16(3, (void *)PLTT, PLTT_SIZE); + gMain.state++; + break; + case 3: + ResetSpriteData(); + FreeAllSpritePalettes(); + ResetPaletteFade(); + gMain.state++; + case 4: + InitBgsAndWindows(); + gMain.state++; + break; + case 5: + sub_80C41D8(); + gMain.state++; + break; + case 6: + if (LoadCardGfx() == TRUE) + gMain.state++; + break; + case 7: + sub_80C4330(); + gMain.state++; + break; + case 8: + HandleGpuRegs(); + gMain.state++; + break; + case 9: + PrintAllVariableNumsOnCardPage2(); + gMain.state++; + break; + case 10: + if (SetCardBgsAndPals() == TRUE) + gMain.state++; + break; + default: + SetTrainerCardCb2(); + break; + } +} + +static u32 GetCappedGameStat(u8 statId, u32 maxValue) +{ + u32 statValue = GetGameStat(statId); + + return min(maxValue, statValue); +} + +static bool8 HasAllFrontierSymbols(void) +{ + u8 i; + for (i = 0; i < NUM_FRONTIER_FACILITIES; i++) + { + if (!FlagGet(FLAG_SYS_TOWER_SILVER + 2 * i) || !FlagGet(FLAG_SYS_TOWER_GOLD + 2 * i)) + return FALSE; + } + return TRUE; +} + +u32 CountPlayerTrainerStars(void) +{ + u8 stars = 0; + + if (GetGameStat(GAME_STAT_ENTERED_HOF)) + stars++; + if (HasAllHoennMons()) + stars++; + if (CountPlayerContestPaintings() > 4) + stars++; + if (HasAllFrontierSymbols()) + stars++; + + return stars; +} + +static u8 GetRubyTrainerStars(struct TrainerCard *trainerCard) +{ + u8 stars = 0; + + if (trainerCard->hofDebutHours || trainerCard->hofDebutMinutes || trainerCard->hofDebutSeconds) + stars++; + if (trainerCard->caughtAllHoenn) + stars++; + if (trainerCard->battleTowerStraightWins > 49) + stars++; + if (trainerCard->hasAllPaintings) + stars++; + + return stars; +} + +static void SetPlayerCardData(struct TrainerCard *trainerCard, u8 cardType) +{ + u32 playTime; + u8 i; + + trainerCard->gender = gSaveBlock2Ptr->playerGender; + trainerCard->playTimeHours = gSaveBlock2Ptr->playTimeHours; + trainerCard->playTimeMinutes = gSaveBlock2Ptr->playTimeMinutes; + + playTime = GetGameStat(GAME_STAT_FIRST_HOF_PLAY_TIME); + if (!GetGameStat(GAME_STAT_ENTERED_HOF)) + playTime = 0; + + trainerCard->hofDebutHours = playTime >> 16; + trainerCard->hofDebutMinutes = (playTime >> 8) & 0xFF; + trainerCard->hofDebutSeconds = playTime & 0xFF; + if ((playTime >> 16) > 999) + { + trainerCard->hofDebutHours = 999; + trainerCard->hofDebutMinutes = 59; + trainerCard->hofDebutSeconds = 59; + } + + trainerCard->hasPokedex = FlagGet(FLAG_SYS_POKEDEX_GET); + trainerCard->caughtAllHoenn = HasAllHoennMons(); + trainerCard->caughtMonsCount = GetCaughtMonsCount(); + + trainerCard->trainerId = (gSaveBlock2Ptr->playerTrainerId[1] << 8) | gSaveBlock2Ptr->playerTrainerId[0]; + + trainerCard->linkBattleWins = GetCappedGameStat(GAME_STAT_LINK_BATTLE_WINS, 9999); + trainerCard->linkBattleLosses = GetCappedGameStat(GAME_STAT_LINK_BATTLE_LOSSES, 9999); + + trainerCard->pokemonTrades = GetCappedGameStat(GAME_STAT_POKEMON_TRADES, 0xFFFF); + + trainerCard->money = GetMoney(&gSaveBlock1Ptr->money); + + for (i = 0; i < 4; i++) + trainerCard->var_28[i] = gSaveBlock1Ptr->easyChatProfile[i]; + + StringCopy(trainerCard->playerName, gSaveBlock2Ptr->playerName); + + switch (cardType) + { + case CARD_TYPE_EMERALD: + trainerCard->battleTowerWins = 0; + trainerCard->battleTowerStraightWins = 0; + // Seems like GF got CARD_TYPE_FRLG and CARD_TYPE_RS wrong. + case CARD_TYPE_FRLG: + trainerCard->contestsWithFriends = GetCappedGameStat(GAME_STAT_WON_LINK_CONTEST, 999); + trainerCard->pokeblocksWithFriends = GetCappedGameStat(GAME_STAT_POKEBLOCKS_WITH_FRIENDS, 0xFFFF); + if (CountPlayerContestPaintings() > 4) + trainerCard->hasAllPaintings = TRUE; + trainerCard->stars = GetRubyTrainerStars(trainerCard); + break; + case CARD_TYPE_RS: + trainerCard->battleTowerWins = 0; + trainerCard->battleTowerStraightWins = 0; + trainerCard->contestsWithFriends = 0; + trainerCard->pokeblocksWithFriends = 0; + trainerCard->hasAllPaintings = 0; + trainerCard->stars = 0; + break; + } +} + +static void TrainerCard_GenerateCardForLinkPlayer(struct TrainerCard *trainerCard) +{ + memset(trainerCard, 0, sizeof(struct TrainerCard)); + trainerCard->version = GAME_VERSION; + SetPlayerCardData(trainerCard, CARD_TYPE_EMERALD); + trainerCard->hasAllSymbols = HasAllFrontierSymbols(); + trainerCard->frontierBP = gSaveBlock2Ptr->frontier.cardBattlePoints; + if (trainerCard->hasAllSymbols) + trainerCard->stars++; + + if (trainerCard->gender == FEMALE) + trainerCard->var_4F = gLinkPlayerFacilityClasses[(trainerCard->trainerId % 8) + 8]; + else + trainerCard->var_4F = gLinkPlayerFacilityClasses[trainerCard->trainerId % 8]; +} + +void TrainerCard_GenerateCardForPlayer(struct TrainerCard *trainerCard) +{ + memset(trainerCard, 0, 0x60); + trainerCard->version = GAME_VERSION; + SetPlayerCardData(trainerCard, CARD_TYPE_EMERALD); + trainerCard->var_3A = HasAllFrontierSymbols(); + *((u16*)&trainerCard->berryCrushPoints) = gSaveBlock2Ptr->frontier.cardBattlePoints; + if (trainerCard->var_3A) + trainerCard->stars++; + + if (trainerCard->gender == FEMALE) + trainerCard->var_4F = gLinkPlayerFacilityClasses[(trainerCard->trainerId % 8) + 8]; + else + trainerCard->var_4F = gLinkPlayerFacilityClasses[trainerCard->trainerId % 8]; +} + +void CopyTrainerCardData(struct TrainerCard *dst, u16 *src, u8 gameVersion) +{ + memset(dst, 0, sizeof(struct TrainerCard)); + dst->version = gameVersion; + + switch (VersionToCardType(gameVersion)) + { + case CARD_TYPE_FRLG: + memcpy(dst, src, 0x60); + break; + case CARD_TYPE_RS: + memcpy(dst, src, 0x38); + break; + case CARD_TYPE_EMERALD: + memcpy(dst, src, 0x60); + dst->berryCrushPoints = 0; + dst->hasAllSymbols = src[29]; + dst->frontierBP = src[30]; + break; + } +} + +static void SetDataFromTrainerCard(void) +{ + u8 i; + u32 badgeFlag; + + sTrainerCardDataPtr->hasPokedex = FALSE; + sTrainerCardDataPtr->hasHofResult = FALSE; + sTrainerCardDataPtr->hasLinkResults = FALSE; + sTrainerCardDataPtr->hasBattleTowerWins = FALSE; + sTrainerCardDataPtr->var_E = 0; + sTrainerCardDataPtr->var_F = 0; + sTrainerCardDataPtr->hasTrades = FALSE; + memset(sTrainerCardDataPtr->badgeCount, 0, sizeof(sTrainerCardDataPtr->badgeCount)); + if (sTrainerCardDataPtr->trainerCard.hasPokedex) + sTrainerCardDataPtr->hasPokedex++; + + if (sTrainerCardDataPtr->trainerCard.hofDebutHours + || sTrainerCardDataPtr->trainerCard.hofDebutMinutes + || sTrainerCardDataPtr->trainerCard.hofDebutSeconds) + sTrainerCardDataPtr->hasHofResult++; + + if (sTrainerCardDataPtr->trainerCard.linkBattleWins || sTrainerCardDataPtr->trainerCard.linkBattleLosses) + sTrainerCardDataPtr->hasLinkResults++; + if (sTrainerCardDataPtr->trainerCard.pokemonTrades) + sTrainerCardDataPtr->hasTrades++; + if (sTrainerCardDataPtr->trainerCard.battleTowerWins || sTrainerCardDataPtr->trainerCard.battleTowerStraightWins) + sTrainerCardDataPtr->hasBattleTowerWins++; + + for (i = 0, badgeFlag = FLAG_BADGE01_GET; badgeFlag <= FLAG_BADGE08_GET; badgeFlag++, i++) + { + if (FlagGet(badgeFlag)) + sTrainerCardDataPtr->badgeCount[i]++; + } +} + +static void HandleGpuRegs(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON | DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG0 | BLDCNT_EFFECT_DARKEN); + SetGpuReg(REG_OFFSET_BLDY, 0); + SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR); + SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ); + SetGpuReg(REG_OFFSET_WIN0V, 160); + SetGpuReg(REG_OFFSET_WIN0H, 240); + if (gReceivedRemoteLinkPlayers) + EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_HBLANK | INTR_FLAG_VCOUNT | INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); + else + EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_HBLANK); +} + +static void sub_80C32EC(u16 arg0) +{ + s8 quotient = (arg0 + 40) / 10; + + if (quotient <= 4) + quotient = 0; + sTrainerCardDataPtr->var_528 = quotient; + SetGpuReg(REG_OFFSET_BLDY, sTrainerCardDataPtr->var_528); + SetGpuReg(REG_OFFSET_WIN0V, (sTrainerCardDataPtr->var_7CA8 * 256) | (160 - sTrainerCardDataPtr->var_7CA8)); +} + +static void ResetGpuRegs(void) +{ + SetVBlankCallback(NULL); + SetHBlankCallback(NULL); + SetGpuReg(REG_OFFSET_DISPCNT, 0); + SetGpuReg(REG_OFFSET_BG0CNT, 0); + SetGpuReg(REG_OFFSET_BG1CNT, 0); + SetGpuReg(REG_OFFSET_BG2CNT, 0); + SetGpuReg(REG_OFFSET_BG3CNT, 0); +} + +static void InitBgsAndWindows(void) +{ + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, gUnknown_0856FAB4, ARRAY_COUNT(gUnknown_0856FAB4)); + 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); + InitWindows(gUnknown_0856FAC4); + DeactivateAllTextPrinters(); + sub_81973A4(); +} + +static void SetTrainerCardCb2(void) +{ + SetMainCallback2(CB2_TrainerCard); +} + +static void sub_80C3414(void) +{ + ResetTasks(); + ScanlineEffect_Stop(); + CreateTask(Task_TrainerCard, 0); + sub_80C4EE4(); + SetDataFromTrainerCard(); +} + +static bool8 PrintAllOnCardPage1(void) +{ + switch (sTrainerCardDataPtr->printState) + { + case 0: + PrintNameOnCard(); + break; + case 1: + PrintIdOnCard(); + break; + case 2: + PrintMoneyOnCard(); + break; + case 3: + PrintPokedexOnCard(); + break; + case 4: + PrintTimeOnCard(); + break; + case 5: + PrintProfilePhraseOnCard(); + break; + default: + sTrainerCardDataPtr->printState = 0; + return TRUE; + } + sTrainerCardDataPtr->printState++; + return FALSE; +} + +static bool8 PrintStringsOnCardPage2(void) +{ + switch (sTrainerCardDataPtr->printState) + { + case 0: + sub_80C3B50(); + break; + case 1: + PrintHofDebutStringOnCard(); + break; + case 2: + PrintWinsLossesStringOnCard(); + break; + case 3: + PrintTradesStringOnCard(); + break; + case 4: + PrintBerryCrushStringOnCard(); + PrintPokeblockStringOnCard(); + break; + case 5: + PrintUnionStringOnCard(); + PrintContestStringOnCard(); + break; + case 6: + TrainerCard_PrintPokemonIconsOnCard(); + PrintBattleFacilityStringOnCard(); + break; + case 7: + sub_80C42A4(); + break; + default: + sTrainerCardDataPtr->printState = 0; + return TRUE; + } + sTrainerCardDataPtr->printState++; + return FALSE; +} + +static void PrintAllVariableNumsOnCardPage2(void) +{ + PrintNameOnCard2(); + PrintHofTimeOnCard(); + PrintLinkResultsNumsOnCard(); + PrintTradesNumOnCard(); + PrintBerryCrushNumOnCard(); + PrintUnionNumOnCard(); + PrintPokeblocksNumOnCard(); + PrintContestNumOnCard(); + PrintBattleFacilityNumsOnCard(); +} + +static void PrintNameOnCard(void) +{ + u8 buffer[32]; + u8* txtPtr; + txtPtr = StringCopy(buffer, gText_TrainerCardName); + StringCopy(txtPtr, sTrainerCardDataPtr->trainerCard.playerName); + ConvertInternationalString(txtPtr, sTrainerCardDataPtr->language); + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG) + AddTextPrinterParameterized3(1, 1, 20, 28, gUnknown_0856FB0C, TEXT_SPEED_FF, buffer); + else + AddTextPrinterParameterized3(1, 1, 16, 33, gUnknown_0856FB0C, TEXT_SPEED_FF, buffer); +} + +static void PrintIdOnCard(void) +{ + u8 buffer[32]; + u8* txtPtr; + s32 xPos; + u32 top; + txtPtr = StringCopy(buffer, gText_TrainerCardIDNo); + ConvertIntToDecimalStringN(txtPtr, sTrainerCardDataPtr->trainerCard.trainerId, STR_CONV_MODE_LEADING_ZEROS, 5); + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG) + { + xPos = GetStringCenterAlignXOffset(1, buffer, 80) + 132; + top = 9; + } + else + { + xPos = GetStringCenterAlignXOffset(1, buffer, 96) + 120; + top = 9; + } + + AddTextPrinterParameterized3(1, 1, xPos, top, gUnknown_0856FB0C, TEXT_SPEED_FF, buffer); +} + +static void PrintMoneyOnCard(void) +{ + s32 xOffset; + u8 top; + + if (!sTrainerCardDataPtr->isHoenn) + AddTextPrinterParameterized3(1, 1, 20, 56, gUnknown_0856FB0C, TEXT_SPEED_FF, gText_TrainerCardMoney); + else + AddTextPrinterParameterized3(1, 1, 16, 57, gUnknown_0856FB0C, TEXT_SPEED_FF, gText_TrainerCardMoney); + + ConvertIntToDecimalStringN(gStringVar1, sTrainerCardDataPtr->trainerCard.money, STR_CONV_MODE_LEFT_ALIGN, 6); + StringExpandPlaceholders(gStringVar4, gText_PokedollarVar1); + if (!sTrainerCardDataPtr->isHoenn) + { + xOffset = GetStringRightAlignXOffset(1, gStringVar4, 144); + top = 56; + } + else + { + xOffset = GetStringRightAlignXOffset(1, gStringVar4, 128); + top = 57; + } + AddTextPrinterParameterized3(1, 1, xOffset, top, gUnknown_0856FB0C, TEXT_SPEED_FF, gStringVar4); +} + +static u16 GetCaughtMonsCount(void) +{ + if (IsNationalPokedexEnabled()) + return GetNationalPokedexCount(FLAG_GET_CAUGHT); + else + return GetHoennPokedexCount(FLAG_GET_CAUGHT); +} + +static void PrintPokedexOnCard(void) +{ + s32 xOffset; + u8 top; + if (FlagGet(FLAG_SYS_POKEDEX_GET)) + { + if (!sTrainerCardDataPtr->isHoenn) + AddTextPrinterParameterized3(1, 1, 20, 72, gUnknown_0856FB0C, TEXT_SPEED_FF, gText_TrainerCardPokedex); + else + AddTextPrinterParameterized3(1, 1, 16, 73, gUnknown_0856FB0C, TEXT_SPEED_FF, gText_TrainerCardPokedex); + StringCopy(ConvertIntToDecimalStringN(gStringVar4, sTrainerCardDataPtr->trainerCard.caughtMonsCount, STR_CONV_MODE_LEFT_ALIGN, 3), gText_EmptyString6); + if (!sTrainerCardDataPtr->isHoenn) + { + xOffset = GetStringRightAlignXOffset(1, gStringVar4, 144); + top = 72; + } + else + { + xOffset = GetStringRightAlignXOffset(1, gStringVar4, 128); + top = 73; + } + AddTextPrinterParameterized3(1, 1, xOffset, top, gUnknown_0856FB0C, TEXT_SPEED_FF, gStringVar4); + } +} + +static const u8 *const gUnknown_0856FB40[] = {gUnknown_0856FB0C, gUnknown_0856FB12}; + +static void PrintTimeOnCard(void) +{ + u16 hours; + u16 minutes; + s32 width; + u32 r7, r4, r10; + + if (!sTrainerCardDataPtr->isHoenn) + AddTextPrinterParameterized3(1, 1, 20, 88, gUnknown_0856FB0C, TEXT_SPEED_FF, gText_TrainerCardTime); + else + AddTextPrinterParameterized3(1, 1, 16, 89, gUnknown_0856FB0C, TEXT_SPEED_FF, gText_TrainerCardTime); + + if (sTrainerCardDataPtr->isLink) + { + hours = sTrainerCardDataPtr->trainerCard.playTimeHours; + minutes = sTrainerCardDataPtr->trainerCard.playTimeMinutes; + } + else + { + hours = gSaveBlock2Ptr->playTimeHours; + minutes = gSaveBlock2Ptr->playTimeMinutes; + } + + if (hours > 999) + hours = 999; + if (minutes > 59) + minutes = 59; + width = GetStringWidth(1, gText_Colon2, 0); + + if (!sTrainerCardDataPtr->isHoenn) + { + r7 = 144; + r4 = 88; + } + else + { + r7 = 128; + r4 = 89; + } + r10 = width + 30; + r7 -= r10; + + FillWindowPixelRect(1, PIXEL_FILL(0), r7, r4, r10, 15); + ConvertIntToDecimalStringN(gStringVar4, hours, STR_CONV_MODE_RIGHT_ALIGN, 3); + AddTextPrinterParameterized3(1, 1, r7, r4, gUnknown_0856FB0C, TEXT_SPEED_FF, gStringVar4); + r7 += 18; + AddTextPrinterParameterized3(1, 1, r7, r4, gUnknown_0856FB40[sTrainerCardDataPtr->var_7], TEXT_SPEED_FF, gText_Colon2); + r7 += width; + ConvertIntToDecimalStringN(gStringVar4, minutes, STR_CONV_MODE_LEADING_ZEROS, 2); + AddTextPrinterParameterized3(1, 1, r7, r4, gUnknown_0856FB0C, TEXT_SPEED_FF, gStringVar4); +} + +static const u8 gUnknown_0856FB48[] = {0x71, 0x68}; +static const u8 gUnknown_0856FB4A[] = {0x81, 0x78}; + +static void PrintProfilePhraseOnCard(void) +{ + if (sTrainerCardDataPtr->isLink) + { + AddTextPrinterParameterized3(1, 1, 8, gUnknown_0856FB48[sTrainerCardDataPtr->isHoenn], gUnknown_0856FB0C, TEXT_SPEED_FF, sTrainerCardDataPtr->var_19[0]); + AddTextPrinterParameterized3(1, 1, GetStringWidth(1, sTrainerCardDataPtr->var_19[0], 0) + 14, gUnknown_0856FB48[sTrainerCardDataPtr->isHoenn], gUnknown_0856FB0C, TEXT_SPEED_FF, sTrainerCardDataPtr->var_19[1]); + AddTextPrinterParameterized3(1, 1, 8, gUnknown_0856FB4A[sTrainerCardDataPtr->isHoenn], gUnknown_0856FB0C, TEXT_SPEED_FF, sTrainerCardDataPtr->var_19[2]); + AddTextPrinterParameterized3(1, 1, GetStringWidth(1, sTrainerCardDataPtr->var_19[2], 0) + 14, gUnknown_0856FB4A[sTrainerCardDataPtr->isHoenn], gUnknown_0856FB0C, TEXT_SPEED_FF, sTrainerCardDataPtr->var_19[3]); + } +} + +static void PrintNameOnCard2(void) +{ + StringCopy(sTrainerCardDataPtr->var_4D, sTrainerCardDataPtr->trainerCard.playerName); + ConvertInternationalString(sTrainerCardDataPtr->var_4D, sTrainerCardDataPtr->language); + if (sTrainerCardDataPtr->cardType != CARD_TYPE_FRLG) + { + StringCopy(gStringVar1, sTrainerCardDataPtr->var_4D); + StringExpandPlaceholders(sTrainerCardDataPtr->var_4D, gText_Var1sTrainerCard); + } +} + +static void sub_80C3B50(void) +{ + if (!sTrainerCardDataPtr->isHoenn) + AddTextPrinterParameterized3(1, 1, 136, 9, gUnknown_0856FB0C, TEXT_SPEED_FF, sTrainerCardDataPtr->var_4D); + else + AddTextPrinterParameterized3(1, 1, GetStringRightAlignXOffset(1, sTrainerCardDataPtr->var_4D, 216), 9, gUnknown_0856FB0C, TEXT_SPEED_FF, sTrainerCardDataPtr->var_4D); +} + +static const u8 gUnknown_0856FB4C[] = {0xfd, 0x02, 0xf0, 0xfd, 0x03, 0xf0, 0xfd, 0x04, 0xff}; + +static void PrintHofTimeOnCard(void) +{ + if (sTrainerCardDataPtr->hasHofResult) + { + ConvertIntToDecimalStringN(gStringVar1, sTrainerCardDataPtr->trainerCard.hofDebutHours, STR_CONV_MODE_RIGHT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar2, sTrainerCardDataPtr->trainerCard.hofDebutMinutes, STR_CONV_MODE_LEADING_ZEROS, 2); + ConvertIntToDecimalStringN(gStringVar3, sTrainerCardDataPtr->trainerCard.hofDebutSeconds, STR_CONV_MODE_LEADING_ZEROS, 2); + StringExpandPlaceholders(sTrainerCardDataPtr->var_93, gUnknown_0856FB4C); + } +} + +static const u8 gUnknown_0856FB55[] = {0x08, 0x10}; +static const u8 gUnknown_0856FB57[] = {0xd8, 0xd8}; + +static void PrintString(u8 top, const u8* str1, u8* str2, const u8* color) +{ + AddTextPrinterParameterized3(1, 1, gUnknown_0856FB55[sTrainerCardDataPtr->isHoenn], top * 16 + 33, gUnknown_0856FB0C, TEXT_SPEED_FF, str1); + AddTextPrinterParameterized3(1, 1, GetStringRightAlignXOffset(1, str2, gUnknown_0856FB57[sTrainerCardDataPtr->isHoenn]), top * 16 + 33, color, TEXT_SPEED_FF, str2); +} + +static void PrintHofDebutStringOnCard(void) +{ + if (sTrainerCardDataPtr->hasHofResult) + PrintString(0, gText_HallOfFameDebut, sTrainerCardDataPtr->var_93, gUnknown_0856FB0F); +} + +static const u8 *const gUnknown_0856FB5C[] = {gText_LinkBattles, gText_LinkCableBattles, gText_LinkBattles}; + +static void PrintLinkResultsNumsOnCard(void) +{ + if (sTrainerCardDataPtr->hasLinkResults) + { + StringCopy(sTrainerCardDataPtr->var_D9, gUnknown_0856FB5C[sTrainerCardDataPtr->cardType]); + ConvertIntToDecimalStringN(sTrainerCardDataPtr->var_165, sTrainerCardDataPtr->trainerCard.linkBattleWins, STR_CONV_MODE_LEFT_ALIGN, 4); + ConvertIntToDecimalStringN(sTrainerCardDataPtr->var_1AB, sTrainerCardDataPtr->trainerCard.linkBattleLosses, STR_CONV_MODE_LEFT_ALIGN, 4); + } +} + +static void PrintWinsLossesStringOnCard(void) +{ + if (sTrainerCardDataPtr->hasLinkResults) + { + StringCopy(gStringVar1, sTrainerCardDataPtr->var_165); + StringCopy(gStringVar2, sTrainerCardDataPtr->var_1AB); + StringExpandPlaceholders(gStringVar4, gText_WinsLosses); + PrintString(1, sTrainerCardDataPtr->var_D9, gStringVar4, gUnknown_0856FB0C); + } +} + +static void PrintTradesNumOnCard(void) +{ + if (sTrainerCardDataPtr->hasTrades) + ConvertIntToDecimalStringN(sTrainerCardDataPtr->var_237, sTrainerCardDataPtr->trainerCard.pokemonTrades, STR_CONV_MODE_RIGHT_ALIGN, 5); +} + +static void PrintTradesStringOnCard(void) +{ + if (sTrainerCardDataPtr->hasTrades) + PrintString(2, gText_PokemonTrades, sTrainerCardDataPtr->var_237, gUnknown_0856FB0F); +} + +static void PrintBerryCrushNumOnCard(void) +{ + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.berryCrushPoints) + ConvertIntToDecimalStringN(sTrainerCardDataPtr->var_2C3, sTrainerCardDataPtr->trainerCard.berryCrushPoints, STR_CONV_MODE_RIGHT_ALIGN, 5); +} + +static void PrintBerryCrushStringOnCard(void) +{ + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.berryCrushPoints) + PrintString(4, gText_BerryCrush, sTrainerCardDataPtr->var_2C3, gUnknown_0856FB0F); +} + +static void PrintUnionNumOnCard(void) +{ + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.unionRoomNum) + ConvertIntToDecimalStringN(sTrainerCardDataPtr->var_34F, sTrainerCardDataPtr->trainerCard.unionRoomNum, STR_CONV_MODE_RIGHT_ALIGN, 5); +} + +static void PrintUnionStringOnCard(void) +{ + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.unionRoomNum) + PrintString(3, gText_UnionTradesAndBattles, sTrainerCardDataPtr->var_34F, gUnknown_0856FB0F); +} + +static void PrintPokeblocksNumOnCard(void) +{ + if (sTrainerCardDataPtr->cardType != CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.pokeblocksWithFriends) + { + ConvertIntToDecimalStringN(gStringVar1, sTrainerCardDataPtr->trainerCard.pokeblocksWithFriends, STR_CONV_MODE_RIGHT_ALIGN, 5); + StringExpandPlaceholders(sTrainerCardDataPtr->var_395, gText_Var1DarkGreyShadowLightGrey); + } +} + +static void PrintPokeblockStringOnCard(void) +{ + if (sTrainerCardDataPtr->cardType != CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.pokeblocksWithFriends) + PrintString(3, gText_PokeblocksWithFriends, sTrainerCardDataPtr->var_395, gUnknown_0856FB0F); +} + +static void PrintContestNumOnCard(void) +{ + if (sTrainerCardDataPtr->cardType != CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.contestsWithFriends) + ConvertIntToDecimalStringN(sTrainerCardDataPtr->var_3DB, sTrainerCardDataPtr->trainerCard.contestsWithFriends, STR_CONV_MODE_RIGHT_ALIGN, 5); +} + +static void PrintContestStringOnCard(void) +{ + if (sTrainerCardDataPtr->cardType != CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.contestsWithFriends) + PrintString(4, gText_WonContestsWFriends, sTrainerCardDataPtr->var_3DB, gUnknown_0856FB0F); +} + +static void PrintBattleFacilityNumsOnCard(void) +{ + switch (sTrainerCardDataPtr->cardType) + { + case CARD_TYPE_RS: + if (sTrainerCardDataPtr->hasBattleTowerWins) + { + ConvertIntToDecimalStringN(gStringVar1, sTrainerCardDataPtr->trainerCard.battleTowerWins, STR_CONV_MODE_RIGHT_ALIGN, 4); + ConvertIntToDecimalStringN(gStringVar2, sTrainerCardDataPtr->trainerCard.battleTowerStraightWins, STR_CONV_MODE_RIGHT_ALIGN, 4); + StringExpandPlaceholders(sTrainerCardDataPtr->var_421, gText_WSlashStraightSlash); + } + break; + case CARD_TYPE_EMERALD: + if (sTrainerCardDataPtr->trainerCard.frontierBP) + { + ConvertIntToDecimalStringN(gStringVar1, sTrainerCardDataPtr->trainerCard.frontierBP, STR_CONV_MODE_RIGHT_ALIGN, 5); + StringExpandPlaceholders(sTrainerCardDataPtr->var_421, gText_Var1DarkLightGreyBP); + } + break; + case CARD_TYPE_FRLG: + break; + } +} + +static void PrintBattleFacilityStringOnCard(void) +{ + switch (sTrainerCardDataPtr->cardType) + { + case CARD_TYPE_RS: + if (sTrainerCardDataPtr->hasBattleTowerWins) + PrintString(5, gText_BattleTower, sTrainerCardDataPtr->var_421, gUnknown_0856FB0C); + break; + case CARD_TYPE_EMERALD: + if (sTrainerCardDataPtr->trainerCard.frontierBP) + PrintString(5, gText_BattlePtsWon, sTrainerCardDataPtr->var_421, gUnknown_0856FB0F); + break; + case CARD_TYPE_FRLG: + break; + } +} + +static void TrainerCard_PrintPokemonIconsOnCard(void) +{ + u8 i; + u8 buffer[] = {0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}; + u8 buffer2[] = {0x00, 0x04, 0x08, 0x0c, 0x10, 0x14}; + + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG) + { + for (i = 0; i < 6; i++) + { + if (sTrainerCardDataPtr->trainerCard.monSpecies[i]) + { + u8 monSpecies = GetMonIconPaletteIndexFromSpecies(sTrainerCardDataPtr->trainerCard.monSpecies[i]); + WriteSequenceToBgTilemapBuffer(3, 16 * i + 224, buffer2[i] + 3, 15, 4, 4, buffer[monSpecies], 1); + } + } + } +} + +static void sub_80C41D8(void) +{ + u8 i; + + CpuSet(gMonIconPalettes, sTrainerCardDataPtr->var_468, 0x60); + switch (sTrainerCardDataPtr->trainerCard.var_4E) + { + case 0: + break; + case 1: + TintPalette_CustomTone(sTrainerCardDataPtr->var_468, 96, 0, 0, 0); + break; + case 2: + TintPalette_CustomTone(sTrainerCardDataPtr->var_468, 96, 500, 330, 310); + break; + case 3: + TintPalette_SepiaTone(sTrainerCardDataPtr->var_468, 96); + break; + } + LoadPalette(sTrainerCardDataPtr->var_468, 80, 192); + + for (i = 0; i < 6; i++) + { + if (sTrainerCardDataPtr->trainerCard.monSpecies[i]) + LoadBgTiles(3, GetMonIconTiles(sTrainerCardDataPtr->trainerCard.monSpecies[i], 0), 512, 16 * i + 32); + } +} + +static void sub_80C42A4(void) +{ + u8 i; + u8 buffer[4] = {0x0b, 0x0c, 0x0d, 0x0e}; + + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG && sTrainerCardDataPtr->trainerCard.var_4C == 1) + { + for (i = 0; i < 3; i++) + { + u8 var_50 = sTrainerCardDataPtr->trainerCard.var_50[i]; + if (sTrainerCardDataPtr->trainerCard.var_50[i]) + WriteSequenceToBgTilemapBuffer(3, i * 4 + 320, i * 3 + 2, 2, 2, 2, buffer[var_50 - 1], 1); + } + } +} + +static void sub_80C4330(void) +{ + LoadPalette(gUnknown_0856F54C, 176, 32); + LoadPalette(gUnknown_0856F56C, 192, 32); + LoadPalette(gUnknown_0856F58C, 208, 32); + LoadPalette(gUnknown_0856F5AC, 224, 32); + LoadBgTiles(3, sTrainerCardDataPtr->var_17A8, 1024, 128); +} + +static void sub_80C438C(u8 windowId) +{ + PutWindowTilemap(windowId); + CopyWindowToVram(windowId, 3); +} + +static u8 SetCardBgsAndPals(void) +{ + switch (sTrainerCardDataPtr->bgPalLoadState) + { + case 0: + LoadBgTiles(3, sTrainerCardDataPtr->var_13A8, 1024, 0); + break; + case 1: + LoadBgTiles(0, sTrainerCardDataPtr->var_19A8, 6144, 0); + break; + case 2: + if (sTrainerCardDataPtr->cardType != CARD_TYPE_FRLG) + { + LoadPalette(gEmeraldTrainerCardStarPals[sTrainerCardDataPtr->trainerCard.stars], 0, 96); + LoadPalette(sEmeraldTrainerCardBadges_Pal, 48, 32); + if (sTrainerCardDataPtr->trainerCard.gender) + LoadPalette(sEmeraldTrainerCardFemaleBackground_Pal, 16, 32); + } + else + { + LoadPalette(gFireRedTrainerCardStarPals[sTrainerCardDataPtr->trainerCard.stars], 0, 96); + LoadPalette(sFireRedTrainerCardBadges_Pal, 48, 32); + if (sTrainerCardDataPtr->trainerCard.gender) + LoadPalette(sFireRedTrainerCardFemaleBackground_Pal, 16, 32); + } + LoadPalette(gUnknown_0856F52C, 64, 32); + break; + case 3: + SetBgTilemapBuffer(0, sTrainerCardDataPtr->var_3CA8); + SetBgTilemapBuffer(2, sTrainerCardDataPtr->var_5CA8); + break; + case 4: + FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 32, 32); + FillBgTilemapBufferRect_Palette0(2, 0, 0, 0, 32, 32); + FillBgTilemapBufferRect_Palette0(3, 0, 0, 0, 32, 32); + default: + return 1; + } + sTrainerCardDataPtr->bgPalLoadState++; + return 0; +} + +static void sub_80C4550(u16 *ptr) +{ + s16 i, j; + u16 *dst = sTrainerCardDataPtr->var_5CA8; + + for (i = 0; i < 20; i++) + { + for (j = 0; j < 32; j++) + { + if (j < 30) + dst[32 * i + j] = ptr[30 * i + j]; + else + dst[32 * i + j] = ptr[0]; + } + } + CopyBgTilemapBufferToVram(2); +} + +static void sub_80C45C0(u16* ptr) +{ + s16 i, j; + u16 *dst = sTrainerCardDataPtr->var_3CA8; + + for (i = 0; i < 20; i++) + { + for (j = 0; j < 32; j++) + { + if (j < 30) + dst[32 * i + j] = ptr[30 * i + j]; + else + dst[32 * i + j] = ptr[0]; + } + } + CopyBgTilemapBufferToVram(0); +} + +static const u8 gUnknown_0856FB78[] = {7, 7}; + +static void TrainerCard_PrintStarsAndBadgesOnCard(void) +{ + s16 i, x; + u16 tileNum = 192; + u8 palNum = 3; + + FillBgTilemapBufferRect(3, 143, 15, gUnknown_0856FB78[sTrainerCardDataPtr->isHoenn], sTrainerCardDataPtr->trainerCard.stars, 1, 4); + if (!sTrainerCardDataPtr->isLink) + { + x = 4; + for (i = 0; i < 8; i++, tileNum += 2, x += 3) + { + if (sTrainerCardDataPtr->badgeCount[i]) + { + FillBgTilemapBufferRect(3, tileNum, x, 15, 1, 1, palNum); + FillBgTilemapBufferRect(3, tileNum + 1, x + 1, 15, 1, 1, palNum); + FillBgTilemapBufferRect(3, tileNum + 16, x, 16, 1, 1, palNum); + FillBgTilemapBufferRect(3, tileNum + 17, x + 1, 16, 1, 1, palNum); + } + } + } + CopyBgTilemapBufferToVram(3); +} + +static void sub_80C474C(void) +{ + if (sTrainerCardDataPtr->cardType == CARD_TYPE_FRLG) + { + if (sTrainerCardDataPtr->hasTrades) + { + FillBgTilemapBufferRect(3, 141, 27, 9, 1, 1, 1); + FillBgTilemapBufferRect(3, 157, 27, 10, 1, 1, 1); + } + if (sTrainerCardDataPtr->trainerCard.berryCrushPoints) + { + FillBgTilemapBufferRect(3, 141, 21, 13, 1, 1, 1); + FillBgTilemapBufferRect(3, 157, 21, 14, 1, 1, 1); + } + if (sTrainerCardDataPtr->trainerCard.unionRoomNum) + { + FillBgTilemapBufferRect(3, 141, 27, 11, 1, 1, 1); + FillBgTilemapBufferRect(3, 157, 27, 12, 1, 1, 1); + } + } + else + { + if (sTrainerCardDataPtr->hasTrades) + { + FillBgTilemapBufferRect(3, 141, 27, 9, 1, 1, 0); + FillBgTilemapBufferRect(3, 157, 27, 10, 1, 1, 0); + } + if (sTrainerCardDataPtr->trainerCard.contestsWithFriends) + { + FillBgTilemapBufferRect(3, 141, 27, 13, 1, 1, 0); + FillBgTilemapBufferRect(3, 157, 27, 14, 1, 1, 0); + } + if (sTrainerCardDataPtr->hasBattleTowerWins) + { + FillBgTilemapBufferRect(3, 141, 17, 15, 1, 1, 0); + FillBgTilemapBufferRect(3, 157, 17, 16, 1, 1, 0); + FillBgTilemapBufferRect(3, 140, 27, 15, 1, 1, 0); + FillBgTilemapBufferRect(3, 156, 27, 16, 1, 1, 0); + } + } + CopyBgTilemapBufferToVram(3); +} + +static void sub_80C48C8(void) +{ + if (++sTrainerCardDataPtr->var_6 > 60) + { + sTrainerCardDataPtr->var_6 = 0; + sTrainerCardDataPtr->var_7 ^= 1; + sTrainerCardDataPtr->var_529 = 1; + } +} + +u8 GetTrainerCardStars(u8 cardId) +{ + struct TrainerCard* trainerCards = gTrainerCards; + return trainerCards[cardId].stars; +} + +static void sub_80C4918(void) +{ + u8 taskId = CreateTask(sub_80C4960, 0); + sub_80C4960(taskId); + SetHBlankCallback(HblankCb_TrainerCard); +} + +static bool8 sub_80C4940(void) +{ + if (FindTaskIdByFunc(sub_80C4960) == 0xFF) + return TRUE; + else + return FALSE; +} + +static void sub_80C4960(u8 taskId) +{ + while(gUnknown_0856FB28[gTasks[taskId].data[0]](&gTasks[taskId])) + ; +} + +static bool8 sub_80C4998(struct Task* task) +{ + u32 i; + + HideBg(1); + HideBg(3); + ScanlineEffect_Stop(); + ScanlineEffect_Clear(); + for (i = 0; i < 160; i++) + gScanlineEffectRegBuffers[1][i] = 0; + task->data[0]++; + return FALSE; +} + +static bool8 sub_80C49D8(struct Task* task) +{ + u32 r4, r5, r10, r7, r6, var_24, r9, var; + s16 i; + + sTrainerCardDataPtr->allowDMACopy = FALSE; + if (task->data[1] >= 77) + task->data[1] = 77; + else + task->data[1] += 7; + + sTrainerCardDataPtr->var_7CA8 = task->data[1]; + sub_80C32EC(task->data[1]); + + // ??? + r7 = task->data[1]; + r9 = 160 - r7; + r4 = r9 - r7; + r6 = -r7 << 16; + r5 = 0xA00000 / r4; + r5 += 0xFFFF0000; + var_24 = r6; + var_24 += r5 * r4; + r10 = r5 / r4; + r5 *= 2; + + for (i = 0; i < r7; i++) + gScanlineEffectRegBuffers[0][i] = -i; + for (; i < (s16)(r9); i++) + { + var = r6 >> 16; + r6 += r5; + r5 -= r10; + gScanlineEffectRegBuffers[0][i] = var; + } + var = var_24 >> 16; + for (; i < 160; i++) + gScanlineEffectRegBuffers[0][i] = var; + + sTrainerCardDataPtr->allowDMACopy = TRUE; + if (task->data[1] >= 77) + task->data[0]++; + + return FALSE; +} + +static bool8 sub_80C4B08(struct Task* task) +{ + sTrainerCardDataPtr->allowDMACopy = FALSE; + if (sub_8087598() == TRUE) + return FALSE; + + do + { + switch (sTrainerCardDataPtr->var_4) + { + case 0: + FillWindowPixelBuffer(1, PIXEL_FILL(0)); + FillBgTilemapBufferRect_Palette0(3, 0, 0, 0, 0x20, 0x20); + break; + case 1: + if (!sTrainerCardDataPtr->var_8) + { + if (!PrintStringsOnCardPage2()) + return FALSE; + } + else + { + if (!PrintAllOnCardPage1()) + return FALSE; + } + break; + case 2: + if (!sTrainerCardDataPtr->var_8) + sub_80C45C0(sTrainerCardDataPtr->var_A48); + else + sub_80C438C(1); + break; + case 3: + if (!sTrainerCardDataPtr->var_8) + sub_80C474C(); + else + FillWindowPixelBuffer(2, PIXEL_FILL(0)); + break; + case 4: + if (sTrainerCardDataPtr->var_8) + sub_80C4FF0(); + break; + default: + task->data[0]++; + sTrainerCardDataPtr->allowDMACopy = TRUE; + sTrainerCardDataPtr->var_4 = 0; + return FALSE; + } + sTrainerCardDataPtr->var_4++; + } while (gReceivedRemoteLinkPlayers == 0); + + return FALSE; +} + +static bool8 sub_80C4C1C(struct Task* task) +{ + sTrainerCardDataPtr->allowDMACopy = FALSE; + if (sTrainerCardDataPtr->var_8) + { + sub_80C438C(2); + sub_80C4550(sTrainerCardDataPtr->var_EF8); + sub_80C45C0(sTrainerCardDataPtr->var_598); + TrainerCard_PrintStarsAndBadgesOnCard(); + } + sub_80C438C(1); + sTrainerCardDataPtr->var_8 ^= 1; + task->data[0]++; + sTrainerCardDataPtr->allowDMACopy = TRUE; + PlaySE(SE_RG_CARD2); + return FALSE; +} + +static bool8 sub_80C4C84(struct Task* task) +{ + u32 r4, r5, r10, r7, r6, var_24, r9, var; + s16 i; + + sTrainerCardDataPtr->allowDMACopy = FALSE; + if (task->data[1] <= 5) + task->data[1] = 0; + else + task->data[1] -= 5; + + sTrainerCardDataPtr->var_7CA8 = task->data[1]; + sub_80C32EC(task->data[1]); + + // ??? + r7 = task->data[1]; + r9 = 160 - r7; + r4 = r9 - r7; + r6 = -r7 << 16; + r5 = 0xA00000 / r4; + r5 += 0xFFFF0000; + var_24 = r6; + var_24 += r5 * r4; + r10 = r5 / r4; + r5 /= 2; + + for (i = 0; i < r7; i++) + gScanlineEffectRegBuffers[0][i] = -i; + for (; i < (s16)(r9); i++) + { + var = r6 >> 16; + r6 += r5; + r5 += r10; + gScanlineEffectRegBuffers[0][i] = var; + } + var = var_24 >> 16; + for (; i < 160; i++) + gScanlineEffectRegBuffers[0][i] = var; + + sTrainerCardDataPtr->allowDMACopy = TRUE; + if (task->data[1] <= 0) + task->data[0]++; + + return FALSE; +} + +static bool8 sub_80C4DB0(struct Task *task) +{ + ShowBg(1); + ShowBg(3); + SetHBlankCallback(NULL); + DestroyTask(FindTaskIdByFunc(sub_80C4960)); + return FALSE; +} + +void ShowPlayerTrainerCard(void (*callback)(void)) +{ + sTrainerCardDataPtr = AllocZeroed(sizeof(*sTrainerCardDataPtr)); + sTrainerCardDataPtr->callback2 = callback; + if (callback == CB2_ReshowFrontierPass) + sTrainerCardDataPtr->var_52C = 0x7FFF; + else + sTrainerCardDataPtr->var_52C = 0; + + if (InUnionRoom() == TRUE) + sTrainerCardDataPtr->isLink = TRUE; + else + sTrainerCardDataPtr->isLink = FALSE; + + sTrainerCardDataPtr->language = GAME_LANGUAGE; + TrainerCard_GenerateCardForLinkPlayer(&sTrainerCardDataPtr->trainerCard); + SetMainCallback2(CB2_InitTrainerCard); +} + +void ShowTrainerCardInLink(u8 cardId, void (*callback)(void)) +{ + sTrainerCardDataPtr = AllocZeroed(sizeof(*sTrainerCardDataPtr)); + sTrainerCardDataPtr->callback2 = callback; + sTrainerCardDataPtr->isLink = TRUE; + sTrainerCardDataPtr->trainerCard = gTrainerCards[cardId]; + sTrainerCardDataPtr->language = gLinkPlayers[cardId].language; + SetMainCallback2(CB2_InitTrainerCard); +} + +static void sub_80C4EE4(void) +{ + u8 i; + + sTrainerCardDataPtr->var_0 = 0; + sTrainerCardDataPtr->var_6 = gSaveBlock2Ptr->playTimeVBlanks; + sTrainerCardDataPtr->var_7 = 0; + sTrainerCardDataPtr->var_8 = 0; + sTrainerCardDataPtr->var_528 = 0; + sTrainerCardDataPtr->cardType = GetSetCardType(); + for (i = 0; i < 4; i++) + CopyEasyChatWord(sTrainerCardDataPtr->var_19[i], sTrainerCardDataPtr->trainerCard.var_28[i]); +} + +static u8 GetSetCardType(void) +{ + if (sTrainerCardDataPtr == NULL) + { + if (gGameVersion == VERSION_FIRE_RED || gGameVersion == VERSION_LEAF_GREEN) + return CARD_TYPE_FRLG; + else if (gGameVersion == VERSION_EMERALD) + return CARD_TYPE_EMERALD; + else + return CARD_TYPE_RS; + } + else + { + if (sTrainerCardDataPtr->trainerCard.version == VERSION_FIRE_RED || sTrainerCardDataPtr->trainerCard.version == VERSION_LEAF_GREEN) + { + sTrainerCardDataPtr->isHoenn = FALSE; + return CARD_TYPE_FRLG; + } + else if (sTrainerCardDataPtr->trainerCard.version == VERSION_EMERALD) + { + sTrainerCardDataPtr->isHoenn = TRUE; + return CARD_TYPE_EMERALD; + } + else + { + sTrainerCardDataPtr->isHoenn = TRUE; + return CARD_TYPE_RS; + } + } +} + +static u8 VersionToCardType(u8 version) +{ + if (version == VERSION_FIRE_RED || version == VERSION_LEAF_GREEN) + return CARD_TYPE_FRLG; + else if (version == VERSION_EMERALD) + return CARD_TYPE_EMERALD; + else + return CARD_TYPE_RS; +} + +static void sub_80C4FF0(void) +{ + if (InUnionRoom() == TRUE && gReceivedRemoteLinkPlayers == 1) + { + sub_818D938(FacilityClassToPicIndex(sTrainerCardDataPtr->trainerCard.var_4F), + TRUE, + gUnknown_0856FB18[sTrainerCardDataPtr->isHoenn][sTrainerCardDataPtr->trainerCard.gender][0], + gUnknown_0856FB18[sTrainerCardDataPtr->isHoenn][sTrainerCardDataPtr->trainerCard.gender][1], + 8, + 2); + } + else + { + sub_818D938(FacilityClassToPicIndex(gUnknown_0856FB20[sTrainerCardDataPtr->cardType][sTrainerCardDataPtr->trainerCard.gender]), + TRUE, + gUnknown_0856FB18[sTrainerCardDataPtr->isHoenn][sTrainerCardDataPtr->trainerCard.gender][0], + gUnknown_0856FB18[sTrainerCardDataPtr->isHoenn][sTrainerCardDataPtr->trainerCard.gender][1], + 8, + 2); + } +} |