diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bard_music.c | 1 | ||||
-rw-r--r-- | src/battle_records.c | 510 | ||||
-rw-r--r-- | src/berry.c | 2 | ||||
-rw-r--r-- | src/berry_blender.c | 20 | ||||
-rw-r--r-- | src/berry_tag_screen.c | 6 | ||||
-rw-r--r-- | src/bg.c | 4 | ||||
-rw-r--r-- | src/field_camera.c | 6 | ||||
-rw-r--r-- | src/field_map_obj.c | 2 | ||||
-rw-r--r-- | src/fieldmap.c | 1034 | ||||
-rw-r--r-- | src/item.c | 1027 | ||||
-rw-r--r-- | src/item_icon.c | 2 | ||||
-rwxr-xr-x | src/item_menu.c | 40 | ||||
-rw-r--r-- | src/item_menu_icons.c | 6 | ||||
-rw-r--r-- | src/lilycove_lady.c | 4 | ||||
-rw-r--r-- | src/load_save.c | 83 | ||||
-rw-r--r-- | src/mail.c | 2 | ||||
-rw-r--r-- | src/mauville_old_man.c | 1247 | ||||
-rw-r--r-- | src/new_game.c | 12 | ||||
-rw-r--r-- | src/overworld.c | 5 | ||||
-rw-r--r-- | src/player_pc.c | 12 | ||||
-rw-r--r-- | src/pokeblock.c | 2 | ||||
-rw-r--r-- | src/pokemon_summary_screen.c | 4 | ||||
-rw-r--r-- | src/random.c | 4 | ||||
-rw-r--r-- | src/save.c | 31 | ||||
-rw-r--r-- | src/secret_base.c | 2 | ||||
-rw-r--r-- | src/trader.c | 209 | ||||
-rw-r--r-- | src/tv.c | 30 |
27 files changed, 4091 insertions, 216 deletions
diff --git a/src/bard_music.c b/src/bard_music.c index 6fb1496e5..6c2578071 100644 --- a/src/bard_music.c +++ b/src/bard_music.c @@ -2,6 +2,7 @@ // Includes #include "global.h" #include "bard_music.h" +#include "constants/easy_chat.h" #include "easy_chat.h" #include "data/bard_music/bard_sounds.h" diff --git a/src/battle_records.c b/src/battle_records.c new file mode 100644 index 000000000..a148f998f --- /dev/null +++ b/src/battle_records.c @@ -0,0 +1,510 @@ +#include "global.h" +#include "battle_records.h" +#include "bg.h" +#include "window.h" +#include "link.h" +#include "battle.h" +#include "overworld.h" +#include "text.h" +#include "text_window.h" +#include "strings.h" +#include "string_util.h" +#include "trainer_card.h" +#include "menu.h" +#include "menu_helpers.h" +#include "palette.h" +#include "main.h" +#include "scanline_effect.h" +#include "international_string_util.h" +#include "sound.h" +#include "constants/songs.h" +#include "malloc.h" +#include "gpu_regs.h" +#include "constants/game_stat.h" + +extern void PrintOnTrainerHillRecordsWindow(void); // pokenav.s + +// this file's functions +static void Task_CloseTrainerHillRecordsOnButton(u8 taskId); +static void Task_BeginPaletteFade(u8 taskId); +static void Task_ExitTrainerHillRecords(u8 taskId); +static void RemoveTrainerHillRecordsWindow(u8 windowId); +static void CB2_ShowTrainerHillRecords(void); + +// EWRAM variables +EWRAM_DATA u8 gRecordsWindowId = 0; +EWRAM_DATA static u8 *sTilemapBuffer = NULL; + +// const rom data +static const u32 sTrainerHillWindowTileset[] = INCBIN_U32("graphics/unknown/unknown_5B3484.4bpp"); +static const u16 sTrainerHillWindowPalette[] = INCBIN_U16("graphics/unknown/unknown_5B3484.gbapal"); +static const u32 sTrainerHillWindowTilemap[] = INCBIN_U32("graphics/unknown/unknown_5B3564.bin"); + +static const struct BgTemplate sTrainerHillRecordsBgTemplates[] = +{ + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0 + }, + { + .bg = 3, + .charBaseIndex = 1, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0 + } +}; + +static const struct WindowTemplate sTrainerHillRecordsWindowTemplates[] = +{ + {0x0, 0x2, 0x1, 0x1A, 0x12, 0xF, 0x14}, + DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate sLinkBattleRecordsWindow = {0x0, 0x2, 0x1, 0x1A, 0x11, 0xF, 0x1}; + +static const u8 sText_DashesNoPlayer[] = _("-------"); +static const u8 sText_DashesNoScore[] = _("----"); + +// code +static void ClearLinkBattleRecord(struct LinkBattleRecord *record) +{ + CpuFill16(0, record, sizeof(struct LinkBattleRecord)); + record->name[0] = EOS; + record->trainerId = 0; + record->wins = 0; + record->losses = 0; + record->draws = 0; +} + +static void ClearLinkBattleRecords(struct LinkBattleRecord *records) +{ + s32 i; + for (i = 0; i < LINK_B_RECORDS_COUNT; i++) + { + ClearLinkBattleRecord(records + 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 FindLinkBattleRecord(struct LinkBattleRecord *records, const u8 *name, u16 trainerId) +{ + s32 i; + + for (i = 0; i < LINK_B_RECORDS_COUNT; i++) + { + if (!StringCompareN(records[i].name, name, OT_NAME_LENGTH) && records[i].trainerId == trainerId) + return i; + } + + return LINK_B_RECORDS_COUNT; +} + +static void SortLinkBattleRecords(struct LinkBattleRecords *records) +{ + s32 i, j; + + for (i = LINK_B_RECORDS_COUNT - 1; i > 0; i--) + { + for (j = i - 1; j >= 0; j--) + { + s32 totalBattlesI = GetLinkBattleRecordTotalBattles(&records->entries[i]); + s32 totalBattlesJ = GetLinkBattleRecordTotalBattles(&records->entries[j]); + + if (totalBattlesI > totalBattlesJ) + { + struct LinkBattleRecord temp1; + u8 temp2; + + temp1 = records->entries[i]; + records->entries[i] = records->entries[j]; + records->entries[j] = temp1; + + temp2 = records->languages[i]; + records->languages[i] = records->languages[j]; + records->languages[j] = temp2; + } + } + } +} + +static void UpdateLinkBattleRecord(struct LinkBattleRecord *record, s32 battleOutcome) +{ + switch (battleOutcome) + { + 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 battleOutcome) +{ + u8 stat; + + switch (battleOutcome) + { + case B_OUTCOME_WON: + stat = GAME_STAT_LINK_BATTLE_WINS; + break; + case B_OUTCOME_LOST: + stat = GAME_STAT_LINK_BATTLE_LOSSES; + break; + case B_OUTCOME_DREW: + stat = GAME_STAT_LINK_BATTLE_DRAWS; + break; + default: + return; + } + + if (GetGameStat(stat) < 9999) + IncrementGameStat(stat); +} + +static void UpdateLinkBattleRecords(struct LinkBattleRecords *records, const u8 *name, u16 trainerId, s32 battleOutcome, u8 battlerId) +{ + s32 index; + + UpdateLinkBattleGameStats(battleOutcome); + SortLinkBattleRecords(records); + index = FindLinkBattleRecord(records->entries, name, trainerId); + if (index == LINK_B_RECORDS_COUNT) + { + index = LINK_B_RECORDS_COUNT - 1; + ClearLinkBattleRecord(&records->entries[index]); + StringCopyN(records->entries[index].name, name, OT_NAME_LENGTH); + records->entries[index].trainerId = trainerId; + records->languages[index] = gLinkPlayers[battlerId].language; + } + UpdateLinkBattleRecord(&records->entries[index], battleOutcome); + SortLinkBattleRecords(records); +} + +void ClearPlayerLinkBattleRecords(void) +{ + ClearLinkBattleRecords(gSaveBlock1Ptr->linkBattleRecords.entries); +} + +static void IncTrainerCardWins(s32 battlerId) +{ + u16 *wins = &gTrainerCards[battlerId].linkBattleWins; + (*wins)++; + if (*wins > 9999) + *wins = 9999; +} + +static void IncTrainerCardLosses(s32 battlerId) +{ + u16 *losses = &gTrainerCards[battlerId].linkBattleLosses; + (*losses)++; + if (*losses > 9999) + *losses = 9999; +} + +static void UpdateTrainerCardWinsLosses(s32 battlerId) +{ + switch (gBattleOutcome) + { + case B_OUTCOME_WON: + IncTrainerCardWins(BATTLE_OPPOSITE(battlerId)); + IncTrainerCardLosses(battlerId); + break; + case B_OUTCOME_LOST: + IncTrainerCardLosses(BATTLE_OPPOSITE(battlerId)); + IncTrainerCardWins(battlerId); + break; + } +} + +void UpdatePlayerLinkBattleRecords(s32 battlerId) +{ + if (InUnionRoom() != TRUE) + { + UpdateTrainerCardWinsLosses(battlerId); + UpdateLinkBattleRecords( + &gSaveBlock1Ptr->linkBattleRecords, + gTrainerCards[battlerId].playerName, + gTrainerCards[battlerId].trainerId, + gBattleOutcome, + battlerId); + } +} + +static void PrintLinkBattleWinsLossesDraws(struct LinkBattleRecord *records) +{ + s32 x; + + ConvertIntToDecimalStringN(gStringVar1, GetGameStat(GAME_STAT_LINK_BATTLE_WINS), STR_CONV_MODE_LEFT_ALIGN, 4); + ConvertIntToDecimalStringN(gStringVar2, GetGameStat(GAME_STAT_LINK_BATTLE_LOSSES), STR_CONV_MODE_LEFT_ALIGN, 4); + ConvertIntToDecimalStringN(gStringVar3, GetGameStat(GAME_STAT_LINK_BATTLE_DRAWS), STR_CONV_MODE_LEFT_ALIGN, 4); + StringExpandPlaceholders(gStringVar4, gText_TotalRecordWLD); + + x = GetStringCenterAlignXOffset(1, gStringVar4, 0xD0); + PrintTextOnWindow(gRecordsWindowId, 1, gStringVar4, x, 0x11, 0, NULL); +} + +static void PrintLinkBattleRecord(struct LinkBattleRecord *record, u8 y, s32 language) +{ + if (record->wins == 0 && record->losses == 0 && record->draws == 0) + { + // empty slot + PrintTextOnWindow(gRecordsWindowId, 1, sText_DashesNoPlayer, 8, (y * 8) + 1, 0, NULL); + PrintTextOnWindow(gRecordsWindowId, 1, sText_DashesNoScore, 80, (y * 8) + 1, 0, NULL); + PrintTextOnWindow(gRecordsWindowId, 1, sText_DashesNoScore, 128, (y * 8) + 1, 0, NULL); + PrintTextOnWindow(gRecordsWindowId, 1, sText_DashesNoScore, 176, (y * 8) + 1, 0, NULL); + } + else + { + StringFillWithTerminator(gStringVar1, 8); + StringCopyN(gStringVar1, record->name, 7); + ConvertInternationalString(gStringVar1, language); + + PrintTextOnWindow(gRecordsWindowId, 1, gStringVar1, 8, (y * 8) + 1, 0, NULL); + + ConvertIntToDecimalStringN(gStringVar1, record->wins, STR_CONV_MODE_RIGHT_ALIGN, 4); + PrintTextOnWindow(gRecordsWindowId, 1, gStringVar1, 80, (y * 8) + 1, 0, NULL); + + ConvertIntToDecimalStringN(gStringVar1, record->losses, STR_CONV_MODE_RIGHT_ALIGN, 4); + PrintTextOnWindow(gRecordsWindowId, 1, gStringVar1, 128, (y * 8) + 1, 0, NULL); + + ConvertIntToDecimalStringN(gStringVar1, record->draws, STR_CONV_MODE_RIGHT_ALIGN, 4); + PrintTextOnWindow(gRecordsWindowId, 1, gStringVar1, 176, (y * 8) + 1, 0, NULL); + } +} + +void ShowLinkBattleRecords(void) +{ + s32 i, x; + + gRecordsWindowId = AddWindow(&sLinkBattleRecordsWindow); + NewMenuHelpers_DrawStdWindowFrame(gRecordsWindowId, FALSE); + FillWindowPixelBuffer(gRecordsWindowId, 0x11); + StringExpandPlaceholders(gStringVar4, gText_PlayersBattleResults); + + x = GetStringCenterAlignXOffset(1, gStringVar4, 208); + PrintTextOnWindow(gRecordsWindowId, 1, gStringVar4, x, 1, 0, NULL); + PrintLinkBattleWinsLossesDraws(gSaveBlock1Ptr->linkBattleRecords.entries); + + StringExpandPlaceholders(gStringVar4, gText_WinLoseDraw); + PrintTextOnWindow(gRecordsWindowId, 1, gStringVar4, 0, 41, 0, NULL); + + for (i = 0; i < LINK_B_RECORDS_COUNT; i++) + { + PrintLinkBattleRecord(&gSaveBlock1Ptr->linkBattleRecords.entries[i], 7 + (i * 2), gSaveBlock1Ptr->linkBattleRecords.languages[i]); + } + + PutWindowTilemap(gRecordsWindowId); + CopyWindowToVram(gRecordsWindowId, 3); +} + +void RemoveRecordsWindow(void) +{ + sub_819746C(gRecordsWindowId, FALSE); + RemoveWindow(gRecordsWindowId); +} + +static void Task_TrainerHillWaitForPaletteFade(u8 taskId) +{ + if (!gPaletteFade.active) + gTasks[taskId].func = Task_CloseTrainerHillRecordsOnButton; +} + +static void Task_CloseTrainerHillRecordsOnButton(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + + if (gMain.newKeys & A_BUTTON || gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + task->func = Task_BeginPaletteFade; + } +} + +static void Task_BeginPaletteFade(u8 taskId) +{ + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gTasks[taskId].func = Task_ExitTrainerHillRecords; +} + +static void Task_ExitTrainerHillRecords(u8 taskId) +{ + if (!gPaletteFade.active) + { + SetMainCallback2(CB2_ReturnToFieldContinueScript); + Free(sTilemapBuffer); + RemoveTrainerHillRecordsWindow(0); + FreeAllWindowBuffers(); + DestroyTask(taskId); + } +} + +static void RemoveTrainerHillRecordsWindow(u8 windowId) +{ + FillWindowPixelBuffer(windowId, 0); + ClearWindowTilemap(windowId); + CopyWindowToVram(windowId, 2); + RemoveWindow(windowId); +} + +static void ClearVramOamPlttRegs(void) +{ + DmaClearLarge16(3, (void*)(VRAM), VRAM_SIZE, 0x1000); + DmaClear32(3, OAM, OAM_SIZE); + DmaClear16(3, PLTT, PLTT_SIZE); + + SetGpuReg(REG_OFFSET_DISPCNT, 0); + SetGpuReg(REG_OFFSET_BG0CNT, 0); + SetGpuReg(REG_OFFSET_BG0HOFS, 0); + SetGpuReg(REG_OFFSET_BG0VOFS, 0); + SetGpuReg(REG_OFFSET_BG1CNT, 0); + SetGpuReg(REG_OFFSET_BG1HOFS, 0); + SetGpuReg(REG_OFFSET_BG1VOFS, 0); + SetGpuReg(REG_OFFSET_BG2CNT, 0); + SetGpuReg(REG_OFFSET_BG2HOFS, 0); + SetGpuReg(REG_OFFSET_BG2VOFS, 0); + SetGpuReg(REG_OFFSET_BG3CNT, 0); + SetGpuReg(REG_OFFSET_BG3HOFS, 0); + SetGpuReg(REG_OFFSET_BG3VOFS, 0); + SetGpuReg(REG_OFFSET_WIN0H, 0); + SetGpuReg(REG_OFFSET_WIN0V, 0); + SetGpuReg(REG_OFFSET_WININ, 0); + SetGpuReg(REG_OFFSET_WINOUT, 0); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_BLDALPHA, 0); + SetGpuReg(REG_OFFSET_BLDY, 0); +} + +static void ClearTasksAndGraphicalStructs(void) +{ + ScanlineEffect_Stop(); + ResetTasks(); + ResetSpriteData(); + ResetPaletteFade(); + FreeAllSpritePalettes(); +} + +static void ResetBgCoordinates(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 SetDispcntReg(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_BG0_ON | DISPCNT_BG3_ON | DISPCNT_OBJ_1D_MAP); +} + +static void LoadTrainerHillRecordsWindowGfx(u8 bgId) +{ + LoadBgTiles(bgId, sTrainerHillWindowTileset, sizeof(sTrainerHillWindowTileset), 0); + CopyToBgTilemapBufferRect(bgId, sTrainerHillWindowTilemap, 0, 0, 0x20, 0x20); + LoadPalette(sTrainerHillWindowPalette, 0, 0x20); +} + +static void VblankCB_TrainerHillRecords(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void MainCB2_TrainerHillRecords(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + UpdatePaletteFade(); +} + +void ShowTrainerHillRecords(void) +{ + SetVBlankCallback(NULL); + SetMainCallback2(CB2_ShowTrainerHillRecords); +} + +static void CB2_ShowTrainerHillRecords(void) +{ + switch (gMain.state) + { + case 0: + SetVBlankCallback(NULL); + ClearVramOamPlttRegs(); + gMain.state++; + break; + case 1: + ClearTasksAndGraphicalStructs(); + gMain.state++; + break; + case 2: + sTilemapBuffer = AllocZeroed(0x800); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sTrainerHillRecordsBgTemplates, ARRAY_COUNT(sTrainerHillRecordsBgTemplates)); + SetBgTilemapBuffer(3, sTilemapBuffer); + ResetBgCoordinates(); + gMain.state++; + break; + case 3: + LoadTrainerHillRecordsWindowGfx(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(sTrainerHillRecordsWindowTemplates); + DeactivateAllTextPrinters(); + gMain.state++; + break; + case 6: + BeginNormalPaletteFade(-1, 0, 0x10, 0, 0); + gMain.state++; + break; + case 7: + SetDispcntReg(); + SetVBlankCallback(VblankCB_TrainerHillRecords); + PrintOnTrainerHillRecordsWindow(); + CreateTask(Task_TrainerHillWaitForPaletteFade, 8); + SetMainCallback2(MainCB2_TrainerHillRecords); + gMain.state = 0; + break; + } +} diff --git a/src/berry.c b/src/berry.c index 74b7090c0..e128eb0ec 100644 --- a/src/berry.c +++ b/src/berry.c @@ -1218,7 +1218,7 @@ void FieldObjectInteractionRemoveBerryTree(void) u8 PlayerHasBerries(void) { - return IsBagPocketNonEmpty(BAG_BERRIES); + return IsBagPocketNonEmpty(POCKET_BERRIES); } void ResetBerryTreeSparkleFlags(void) diff --git a/src/berry_blender.c b/src/berry_blender.c index 9e6a0fef7..c3b0cc80d 100644 --- a/src/berry_blender.c +++ b/src/berry_blender.c @@ -30,6 +30,7 @@ #include "trig.h" #include "tv.h" #include "item_menu.h" +#include "battle_records.h" #define BLENDER_SCORE_BEST 0 #define BLENDER_SCORE_GOOD 1 @@ -131,7 +132,6 @@ extern struct MusicPlayerInfo gMPlayInfo_SE2; extern struct MusicPlayerInfo gMPlayInfo_BGM; extern u8 gInGameOpponentsNo; extern u8 gUnknown_020322D5; -extern u8 gResultsWindowId; // graphics extern const u8 gBerryBlenderArrowTiles[]; @@ -2472,7 +2472,7 @@ static void CB2_HandleBlenderEndGame(void) sub_8081F94(&gSendCmd[0]); if (sBerryBlenderData->yesNoAnswer == 0) { - if (IsBagPocketNonEmpty(BAG_BERRIES) == FALSE) // no berries + if (IsBagPocketNonEmpty(POCKET_BERRIES) == FALSE) // no berries { sBerryBlenderData->playAgainState = CANT_PLAY_NO_BERRIES; gSendCmd[1] = 0x9999; @@ -3485,13 +3485,13 @@ void ShowBerryBlenderRecordWindow(void) u8 text[32]; winTemplate = sBlenderRecordWindowTemplate; - gResultsWindowId = AddWindow(&winTemplate); - NewMenuHelpers_DrawStdWindowFrame(gResultsWindowId, 0); - FillWindowPixelBuffer(gResultsWindowId, 0x11); + gRecordsWindowId = AddWindow(&winTemplate); + NewMenuHelpers_DrawStdWindowFrame(gRecordsWindowId, 0); + FillWindowPixelBuffer(gRecordsWindowId, 0x11); xPos = GetStringCenterAlignXOffset(1, gText_BlenderMaxSpeedRecord, 0x90); - PrintTextOnWindow(gResultsWindowId, 1, gText_BlenderMaxSpeedRecord, xPos, 1, 0, NULL); - PrintTextOnWindow(gResultsWindowId, 1, gText_234Players, 4, 0x29, 0, NULL); + PrintTextOnWindow(gRecordsWindowId, 1, gText_BlenderMaxSpeedRecord, xPos, 1, 0, NULL); + PrintTextOnWindow(gRecordsWindowId, 1, gText_234Players, 4, 0x29, 0, NULL); for (i = 0, yPos = 0x29; i < BLENDER_SCORES_NO; i++) { @@ -3506,11 +3506,11 @@ void ShowBerryBlenderRecordWindow(void) txtPtr = StringAppend(txtPtr, sText_RPM); xPos = GetStringRightAlignXOffset(1, text, 0x8C); - PrintTextOnWindow(gResultsWindowId, 1, text, xPos, yPos + (i * 16), 0, NULL); + PrintTextOnWindow(gRecordsWindowId, 1, text, xPos, yPos + (i * 16), 0, NULL); } - PutWindowTilemap(gResultsWindowId); - CopyWindowToVram(gResultsWindowId, 3); + PutWindowTilemap(gRecordsWindowId); + CopyWindowToVram(gRecordsWindowId, 3); } static void sub_8083F3C(u8 taskId) diff --git a/src/berry_tag_screen.c b/src/berry_tag_screen.c index 1a0d1bce0..9a6e78c81 100644 --- a/src/berry_tag_screen.c +++ b/src/berry_tag_screen.c @@ -517,7 +517,7 @@ static void TryChangeDisplayedBerry(u8 taskId, s8 toMove) s16 *data = gTasks[taskId].data; s16 currPocketPosition = gUnknown_0203CE58.scrollPosition[3] + gUnknown_0203CE58.cursorPosition[3]; u32 newPocketPosition = currPocketPosition + toMove; - if (newPocketPosition < 46 && BagGetItemIdByPocketPosition(BAG_BERRIES, newPocketPosition) != 0) + if (newPocketPosition < 46 && BagGetItemIdByPocketPosition(POCKET_BERRIES, newPocketPosition) != 0) { if (toMove < 0) data[1] = 2; @@ -537,7 +537,7 @@ static void HandleBagCursorPositionChange(s8 toMove) u16 *cursorPos = &gUnknown_0203CE58.cursorPosition[3]; if (toMove > 0) { - if (*cursorPos < 4 || BagGetItemIdByPocketPosition(BAG_BERRIES, *scrollPos + 8) == 0) + if (*cursorPos < 4 || BagGetItemIdByPocketPosition(POCKET_BERRIES, *scrollPos + 8) == 0) *cursorPos += toMove; else *scrollPos += toMove; @@ -550,7 +550,7 @@ static void HandleBagCursorPositionChange(s8 toMove) *scrollPos += toMove; } - sBerryTag->berryId = ItemIdToBerryType(BagGetItemIdByPocketPosition(BAG_BERRIES, *scrollPos + *cursorPos)); + sBerryTag->berryId = ItemIdToBerryType(BagGetItemIdByPocketPosition(POCKET_BERRIES, *scrollPos + *cursorPos)); } static void Task_DisplayAnotherBerry(u8 taskId) @@ -965,9 +965,9 @@ void CopyBgTilemapBufferToVram(u8 bg) } } -void CopyToBgTilemapBufferRect(u8 bg, void* src, u8 destX, u8 destY, u8 width, u8 height) +void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height) { - void* srcCopy; + const void* srcCopy; u16 destX16; u16 destY16; u16 mode; diff --git a/src/field_camera.c b/src/field_camera.c index f653e0bf1..95167ee10 100644 --- a/src/field_camera.c +++ b/src/field_camera.c @@ -12,6 +12,8 @@ #include "sprite.h" #include "text.h" +EWRAM_DATA bool8 gUnusedBikeCameraAheadPanback = FALSE; + // Static type declarations struct FieldCameraUnknownStruct { @@ -40,6 +42,10 @@ static IWRAM_DATA s16 gUnknown_03000E2A; static IWRAM_DATA u8 gUnknown_03000E2C; static IWRAM_DATA void (*gUnknown_03000E30)(void); +struct CameraObject gUnknown_03005DD0; +u16 gUnknown_03005DE8; +u16 gUnknown_03005DEC; + // text static void move_tilemap_camera_to_upper_left_corner_(struct FieldCameraUnknownStruct *a) { diff --git a/src/field_map_obj.c b/src/field_map_obj.c index a5be62442..81cbe5210 100644 --- a/src/field_map_obj.c +++ b/src/field_map_obj.c @@ -1146,7 +1146,7 @@ const struct MapObjectGraphicsInfo *GetFieldObjectGraphicsInfo(u8 graphicsId) } if (graphicsId == 0x45) { - bard = sub_81201C8(); + bard = GetCurrentMauvilleOldMan(); return gMauvilleOldManGraphicsInfoPointers[bard]; } if (graphicsId >= NUM_OBJECT_GRAPHICS_INFO) diff --git a/src/fieldmap.c b/src/fieldmap.c new file mode 100644 index 000000000..245c88327 --- /dev/null +++ b/src/fieldmap.c @@ -0,0 +1,1034 @@ +#include "global.h" +#include "overworld.h" +#include "bg.h" +#include "battle_frontier_2.h" +#include "constants/rgb.h" +#include "fieldmap.h" +#include "fldeff_80F9BCC.h" +#include "fldeff_cut.h" +#include "fldeff_groundshake.h" +#include "menu.h" +#include "palette.h" +#include "pokenav.h" +#include "script.h" +#include "secret_base.h" +#include "tv.h" + +struct ConnectionFlags +{ + u8 south:1; + u8 north:1; + u8 west:1; + u8 east:1; +}; + +EWRAM_DATA static u16 gUnknown_02032318[0x2800] = {0}; +EWRAM_DATA struct MapHeader gMapHeader = {0}; +EWRAM_DATA struct Camera gCamera = {0}; +EWRAM_DATA static struct ConnectionFlags gUnknown_02037340 = {0}; +EWRAM_DATA static u32 sFiller_02037344 = 0; // without this, the next file won't align properly + +struct BackupMapData gUnknown_03005DC0; + +static const struct ConnectionFlags sDummyConnectionFlags = {0}; + +struct MapHeader const *const mapconnection_get_mapheader(struct MapConnection *connection) +{ + return Overworld_GetMapHeaderByGroupAndId(connection->mapGroup, connection->mapNum); +} + +void not_trainer_hill_battle_pyramid(void) +{ + mapheader_copy_mapdata_with_padding(&gMapHeader); + sub_80E8EE0(gMapHeader.events); + mapheader_run_script_with_tag_x1(); +} + +void sub_8087D74(void) +{ + mapheader_copy_mapdata_with_padding(&gMapHeader); + sub_80E9238(0); + sub_80E8EE0(gMapHeader.events); + mapdata_from_sav2(); + mapheader_run_script_with_tag_x1(); + UpdateTVScreensOnMap(gUnknown_03005DC0.width, gUnknown_03005DC0.height); +} + +void battle_pyramid_map_load_related(u8 a0) +{ + CpuFastFill(0x03ff03ff, gUnknown_02032318, sizeof(gUnknown_02032318)); + sub_81AA078(gUnknown_02032318, a0); +} + +void trainer_hill_map_load_related(void) +{ + CpuFastFill(0x03ff03ff, gUnknown_02032318, sizeof(gUnknown_02032318)); + sub_81D5FB4(gUnknown_02032318); +} + +void mapheader_copy_mapdata_with_padding(struct MapHeader *mapHeader) +{ + struct MapData const *mapData; + int width; + int height; + mapData = mapHeader->mapData; + CpuFastFill16(0x03ff, gUnknown_02032318, sizeof(gUnknown_02032318)); + gUnknown_03005DC0.map = gUnknown_02032318; + width = mapData->width + 15; + gUnknown_03005DC0.width = width; + height = mapData->height + 14; + gUnknown_03005DC0.height = height; + if (width * height <= 0x2800) + { + map_copy_with_padding(mapData->map, mapData->width, mapData->height); + mapheader_copy_mapdata_of_adjacent_maps(mapHeader); + } +} + +void map_copy_with_padding(u16 *map, u16 width, u16 height) +{ + u16 *dest; + int y; + dest = gUnknown_03005DC0.map; + dest += gUnknown_03005DC0.width * 7 + 7; + for (y = 0; y < height; y++) + { + CpuCopy16(map, dest, width * 2); + dest += width + 0xf; + map += width; + } +} + +void mapheader_copy_mapdata_of_adjacent_maps(struct MapHeader *mapHeader) +{ + int count; + struct MapConnection *connection; + int i; + + if (mapHeader->connections) + { + count = mapHeader->connections->count; + connection = mapHeader->connections->connections; + + gUnknown_02037340 = sDummyConnectionFlags; + for (i = 0; i < count; i++, connection++) + { + struct MapHeader const *cMap = mapconnection_get_mapheader(connection); + u32 offset = connection->offset; + + switch (connection->direction) + { + case CONNECTION_SOUTH: + fillSouthConnection(mapHeader, cMap, offset); + gUnknown_02037340.south = 1; + break; + case CONNECTION_NORTH: + fillNorthConnection(mapHeader, cMap, offset); + gUnknown_02037340.north = 1; + break; + case CONNECTION_WEST: + fillWestConnection(mapHeader, cMap, offset); + gUnknown_02037340.west = 1; + break; + case CONNECTION_EAST: + fillEastConnection(mapHeader, cMap, offset); + gUnknown_02037340.east = 1; + break; + } + } + } +} + +void sub_8087F54(int x, int y, struct MapHeader const *mapHeader, int x2, int y2, int width, int height) +{ + int i; + u16 *src; + u16 *dest; + int mapWidth; + + mapWidth = mapHeader->mapData->width; + src = &mapHeader->mapData->map[mapWidth * y2 + x2]; + dest = &gUnknown_03005DC0.map[gUnknown_03005DC0.width * y + x]; + + for (i = 0; i < height; i++) + { + CpuCopy16(src, dest, width * 2); + dest += gUnknown_03005DC0.width; + src += mapWidth; + } +} + +void fillSouthConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset) +{ + int x, y; + int x2; + int width; + int cWidth; + + if (connectedMapHeader) + { + cWidth = connectedMapHeader->mapData->width; + x = offset + 7; + y = mapHeader->mapData->height + 7; + if (x < 0) + { + x2 = -x; + x += cWidth; + if (x < gUnknown_03005DC0.width) + { + width = x; + } + else + { + width = gUnknown_03005DC0.width; + } + x = 0; + } + else + { + x2 = 0; + if (x + cWidth < gUnknown_03005DC0.width) + { + width = cWidth; + } + else + { + width = gUnknown_03005DC0.width - x; + } + } + + sub_8087F54( + x, y, + connectedMapHeader, + x2, /*y2*/ 0, + width, /*height*/ 7); + } +} + +void fillNorthConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset) +{ + int x; + int x2, y2; + int width; + int cWidth, cHeight; + + if (connectedMapHeader) + { + cWidth = connectedMapHeader->mapData->width; + cHeight = connectedMapHeader->mapData->height; + x = offset + 7; + y2 = cHeight - 7; + if (x < 0) + { + x2 = -x; + x += cWidth; + if (x < gUnknown_03005DC0.width) + { + width = x; + } + else + { + width = gUnknown_03005DC0.width; + } + x = 0; + } + else + { + x2 = 0; + if (x + cWidth < gUnknown_03005DC0.width) + { + width = cWidth; + } + else + { + width = gUnknown_03005DC0.width - x; + } + } + + sub_8087F54( + x, /*y*/ 0, + connectedMapHeader, + x2, y2, + width, /*height*/ 7); + + } +} + +void fillWestConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset) +{ + int y; + int x2, y2; + int height; + int cWidth, cHeight; + if (connectedMapHeader) + { + cWidth = connectedMapHeader->mapData->width; + cHeight = connectedMapHeader->mapData->height; + y = offset + 7; + x2 = cWidth - 7; + if (y < 0) + { + y2 = -y; + if (y + cHeight < gUnknown_03005DC0.height) + { + height = y + cHeight; + } + else + { + height = gUnknown_03005DC0.height; + } + y = 0; + } + else + { + y2 = 0; + if (y + cHeight < gUnknown_03005DC0.height) + { + height = cHeight; + } + else + { + height = gUnknown_03005DC0.height - y; + } + } + + sub_8087F54( + /*x*/ 0, y, + connectedMapHeader, + x2, y2, + /*width*/ 7, height); + } +} + +void fillEastConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset) +{ + int x, y; + int y2; + int height; + int cHeight; + if (connectedMapHeader) + { + cHeight = connectedMapHeader->mapData->height; + x = mapHeader->mapData->width + 7; + y = offset + 7; + if (y < 0) + { + y2 = -y; + if (y + cHeight < gUnknown_03005DC0.height) + { + height = y + cHeight; + } + else + { + height = gUnknown_03005DC0.height; + } + y = 0; + } + else + { + y2 = 0; + if (y + cHeight < gUnknown_03005DC0.height) + { + height = cHeight; + } + else + { + height = gUnknown_03005DC0.height - y; + } + } + + sub_8087F54( + x, y, + connectedMapHeader, + /*x2*/ 0, y2, + /*width*/ 8, height); + } +} + +union Block +{ + struct + { + u16 block:10; + u16 collision:2; + u16 elevation:4; + } block; + u16 value; +}; + +u8 MapGridGetZCoordAt(int x, int y) +{ + u16 block; + int i; + u16 *border; + + if (x >= 0 && x < gUnknown_03005DC0.width + && y >= 0 && y < gUnknown_03005DC0.height) + { + block = gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y]; + } + else + { + border = gMapHeader.mapData->border; + i = (x + 1) & 1; + i += ((y + 1) & 1) * 2; + block = gMapHeader.mapData->border[i]; + block |= 0xc00; + } + + if (block == 0x3ff) + { + return 0; + } + + return block >> 12; +} + +u8 MapGridIsImpassableAt(int x, int y) +{ + u16 block; + int i; + u16 *border; + + if (x >= 0 && x < gUnknown_03005DC0.width + && y >= 0 && y < gUnknown_03005DC0.height) + { + block = gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y]; + } + else + { + border = gMapHeader.mapData->border; + i = (x + 1) & 1; + i += ((y + 1) & 1) * 2; + block = gMapHeader.mapData->border[i]; + block |= 0xc00; + } + if (block == 0x3ff) + { + return 1; + } + return (block & 0xc00) >> 10; +} + +u32 MapGridGetMetatileIdAt(int x, int y) +{ + u16 block; + int i; + int j; + struct MapData const *mapData; + u16 *border; + u16 block2; + + if (x >= 0 && x < gUnknown_03005DC0.width + && y >= 0 && y < gUnknown_03005DC0.height) + { + block = gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y]; + } + else + { + mapData = gMapHeader.mapData; + i = (x + 1) & 1; + i += ((y + 1) & 1) * 2; + block = mapData->border[i] | 0xc00; + } + if (block == 0x3ff) + { + border = gMapHeader.mapData->border; + j = (x + 1) & 1; + j += ((y + 1) & 1) * 2; + block2 = gMapHeader.mapData->border[j]; + block2 |= 0xc00; + return block2 & block; + } + return block & 0x3ff; +} + +u32 MapGridGetMetatileBehaviorAt(int x, int y) +{ + u16 metatile; + metatile = MapGridGetMetatileIdAt(x, y); + return GetBehaviorByMetatileId(metatile) & 0xff; +} + +u8 MapGridGetMetatileLayerTypeAt(int x, int y) +{ + u16 metatile; + metatile = MapGridGetMetatileIdAt(x, y); + return (GetBehaviorByMetatileId(metatile) & 0xf000) >> 12; +} + +void MapGridSetMetatileIdAt(int x, int y, u16 metatile) +{ + int i; + if (x >= 0 && x < gUnknown_03005DC0.width + && y >= 0 && y < gUnknown_03005DC0.height) + { + i = x + y * gUnknown_03005DC0.width; + gUnknown_03005DC0.map[i] = (gUnknown_03005DC0.map[i] & 0xf000) | (metatile & 0xfff); + } +} + +void MapGridSetMetatileEntryAt(int x, int y, u16 metatile) +{ + int i; + if (x >= 0 && x < gUnknown_03005DC0.width + && y >= 0 && y < gUnknown_03005DC0.height) + { + i = x + gUnknown_03005DC0.width * y; + gUnknown_03005DC0.map[i] = metatile; + } +} + +u16 GetBehaviorByMetatileId(u16 metatile) +{ + u16 *attributes; + if (metatile <= 0x1ff) + { + attributes = gMapHeader.mapData->primaryTileset->metatileAttributes; + return attributes[metatile]; + } + else if (metatile <= 0x3ff) + { + attributes = gMapHeader.mapData->secondaryTileset->metatileAttributes; + return attributes[metatile - 0x200]; + } + else + { + return 0xff; + } +} + +void save_serialize_map(void) +{ + int i, j; + int x, y; + u16 *mapView; + int width; + mapView = gSaveBlock1Ptr->mapView; + width = gUnknown_03005DC0.width; + x = gSaveBlock1Ptr->pos.x; + y = gSaveBlock1Ptr->pos.y; + for (i = y; i < y + 14; i++) + { + for (j = x; j < x + 15; j++) + { + *mapView++ = gUnknown_02032318[width * i + j]; + } + } +} + +int sub_8088438(void) +{ + u16 i; + u32 r2; + r2 = 0; + for (i = 0; i < 0x200; i++) + { + r2 |= gSaveBlock1Ptr->mapView[i]; + } + if (r2 == 0) + { + return 1; + } + return 0; +} + +void sav2_mapdata_clear(void) +{ + CpuFill16(0, gSaveBlock1Ptr->mapView, sizeof(gSaveBlock1Ptr->mapView)); +} + +void mapdata_from_sav2(void) +{ + u8 a0; + int i, j; + int x, y; + u16 *mapView; + int width; + mapView = gSaveBlock1Ptr->mapView; + if (!sub_8088438()) + { + width = gUnknown_03005DC0.width; + x = gSaveBlock1Ptr->pos.x; + y = gSaveBlock1Ptr->pos.y; + for (i = y; i < y + 14; i++) + { + if (i == y && i != 0) + a0 = 0; + else if (i == y + 13 && i != gMapHeader.mapData->height - 1) + a0 = 1; + else + a0 = -1; + + for (j = x; j < x + 15; j++) + { + if (!sub_8088BF0(&gUnknown_02032318[j + width * i], width, a0)) + gUnknown_02032318[j + width * i] = *mapView; + mapView++; + } + } + for (j = x; j < x + 15; j++) + { + if (y != 0) + sub_80D423C(j, y - 1); + if (i < gMapHeader.mapData->height - 1) + sub_80D42B8(j, y + 13); + } + sav2_mapdata_clear(); + } +} + +void sub_80885C4(u8 a1) +{ + int width; + u16 *mapView; + int x0, y0; + int x2, y2; + u16 *src, *dest; + int srci, desti; + int r9, r8; + int x, y; + int i, j; + mapView = gSaveBlock1Ptr->mapView; + width = gUnknown_03005DC0.width; + r9 = 0; + r8 = 0; + x0 = gSaveBlock1Ptr->pos.x; + y0 = gSaveBlock1Ptr->pos.y; + x2 = 15; + y2 = 14; + switch (a1) + { + case CONNECTION_NORTH: + y0 += 1; + y2 = 13; + break; + case CONNECTION_SOUTH: + r8 = 1; + y2 = 13; + break; + case CONNECTION_WEST: + x0 += 1; + x2 = 14; + break; + case CONNECTION_EAST: + r9 = 1; + x2 = 14; + break; + } + for (y = 0; y < y2; y++) + { + i = 0; + j = 0; + for (x = 0; x < x2; x++) + { + desti = width * (y + y0); + srci = (y + r8) * 15 + r9; + src = &mapView[srci + i]; + dest = &gUnknown_02032318[x0 + desti + j]; + *dest = *src; + i++; + j++; + } + } + sav2_mapdata_clear(); +} + +int GetMapBorderIdAt(int x, int y) +{ + struct MapData const *mapData; + u16 block, block2; + int i, j; + if (x >= 0 && x < gUnknown_03005DC0.width + && y >= 0 && y < gUnknown_03005DC0.height) + { + i = gUnknown_03005DC0.width; + i *= y; + block = gUnknown_03005DC0.map[x + i]; + if (block == 0x3ff) + { + goto fail; + } + } + else + { + mapData = gMapHeader.mapData; + j = (x + 1) & 1; + j += ((y + 1) & 1) * 2; + block2 = 0xc00 | mapData->border[j]; + if (block2 == 0x3ff) + { + goto fail; + } + } + goto success; +fail: + return -1; +success: + + if (x >= (gUnknown_03005DC0.width - 8)) + { + if (!gUnknown_02037340.east) + { + return -1; + } + return CONNECTION_EAST; + } + else if (x < 7) + { + if (!gUnknown_02037340.west) + { + return -1; + } + return CONNECTION_WEST; + } + else if (y >= (gUnknown_03005DC0.height - 7)) + { + if (!gUnknown_02037340.south) + { + return -1; + } + return CONNECTION_SOUTH; + } + else if (y < 7) + { + if (!gUnknown_02037340.north) + { + return -1; + } + return CONNECTION_NORTH; + } + else + { + return 0; + } +} + +int GetPostCameraMoveMapBorderId(int x, int y) +{ + return GetMapBorderIdAt(gSaveBlock1Ptr->pos.x + 7 + x, gSaveBlock1Ptr->pos.y + 7 + y); +} + +int CanCameraMoveInDirection(int direction) +{ + int x, y; + x = gSaveBlock1Ptr->pos.x + 7 + gUnknown_08339D64[direction].x; + y = gSaveBlock1Ptr->pos.y + 7 + gUnknown_08339D64[direction].y; + if (GetMapBorderIdAt(x, y) == -1) + { + return 0; + } + return 1; +} + +void sub_80887F8(struct MapConnection *connection, int direction, int x, int y) +{ + struct MapHeader const *mapHeader; + mapHeader = mapconnection_get_mapheader(connection); + switch (direction) + { + case CONNECTION_EAST: + gSaveBlock1Ptr->pos.x = -x; + gSaveBlock1Ptr->pos.y -= connection->offset; + break; + case CONNECTION_WEST: + gSaveBlock1Ptr->pos.x = mapHeader->mapData->width; + gSaveBlock1Ptr->pos.y -= connection->offset; + break; + case CONNECTION_SOUTH: + gSaveBlock1Ptr->pos.x -= connection->offset; + gSaveBlock1Ptr->pos.y = -y; + break; + case CONNECTION_NORTH: + gSaveBlock1Ptr->pos.x -= connection->offset; + gSaveBlock1Ptr->pos.y = mapHeader->mapData->height; + break; + } +} + +bool8 CameraMove(int x, int y) +{ + unsigned int direction; + struct MapConnection *connection; + int old_x, old_y; + gCamera.active = FALSE; + direction = GetPostCameraMoveMapBorderId(x, y); + if (direction + 1 <= 1) + { + gSaveBlock1Ptr->pos.x += x; + gSaveBlock1Ptr->pos.y += y; + } + else + { + save_serialize_map(); + sub_81BE72C(); + old_x = gSaveBlock1Ptr->pos.x; + old_y = gSaveBlock1Ptr->pos.y; + connection = sub_8088950(direction, gSaveBlock1Ptr->pos.x, gSaveBlock1Ptr->pos.y); + sub_80887F8(connection, direction, x, y); + mliX_load_map(connection->mapGroup, connection->mapNum); + gCamera.active = TRUE; + gCamera.x = old_x - gSaveBlock1Ptr->pos.x; + gCamera.y = old_y - gSaveBlock1Ptr->pos.y; + gSaveBlock1Ptr->pos.x += x; + gSaveBlock1Ptr->pos.y += y; + sub_80885C4(direction); + } + return gCamera.active; +} + +struct MapConnection *sub_8088950(u8 direction, int x, int y) +{ + int count; + struct MapConnection *connection; + int i; + count = gMapHeader.connections->count; + connection = gMapHeader.connections->connections; + for (i = 0; i < count; i++, connection++) + { + if (connection->direction == direction && sub_80889A8(direction, x, y, connection) == TRUE) + return connection; + } + return NULL; +} + +bool8 sub_80889A8(u8 direction, int x, int y, struct MapConnection *connection) +{ + struct MapHeader const *mapHeader; + mapHeader = mapconnection_get_mapheader(connection); + switch (direction) + { + case CONNECTION_SOUTH: + case CONNECTION_NORTH: + return sub_8088A0C(x, gMapHeader.mapData->width, mapHeader->mapData->width, connection->offset); + case CONNECTION_WEST: + case CONNECTION_EAST: + return sub_8088A0C(y, gMapHeader.mapData->height, mapHeader->mapData->height, connection->offset); + } + return FALSE; +} + +bool8 sub_8088A0C(int x, int src_width, int dest_width, int offset) +{ + int offset2; + offset2 = offset; + + if (offset2 < 0) + offset2 = 0; + + if (dest_width + offset < src_width) + src_width = dest_width + offset; + + if (offset2 <= x && x <= src_width) + return TRUE; + + return FALSE; +} + +int sub_8088A38(int x, int width) +{ + if (x >= 0 && x < width) + return TRUE; + + return FALSE; +} + +int sub_8088A4C(struct MapConnection *connection, int x, int y) +{ + struct MapHeader const *mapHeader; + mapHeader = mapconnection_get_mapheader(connection); + switch (connection->direction) + { + case CONNECTION_SOUTH: + case CONNECTION_NORTH: + return sub_8088A38(x - connection->offset, mapHeader->mapData->width); + case CONNECTION_WEST: + case CONNECTION_EAST: + return sub_8088A38(y - connection->offset, mapHeader->mapData->height); + } + return FALSE; +} + +struct MapConnection *sub_8088A8C(s16 x, s16 y) +{ + int count; + struct MapConnection *connection; + int i; + u8 direction; + if (!gMapHeader.connections) + { + return NULL; + } + else + { + count = gMapHeader.connections->count; + connection = gMapHeader.connections->connections; + for (i = 0; i < count; i++, connection++) + { + direction = connection->direction; + if ((direction == CONNECTION_DIVE || direction == CONNECTION_EMERGE) + || (direction == CONNECTION_NORTH && y > 6) + || (direction == CONNECTION_SOUTH && y < gMapHeader.mapData->height + 7) + || (direction == CONNECTION_WEST && x > 6) + || (direction == CONNECTION_EAST && x < gMapHeader.mapData->width + 7)) + { + continue; + } + if (sub_8088A4C(connection, x - 7, y - 7) == TRUE) + { + return connection; + } + } + } + return NULL; +} + +void sub_8088B3C(u16 x, u16 y) +{ + gSaveBlock1Ptr->pos.x = x - 7; + gSaveBlock1Ptr->pos.y = y - 7; +} + +void sav1_camera_get_focus_coords(u16 *x, u16 *y) +{ + *x = gSaveBlock1Ptr->pos.x + 7; + *y = gSaveBlock1Ptr->pos.y + 7; +} + +void SetCameraCoords(u16 x, u16 y) +{ + gSaveBlock1Ptr->pos.x = x; + gSaveBlock1Ptr->pos.y = y; +} + +void GetCameraCoords(u16 *x, u16 *y) +{ + *x = gSaveBlock1Ptr->pos.x; + *y = gSaveBlock1Ptr->pos.y; +} + +void sub_8088B94(int x, int y, int a2) +{ + if (x >= 0 && x < gUnknown_03005DC0.width && y >= 0 && y < gUnknown_03005DC0.height) + { + if (a2 != 0) + gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y] |= 0xC00; + else + gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y] &= 0xF3FF; + } +} + +bool8 sub_8088BF0(u16* a0, u16 a1, u8 a2) +{ + if (a2 == 0xFF) + return FALSE; + + if (a2 == 0) + a0 -= a1; + else + a0 += a1; + + if (sub_80FADE4(*a0 & 0x3FF, a2) == 1) + return TRUE; + return FALSE; +} + +void copy_tileset_patterns_to_vram(struct Tileset const *tileset, u16 numTiles, u16 offset) +{ + if (tileset) + { + if (!tileset->isCompressed) + LoadBgTiles(2, tileset->tiles, numTiles * 32, offset); + else + decompress_and_copy_tile_data_to_vram(2, tileset->tiles, numTiles * 32, offset, 0); + } +} + +void copy_tileset_patterns_to_vram2(struct Tileset const *tileset, u16 numTiles, u16 offset) +{ + if (tileset) + { + if (!tileset->isCompressed) + LoadBgTiles(2, tileset->tiles, numTiles * 32, offset); + else + copy_decompressed_tile_data_to_vram_autofree(2, tileset->tiles, numTiles * 32, offset, 0); + } +} + +void nullsub_3(u16 a0, u16 a1) +{ + +} + +void nullsub_90(void) +{ + +} + +void apply_map_tileset_palette(struct Tileset const *tileset, u16 destOffset, u16 size) +{ + u16 black = RGB_BLACK; + + if (tileset) + { + if (tileset->isSecondary == FALSE) + { + LoadPalette(&black, destOffset, 2); + LoadPalette(((u16*)tileset->palettes) + 1, destOffset + 1, size - 2); + nullsub_3(destOffset + 1, (size - 2) >> 1); + } + else if (tileset->isSecondary == TRUE) + { + LoadPalette(((u16*)tileset->palettes) + 0x60, destOffset, size); + nullsub_3(destOffset, size >> 1); + } + else + { + LoadCompressedPalette((u16*)tileset->palettes, destOffset, size); + nullsub_3(destOffset, size >> 1); + } + } +} + +void copy_map_tileset1_to_vram(struct MapData const *mapData) +{ + copy_tileset_patterns_to_vram(mapData->primaryTileset, 0x200, 0); +} + +void copy_map_tileset2_to_vram(struct MapData const *mapData) +{ + copy_tileset_patterns_to_vram(mapData->secondaryTileset, 0x200, 0x200); +} + +void copy_map_tileset2_to_vram_2(struct MapData const *mapData) +{ + copy_tileset_patterns_to_vram2(mapData->secondaryTileset, 0x200, 0x200); +} + +void apply_map_tileset1_palette(struct MapData const *mapData) +{ + apply_map_tileset_palette(mapData->primaryTileset, 0, 0xC0); +} + +void apply_map_tileset2_palette(struct MapData const *mapData) +{ + apply_map_tileset_palette(mapData->secondaryTileset, 0x60, 0xE0); +} + +void copy_map_tileset1_tileset2_to_vram(struct MapData const *mapData) +{ + if (mapData) + { + copy_tileset_patterns_to_vram2(mapData->primaryTileset, 0x200, 0); + copy_tileset_patterns_to_vram2(mapData->secondaryTileset, 0x200, 0x200); + } +} + +void apply_map_tileset1_tileset2_palette(struct MapData const *mapData) +{ + if (mapData) + { + apply_map_tileset1_palette(mapData); + apply_map_tileset2_palette(mapData); + } +} diff --git a/src/item.c b/src/item.c index 0c60c417d..975fef3ae 100644 --- a/src/item.c +++ b/src/item.c @@ -5,52 +5,48 @@ #include "string_util.h" #include "text.h" #include "event_data.h" +#include "malloc.h" +#include "secret_base.h" +#include "item_menu.h" +#include "strings.h" +#include "load_save.h" -extern void ApplyNewEncryptionKeyToHword(u16* hword, u32 newKey); extern bool8 InBattlePyramid(void); +extern u16 gUnknown_0203CF30[]; +extern const struct Item gItems[]; -extern const u8 gText_PokeBalls[]; -extern const u8 gText_Berries[]; -extern const u8 gText_Berry[]; +// this file's functions +static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count); +static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count); -bool8 CheckPyramidBagHasItem(u16 itemId, u16 count); -bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count); +// EWRAM variables +EWRAM_DATA struct BagPocket gBagPockets[POCKETS_COUNT] = {0}; -enum -{ - ITEMS_POCKET, - BALLS_POCKET, - TMHM_POCKET, - BERRIES_POCKET, - KEYITEMS_POCKET -}; - -EWRAM_DATA struct BagPocket gBagPockets[5] = {}; - -u16 GetBagItemQuantity(u16* quantity) +// code +static u16 GetBagItemQuantity(u16 *quantity) { return gSaveBlock2Ptr->encryptionKey ^ *quantity; } -void SetBagItemQuantity(u16* quantity, u16 newValue) +static void SetBagItemQuantity(u16 *quantity, u16 newValue) { *quantity = newValue ^ gSaveBlock2Ptr->encryptionKey; } -u16 GetBagItemId(u16* slot) +static u16 GetPCItemQuantity(u16 *quantity) { - return *slot; + return *quantity; } -void SetBagItemId(u16* slot, u16 newItemId) +static void SetPCItemQuantity(u16 *quantity, u16 newValue) { - *slot = newItemId; + *quantity = newValue; } void ApplyNewEncryptionKeyToBagItems(u32 newKey) { u32 pocket, item; - for (pocket = 0; pocket < 5; pocket++) + for (pocket = 0; pocket < POCKETS_COUNT; pocket++) { for (item = 0; item < gBagPockets[pocket].capacity; item++) ApplyNewEncryptionKeyToHword(&(gBagPockets[pocket].itemSlots[item].quantity), newKey); @@ -62,58 +58,57 @@ void ApplyNewEncryptionKeyToBagItems_(u32 newKey) // really GF? ApplyNewEncryptionKeyToBagItems(newKey); } -// TODO: move those max values to defines - void SetBagItemsPointers(void) { gBagPockets[ITEMS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_Items; - gBagPockets[ITEMS_POCKET].capacity = 30; + gBagPockets[ITEMS_POCKET].capacity = BAG_ITEMS_COUNT; gBagPockets[KEYITEMS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_KeyItems; - gBagPockets[KEYITEMS_POCKET].capacity = 30; + gBagPockets[KEYITEMS_POCKET].capacity = BAG_KEYITEMS_COUNT; gBagPockets[BALLS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_PokeBalls; - gBagPockets[BALLS_POCKET].capacity = 16; + gBagPockets[BALLS_POCKET].capacity = BAG_POKEBALLS_COUNT; gBagPockets[TMHM_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_TMHM; - gBagPockets[TMHM_POCKET].capacity = 64; + gBagPockets[TMHM_POCKET].capacity = BAG_TMHM_COUNT; gBagPockets[BERRIES_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_Berries; - gBagPockets[BERRIES_POCKET].capacity = 46; + gBagPockets[BERRIES_POCKET].capacity = BAG_BERRIES_COUNT; } -void CopyItemName(u16 itemId, u8 *string) +void CopyItemName(u16 itemId, u8 *dst) { - StringCopy(string, ItemId_GetItem(itemId)->name); + StringCopy(dst, ItemId_GetName(itemId)); } -void CopyItemNameHandlePlural(u16 itemId, u8 *string, u32 quantity) +void CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity) { if (itemId == ITEM_POKE_BALL) { if (quantity < 2) - StringCopy(string, ItemId_GetItem(ITEM_POKE_BALL)->name); + StringCopy(dst, ItemId_GetName(ITEM_POKE_BALL)); else - StringCopy(string, gText_PokeBalls); + StringCopy(dst, gText_PokeBalls); } else { if (itemId >= ITEM_CHERI_BERRY && itemId <= ITEM_ENIGMA_BERRY) - GetBerryCountString(string, gBerries[itemId - ITEM_CHERI_BERRY].name, quantity); + GetBerryCountString(dst, gBerries[itemId - ITEM_CHERI_BERRY].name, quantity); else - StringCopy(string, ItemId_GetItem(itemId)->name); + StringCopy(dst, ItemId_GetName(itemId)); } } -void GetBerryCountString(u8* dst, const u8* berryName, u32 quantity) +void GetBerryCountString(u8 *dst, const u8 *berryName, u32 quantity) { - const u8* berryString; - u8* txtPtr; + const u8 *berryString; + u8 *txtPtr; if (quantity < 2) berryString = gText_Berry; else berryString = gText_Berries; + txtPtr = StringCopy(dst, berryName); *txtPtr = CHAR_SPACE; StringCopy(txtPtr + 1, berryString); @@ -138,21 +133,21 @@ bool8 CheckBagHasItem(u16 itemId, u16 count) if (ItemId_GetPocket(itemId) == 0) return FALSE; - if (InBattlePyramid() || FlagGet(0x4004) == TRUE) + if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE) return CheckPyramidBagHasItem(itemId, count); pocket = ItemId_GetPocket(itemId) - 1; - //Check for item slots that contain the item + // Check for item slots that contain the item for (i = 0; i < gBagPockets[pocket].capacity; i++) { if (gBagPockets[pocket].itemSlots[i].itemId == itemId) { u16 quantity; - //Does this item slot contain enough of the item? + // Does this item slot contain enough of the item? quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); if (quantity >= count) return TRUE; count -= quantity; - //Does this item slot and all previous slots contain enough of the item? + // Does this item slot and all previous slots contain enough of the item? if (count == 0) return TRUE; } @@ -163,69 +158,945 @@ bool8 CheckBagHasItem(u16 itemId, u16 count) bool8 HasAtLeastOneBerry(void) { u16 i; - for (i = 0x85; i < 0xB3; i++) + + for (i = FIRST_BERRY_INDEX; i < ITEM_BRIGHT_POWDER; i++) { if (CheckBagHasItem(i, 1) == TRUE) { - gSpecialVar_Result = 1; + gSpecialVar_Result = TRUE; return TRUE; } } - gSpecialVar_Result = 0; + gSpecialVar_Result = FALSE; return FALSE; } -/* Refuses to match. +#ifdef NONMATCHING +// Refuses to match. bool8 CheckBagHasSpace(u16 itemId, u16 count) { u8 i; - u8 pocket; - u16 slotCapacity; - u16 quantity; - if (ItemId_GetPocket(itemId) == 0) + if (ItemId_GetPocket(itemId) == POCKET_NONE) return FALSE; - if (InBattlePyramid() || FlagGet(0x4004) == TRUE) + + if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE) + { return CheckPyramidBagHasSpace(itemId, count); - pocket = ItemId_GetPocket(itemId) - 1; - if (pocket != BERRIES_POCKET) - slotCapacity = 99; + } else - slotCapacity = 999; + { + u8 pocket; + u16 slotCapacity; + u16 ownedCount; - //Check space in any existing item slots that already contain this item - for (i = 0; i < gBagPockets[pocket].capacity; i++) + pocket = ItemId_GetPocket(itemId) - 1; + if (pocket != BERRIES_POCKET) + slotCapacity = 99; + else + slotCapacity = 999; + + // Check space in any existing item slots that already contain this item + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == itemId) + { + ownedCount = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); + if (ownedCount + count <= slotCapacity) + return TRUE; + if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET) + return FALSE; + count -= slotCapacity - ownedCount; + if (count == 0) + return TRUE; + } + } + + // Check space in empty item slots + if (count > 0) + { + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == 0) + { + if (count <= slotCapacity) + return TRUE; + if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET) + return FALSE; + count -= slotCapacity; + } + } + if (count > 0) + return FALSE; // No more item slots. The bag is full + } + + return TRUE; + } +} +#else +ASM_DIRECT +bool8 CheckBagHasSpace(u16 itemId, u16 count) +{ + asm_unified("push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0x4\n\ + lsls r0, 16\n\ + lsrs r0, 16\n\ + mov r8, r0\n\ + lsls r1, 16\n\ + lsrs r5, r1, 16\n\ + bl ItemId_GetPocket\n\ + lsls r0, 24\n\ + cmp r0, 0\n\ + beq _080D6906\n\ + bl InBattlePyramid\n\ + lsls r0, 24\n\ + cmp r0, 0\n\ + bne _080D6838\n\ + ldr r0, =0x00004004\n\ + bl FlagGet\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + cmp r0, 0x1\n\ + bne _080D684C\n\ +_080D6838:\n\ + mov r0, r8\n\ + adds r1, r5, 0\n\ + bl CheckPyramidBagHasSpace\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + b _080D6916\n\ + .pool\n\ +_080D684C:\n\ + mov r0, r8\n\ + bl ItemId_GetPocket\n\ + subs r0, 0x1\n\ + lsls r0, 24\n\ + lsrs r2, r0, 24\n\ + ldr r7, =0x000003e7\n\ + cmp r2, 0x3\n\ + beq _080D6860\n\ + movs r7, 0x63\n\ +_080D6860:\n\ + movs r6, 0\n\ + ldr r1, =gBagPockets\n\ + lsls r4, r2, 3\n\ + adds r0, r4, r1\n\ + mov r9, r4\n\ + ldrb r0, [r0, 0x4]\n\ + cmp r6, r0\n\ + bcs _080D68BC\n\ + subs r0, r2, 0x2\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + mov r10, r0\n\ +_080D6878:\n\ + adds r0, r4, r1\n\ + ldr r1, [r0]\n\ + lsls r0, r6, 2\n\ + adds r1, r0, r1\n\ + ldrh r0, [r1]\n\ + cmp r0, r8\n\ + bne _080D68AC\n\ + adds r0, r1, 0x2\n\ + str r2, [sp]\n\ + bl GetBagItemQuantity\n\ + lsls r0, 16\n\ + lsrs r1, r0, 16\n\ + adds r0, r1, r5\n\ + ldr r2, [sp]\n\ + cmp r0, r7\n\ + ble _080D6914\n\ + mov r0, r10\n\ + cmp r0, 0x1\n\ + bls _080D6906\n\ + subs r0, r7, r1\n\ + subs r0, r5, r0\n\ + lsls r0, 16\n\ + lsrs r5, r0, 16\n\ + cmp r5, 0\n\ + beq _080D6914\n\ +_080D68AC:\n\ + adds r0, r6, 0x1\n\ + lsls r0, 24\n\ + lsrs r6, r0, 24\n\ + ldr r1, =gBagPockets\n\ + adds r0, r4, r1\n\ + ldrb r0, [r0, 0x4]\n\ + cmp r6, r0\n\ + bcc _080D6878\n\ +_080D68BC:\n\ + cmp r5, 0\n\ + beq _080D6914\n\ + movs r6, 0\n\ + ldr r3, =gBagPockets\n\ + mov r1, r9\n\ + adds r0, r1, r3\n\ + ldrb r0, [r0, 0x4]\n\ + cmp r6, r0\n\ + bcs _080D6902\n\ + adds r4, r3, 0\n\ + subs r0, r2, 0x2\n\ + lsls r0, 24\n\ + lsrs r2, r0, 24\n\ +_080D68D6:\n\ + adds r0, r1, r4\n\ + ldr r1, [r0]\n\ + lsls r0, r6, 2\n\ + adds r0, r1\n\ + ldrh r0, [r0]\n\ + cmp r0, 0\n\ + bne _080D68F2\n\ + cmp r5, r7\n\ + bls _080D6914\n\ + cmp r2, 0x1\n\ + bls _080D6906\n\ + subs r0, r5, r7\n\ + lsls r0, 16\n\ + lsrs r5, r0, 16\n\ +_080D68F2:\n\ + adds r0, r6, 0x1\n\ + lsls r0, 24\n\ + lsrs r6, r0, 24\n\ + mov r1, r9\n\ + adds r0, r1, r3\n\ + ldrb r0, [r0, 0x4]\n\ + cmp r6, r0\n\ + bcc _080D68D6\n\ +_080D6902:\n\ + cmp r5, 0\n\ + beq _080D6914\n\ +_080D6906:\n\ + movs r0, 0\n\ + b _080D6916\n\ + .pool\n\ +_080D6914:\n\ + movs r0, 0x1\n\ +_080D6916:\n\ + add sp, 0x4\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r1}\n\ + bx r1"); +} +#endif // NONMATCHING + +bool8 AddBagItem(u16 itemId, u16 count) +{ + u8 i; + + if (ItemId_GetPocket(itemId) == POCKET_NONE) + return FALSE; + + // check Battle Pyramid Bag + if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE) { - if (gBagPockets[pocket].itemSlots[i].itemId == itemId) + return AddPyramidBagItem(itemId, count); + } + else + { + struct BagPocket *itemPocket; + struct ItemSlot *newItems; + u16 slotCapacity; + u16 ownedCount; + u8 pocket = ItemId_GetPocket(itemId) - 1; + + itemPocket = &gBagPockets[pocket]; + newItems = AllocZeroed(itemPocket->capacity * sizeof(struct ItemSlot)); + memcpy(newItems, itemPocket->itemSlots, itemPocket->capacity * sizeof(struct ItemSlot)); + + if (pocket != BERRIES_POCKET) + slotCapacity = 99; + else + slotCapacity = 999; + + for (i = 0; i < itemPocket->capacity; i++) { - quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); - if (quantity + count <= slotCapacity) - return TRUE; - if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET) + if (newItems[i].itemId == itemId) + { + ownedCount = GetBagItemQuantity(&newItems[i].quantity); + // check if won't exceed max slot capacity + if (ownedCount + count <= slotCapacity) + { + // successfully added to already existing item's count + SetBagItemQuantity(&newItems[i].quantity, ownedCount + count); + + // goto SUCCESS_ADD_ITEM; + // is equivalent but won't match + + memcpy(itemPocket->itemSlots, newItems, itemPocket->capacity * sizeof(struct ItemSlot)); + Free(newItems); + return TRUE; + } + else + { + // try creating another instance of the item if possible + if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET) + { + Free(newItems); + return FALSE; + } + else + { + count -= slotCapacity - ownedCount; + SetBagItemQuantity(&newItems[i].quantity, slotCapacity); + // don't create another instance of the item if it's at max slot capacity and count is equal to 0 + if (count == 0) + { + goto SUCCESS_ADD_ITEM; + } + } + } + } + } + + // we're done if quantity is equal to 0 + if (count > 0) + { + // either no existing item was found or we have to create another instance, because the capacity was exceeded + for (i = 0; i < itemPocket->capacity; i++) + { + if (newItems[i].itemId == ITEM_NONE) + { + newItems[i].itemId = itemId; + if (count > slotCapacity) + { + // try creating a new slot with max capacity if duplicates are possible + if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET) + { + Free(newItems); + return FALSE; + } + count -= slotCapacity; + SetBagItemQuantity(&newItems[i].quantity, slotCapacity); + } + else + { + // created a new slot and added quantity + SetBagItemQuantity(&newItems[i].quantity, count); + goto SUCCESS_ADD_ITEM; + } + } + } + + if (count > 0) + { + Free(newItems); return FALSE; - count -= slotCapacity - quantity; + } + } + + SUCCESS_ADD_ITEM: + memcpy(itemPocket->itemSlots, newItems, itemPocket->capacity * sizeof(struct ItemSlot)); + Free(newItems); + return TRUE; + } +} + +bool8 RemoveBagItem(u16 itemId, u16 count) +{ + u8 i; + u16 totalQuantity = 0; + + if (ItemId_GetPocket(itemId) == POCKET_NONE || itemId == ITEM_NONE) + return FALSE; + + // check Battle Pyramid Bag + if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE) + { + return RemovePyramidBagItem(itemId, count); + } + else + { + u8 pocket; + u8 var; + u16 ownedCount; + struct BagPocket *itemPocket; + + pocket = ItemId_GetPocket(itemId) - 1; + itemPocket = &gBagPockets[pocket]; + + for (i = 0; i < itemPocket->capacity; i++) + { + if (itemPocket->itemSlots[i].itemId == itemId) + totalQuantity += GetBagItemQuantity(&itemPocket->itemSlots[i].quantity); + } + + if (totalQuantity < count) + return FALSE; // We don't have enough of the item + + if (CurrentMapIsSecretBase() == TRUE) + { + VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x200); + VarSet(VAR_0x40ED, itemId); + } + + var = sub_81ABB2C(pocket); + if (itemPocket->capacity > var + && itemPocket->itemSlots[var].itemId == itemId) + { + ownedCount = GetBagItemQuantity(&itemPocket->itemSlots[var].quantity); + if (ownedCount >= count) + { + SetBagItemQuantity(&itemPocket->itemSlots[var].quantity, ownedCount - count); + count = 0; + } + else + { + count -= ownedCount; + SetBagItemQuantity(&itemPocket->itemSlots[var].quantity, 0); + } + + if (GetBagItemQuantity(&itemPocket->itemSlots[var].quantity) == 0) + itemPocket->itemSlots[var].itemId = ITEM_NONE; + if (count == 0) return TRUE; } + + for (i = 0; i < itemPocket->capacity; i++) + { + if (itemPocket->itemSlots[i].itemId == itemId) + { + ownedCount = GetBagItemQuantity(&itemPocket->itemSlots[i].quantity); + if (ownedCount >= count) + { + SetBagItemQuantity(&itemPocket->itemSlots[i].quantity, ownedCount - count); + count = 0; + } + else + { + count -= ownedCount; + SetBagItemQuantity(&itemPocket->itemSlots[i].quantity, 0); + } + + if (GetBagItemQuantity(&itemPocket->itemSlots[i].quantity) == 0) + itemPocket->itemSlots[i].itemId = ITEM_NONE; + + if (count == 0) + return TRUE; + } + } + return TRUE; } +} - //Check space in empty item slots - if (count > 0) +u8 GetPocketByItemId(u16 itemId) +{ + return ItemId_GetPocket(itemId); +} + +void ClearItemSlots(struct ItemSlot *itemSlots, u8 itemCount) +{ + u16 i; + + for (i = 0; i < itemCount; i++) { - for (i = 0; i < gBagPockets[pocket].capacity; i++) + itemSlots[i].itemId = ITEM_NONE; + SetBagItemQuantity(&itemSlots[i].quantity, 0); + } +} + +static s32 FindFreePCItemSlot(void) +{ + s8 i; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == ITEM_NONE) + return i; + } + return -1; +} + +u8 CountUsedPCItemSlots(void) +{ + u8 usedSlots = 0; + u8 i; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId != ITEM_NONE) + usedSlots++; + } + return usedSlots; +} + +bool8 CheckPCHasItem(u16 itemId, u16 count) +{ + u8 i; + + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == itemId && GetPCItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity) >= count) + return TRUE; + } + return FALSE; +} + +bool8 AddPCItem(u16 itemId, u16 count) +{ + u8 i; + s8 freeSlot; + u16 ownedCount; + struct ItemSlot *newItems; + + // Copy PC items + newItems = AllocZeroed(sizeof(gSaveBlock1Ptr->pcItems)); + memcpy(newItems, gSaveBlock1Ptr->pcItems, sizeof(gSaveBlock1Ptr->pcItems)); + + // Use any item slots that already contain this item + for (i = 0; i < PC_ITEMS_COUNT; i++) + { + if (newItems[i].itemId == itemId) { - if (gBagPockets[pocket].itemSlots[i].itemId == 0) + ownedCount = GetPCItemQuantity(&newItems[i].quantity); + if (ownedCount + count <= 999) { - if (count <= slotCapacity) - return TRUE; - if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET) - return FALSE; - count -= slotCapacity; + SetPCItemQuantity(&newItems[i].quantity, ownedCount + count); + memcpy(gSaveBlock1Ptr->pcItems, newItems, sizeof(gSaveBlock1Ptr->pcItems)); + Free(newItems); + return TRUE; + } + count += ownedCount - 999; + SetPCItemQuantity(&newItems[i].quantity, 999); + if (count == 0) + { + memcpy(gSaveBlock1Ptr->pcItems, newItems, sizeof(gSaveBlock1Ptr->pcItems)); + Free(newItems); + return TRUE; } } - if (count > 0) - return FALSE; //No more item slots. The bag is full } + // Put any remaining items into a new item slot. + if (count > 0) + { + freeSlot = FindFreePCItemSlot(); + if (freeSlot == -1) + { + Free(newItems); + return FALSE; + } + else + { + newItems[freeSlot].itemId = itemId; + SetPCItemQuantity(&newItems[freeSlot].quantity, count); + } + } + + // Copy items back to the PC + memcpy(gSaveBlock1Ptr->pcItems, newItems, sizeof(gSaveBlock1Ptr->pcItems)); + Free(newItems); return TRUE; -}*/ +} + +void RemovePCItem(u8 index, u16 count) +{ + // UB: should use GetPCItemQuantity and SetPCItemQuantity functions + gSaveBlock1Ptr->pcItems[index].quantity -= count; + if (gSaveBlock1Ptr->pcItems[index].quantity == 0) + { + gSaveBlock1Ptr->pcItems[index].itemId = ITEM_NONE; + CompactPCItems(); + } +} + +void CompactPCItems(void) +{ + u16 i; + u16 j; + + for (i = 0; i < PC_ITEMS_COUNT - 1; i++) + { + for (j = i + 1; j < PC_ITEMS_COUNT; j++) + { + if (gSaveBlock1Ptr->pcItems[i].itemId == 0) + { + struct ItemSlot temp = gSaveBlock1Ptr->pcItems[i]; + gSaveBlock1Ptr->pcItems[i] = gSaveBlock1Ptr->pcItems[j]; + gSaveBlock1Ptr->pcItems[j] = temp; + } + } + } +} + +void SwapRegisteredBike(void) +{ + switch (gSaveBlock1Ptr->registeredItem) + { + case ITEM_MACH_BIKE: + gSaveBlock1Ptr->registeredItem = ITEM_ACRO_BIKE; + break; + case ITEM_ACRO_BIKE: + gSaveBlock1Ptr->registeredItem = ITEM_MACH_BIKE; + break; + } +} + +u16 BagGetItemIdByPocketPosition(u8 pocketId, u16 pocketPos) +{ + return gBagPockets[pocketId - 1].itemSlots[pocketPos].itemId; +} + +u16 BagGetQuantityByPocketPosition(u8 pocketId, u16 pocketPos) +{ + return GetBagItemQuantity(&gBagPockets[pocketId - 1].itemSlots[pocketPos].quantity); +} + +static void SwapItemSlots(struct ItemSlot *a, struct ItemSlot *b) +{ + struct ItemSlot temp = *a; + *a = *b; + *b = temp; +} + +void CompactItemsInBagPocket(struct BagPocket *bagPocket) +{ + u16 i, j; + + for (i = 0; i < bagPocket->capacity - 1; i++) + { + for (j = i + 1; j < bagPocket->capacity; j++) + { + if (GetBagItemQuantity(&bagPocket->itemSlots[i].quantity) == 0) + SwapItemSlots(&bagPocket->itemSlots[i], &bagPocket->itemSlots[j]); + } + } +} + +void SortBerriesOrTMHMs(struct BagPocket *bagPocket) +{ + u16 i, j; + + for (i = 0; i < bagPocket->capacity - 1; i++) + { + for (j = i + 1; j < bagPocket->capacity; j++) + { + if (GetBagItemQuantity(&bagPocket->itemSlots[i].quantity) != 0) + { + if (GetBagItemQuantity(&bagPocket->itemSlots[j].quantity) == 0) + continue; + if (bagPocket->itemSlots[i].itemId <= bagPocket->itemSlots[j].itemId) + continue; + } + SwapItemSlots(&bagPocket->itemSlots[i], &bagPocket->itemSlots[j]); + } + } +} + +void MoveItemSlotInList(struct ItemSlot* itemSlots_, u32 from, u32 to_) +{ + // dumb assignments needed to match + struct ItemSlot *itemSlots = itemSlots_; + u32 to = to_; + + if (from != to) + { + s16 i, count; + struct ItemSlot firstSlot = itemSlots[from]; + + if (to > from) + { + to--; + for (i = from, count = to; i < count; i++) + itemSlots[i] = itemSlots[i + 1]; + } + else + { + for (i = from, count = to; i > count; i--) + itemSlots[i] = itemSlots[i - 1]; + } + itemSlots[to] = firstSlot; + } +} + +void ClearBag(void) +{ + u16 i; + + for (i = 0; i < POCKETS_COUNT; i++) + { + ClearItemSlots(gBagPockets[i].itemSlots, gBagPockets[i].capacity); + } +} + +u16 CountTotalItemQuantityInBag(u16 itemId) +{ + u16 i; + u16 ownedCount = 0; + struct BagPocket *bagPocket = &gBagPockets[ItemId_GetPocket(itemId) - 1]; + + for (i = 0; i < bagPocket->capacity; i++) + { + if (bagPocket->itemSlots[i].itemId == itemId) + ownedCount += GetBagItemQuantity(&bagPocket->itemSlots[i].quantity); + } + + return ownedCount; +} + +static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count) +{ + u8 i; + u16 *items = gSaveBlock2Ptr->pyramidBag.itemId[gSaveBlock2Ptr->frontierChosenLvl]; + u8 *quantities = gSaveBlock2Ptr->pyramidBag.quantity[gSaveBlock2Ptr->frontierChosenLvl]; + + for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++) + { + if (items[i] == itemId) + { + if (quantities[i] >= count) + return TRUE; + + count -= quantities[i]; + if (count == 0) + return TRUE; + } + } + + return FALSE; +} + +static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count) +{ + u8 i; + u16 *items = gSaveBlock2Ptr->pyramidBag.itemId[gSaveBlock2Ptr->frontierChosenLvl]; + u8 *quantities = gSaveBlock2Ptr->pyramidBag.quantity[gSaveBlock2Ptr->frontierChosenLvl]; + + for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++) + { + if (items[i] == itemId || items[i] == ITEM_NONE) + { + if (quantities[i] + count <= 99) + return TRUE; + + count = (quantities[i] + count) - 99; + if (count == 0) + return TRUE; + } + } + + return FALSE; +} + +bool8 AddPyramidBagItem(u16 itemId, u16 count) +{ + u16 i; + + u16 *items = gSaveBlock2Ptr->pyramidBag.itemId[gSaveBlock2Ptr->frontierChosenLvl]; + u8 *quantities = gSaveBlock2Ptr->pyramidBag.quantity[gSaveBlock2Ptr->frontierChosenLvl]; + + u16 *newItems = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(u16)); + u8 *newQuantities = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(u8)); + + memcpy(newItems, items, PYRAMID_BAG_ITEMS_COUNT * sizeof(u16)); + memcpy(newQuantities, quantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(u8)); + + for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++) + { + if (newItems[i] == itemId && newQuantities[i] < 99) + { + newQuantities[i] += count; + if (newQuantities[i] > 99) + { + count = newQuantities[i] - 99; + newQuantities[i] = 99; + } + else + { + count = 0; + } + + if (count == 0) + break; + } + } + + if (count > 0) + { + for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++) + { + if (newItems[i] == ITEM_NONE) + { + newItems[i] = itemId; + newQuantities[i] = count; + if (newQuantities[i] > 99) + { + count = newQuantities[i] - 99; + newQuantities[i] = 99; + } + else + { + count = 0; + } + + if (count == 0) + break; + } + } + } + + if (count == 0) + { + memcpy(items, newItems, PYRAMID_BAG_ITEMS_COUNT * sizeof(u16)); + memcpy(quantities, newQuantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(u8)); + Free(newItems); + Free(newQuantities); + return TRUE; + } + else + { + Free(newItems); + Free(newQuantities); + return FALSE; + } +} + +bool8 RemovePyramidBagItem(u16 itemId, u16 count) +{ + u16 i; + + u16 *items = gSaveBlock2Ptr->pyramidBag.itemId[gSaveBlock2Ptr->frontierChosenLvl]; + u8 *quantities = gSaveBlock2Ptr->pyramidBag.quantity[gSaveBlock2Ptr->frontierChosenLvl]; + + i = gUnknown_0203CF30[3] + gUnknown_0203CF30[4]; + if (items[i] == itemId && quantities[i] >= count) + { + quantities[i] -= count; + if (quantities[i] == 0) + items[i] = ITEM_NONE; + return TRUE; + } + else + { + u16 *newItems = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(u16)); + u8 *newQuantities = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(u8)); + + memcpy(newItems, items, PYRAMID_BAG_ITEMS_COUNT * sizeof(u16)); + memcpy(newQuantities, quantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(u8)); + + for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++) + { + if (newItems[i] == itemId) + { + if (newQuantities[i] >= count) + { + newQuantities[i] -= count; + count = 0; + if (newQuantities[i] == 0) + newItems[i] = ITEM_NONE; + } + else + { + count -= newQuantities[i]; + newQuantities[i] = 0; + newItems[i] = ITEM_NONE; + } + + if (count == 0) + break; + } + } + + if (count == 0) + { + memcpy(items, newItems, PYRAMID_BAG_ITEMS_COUNT * sizeof(u16)); + memcpy(quantities, newQuantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(u8)); + Free(newItems); + Free(newQuantities); + return TRUE; + } + else + { + Free(newItems); + Free(newQuantities); + return FALSE; + } + } +} + +static u16 SanitizeItemId(u16 itemId) +{ + if (itemId >= ITEM_LAST_ID + 1) + return ITEM_NONE; + else + return itemId; +} + +const u8 *ItemId_GetName(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].name; +} + +u16 ItemId_GetId(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].itemId; +} + +u16 ItemId_GetPrice(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].price; +} + +u8 ItemId_GetHoldEffect(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].holdEffect; +} + +u8 ItemId_GetHoldEffectParam(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].holdEffectParam; +} + +const u8 *ItemId_GetDescription(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].description; +} + +u8 ItemId_GetImportance(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].importance; +} + +// unused +u8 ItemId_GetUnknownValue(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].unk19; +} + +u8 ItemId_GetPocket(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].pocket; +} + +u8 ItemId_GetType(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].type; +} + +ItemUseFunc ItemId_GetFieldFunc(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].fieldUseFunc; +} + +u8 ItemId_GetBattleUsage(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].battleUsage; +} + +ItemUseFunc ItemId_GetBattleFunc(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].battleUseFunc; +} + +u8 ItemId_GetSecondaryId(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].secondaryId; +} diff --git a/src/item_icon.c b/src/item_icon.c index 4aaad9c31..d6fedf892 100644 --- a/src/item_icon.c +++ b/src/item_icon.c @@ -4,13 +4,13 @@ #include "sprite.h" #include "decompress.h" #include "constants/items.h" +#include "data/item_icon_table.h" // EWRAM vars EWRAM_DATA void *gItemIconDecompressionBuffer = NULL; EWRAM_DATA void *gItemIcon4x4Buffer = NULL; // const rom data -extern const void *const gItemIconTable[][2]; // todo: move to C file static const struct OamData sOamData_ItemIcon = { diff --git a/src/item_menu.c b/src/item_menu.c index 8c05f0828..d7edea301 100755 --- a/src/item_menu.c +++ b/src/item_menu.c @@ -72,7 +72,7 @@ void AddBagItemIconSprite(u16, u8); void bag_menu_print_description_box_text(int); void bag_menu_print_cursor(u8, u8); void bag_menu_print(u8, u8, const u8*, u8, u8, u8, u8, u8, u8); -bool8 itemid_is_unique(u16); +bool8 ItemId_GetImportance(u16); u16 BagGetQuantityByPocketPosition(u8, u16); void sub_81AB89C(void); void task_close_bag_menu_2(u8); @@ -687,7 +687,7 @@ void sub_81AB520(u8 rboxId, int item_index_in_pocket, u8 a) offset = GetStringRightAlignXOffset(7, gStringVar4, 0x77); bag_menu_print(rboxId, 7, gStringVar4, offset, a, 0, 0, -1, 0); } - else if (gUnknown_0203CE58.pocket != 4 && (unique = itemid_is_unique(itemId)) == FALSE) + else if (gUnknown_0203CE58.pocket != 4 && (unique = ItemId_GetImportance(itemId)) == FALSE) { ConvertIntToDecimalStringN(gStringVar1, itemQuantity, 1, 2); StringExpandPlaceholders(gStringVar4, gText_xVar1); @@ -804,10 +804,10 @@ void sub_81AB9A8(u8 pocketId) { case 2: case 3: - sub_80D6FB4(pocket); + SortBerriesOrTMHMs(pocket); break; default: - sub_80D6F64(pocket); + CompactItemsInBagPocket(pocket); break; } gUnknown_0203CE54->unk829[pocketId] = 0; @@ -847,9 +847,9 @@ void sub_81ABAE0(void) sub_8122298(&gUnknown_0203CE58.scrollPosition[i], &gUnknown_0203CE58.cursorPosition[i], gUnknown_0203CE54->unk82E[i], gUnknown_0203CE54->unk829[i], 8); } -u8 sub_81ABB2C(u8 a) +u8 sub_81ABB2C(u8 pocketId) { - return gUnknown_0203CE58.scrollPosition[a] + gUnknown_0203CE58.cursorPosition[a]; + return gUnknown_0203CE58.scrollPosition[pocketId] + gUnknown_0203CE58.cursorPosition[pocketId]; } void DisplayItemMessage(u8 taskId, u8 fontId, const u8 *str, void ( *callback)(u8 taskId)) @@ -1179,7 +1179,7 @@ void sub_81AC498(u8 taskId) sub_81AC590(taskId); else { - sub_80D702C(gBagPockets[gUnknown_0203CE58.pocket].itemSlots, data[1], realPos); + MoveItemSlotInList(gBagPockets[gUnknown_0203CE58.pocket].itemSlots, data[1], realPos); gUnknown_0203CE54->unk81A = -1; DestroyListMenuTask(data[0], scrollPos, cursorPos); if (data[1] < realPos) @@ -1231,7 +1231,7 @@ void sub_81AC644(u8 unused) gUnknown_0203CE54->unk828 = 4; break; case 8: - if (!itemid_is_unique(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY) + if (!ItemId_GetImportance(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY) { gUnknown_0203CE54->unk820 = gUnknown_0861404B; gUnknown_0203CE54->unk828 = 2; @@ -1243,7 +1243,7 @@ void sub_81AC644(u8 unused) } break; case 6: - if (!itemid_is_unique(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY) + if (!ItemId_GetImportance(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY) { gUnknown_0203CE54->unk820 = gUnknown_0861404D; gUnknown_0203CE54->unk828 = 2; @@ -1255,7 +1255,7 @@ void sub_81AC644(u8 unused) } break; case 7: - if (!itemid_is_unique(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY) + if (!ItemId_GetImportance(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY) { gUnknown_0203CE54->unk820 = gUnknown_0861404F; gUnknown_0203CE54->unk828 = 2; @@ -1605,7 +1605,7 @@ void ItemMenu_Give(u8 taskId) { DisplayItemMessage(taskId, 1, gText_CantWriteMail, sub_81AD350); } - else if (!itemid_is_unique(gSpecialVar_ItemId)) + else if (!ItemId_GetImportance(gSpecialVar_ItemId)) { if (CalculatePlayerPartyCount() == 0) bag_menu_print_there_is_no_pokemon(taskId); @@ -1686,7 +1686,7 @@ void item_menu_type_2(u8 taskId) StringExpandPlaceholders(gStringVar4, gText_Var1CantBeHeldHere); DisplayItemMessage(taskId, 1, gStringVar4, sub_81AD350); } - else if (gUnknown_0203CE58.pocket != 4 && !itemid_is_unique(gSpecialVar_ItemId)) + else if (gUnknown_0203CE58.pocket != 4 && !ItemId_GetImportance(gSpecialVar_ItemId)) { unknown_ItemMenu_Confirm(taskId); } @@ -1700,7 +1700,7 @@ void item_menu_type_b(u8 taskId) { if (ItemIsMail(gSpecialVar_ItemId) == TRUE) DisplayItemMessage(taskId, 1, gText_CantWriteMail, sub_81AD350); - else if (gUnknown_0203CE58.pocket != 4 && !itemid_is_unique(gSpecialVar_ItemId)) + else if (gUnknown_0203CE58.pocket != 4 && !ItemId_GetImportance(gSpecialVar_ItemId)) gTasks[taskId].func = unknown_ItemMenu_Confirm; else bag_menu_print_cant_be_held_msg(taskId); @@ -1738,7 +1738,7 @@ void display_sell_item_ask_str(u8 taskId) { s16* data = gTasks[taskId].data; - if (itemid_get_market_price(gSpecialVar_ItemId) == 0) + if (ItemId_GetPrice(gSpecialVar_ItemId) == 0) { CopyItemName(gSpecialVar_ItemId, gStringVar2); StringExpandPlaceholders(gStringVar4, gText_CantBuyKeyItem); @@ -1765,7 +1765,7 @@ void sub_81AD680(u8 taskId) { s16* data = gTasks[taskId].data; - ConvertIntToDecimalStringN(gStringVar1, (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8], 0, 6); + ConvertIntToDecimalStringN(gStringVar1, (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8], 0, 6); StringExpandPlaceholders(gStringVar4, gText_ICanPayVar1); DisplayItemMessage(taskId, 1, gStringVar4, sub_81AD6E4); } @@ -1790,7 +1790,7 @@ void sub_81AD730(u8 taskId) s16* data = gTasks[taskId].data; u8 windowId = bag_menu_add_window(8); - sub_81ABCC0(windowId, 1, (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8]); + sub_81ABCC0(windowId, 1, (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8]); bag_menu_AddMoney_window(); gTasks[taskId].func = sub_81AD794; } @@ -1801,7 +1801,7 @@ void sub_81AD794(u8 taskId) if (AdjustQuantityAccordingToDPadInput(&data[8], data[2]) == TRUE) { - sub_81ABCC0(gUnknown_0203CE54->unk818, data[8], (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8]); + sub_81ABCC0(gUnknown_0203CE54->unk818, data[8], (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8]); } else if (gMain.newKeys & A_BUTTON) { @@ -1825,7 +1825,7 @@ void sub_81AD84C(u8 taskId) s16* data = gTasks[taskId].data; CopyItemName(gSpecialVar_ItemId, gStringVar2); - ConvertIntToDecimalStringN(gStringVar1, (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8], 0, 6); + ConvertIntToDecimalStringN(gStringVar1, (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8], 0, 6); StringExpandPlaceholders(gStringVar4, gText_TurnedOverVar1ForVar2); DisplayItemMessage(taskId, 1, gStringVar4, sub_81AD8C8); } @@ -1838,7 +1838,7 @@ void sub_81AD8C8(u8 taskId) PlaySE(SE_REGI); RemoveBagItem(gSpecialVar_ItemId, data[8]); - AddMoney(&gSaveBlock1Ptr->money, (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8]); + AddMoney(&gSaveBlock1Ptr->money, (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8]); DestroyListMenuTask(data[0], scrollPos, cursorPos); sub_81AB9A8(gUnknown_0203CE58.pocket); sub_81ABA88(gUnknown_0203CE58.pocket); @@ -1908,7 +1908,7 @@ void sub_81ADB14(u8 taskId) s16* data = gTasks[taskId].data; FillWindowPixelBuffer(1, 0); - if (itemid_is_unique(gSpecialVar_ItemId)) + if (ItemId_GetImportance(gSpecialVar_ItemId)) { bag_menu_print(1, 1, gText_CantStoreImportantItems, 3, 1, 0, 0, 0, 0); gTasks[taskId].func = sub_81ADC0C; diff --git a/src/item_menu_icons.c b/src/item_menu_icons.c index 1d9dbb106..f12bb454e 100644 --- a/src/item_menu_icons.c +++ b/src/item_menu_icons.c @@ -9,6 +9,9 @@ #include "berry.h" #include "graphics.h" #include "constants/items.h" +#include "item.h" +#include "item_use.h" +#include "constants/hold_effects.h" struct CompressedTilesPal { @@ -466,6 +469,9 @@ const struct SpriteTemplate gUnknown_0857FE88 = .callback = sub_80D5B48, }; +#include "data/text/item_descriptions.h" +#include "data/items.h" + // code void RemoveBagSprite(u8 id) { diff --git a/src/lilycove_lady.c b/src/lilycove_lady.c index 812f1f975..ea244b6a0 100644 --- a/src/lilycove_lady.c +++ b/src/lilycove_lady.c @@ -392,7 +392,7 @@ bool8 sub_818DC60(void) static void sub_818DCAC(u8 *dest, u16 itemId) { - StringCopy(dest, ItemId_GetItem(itemId)->name); + StringCopy(dest, ItemId_GetName(itemId)); } void sub_818DCC8(void) @@ -671,7 +671,7 @@ static u8 sub_818E258(const u8 *str) void sub_818E274(void) { - StringCopy(gStringVar1, ItemId_GetItem(gUnknown_0203CD68->itemId)->name); + StringCopy(gStringVar1, ItemId_GetName(gUnknown_0203CD68->itemId)); } bool8 sub_818E298(void) diff --git a/src/load_save.c b/src/load_save.c index e3de66bb8..917c1dfe1 100644 --- a/src/load_save.c +++ b/src/load_save.c @@ -4,33 +4,30 @@ #include "main.h" #include "pokemon.h" #include "random.h" +#include "malloc.h" +#include "item.h" extern void* gUnknown_0203CF5C; extern bool16 IdentifyFlash(void); -extern void SetBagItemsPointers(void); extern void SetDecorationInventoriesPointers(void); extern void ApplyNewEncryptionKeyToGameStats(u32 key); -extern void ApplyNewEncryptionKeyToBagItems(u32 newKey); -extern void ApplyNewEncryptionKeyToBagItems_(u32 key); extern void ApplyNewEncryptionKeyToBerryPowder(u32 key); extern void sub_8084FAC(int unused); -// this is probably wrong or misleading due to it being used in ResetHeap... -extern void InitHeap(void *pointer, u32 size); - #define SAVEBLOCK_MOVE_RANGE 128 struct LoadedSaveData { - /*0x0000*/ struct ItemSlot items[30]; - /*0x0078*/ struct ItemSlot keyItems[30]; - /*0x00F0*/ struct ItemSlot pokeBalls[16]; - /*0x0130*/ struct ItemSlot TMsHMs[64]; - /*0x0230*/ struct ItemSlot berries[46]; + /*0x0000*/ struct ItemSlot items[BAG_ITEMS_COUNT]; + /*0x0078*/ struct ItemSlot keyItems[BAG_KEYITEMS_COUNT]; + /*0x00F0*/ struct ItemSlot pokeBalls[BAG_POKEBALLS_COUNT]; + /*0x0130*/ struct ItemSlot TMsHMs[BAG_TMHM_COUNT]; + /*0x0230*/ struct ItemSlot berries[BAG_BERRIES_COUNT]; /*0x02E8*/ struct MailStruct mail[MAIL_COUNT]; }; +// EWRAM DATA EWRAM_DATA struct SaveBlock2 gSaveblock2 = {0}; EWRAM_DATA u8 gSaveblock2_DMA[SAVEBLOCK_MOVE_RANGE] = {0}; @@ -43,8 +40,13 @@ EWRAM_DATA u8 gSaveblock3_DMA[SAVEBLOCK_MOVE_RANGE] = {0}; EWRAM_DATA struct LoadedSaveData gLoadedSaveData = {0}; EWRAM_DATA u32 gLastEncryptionKey = {0}; -void ApplyNewEncryptionKeyToAllEncryptedData(u32 encryptionKey); +// IWRAM common +IWRAM_DATA bool32 gFlashMemoryPresent; +IWRAM_DATA struct SaveBlock1 *gSaveBlock1Ptr; +IWRAM_DATA struct SaveBlock2 *gSaveBlock2Ptr; +IWRAM_DATA struct PokemonStorage *gPokemonStoragePtr; +// code void CheckForFlashMemory(void) { if (!IdentifyFlash()) @@ -53,7 +55,9 @@ void CheckForFlashMemory(void) InitFlashTimer(); } else + { gFlashMemoryPresent = FALSE; + } } void ClearSav2(void) @@ -80,8 +84,6 @@ void SetSaveBlocksPointers(u16 offset) SetDecorationInventoriesPointers(); } -extern u8 gHeap[]; - void MoveSaveBlocks_ResetHeap(void) { void *vblankCB, *hblankCB; @@ -132,7 +134,6 @@ void MoveSaveBlocks_ResetHeap(void) gSaveBlock2Ptr->encryptionKey = encryptionKey; } - u32 GetSecretBase2Field_9(void) { return gSaveBlock2Ptr->specialSaveWarp & 1; @@ -159,112 +160,112 @@ void sav2_gender2_inplace_and_xFE(void) gSaveBlock2Ptr->specialSaveWarp &= ~1; } -void copy_player_party_to_sav1(void) // SavePlayerParty +void SavePlayerParty(void) { int i; gSaveBlock1Ptr->playerPartyCount = gPlayerPartyCount; - for (i = 0; i < 6; i++) + for (i = 0; i < PARTY_SIZE; i++) gSaveBlock1Ptr->playerParty[i] = gPlayerParty[i]; } -void copy_player_party_from_sav1(void) // LoadPlayerParty +void LoadPlayerParty(void) { int i; gPlayerPartyCount = gSaveBlock1Ptr->playerPartyCount; - for (i = 0; i < 6; i++) + for (i = 0; i < PARTY_SIZE; i++) gPlayerParty[i] = gSaveBlock1Ptr->playerParty[i]; } -void save_serialize_npcs(void) // SaveMapObjects +void SaveMapObjects(void) { int i; - for (i = 0; i < 16; i++) + for (i = 0; i < MAP_OBJECTS_COUNT; i++) gSaveBlock1Ptr->mapObjects[i] = gMapObjects[i]; } -void save_deserialize_npcs(void) // LoadMapObjects +void LoadMapObjects(void) { int i; - for (i = 0; i < 16; i++) + for (i = 0; i < MAP_OBJECTS_COUNT; i++) gMapObjects[i] = gSaveBlock1Ptr->mapObjects[i]; } void SaveSerializedGame(void) { - copy_player_party_to_sav1(); - save_serialize_npcs(); + SavePlayerParty(); + SaveMapObjects(); } void LoadSerializedGame(void) { - copy_player_party_from_sav1(); - save_deserialize_npcs(); + LoadPlayerParty(); + LoadMapObjects(); } -void copy_bags_and_unk_data_from_save_blocks(void) +void LoadPlayerBag(void) { int i; // load player items. - for (i = 0; i < 30; i++) + for (i = 0; i < BAG_ITEMS_COUNT; i++) gLoadedSaveData.items[i] = gSaveBlock1Ptr->bagPocket_Items[i]; // load player key items. - for (i = 0; i < 30; i++) + for (i = 0; i < BAG_KEYITEMS_COUNT; i++) gLoadedSaveData.keyItems[i] = gSaveBlock1Ptr->bagPocket_KeyItems[i]; // load player pokeballs. - for (i = 0; i < 16; i++) + for (i = 0; i < BAG_POKEBALLS_COUNT; i++) gLoadedSaveData.pokeBalls[i] = gSaveBlock1Ptr->bagPocket_PokeBalls[i]; // load player TMs and HMs. - for (i = 0; i < 64; i++) + for (i = 0; i < BAG_TMHM_COUNT; i++) gLoadedSaveData.TMsHMs[i] = gSaveBlock1Ptr->bagPocket_TMHM[i]; // load player berries. - for (i = 0; i < 46; i++) + for (i = 0; i < BAG_BERRIES_COUNT; i++) gLoadedSaveData.berries[i] = gSaveBlock1Ptr->bagPocket_Berries[i]; // load mail. - for (i = 0; i < 16; i++) + for (i = 0; i < MAIL_COUNT; i++) gLoadedSaveData.mail[i] = gSaveBlock1Ptr->mail[i]; gLastEncryptionKey = gSaveBlock2Ptr->encryptionKey; } -void copy_bags_and_unk_data_to_save_blocks(void) +void SavePlayerBag(void) { int i; u32 encryptionKeyBackup; // save player items. - for (i = 0; i < 30; i++) + for (i = 0; i < BAG_ITEMS_COUNT; i++) gSaveBlock1Ptr->bagPocket_Items[i] = gLoadedSaveData.items[i]; // save player key items. - for (i = 0; i < 30; i++) + for (i = 0; i < BAG_KEYITEMS_COUNT; i++) gSaveBlock1Ptr->bagPocket_KeyItems[i] = gLoadedSaveData.keyItems[i]; // save player pokeballs. - for (i = 0; i < 16; i++) + for (i = 0; i < BAG_POKEBALLS_COUNT; i++) gSaveBlock1Ptr->bagPocket_PokeBalls[i] = gLoadedSaveData.pokeBalls[i]; // save player TMs and HMs. - for (i = 0; i < 64; i++) + for (i = 0; i < BAG_TMHM_COUNT; i++) gSaveBlock1Ptr->bagPocket_TMHM[i] = gLoadedSaveData.TMsHMs[i]; // save player berries. - for (i = 0; i < 46; i++) + for (i = 0; i < BAG_BERRIES_COUNT; i++) gSaveBlock1Ptr->bagPocket_Berries[i] = gLoadedSaveData.berries[i]; // save mail. - for (i = 0; i < 16; i++) + for (i = 0; i < MAIL_COUNT; i++) gSaveBlock1Ptr->mail[i] = gLoadedSaveData.mail[i]; encryptionKeyBackup = gSaveBlock2Ptr->encryptionKey; diff --git a/src/mail.c b/src/mail.c index 85ba86974..8fddc7045 100644 --- a/src/mail.c +++ b/src/mail.c @@ -101,7 +101,7 @@ struct MailRead /*0x021c*/ u8 monIconSprite; /*0x021d*/ u8 language; /*0x021e*/ bool8 playerIsSender; - /*0x0220*/ void (*parserSingle)(u8 *dest, u16 word); + /*0x0220*/ u8 * (*parserSingle)(u8 *dest, u16 word); /*0x0224*/ void (*parserMultiple)(u8 *dest, const u16 *src, u16 length1, u16 length2); /*0x0228*/ const struct MailLayout *layout; /*0x022c*/ u8 bg1TilemapBuffer[0x1000]; diff --git a/src/mauville_old_man.c b/src/mauville_old_man.c new file mode 100644 index 000000000..ea466b2ec --- /dev/null +++ b/src/mauville_old_man.c @@ -0,0 +1,1247 @@ +#include "global.h" +#include "main.h" +#include "constants/songs.h" +#include "constants/easy_chat.h" +#include "constants/map_objects.h" +#include "constants/vars.h" +#include "mauville_old_man.h" +#include "event_data.h" +#include "string_util.h" +#include "text.h" +#include "easy_chat.h" +#include "script.h" +#include "random.h" +#include "event_scripts.h" +#include "task.h" +#include "menu.h" +#include "m4a.h" +#include "bard_music.h" +#include "sound.h" +#include "strings.h" +#include "overworld.h" +#include "field_message_box.h" +#include "script_menu.h" +#include "trader.h" + +#define CHAR_SONG_WORD_SEPARATOR 0x37 + +extern struct MusicPlayerInfo gMPlayInfo_SE2; + +static void InitGiddyTaleList(void); +static void StartBardSong(bool8 useTemporaryLyrics); +static void Task_BardSong(u8 taskId); +static void StorytellerSetup(void); +static void Storyteller_ResetFlag(void); + +IWRAM_DATA u8 sSelectedStory; + +struct BardSong gBardSong; + +static EWRAM_DATA u16 sUnknownBardRelated = 0; +static EWRAM_DATA struct MauvilleManStoryteller * sStorytellerPtr = NULL; +static EWRAM_DATA u8 sStorytellerWindowId = 0; + +static const u16 sDefaultBardSongLyrics[6] = { + EC_WORD_SHAKE, + EC_WORD_IT, + EC_WORD_DO, + EC_WORD_THE, + EC_WORD_DIET, + EC_WORD_DANCE +}; + +static const u8 * const sGiddyAdjectives[] = { + gText_SoPretty, + gText_SoDarling, + gText_SoRelaxed, + gText_SoSunny, + gText_SoDesirable, + gText_SoExciting, + gText_SoAmusing, + gText_SoMagical +}; + +static const u8 * const sGiddyQuestions[] = { + gUnknown_08294313, + gUnknown_08294359, + gUnknown_08294398, + gUnknown_082943DA, + gUnknown_0829441C, + gUnknown_08294460, + gUnknown_082944A0, + gUnknown_082944D5 +}; + +static void SetupBard(void) +{ + u16 i; + struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard; + + bard->id = MAUVILLE_MAN_BARD; + bard->hasChangedSong = FALSE; + bard->language = gGameLanguage; + for (i = 0; i < 6; i++) + bard->songLyrics[i] = sDefaultBardSongLyrics[i]; +} + +static void SetupHipster(void) +{ + struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster; + + hipster->id = MAUVILLE_MAN_HIPSTER; + hipster->alreadySpoken = FALSE; + hipster->language = gGameLanguage; +} + +static void SetupStoryteller(void) +{ + StorytellerSetup(); +} + +static void SetupGiddy(void) +{ + struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy; + + giddy->id = MAUVILLE_MAN_GIDDY; + giddy->taleCounter = 0; + giddy->language = gGameLanguage; +} + +static void SetupTrader(void) +{ + TraderSetup(); +} + +void SetMauvilleOldMan(void) +{ + u16 trainerId = (gSaveBlock2Ptr->playerTrainerId[1] << 8) | gSaveBlock2Ptr->playerTrainerId[0]; + + + // Determine man based on the last digit of the player's trainer ID. + switch ((trainerId % 10) / 2) + { + case MAUVILLE_MAN_BARD: + SetupBard(); + break; + case MAUVILLE_MAN_HIPSTER: + SetupHipster(); + break; + case MAUVILLE_MAN_TRADER: + SetupTrader(); + break; + case MAUVILLE_MAN_STORYTELLER: + SetupStoryteller(); + break; + case MAUVILLE_MAN_GIDDY: + SetupGiddy(); + break; + } + ScrSpecial_SetMauvilleOldManMapObjGfx(); +} + +u8 GetCurrentMauvilleOldMan(void) +{ + struct MauvilleManCommon *common = &gSaveBlock1Ptr->oldMan.common; + + return common->id; +} + +void ScrSpecial_GetCurrentMauvilleMan(void) +{ + gSpecialVar_Result = GetCurrentMauvilleOldMan(); +} + +void ScrSpecial_HasBardSongBeenChanged(void) +{ + u16 *scriptResult = &gSpecialVar_Result; // why?? + struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard; + + *scriptResult = bard->hasChangedSong; +} + +void ScrSpecial_SaveBardSongLyrics(void) +{ + u16 i; + struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard; + + StringCopy(bard->playerName, gSaveBlock2Ptr->playerName); + + for (i = 0; i < 4; i++) + bard->playerTrainerId[i] = gSaveBlock2Ptr->playerTrainerId[i]; + + for (i = 0; i < 6; i++) + bard->songLyrics[i] = bard->temporaryLyrics[i]; + + bard->hasChangedSong = TRUE; +} + +// Copies lyrics into gStringVar4 +static void PrepareSongText(void) +{ + struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard; + u16 * lyrics = gSpecialVar_0x8004 == 0 ? bard->songLyrics : bard->temporaryLyrics; + u8 * wordEnd = gStringVar4; + u8 * str = wordEnd; + u16 lineNum; + + // Put three words on each line + for (lineNum = 0; lineNum < 2; lineNum++) + { + wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++)); + while (wordEnd != str) + { + if (*str == CHAR_SPACE) + *str = CHAR_SONG_WORD_SEPARATOR; + str++; + } + + str++; + *(wordEnd++) = CHAR_SPACE; + + wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++)); + while (wordEnd != str) + { + if (*str == CHAR_SPACE) + *str = CHAR_SONG_WORD_SEPARATOR; + str++; + } + + str++; + *(wordEnd++) = CHAR_NEWLINE; + + wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++)); + while (wordEnd != str) + { + if (*str == CHAR_SPACE) + *str = CHAR_SONG_WORD_SEPARATOR; + str++; + } + + if (lineNum == 0) + { + *(wordEnd++) = EXT_CTRL_CODE_BEGIN; + *(wordEnd++) = 15; + } + } +} + +void ScrSpecial_PlayBardSong(void) +{ + StartBardSong(gSpecialVar_0x8004); + ScriptContext1_Stop(); +} + +void ScrSpecial_GetHipsterSpokenFlag(void) +{ + u16 *scriptResult = &gSpecialVar_Result; // again?? + struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster; + + *scriptResult = hipster->alreadySpoken; +} + +void ScrSpecial_SetHipsterSpokenFlag(void) +{ + struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster; + + hipster->alreadySpoken = TRUE; +} + +void ScrSpecial_HipsterTeachWord(void) +{ + u16 var = sub_811F01C(); + + if (var == 0xFFFF) + { + gSpecialVar_Result = FALSE; + } + else + { + CopyEasyChatWord(gStringVar1, var); + gSpecialVar_Result = TRUE; + } +} + +void ScrSpecial_GiddyShouldTellAnotherTale(void) +{ + struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy; + + if (giddy->taleCounter == 10) + { + gSpecialVar_Result = FALSE; + giddy->taleCounter = 0; + } + else + { + gSpecialVar_Result = TRUE; + } +} + +void ScrSpecial_GenerateGiddyLine(void) +{ + struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy; + + if (giddy->taleCounter == 0) + InitGiddyTaleList(); + + if (giddy->randomWords[giddy->taleCounter] != 0xFFFF) // is not the last element of the array? + { + u8 *stringPtr; + u32 adjective = Random(); + + adjective %= 8; + stringPtr = CopyEasyChatWord(gStringVar4, giddy->randomWords[giddy->taleCounter]); + stringPtr = StringCopy(stringPtr, gOtherText_Is); + stringPtr = StringCopy(stringPtr, sGiddyAdjectives[adjective]); + StringCopy(stringPtr, gOtherText_DontYouAgree); + } + else + { + StringCopy(gStringVar4, sGiddyQuestions[giddy->questionList[giddy->questionNum++]]); + } + + if (!(Random() % 10)) + giddy->taleCounter = 10; + else + giddy->taleCounter++; + + gSpecialVar_Result = TRUE; +} + +static void InitGiddyTaleList(void) +{ + struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy; + u16 arr[][2] = { + {EC_GROUP_POKEMON, 0}, + {EC_GROUP_LIFESTYLE, 0}, + {EC_GROUP_HOBBIES, 0}, + {EC_GROUP_MOVE_1, 0}, + {EC_GROUP_MOVE_2, 0}, + {EC_GROUP_POKEMON_2, 0} + }; + u16 i; + u16 r10; + u16 r7; + u16 r1; + + for (i = 0; i < 8; i++) + giddy->questionList[i] = i; + + for (i = 0; i < 8; i++) + { + r1 = Random() % (i + 1); + r7 = giddy->questionList[i]; + giddy->questionList[i] = giddy->questionList[r1]; + giddy->questionList[r1] = r7; + } + + r10 = 0; + for (i = 0; i < 6; i++) + { + arr[i][1] = EasyChat_GetNumWordsInGroup(arr[i][0]); + r10 += arr[i][1]; + } + + giddy->questionNum = 0; + r7 = 0; + for (i = 0; i < 10; i++) + { + r1 = Random() % 10; + if (r1 < 3 && r7 < 8) + { + giddy->randomWords[i] = 0xFFFF; + r7++; + } + else + { + s16 r2 = Random() % r10; + for (r1 = 0; i < 6; r1++) + if ((r2 -= arr[r1][1]) <= 0) + break; + if (r1 == 6) + r1 = 0; + giddy->randomWords[i] = sub_811EE90(arr[r1][0]); + } + } +} +static void ResetBardFlag(void) +{ + struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard; + + bard->hasChangedSong = FALSE; +} + +static void ResetHipsterFlag(void) +{ + struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster; + + hipster->alreadySpoken = FALSE; +} + +static void ResetTraderFlag(void) +{ + Trader_ResetFlag(); +} + +static void ResetStorytellerFlag(void) +{ + Storyteller_ResetFlag(); +} + +void ResetMauvilleOldManFlag(void) // ResetMauvilleOldManFlag +{ + switch (GetCurrentMauvilleOldMan()) + { + case MAUVILLE_MAN_BARD: + ResetBardFlag(); + break; + case MAUVILLE_MAN_HIPSTER: + ResetHipsterFlag(); + break; + case MAUVILLE_MAN_STORYTELLER: + ResetStorytellerFlag(); + break; + case MAUVILLE_MAN_TRADER: + ResetTraderFlag(); + break; + case MAUVILLE_MAN_GIDDY: + break; + } + ScrSpecial_SetMauvilleOldManMapObjGfx(); +} + + +#define tState data[0] +#define tCharIndex data[3] +#define tCurrWord data[4] +#define tUseTemporaryLyrics data[5] + +#define MACRO1(a) (((a) & 3) + (((a) / 8) & 1)) +#define MACRO2(a) (((a) % 4) + (((a) / 8) & 1)) + +static void StartBardSong(bool8 useTemporaryLyrics) +{ + u8 taskId = CreateTask(Task_BardSong, 80); + + gTasks[taskId].tUseTemporaryLyrics = useTemporaryLyrics; +} + +static void sub_81206F0(void) +{ + gUnknown_03002F84 = FALSE; +} + +static void BardSong_TextSubPrinter(struct TextSubPrinter * printer, u16 a1) +{ + gUnknown_03002F84 = TRUE; +} + +static void sub_8120708(const u8 * src) +{ + NewMenuHelpers_DrawDialogueFrame(0, 0); + PrintTextOnWindow(0, 1, src, 0, 1, 1, BardSong_TextSubPrinter); + gUnknown_03002F84 = TRUE; + CopyWindowToVram(0, 3); +} + +static void BardSing(struct Task *task, struct BardSong *song) +{ + switch (task->tState) + { + case 0: // Initialize song + { + struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard; + u16 *lyrics; + s32 i; + + // Copy lyrics + if (gSpecialVar_0x8004 == 0) + lyrics = bard->songLyrics; + else + lyrics = bard->temporaryLyrics; + for (i = 0; i < 6; i++) + song->lyrics[i] = lyrics[i]; + song->currWord = 0; + } + break; + case 1: // Wait for BGM to end + break; + case 2: // Initialize word + { + u16 word = song->lyrics[song->currWord]; + song->sound = GetWordSounds(word); + GetWordPhonemes(song, MACRO1(word)); + song->currWord++; + if (song->sound->var00 != 0xFF) + song->state = 0; + else + { + song->state = 3; + song->phonemeTimer = 2; + } + break; + } + case 3: + case 4: + { + const struct BardSound *sound = &song->sound[song->currPhoneme]; + + switch (song->state) + { + case 0: + song->phonemeTimer = song->phonemes[song->currPhoneme].length; + if (sound->var00 <= 50) + { + u8 num = sound->var00 / 3; + m4aSongNumStart(PH_TRAP_HELD + 3 * num); + } + song->state = 2; + song->phonemeTimer--; + break; + case 2: + song->state = 1; + if (sound->var00 <= 50) + { + song->volume = 0x100 + sound->volume * 16; + m4aMPlayVolumeControl(&gMPlayInfo_SE2, 0xFFFF, song->volume); + song->pitch = 0x200 + song->phonemes[song->currPhoneme].pitch; + m4aMPlayPitchControl(&gMPlayInfo_SE2, 0xFFFF, song->pitch); + } + break; + case 1: + if (song->voiceInflection > 10) + song->volume -= 2; + if (song->voiceInflection & 1) + song->pitch += 64; + else + song->pitch -= 64; + m4aMPlayVolumeControl(&gMPlayInfo_SE2, 0xFFFF, song->volume); + m4aMPlayPitchControl(&gMPlayInfo_SE2, 0xFFFF, song->pitch); + song->voiceInflection++; + song->phonemeTimer--; + if (song->phonemeTimer == 0) + { + song->currPhoneme++; + if (song->currPhoneme != 6 && song->sound[song->currPhoneme].var00 != 0xFF) + song->state = 0; + else + { + song->state = 3; + song->phonemeTimer = 2; + } + } + break; + case 3: + song->phonemeTimer--; + if (song->phonemeTimer == 0) + { + m4aMPlayStop(&gMPlayInfo_SE2); + song->state = 4; + } + break; + } + } + break; + case 5: + break; + } +} + +static void Task_BardSong(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; // r5 + + BardSing(task, &gBardSong); + switch (task->tState) + { + case 0: // Initialize song + PrepareSongText(); + sub_8120708(gStringVar4); + task->data[1] = 0; + task->data[2] = 0; + task->tCharIndex = 0; + task->tCurrWord = 0; + FadeOutBGMTemporarily(4); + task->tState = 1; + break; + case 1: // Wait for BGM to end + if (IsBGMPausedOrStopped()) + task->tState = 2; + break; + case 2: // Initialize word + { + struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard; + u8 *str = gStringVar4 + task->tCharIndex; + u16 wordLen = 0; + // Can't get it to match without hacking + u32 temp; + register s16 zero asm("r1"); + + while (*str != CHAR_SPACE + && *str != CHAR_NEWLINE + && *str != EXT_CTRL_CODE_BEGIN + && *str != EOS) + { + str++; + wordLen++; + } + if (!task->tUseTemporaryLyrics) + sUnknownBardRelated = MACRO2(bard->songLyrics[task->tCurrWord]); + else + sUnknownBardRelated = MACRO2(bard->temporaryLyrics[task->tCurrWord]); + temp = gBardSong.length / wordLen; + zero = 0; + gBardSong.length = temp; + if (gBardSong.length <= 0) + gBardSong.length = 1; + task->tCurrWord++; + if (task->data[2] == 0) + task->tState = 3; + else + task->tState = 5; + task->data[1] = zero; + } + break; + case 5: + if (task->data[2] == 0) + task->tState = 3; + else + task->data[2]--; + break; + case 3: + if (gStringVar4[task->tCharIndex] == EOS) + { + FadeInBGM(6); + m4aMPlayFadeOutTemporarily(&gMPlayInfo_SE2, 2); + EnableBothScriptContexts(); + DestroyTask(taskId); + } + else if (gStringVar4[task->tCharIndex] == CHAR_SPACE) + { + + sub_81206F0(); + task->tCharIndex++; + task->tState = 2; + task->data[2] = 0; + } + else if (gStringVar4[task->tCharIndex] == CHAR_NEWLINE) + { + task->tCharIndex++; + task->tState = 2; + task->data[2] = 0; + } + else if (gStringVar4[task->tCharIndex] == EXT_CTRL_CODE_BEGIN) + { + task->tCharIndex += 2; // skip over control codes + task->tState = 2; + task->data[2] = 8; + } + else if (gStringVar4[task->tCharIndex] == CHAR_SONG_WORD_SEPARATOR) + { + gStringVar4[task->tCharIndex] = CHAR_SPACE; // restore it back to a space + sub_81206F0(); + task->tCharIndex++; + task->data[2] = 0; + } + else + { + switch (task->data[1]) + { + case 0: + sub_81206F0(); + task->data[1]++; + break; + case 1: + task->data[1]++; + break; + case 2: + task->tCharIndex++; + task->data[1] = 0; + task->data[2] = gBardSong.length; + task->tState = 4; + break; + } + } + break; + case 4: + task->data[2]--; + if (task->data[2] == 0) + task->tState = 3; + break; + } + sub_8197224(); +} + +void ScrSpecial_SetMauvilleOldManMapObjGfx(void) +{ + VarSet(VAR_0x4010, MAP_OBJ_GFX_BARD); +} + +// Language fixers? + +void sub_8120B70(union OldMan * oldMan) +{ + s32 i; + u8 sp00[8]; + + switch (oldMan->common.id) + { + case MAUVILLE_MAN_TRADER: + { + struct MauvilleOldManTrader * trader = &oldMan->trader; + for (i = 0; i < 4; i++) + { + if (trader->language[i] == LANGUAGE_JAPANESE) + { + ConvertInternationalString(trader->playerNames[i], LANGUAGE_JAPANESE); + } + } + } + break; + case MAUVILLE_MAN_STORYTELLER: + { + struct MauvilleManStoryteller * storyteller = &oldMan->storyteller; + for (i = 0; i < 4; i++) + { + if (storyteller->gameStatIDs[i] != 0) + { + memcpy(sp00, storyteller->trainerNames[i], 7); + sp00[7] = EOS; + if (IsStringJapanese(sp00)) + { + memset(sp00, CHAR_SPACE, 8); + StringCopy(sp00, gText_Friend); + memcpy(storyteller->trainerNames[i], sp00, 7); + storyteller->language[i] = GAME_LANGUAGE; + } + } + } + } + break; + } +} + +void sub_8120C0C(union OldMan * oldMan, u32 r8, u32 r7, u32 r3) +{ + s32 i; + + switch (oldMan->common.id) + { + case MAUVILLE_MAN_TRADER: + { + struct MauvilleOldManTrader * trader = &oldMan->trader; + + for (i = 0; i < 4; i++) + { + if (IsStringJapanese(trader->playerNames[i])) + { + trader->language[i] = r8; + } + else + { + trader->language[i] = r7; + } + } + } + break; + case MAUVILLE_MAN_STORYTELLER: + { + struct MauvilleManStoryteller * storyteller = &oldMan->storyteller; + + for (i = 0; i < 4; i++) + { + if (IsStringJapanese(storyteller->trainerNames[i])) + { + storyteller->language[i] = r8; + } + else + { + storyteller->language[i] = r7; + } + } + } + break; + case MAUVILLE_MAN_BARD: + { + struct MauvilleManBard * bard = &oldMan->bard; + + if (r3 == LANGUAGE_JAPANESE) + bard->language = r8; + else + bard->language = r7; + } + break; + case MAUVILLE_MAN_HIPSTER: + { + struct MauvilleManHipster * hipster = &oldMan->hipster; + + if (r3 == LANGUAGE_JAPANESE) + hipster->language = r8; + else + hipster->language = r7; + } + break; + case MAUVILLE_MAN_GIDDY: + { + struct MauvilleManGiddy * giddy = &oldMan->giddy; + + if (r3 == LANGUAGE_JAPANESE) + giddy->language = r8; + else + giddy->language = r7; + } + break; + } +} + +void sub_8120CD0(union OldMan * oldMan, u32 unused, u32 a2) +{ + u8 sp00[8]; + s32 i; + if (oldMan->common.id == MAUVILLE_MAN_STORYTELLER && a2 == LANGUAGE_JAPANESE) + { + struct MauvilleManStoryteller * storyteller = &oldMan->storyteller; + + for (i = 0; i < 4; i++) + { + if (storyteller->gameStatIDs[i] != 0) + { + memcpy(sp00, storyteller->trainerNames[i], 7); + sp00[7] = EOS; + if (IsStringJapanese(sp00)) + storyteller->language[i] = LANGUAGE_JAPANESE; + else + storyteller->language[i] = GAME_LANGUAGE; + } + } + } +} + +void sub_8120D34(union OldMan * oldMan, u32 r1, u32 r6) +{ + u32 r2 = (r1 == LANGUAGE_JAPANESE || r1 == LANGUAGE_ENGLISH) ? 1 : 0; + switch (oldMan->common.id) + { + case MAUVILLE_MAN_TRADER: + { + struct MauvilleOldManTrader * trader = &oldMan->trader; + s32 i; + + if (r2) + { + for (i = 0; i < 4; i++) + { + u8 * str = trader->playerNames[i]; + if (str[0] == EXT_CTRL_CODE_BEGIN && str[1] == EXT_CTRL_CODE_JPN) + { + StripExtCtrlCodes(str); + trader->language[i] = LANGUAGE_JAPANESE; + } + else + trader->language[i] = r6; + } + } + else + { + for (i = 0; i < 4; i++) + { + if (trader->language[i] == LANGUAGE_JAPANESE) + { + StripExtCtrlCodes(trader->playerNames[i]); + } + } + } + } + break; + case MAUVILLE_MAN_STORYTELLER: + { + + struct MauvilleManStoryteller * storyteller = &oldMan->storyteller; + s32 i; + + if (r2) + { + for (i = 0; i < 4; i++) + { + if (storyteller->gameStatIDs[i] != 0) + storyteller->language[i] = r6; + } + } + } + break; + case MAUVILLE_MAN_BARD: + { + struct MauvilleManBard * bard = &oldMan->bard; + + if (r2) + { + bard->language = r6; + } + } + break; + case MAUVILLE_MAN_HIPSTER: + { + struct MauvilleManHipster * hipster = &oldMan->hipster; + + if (r2) + { + hipster->language = r6; + } + } + break; + case MAUVILLE_MAN_GIDDY: + { + struct MauvilleManGiddy * giddy = &oldMan->giddy; + + if (r2) + { + giddy->language = r6; + } + } + break; + } +} + +struct Story +{ + u8 stat; + u8 minVal; + const u8 *title; + const u8 *action; + const u8 *fullText; +}; + +static const struct Story sStorytellerStories[] = { + {GAME_STAT_50, 1, MauvilleCity_PokemonCenter_1F_Text_28E930, MauvilleCity_PokemonCenter_1F_Text_28E947, MauvilleCity_PokemonCenter_1F_Text_28E956}, + {GAME_STAT_STARTED_TRENDS, 1, MauvilleCity_PokemonCenter_1F_Text_28E9D7, MauvilleCity_PokemonCenter_1F_Text_28E9EF, MauvilleCity_PokemonCenter_1F_Text_28E9FE}, + {GAME_STAT_PLANTED_BERRIES, 1, MauvilleCity_PokemonCenter_1F_Text_28EA7D, MauvilleCity_PokemonCenter_1F_Text_28EA98, MauvilleCity_PokemonCenter_1F_Text_28EAA8}, + {GAME_STAT_TRADED_BIKES, 1, MauvilleCity_PokemonCenter_1F_Text_28EB19, MauvilleCity_PokemonCenter_1F_Text_28EB31, MauvilleCity_PokemonCenter_1F_Text_28EB3E}, + {GAME_STAT_GOT_INTERVIEWED, 1, MauvilleCity_PokemonCenter_1F_Text_28EBB5, MauvilleCity_PokemonCenter_1F_Text_28EBCD, MauvilleCity_PokemonCenter_1F_Text_28EBDD}, + {GAME_STAT_TRAINER_BATTLES, 1, MauvilleCity_PokemonCenter_1F_Text_28EC60, MauvilleCity_PokemonCenter_1F_Text_28EC79, MauvilleCity_PokemonCenter_1F_Text_28EC81}, + {GAME_STAT_POKEMON_CAPTURES, 1, MauvilleCity_PokemonCenter_1F_Text_28ED04, MauvilleCity_PokemonCenter_1F_Text_28ED21, MauvilleCity_PokemonCenter_1F_Text_28ED30}, + {GAME_STAT_FISHING_CAPTURES, 1, MauvilleCity_PokemonCenter_1F_Text_28EDA1, MauvilleCity_PokemonCenter_1F_Text_28EDB5, MauvilleCity_PokemonCenter_1F_Text_28EDCF}, + {GAME_STAT_HATCHED_EGGS, 1, MauvilleCity_PokemonCenter_1F_Text_28EE45, MauvilleCity_PokemonCenter_1F_Text_28EE5D, MauvilleCity_PokemonCenter_1F_Text_28EE6A}, + {GAME_STAT_EVOLVED_POKEMON, 1, MauvilleCity_PokemonCenter_1F_Text_28EEDD, MauvilleCity_PokemonCenter_1F_Text_28EEF1, MauvilleCity_PokemonCenter_1F_Text_28EF01}, + {GAME_STAT_USED_POKECENTER, 1, MauvilleCity_PokemonCenter_1F_Text_28EF73, MauvilleCity_PokemonCenter_1F_Text_28EF95, MauvilleCity_PokemonCenter_1F_Text_28EFAA}, + {GAME_STAT_RESTED_AT_HOME, 1, MauvilleCity_PokemonCenter_1F_Text_28F045, MauvilleCity_PokemonCenter_1F_Text_28F05A, MauvilleCity_PokemonCenter_1F_Text_28F071}, + {GAME_STAT_ENTERED_SAFARI_ZONE, 1, MauvilleCity_PokemonCenter_1F_Text_28F0F3, MauvilleCity_PokemonCenter_1F_Text_28F10D, MauvilleCity_PokemonCenter_1F_Text_28F125}, + {GAME_STAT_USED_CUT, 1, MauvilleCity_PokemonCenter_1F_Text_28F1BE, MauvilleCity_PokemonCenter_1F_Text_28F1D5, MauvilleCity_PokemonCenter_1F_Text_28F1DE}, + {GAME_STAT_USED_ROCK_SMASH, 1, MauvilleCity_PokemonCenter_1F_Text_28F24F, MauvilleCity_PokemonCenter_1F_Text_28F269, MauvilleCity_PokemonCenter_1F_Text_28F277}, + {GAME_STAT_MOVED_SECRET_BASE, 1, MauvilleCity_PokemonCenter_1F_Text_28F2FC, MauvilleCity_PokemonCenter_1F_Text_28F314, MauvilleCity_PokemonCenter_1F_Text_28F32A}, + {GAME_STAT_USED_SPLASH, 1, MauvilleCity_PokemonCenter_1F_Text_28F3AD, MauvilleCity_PokemonCenter_1F_Text_28F3C6, MauvilleCity_PokemonCenter_1F_Text_28F3D2}, + {GAME_STAT_USED_STRUGGLE, 1, MauvilleCity_PokemonCenter_1F_Text_28F44B, MauvilleCity_PokemonCenter_1F_Text_28F461, MauvilleCity_PokemonCenter_1F_Text_28F47C}, + {GAME_STAT_SLOT_JACKPOTS, 1, MauvilleCity_PokemonCenter_1F_Text_28F50C, MauvilleCity_PokemonCenter_1F_Text_28F51B, MauvilleCity_PokemonCenter_1F_Text_28F538}, + {GAME_STAT_CONSECUTIVE_ROULETTE_WINS, 2, MauvilleCity_PokemonCenter_1F_Text_28F5BE, MauvilleCity_PokemonCenter_1F_Text_28F5D1, MauvilleCity_PokemonCenter_1F_Text_28F5F2}, + {GAME_STAT_ENTERED_BATTLE_TOWER, 1, MauvilleCity_PokemonCenter_1F_Text_28F678, MauvilleCity_PokemonCenter_1F_Text_28F694, MauvilleCity_PokemonCenter_1F_Text_28F6B4}, + {GAME_STAT_POKEBLOCKS, 1, MauvilleCity_PokemonCenter_1F_Text_28F751, MauvilleCity_PokemonCenter_1F_Text_28F76A, MauvilleCity_PokemonCenter_1F_Text_28F776}, + {GAME_STAT_ENTERED_CONTEST, 1, MauvilleCity_PokemonCenter_1F_Text_28F7F6, MauvilleCity_PokemonCenter_1F_Text_28F811, MauvilleCity_PokemonCenter_1F_Text_28F822}, + {GAME_STAT_WON_CONTEST, 1, MauvilleCity_PokemonCenter_1F_Text_28F89C, MauvilleCity_PokemonCenter_1F_Text_28F8AF, MauvilleCity_PokemonCenter_1F_Text_28F8BC}, + {GAME_STAT_SHOPPED, 1, MauvilleCity_PokemonCenter_1F_Text_28F92F, MauvilleCity_PokemonCenter_1F_Text_28F941, MauvilleCity_PokemonCenter_1F_Text_28F949}, + {GAME_STAT_USED_ITEMFINDER, 1, MauvilleCity_PokemonCenter_1F_Text_28F9D1, MauvilleCity_PokemonCenter_1F_Text_28F9EA, MauvilleCity_PokemonCenter_1F_Text_28F9FD}, + {GAME_STAT_GOT_RAINED_ON, 1, MauvilleCity_PokemonCenter_1F_Text_28FA81, MauvilleCity_PokemonCenter_1F_Text_28FA99, MauvilleCity_PokemonCenter_1F_Text_28FAA7}, + {GAME_STAT_CHECKED_POKEDEX, 1, MauvilleCity_PokemonCenter_1F_Text_28FB1D, MauvilleCity_PokemonCenter_1F_Text_28FB35, MauvilleCity_PokemonCenter_1F_Text_28FB47}, + {GAME_STAT_RECEIVED_RIBBONS, 1, MauvilleCity_PokemonCenter_1F_Text_28FBC4, MauvilleCity_PokemonCenter_1F_Text_28FBD9, MauvilleCity_PokemonCenter_1F_Text_28FBEA}, + {GAME_STAT_JUMPED_DOWN_LEDGES, 1, MauvilleCity_PokemonCenter_1F_Text_28FC6B, MauvilleCity_PokemonCenter_1F_Text_28FC85, MauvilleCity_PokemonCenter_1F_Text_28FC98}, + {GAME_STAT_WATCHED_TV, 1, MauvilleCity_PokemonCenter_1F_Text_28FD1D, MauvilleCity_PokemonCenter_1F_Text_28FD35, MauvilleCity_PokemonCenter_1F_Text_28FD40}, + {GAME_STAT_CHECKED_CLOCK, 1, MauvilleCity_PokemonCenter_1F_Text_28FDA2, MauvilleCity_PokemonCenter_1F_Text_28FDBD, MauvilleCity_PokemonCenter_1F_Text_28FDCE}, + {GAME_STAT_WON_POKEMON_LOTTERY, 1, MauvilleCity_PokemonCenter_1F_Text_28FE57, MauvilleCity_PokemonCenter_1F_Text_28FE72, MauvilleCity_PokemonCenter_1F_Text_28FE88}, + {GAME_STAT_USED_DAYCARE, 1, MauvilleCity_PokemonCenter_1F_Text_28FF0C, MauvilleCity_PokemonCenter_1F_Text_28FF27, MauvilleCity_PokemonCenter_1F_Text_28FF44}, + {GAME_STAT_RODE_CABLE_CAR, 1, MauvilleCity_PokemonCenter_1F_Text_28FFDD, MauvilleCity_PokemonCenter_1F_Text_28FFFA, MauvilleCity_PokemonCenter_1F_Text_29000D}, + {GAME_STAT_ENTERED_HOT_SPRINGS, 1, MauvilleCity_PokemonCenter_1F_Text_290097, MauvilleCity_PokemonCenter_1F_Text_2900B5, MauvilleCity_PokemonCenter_1F_Text_2900CB} +}; + +static void StorytellerSetup(void) +{ + s32 i; + sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller; + + sStorytellerPtr->id = MAUVILLE_MAN_STORYTELLER; + sStorytellerPtr->alreadyRecorded = FALSE; + for (i = 0; i < 4; i++) + { + sStorytellerPtr->gameStatIDs[i] = 0; + sStorytellerPtr->trainerNames[0][i] = EOS; // Maybe they meant storyteller->trainerNames[i][0] instead? + } +} + +static void Storyteller_ResetFlag(void) +{ + sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller; + + sStorytellerPtr->id = MAUVILLE_MAN_STORYTELLER; + sStorytellerPtr->alreadyRecorded = FALSE; +} + +static u32 StorytellerGetGameStat(u8 stat) +{ + if (stat == 50) + stat = 0; + return GetGameStat(stat); +} + +static const struct Story *GetStoryByStat(u32 stat) +{ + s32 i; + + for (i = 0; i < 36; i++) + { + if (sStorytellerStories[i].stat == stat) + return &sStorytellerStories[i]; + } + return &sStorytellerStories[35]; +} + +static const u8 *GetStoryTitleByStat(u32 stat) +{ + return GetStoryByStat(stat)->title; +} + +static const u8 *GetStoryTextByStat(u32 stat) +{ + return GetStoryByStat(stat)->fullText; +} + +static const u8 *GetStoryActionByStat(u32 stat) +{ + return GetStoryByStat(stat)->action; +} + +static u8 GetFreeStorySlot(void) +{ + u8 i; + + for (i = 0; i < 4; i++) + { + if (sStorytellerPtr->gameStatIDs[i] == 0) + break; + } + return i; +} + +static u32 StorytellerGetRecordedTrainerStat(u32 trainer) +{ + u8 *ptr = sStorytellerPtr->statValues[trainer]; + + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); +} + +static void StorytellerSetRecordedTrainerStat(u32 trainer, u32 val) +{ + u8 *ptr = sStorytellerPtr->statValues[trainer]; + + ptr[0] = val; + ptr[1] = val >> 8; + ptr[2] = val >> 16; + ptr[3] = val >> 24; +} + +static bool32 HasTrainerStatIncreased(u32 trainer) +{ + if (StorytellerGetGameStat(sStorytellerPtr->gameStatIDs[trainer]) > StorytellerGetRecordedTrainerStat(trainer)) + return TRUE; + else + return FALSE; +} + +static void GetStoryByStattellerPlayerName(u32 player, void *dst) +{ + u8 *name = sStorytellerPtr->trainerNames[player]; + + memset(dst, EOS, 8); + memcpy(dst, name, 7); +} + +static void StorytellerSetPlayerName(u32 player, const u8 * src) +{ + u8 * name = sStorytellerPtr->trainerNames[player]; + memset(name, EOS, 7); + memcpy(name, src, 7); +} + + +static void StorytellerRecordNewStat(u32 player, u32 stat) +{ + sStorytellerPtr->gameStatIDs[player] = stat; + StorytellerSetPlayerName(player, gSaveBlock2Ptr->playerName); + StorytellerSetRecordedTrainerStat(player, StorytellerGetGameStat(stat)); + ConvertIntToDecimalStringN(gStringVar1, StorytellerGetGameStat(stat), STR_CONV_MODE_LEFT_ALIGN, 10); + StringCopy(gStringVar2, GetStoryActionByStat(stat)); + sStorytellerPtr->language[player] = gGameLanguage; +} + +static void ScrambleStatList(u8 * arr, s32 count) +{ + s32 i; + + for (i = 0; i < count; i++) + arr[i] = i; + for (i = 0; i < count; i++) + { + u32 a = Random() % count; + u32 b = Random() % count; + u8 temp = arr[a]; + arr[a] = arr[b]; + arr[b] = temp; + } +} + +struct UnknownStruct_0859F288 +{ + s32 length; + u32 unused2; +}; + +static const struct UnknownStruct_0859F288 sStorytellerStuff = { + ARRAY_COUNT(sStorytellerStories), + sizeof(sStorytellerStuff) +}; + +static bool8 StorytellerInitializeRandomStat(void) +{ + u8 arr[sStorytellerStuff.length]; + s32 i; + s32 j; + + ScrambleStatList(arr, ARRAY_COUNT(sStorytellerStories)); + for (i = 0; i < (s32)ARRAY_COUNT(sStorytellerStories); i++) + { + u8 stat = sStorytellerStories[arr[i]].stat; + u8 minVal = sStorytellerStories[arr[i]].minVal; + + for (j = 0; j < 4; j++) + { + if (sStorytellerPtr->gameStatIDs[j] == stat) + break; + } + if (j == 4 && StorytellerGetGameStat(stat) >= minVal) + { + sStorytellerPtr->alreadyRecorded = TRUE; + if (GetFreeStorySlot() == 4) + StorytellerRecordNewStat(sSelectedStory, stat); + else + StorytellerRecordNewStat(GetFreeStorySlot(), stat); + return TRUE; + } + } + return FALSE; +} + +static void StorytellerDisplayStory(u32 player) +{ + u8 stat = sStorytellerPtr->gameStatIDs[player]; + + ConvertIntToDecimalStringN(gStringVar1, StorytellerGetRecordedTrainerStat(player), 0, 10); + StringCopy(gStringVar2, GetStoryActionByStat(stat)); + GetStoryByStattellerPlayerName(player, gStringVar3); + ConvertInternationalString(gStringVar3, sStorytellerPtr->language[player]); + ShowFieldMessage(GetStoryTextByStat(stat)); +} + +static void PrintStoryList(void) +{ + s32 i; + s32 width = GetStringWidth(1, gText_Exit, 0); + u8 tileWidth; + for (i = 0; i < 4; i++) + { + s32 curWidth; + u16 gameStatID = sStorytellerPtr->gameStatIDs[i]; + + if (gameStatID == 0) + break; + curWidth = GetStringWidth(1, GetStoryTitleByStat(gameStatID), 0); + if (curWidth > width) + width = curWidth; + } + sStorytellerWindowId = CreateWindowFromRect(0, 0, convert_pixel_width_to_tile_width(width), GetFreeStorySlot() * 2 + 2); + SetStandardWindowBorderStyle(sStorytellerWindowId, 0); + for (i = 0; i < 4; i++) + { + u16 gameStatID = sStorytellerPtr->gameStatIDs[i]; + if (gameStatID == 0) + break; + PrintTextOnWindow(sStorytellerWindowId, 1, GetStoryTitleByStat(gameStatID), 8, 16 * i + 1, 0xFF, NULL); + } + PrintTextOnWindow(sStorytellerWindowId, 1, gText_Exit, 8, 16 * i + 1, 0xFF, NULL); + InitMenuInUpperLeftCornerPlaySoundWhenAPressed(sStorytellerWindowId, GetFreeStorySlot() + 1, 0); + CopyWindowToVram(sStorytellerWindowId, 3); +} + +static void Task_StoryListMenu(u8 taskId) // Task_StoryListMenu +{ + struct Task *task = &gTasks[taskId]; + s32 selection; + + switch (task->data[0]) + { + case 0: + PrintStoryList(); + task->data[0]++; + break; + case 1: + selection = ProcessMenuInput(); + if (selection == -2) + break; + if (selection == -1 || selection == GetFreeStorySlot()) + { + gSpecialVar_Result = 0; + } + else + { + gSpecialVar_Result = 1; + sSelectedStory = selection; + } + sub_80E2A78(sStorytellerWindowId); + DestroyTask(taskId); + EnableBothScriptContexts(); + break; + } +} + +// Sets gSpecialVar_Result to TRUE if player selected a story +void ScrSpecial_StorytellerStoryListMenu(void) +{ + CreateTask(Task_StoryListMenu, 80); +} + +void ScrSpecial_StorytellerDisplayStory(void) +{ + StorytellerDisplayStory(sSelectedStory); +} + +u8 ScrSpecial_StorytellerGetFreeStorySlot(void) +{ + sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller; + return GetFreeStorySlot(); +} + +// Returns TRUE if stat has increased +bool8 ScrSpecial_StorytellerUpdateStat(void) +{ + u8 r4; + sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller; + r4 = sStorytellerPtr->gameStatIDs[sSelectedStory]; + + if (HasTrainerStatIncreased(sSelectedStory) == TRUE) + { + StorytellerRecordNewStat(sSelectedStory, r4); + return TRUE; + } + return FALSE; +} + +bool8 ScrSpecial_HasStorytellerAlreadyRecorded(void) +{ + sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller; + + if (sStorytellerPtr->alreadyRecorded == FALSE) + return FALSE; + else + return TRUE; +} + +bool8 ScrSpecial_StorytellerInitializeRandomStat(void) +{ + sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller; + return StorytellerInitializeRandomStat(); +} + diff --git a/src/new_game.c b/src/new_game.c index 89771e92b..37336016e 100644 --- a/src/new_game.c +++ b/src/new_game.c @@ -20,8 +20,10 @@ #include "tv.h" #include "coins.h" #include "text.h" +#include "overworld.h" +#include "mail.h" +#include "battle_records.h" -extern u8 gPlayerPartyCount; extern u8 gDifferentSaveFile; extern u16 gSaveFileStatus; extern u8 gUnknown_030060B0; @@ -29,19 +31,15 @@ extern u8 gUnknown_030060B0; // TODO: replace those declarations with file headers extern u16 GetGeneratedTrainerIdLower(void); extern void ClearContestWinnerPicsInContestHall(void); -extern void Overworld_SetWarpDestination(s8 mapBank, s8 mapNo, s8 warpNo, s8 xPos, s8 yPos); extern void warp_in(void); extern void sub_80BB358(void); extern void ResetBagScrollPositions(void); extern void ResetPokedex(void); extern void sub_8084400(void); -extern void ClearMailData(void); extern void ResetGabbyAndTy(void); extern void ResetSecretBases(void); extern void ResetLinkContestBoolean(void); -extern void ResetGameStats(void); extern void sub_8052DA8(void); -extern void InitLinkBattleRecords(void); extern void ResetPokemonStorageSystem(void); extern void ClearBag(void); extern void NewGameInitPCItems(void); @@ -58,7 +56,7 @@ extern void ResetContestLinkResults(void); extern void ResetPokeJumpResults(void); extern void SetBerryPowder(u32* powder, u32 newValue); -extern u8 EventScript_2715DE[]; +extern const u8 EventScript_2715DE[]; void WriteUnalignedWord(u32 var, u8 *dataPtr) { @@ -178,7 +176,7 @@ void NewGameInitData(void) ResetLinkContestBoolean(); ResetGameStats(); ClearAllContestWinnerPics(); - InitLinkBattleRecords(); + ClearPlayerLinkBattleRecords(); InitSeedotSizeRecord(); InitLotadSizeRecord(); gPlayerPartyCount = 0; diff --git a/src/overworld.c b/src/overworld.c index 532615f27..f42f0db7f 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -137,7 +137,6 @@ extern void trainer_hill_map_load_related(void); extern void sub_8087D74(void); extern void battle_pyramid_map_load_related(u8); extern void sub_80B00E8(u8); -extern void UpdateTVScreensOnMap(u32, u32); extern void sub_80E9238(u8); extern void sub_81A3908(void); extern void sub_81AA2F8(void); @@ -614,12 +613,12 @@ bool32 warp_data_is_not_neg_1(struct WarpData *warp) return TRUE; } -const struct MapHeader *Overworld_GetMapHeaderByGroupAndId(u16 mapGroup, u16 mapNum) +struct MapHeader const *const Overworld_GetMapHeaderByGroupAndId(u16 mapGroup, u16 mapNum) { return gMapGroups[mapGroup][mapNum]; } -const struct MapHeader *warp1_get_mapheader(void) +struct MapHeader const *const warp1_get_mapheader(void) { return Overworld_GetMapHeaderByGroupAndId(sWarpDestination.mapGroup, sWarpDestination.mapNum); } diff --git a/src/player_pc.c b/src/player_pc.c index f56ecb128..6f39fa449 100644 --- a/src/player_pc.c +++ b/src/player_pc.c @@ -444,7 +444,7 @@ static void ItemStorage_Withdraw(u8 taskId) { s16 *data = gTasks[taskId].data; - NUM_ITEMS = sub_80D6CE4(); + NUM_ITEMS = CountUsedPCItemSlots(); if (NUM_ITEMS != 0) ItemStorage_WithdrawToss_Helper(taskId, FALSE); else @@ -459,7 +459,7 @@ static void ItemStorage_Toss(u8 taskId) { s16 *data = gTasks[taskId].data; - NUM_ITEMS = sub_80D6CE4(); + NUM_ITEMS = CountUsedPCItemSlots(); if (NUM_ITEMS != 0) ItemStorage_WithdrawToss_Helper(taskId, TRUE); else @@ -967,7 +967,7 @@ static void sub_816C0C8(void) static void sub_816C110(void) { - sub_80D6E84(); + CompactPCItems(); sub_812220C(gSaveBlock1Ptr->pcItems, 50, &(playerPCItemPageInfo.pageItems), &(playerPCItemPageInfo.count), 0x8); } @@ -1180,7 +1180,7 @@ static void ItemStorage_DoItemSwap(u8 taskId, bool8 a) { if(c != b - 1) { - sub_80D702C(gSaveBlock1Ptr->pcItems, c, b); + MoveItemSlotInList(gSaveBlock1Ptr->pcItems, c, b); ItemStorage_RefreshListMenu(); } } @@ -1301,7 +1301,7 @@ static void ItemStorage_DoItemToss(u8 taskId) data = gTasks[taskId].data; b = (playerPCItemPageInfo.cursorPos + playerPCItemPageInfo.itemsAbove); - if(!itemid_is_unique(gSaveBlock1Ptr->pcItems[b].itemId)) + if(!ItemId_GetImportance(gSaveBlock1Ptr->pcItems[b].itemId)) { CopyItemName(gSaveBlock1Ptr->pcItems[b].itemId, gStringVar1); ConvertIntToDecimalStringN(gStringVar2, data[2], STR_CONV_MODE_LEFT_ALIGN, 3); @@ -1335,7 +1335,7 @@ static void ItemStorage_HandleRemoveItem(u8 taskId) data = gTasks[taskId].data; if(gMain.newKeys & (A_BUTTON | B_BUTTON)) { - sub_80D6E48((playerPCItemPageInfo.cursorPos + playerPCItemPageInfo.itemsAbove), data[2]); + RemovePCItem((playerPCItemPageInfo.cursorPos + playerPCItemPageInfo.itemsAbove), data[2]); DestroyListMenuTask(data[5], &(playerPCItemPageInfo.itemsAbove), &(playerPCItemPageInfo.cursorPos)); sub_816C110(); sub_816C140(); diff --git a/src/pokeblock.c b/src/pokeblock.c index e829452b2..60087b5bf 100644 --- a/src/pokeblock.c +++ b/src/pokeblock.c @@ -589,7 +589,7 @@ static void PutPokeblockInfoText(void) { u8 i; - const u8 *itemName = ItemId_GetItem(ITEM_POKEBLOCK_CASE)->name; + const u8 *itemName = ItemId_GetName(ITEM_POKEBLOCK_CASE); PrintOnPokeblockWindow(0, itemName, GetStringCenterAlignXOffset(1, itemName, 0x48)); PrintOnPokeblockWindow(2, gText_Spicy, 0); diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index e7fcce629..f77b7c38c 100644 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -3173,11 +3173,11 @@ void sub_81C3554(u8 taskId) void sub_81C35E4() { - u8 *text; + const u8 *text; int offset; if (gUnknown_0203CF1C->summary.item == ITEM_ENIGMA_BERRY && sub_81B1250() == 1 && (gUnknown_0203CF1C->unk40BE == 1 || gUnknown_0203CF1C->unk40BE == 4 || gUnknown_0203CF1C->unk40BE == 5)) { - text = (u8*)ItemId_GetItem(ITEM_ENIGMA_BERRY); + text = ItemId_GetName(ITEM_ENIGMA_BERRY); } else if (gUnknown_0203CF1C->summary.item == ITEM_NONE) text = gText_None; diff --git a/src/random.c b/src/random.c index f2f0ede58..f0b2d9e5f 100644 --- a/src/random.c +++ b/src/random.c @@ -7,6 +7,10 @@ EWRAM_DATA static u8 sUnknown = 0; EWRAM_DATA static u32 sRandCount = 0; +// IWRAM common +IWRAM_DATA u32 gRngValue; +IWRAM_DATA u32 gRng2Value; + u16 Random(void) { gRngValue = 1103515245 * gRngValue + 24691; diff --git a/src/save.c b/src/save.c index 8025d6586..81731692e 100644 --- a/src/save.c +++ b/src/save.c @@ -4,17 +4,15 @@ #include "constants/game_stat.h" #include "task.h" #include "decompress.h" +#include "load_save.h" +#include "overworld.h" // for the chunk declarations -extern struct SaveBlock2 gSaveblock2; -extern struct SaveBlock1 gSaveblock1; -extern struct PokemonStorage gPokemonStorage; extern struct SaveSectionLocation gRamSaveSectionLocations[0xE]; -extern u8 gDecompressionBuffer[]; -extern u32 gFlashMemoryPresent; extern u16 gUnknown_03006294; extern bool8 gSoftResetDisabled; +extern u32 gUnknown_0203CF5C; // Divide save blocks into individual chunks to be written to flash sectors @@ -24,13 +22,13 @@ extern bool8 gSoftResetDisabled; /* * Sector Layout: - * + * * Sectors 0 - 13: Save Slot 1 * Sectors 14 - 27: Save Slot 2 * Sectors 28 - 29: Hall of Fame * Sector 30: e-Reader/Mystery Gift Stuff (note: e-Reader is deprecated in Emerald US) * Sector 31: Recorded Battle - * + * * There are two save slots for saving the player's game data. We alternate between * them each time the game is saved, so that if the current save slot is corrupt, * we can load the previous one. We also rotate the sectors in each save slot @@ -41,7 +39,7 @@ extern bool8 gSoftResetDisabled; // (u8 *)structure was removed from the first statement of the macro in Emerald. // This is because malloc is used to allocate addresses so storing the raw -// addresses should not be done in the offsets information. +// addresses should not be done in the offsets information. #define SAVEBLOCK_CHUNK(structure, chunkNum) \ { \ chunkNum * SECTOR_DATA_SIZE, \ @@ -69,8 +67,10 @@ const struct SaveSectionOffsets gSaveSectionOffsets[] = }; extern void DoSaveFailedScreen(u8); // save_failed_screen -extern void LoadSerializedGame(void); // load_save extern bool32 ProgramFlashSectorAndVerify(u8 sector, u8 *data); +extern void save_serialize_map(void); +extern void sub_800ADF8(void); +extern bool8 sub_800A520(void); // iwram common u16 gLastWrittenSector; @@ -656,11 +656,6 @@ void UpdateSaveAddresses(void) } } -extern u32 GetGameStat(u8 index); // rom4 -extern void IncrementGameStat(u8 index); // rom4 -extern void SaveSerializedGame(void); // load_save -extern u32 gUnknown_0203CF5C; - u8 HandleSavingData(u8 saveType) { u8 i; @@ -836,7 +831,7 @@ u16 sub_815355C(void) struct SaveSection* savSection; savSection = gFastSaveSection = &gSaveDataBuffer; - if (gFlashMemoryPresent != 1) + if (gFlashMemoryPresent != TRUE) return 0; UpdateSaveAddresses(); GetSaveValidStatus(gRamSaveSectionLocations); @@ -897,12 +892,6 @@ u32 sub_8153634(u8 sector, u8* src) return 1; } -extern void save_serialize_map(void); -extern void sub_8076D5C(void); -extern void sav2_gender2_inplace_and_xFE(void); -extern void sub_800ADF8(void); -extern bool8 sub_800A520(void); - void sub_8153688(u8 taskId) { s16* taskData = gTasks[taskId].data; diff --git a/src/secret_base.c b/src/secret_base.c index c886912f4..cd6143ed0 100644 --- a/src/secret_base.c +++ b/src/secret_base.c @@ -327,7 +327,7 @@ void sub_80E8E18(void) VarSet(VAR_SECRET_BASE_MAP, gMapHeader.regionMapSectionId); } -void sub_80E8EE0(struct MapEvents *events) +void sub_80E8EE0(struct MapEvents const *events) { u16 bgEventIndex; u16 i; diff --git a/src/trader.c b/src/trader.c new file mode 100644 index 000000000..c4d70ac9a --- /dev/null +++ b/src/trader.c @@ -0,0 +1,209 @@ +#include "global.h" +#include "constants/decorations.h" +#include "constants/mauville_man.h" +#include "decoration.h" +#include "decoration_inventory.h" +#include "event_data.h" +#include "main.h" +#include "menu.h" +#include "menu_helpers.h" +#include "script.h" +#include "constants/songs.h" +#include "sound.h" +#include "string_util.h" +#include "strings.h" +#include "task.h" +#include "script_menu.h" + +static const u8 * const sDefaultTraderNames[] = +{ + gText_Tristan, + gText_Philip, + gText_Dennis, + gText_Roberto, +}; + +static const u8 sDefaultTraderDecorations[] = +{ + DECOR_DUSKULL_DOLL, + DECOR_BALL_CUSHION, + DECOR_TIRE, + DECOR_PRETTY_FLOWERS, +}; + +void TraderSetup(void) +{ + u8 i; + struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader; + + trader->id = MAUVILLE_MAN_TRADER; + trader->alreadyTraded = FALSE; + + for (i = 0; i < 4; i++) + { + StringCopy(trader->playerNames[i], sDefaultTraderNames[i]); + trader->decorIds[i] = sDefaultTraderDecorations[i]; + trader->language[i] = GAME_LANGUAGE; + } +} + +void Trader_ResetFlag(void) +{ + struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader; + trader->alreadyTraded = FALSE; +} + +void CreateAvailableDecorationsMenu(u8 taskId) +{ + u8 i; + s16 * data = gTasks[taskId].data; + struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader; + struct WindowTemplate windowTemplate = {0, 1, 1, 10, 10, 15, 1}; + s32 windowWidth = GetStringWidth(1, gText_Exit, 0); + s32 fiveMarksWidth = GetStringWidth(1, gText_FiveMarks, 0); + for (i = 0; i < 4; i++) + { + s32 curWidth; + if (trader->decorIds[i] > NUM_DECORATIONS) + curWidth = fiveMarksWidth; + else + curWidth = GetStringWidth(1, gDecorations[trader->decorIds[i]].name, 0); + if (curWidth > windowWidth) + windowWidth = curWidth; + } + windowTemplate.width = convert_pixel_width_to_tile_width(windowWidth); + data[3] = AddWindow(&windowTemplate); + SetWindowBorderStyle(data[3], FALSE, 0x214, 14); + for (i = 0; i < 4; i++) + { + if (trader->decorIds[i] > NUM_DECORATIONS) + PrintTextOnWindow(data[3], 1, gText_FiveMarks, 8, 16 * i + 1, 255, NULL); + else + PrintTextOnWindow(data[3], 1, gDecorations[trader->decorIds[i]].name, 8, 16 * i + 1, 255, NULL); + } + PrintTextOnWindow(data[3], 1, gText_Exit, 8, 16 * i + 1, 255, NULL); + InitMenuInUpperLeftCornerPlaySoundWhenAPressed(data[3], 5, 0); + schedule_bg_copy_tilemap_to_vram(0); +} + +void sub_8133BE4(u8 taskId, u8 decorationId) +{ + s16 * data = gTasks[taskId].data; + if (decorationId > NUM_DECORATIONS) + { + gSpecialVar_0x8004 = 0xFFFF; + } + else + { + gSpecialVar_0x8004 = decorationId; + } + + sub_8198070(data[3], FALSE); + ClearWindowTilemap(data[3]); + RemoveWindow(data[3]); + schedule_bg_copy_tilemap_to_vram(0); + DestroyTask(taskId); + EnableBothScriptContexts(); +} + +void Task_HandleGetDecorationMenuInput(u8 taskId) +{ + struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader; + s8 input = ProcessMenuInput(); + + switch (input) + { + case -2: + break; + case -1: + case 4: + PlaySE(SE_SELECT); + sub_8133BE4(taskId, 0); + break; + default: + PlaySE(SE_SELECT); + gSpecialVar_0x8005 = input; + StringCopy(gStringVar1, trader->playerNames[input]); + ConvertInternationalString(gStringVar1, trader->language[input]); + sub_8133BE4(taskId, trader->decorIds[input]); + break; + } +} + +void ScrSpecial_GetTraderTradedFlag(void) +{ + struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader; + gSpecialVar_Result = trader->alreadyTraded; +} + +void ScrSpecial_DoesPlayerHaveNoDecorations(void) +{ + u8 i; + + for (i = 0; i < 8; i++) + { + if (CountDecorationCategoryN(i)) + { + gSpecialVar_Result = FALSE; + return; + } + } + gSpecialVar_Result = TRUE; +} + +void ScrSpecial_IsDecorationFull(void) +{ + gSpecialVar_Result = FALSE; + if (gDecorations[gSpecialVar_0x8004].category != gDecorations[gSpecialVar_0x8006].category + && GetFirstEmptyDecorSlot(gDecorations[gSpecialVar_0x8004].category) == -1) + { + sub_8127250(gStringVar2, gDecorations[gSpecialVar_0x8004].category); + gSpecialVar_Result = TRUE; + } +} + +void ScrSpecial_TraderMenuGiveDecoration(void) +{ + CreateTask(sub_8127208, 0); +} + +void sub_8133DA0(u8 taskId) +{ + if (IsSelectedDecorInThePC() == TRUE) + { + gSpecialVar_0x8006 = gCurDecorInventoryItems[gCurDecorationIndex]; + StringCopy(gStringVar3, gDecorations[gSpecialVar_0x8004].name); + StringCopy(gStringVar2, gDecorations[gSpecialVar_0x8006].name); + } + else + { + gSpecialVar_0x8006 = 0xFFFF; + } + DestroyTask(taskId); + EnableBothScriptContexts(); +} + +void sub_8133E1C(u8 taskId) +{ + gSpecialVar_0x8006 = 0; + DestroyTask(taskId); + EnableBothScriptContexts(); +} + +void ScrSpecial_TraderDoDecorationTrade(void) +{ + struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader; + + DecorationRemove(gSpecialVar_0x8006); + DecorationAdd(gSpecialVar_0x8004); + StringCopy(trader->playerNames[gSpecialVar_0x8005], gSaveBlock2Ptr->playerName); + trader->decorIds[gSpecialVar_0x8005] = gSpecialVar_0x8006; + trader->language[gSpecialVar_0x8005] = GAME_LANGUAGE; + trader->alreadyTraded = TRUE; +} + +void ScrSpecial_TraderMenuGetDecoration(void) +{ + u8 taskId = CreateTask(Task_HandleGetDecorationMenuInput, 0); + CreateAvailableDecorationsMenu(taskId); +} @@ -1380,13 +1380,13 @@ void PutFanClubSpecialOnTheAir(void) StringCopy(show->fanClubSpecial.idolName, name); tv_store_id_2x(show); show->fanClubSpecial.language = gGameLanguage; - if (show->fanClubSpecial.language == LANGUAGE_JAPANESE || gSaveBlock1Ptr->unk_31A0 == LANGUAGE_JAPANESE) + if (show->fanClubSpecial.language == LANGUAGE_JAPANESE || gSaveBlock1Ptr->linkBattleRecords.languages[0] == LANGUAGE_JAPANESE) { show->fanClubSpecial.idolNameLanguage = LANGUAGE_JAPANESE; } else { - show->fanClubSpecial.idolNameLanguage = gSaveBlock1Ptr->unk_31A0; + show->fanClubSpecial.idolNameLanguage = gSaveBlock1Ptr->linkBattleRecords.languages[0]; } } @@ -2465,7 +2465,7 @@ bool8 sub_80EE7C0(void) { return TRUE; } - if (gSaveBlock1Ptr->linkBattleRecords[0].name[0] == EOS) + if (gSaveBlock1Ptr->linkBattleRecords.entries[0].name[0] == EOS) { return TRUE; } @@ -2945,7 +2945,7 @@ static void sub_80EF40C(u8 varIdx, TVShow *show) { if (show->smartshopperShow.itemIds[i] != ITEM_NONE) { - price += itemid_get_market_price(show->smartshopperShow.itemIds[i]) * show->smartshopperShow.itemAmounts[i]; + price += ItemId_GetPrice(show->smartshopperShow.itemIds[i]) * show->smartshopperShow.itemAmounts[i]; } } if (show->smartshopperShow.priceReduced == TRUE) @@ -5120,7 +5120,7 @@ static void DoTVShowTodaysSmartShopper(void) break; case 1: TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); - StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[0])->name); + StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[0])); TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[0]); sTVShowState += 1 + (Random() % 4); break; @@ -5148,7 +5148,7 @@ static void DoTVShowTodaysSmartShopper(void) } break; case 6: - StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[1])->name); + StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[1])); TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[1]); if (show->smartshopperShow.itemIds[2] != ITEM_NONE) { @@ -5164,7 +5164,7 @@ static void DoTVShowTodaysSmartShopper(void) } break; case 7: - StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[2])->name); + StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[2])); TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[2]); if (show->smartshopperShow.priceReduced == TRUE) { @@ -5201,7 +5201,7 @@ static void DoTVShowTodaysSmartShopper(void) break; case 11: TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); - StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[0])->name); + StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[0])); if (show->smartshopperShow.priceReduced == TRUE) { sTVShowState = 8; @@ -5344,7 +5344,7 @@ static void DoTVShowPokemonTodaySuccessfulCapture(void) sTVShowState = 2; break; case 2: - StringCopy(gStringVar2, ItemId_GetItem(show->pokemonToday.ball)->name); + StringCopy(gStringVar2, ItemId_GetName(show->pokemonToday.ball)); TV_PrintIntToStringVar(2, show->pokemonToday.nBallsUsed); if (show->pokemonToday.nBallsUsed < 4) { @@ -6457,7 +6457,7 @@ static void DoTVShowHoennTreasureInvestigators(void) switch (state) { case 0: - StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name); + StringCopy(gStringVar1, ItemId_GetName(show->treasureInvestigators.item)); if (show->treasureInvestigators.location == MAPSEC_DYNAMIC) { switch (show->treasureInvestigators.mapDataId) @@ -6476,13 +6476,13 @@ static void DoTVShowHoennTreasureInvestigators(void) } break; case 1: - StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name); + StringCopy(gStringVar1, ItemId_GetName(show->treasureInvestigators.item)); TVShowConvertInternationalString(gStringVar2, show->treasureInvestigators.playerName, show->treasureInvestigators.language); GetMapName(gStringVar3, show->treasureInvestigators.location, 0); TVShowDone(); break; case 2: - StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name); + StringCopy(gStringVar1, ItemId_GetName(show->treasureInvestigators.item)); TVShowConvertInternationalString(gStringVar2, show->treasureInvestigators.playerName, show->treasureInvestigators.language); TVShowDone(); break; @@ -6598,7 +6598,7 @@ static void DoTVShowBreakingNewsTV(void) break; case 3: TV_PrintIntToStringVar(0, show->breakingNews.balls); - StringCopy(gStringVar2, ItemId_GetItem(show->breakingNews.caughtMonBall)->name); + StringCopy(gStringVar2, ItemId_GetName(show->breakingNews.caughtMonBall)); sTVShowState = 4; break; case 4: @@ -6788,7 +6788,7 @@ static void DoTVShowPokemonLotteryWinnerFlashReport(void) { StringCopy(gStringVar2, gText_Third); } - StringCopy(gStringVar3, ItemId_GetItem(show->lottoWinner.item)->name); + StringCopy(gStringVar3, ItemId_GetName(show->lottoWinner.item)); TVShowDone(); ShowFieldMessage(sTVPokemonLotteryWinnerFlashReportTextGroup[state]); } @@ -7530,7 +7530,7 @@ static void DoTVShowSecretBaseSecrets(void) sTVShowState = show->secretBaseSecrets.savedState; break; case 19: - StringCopy(gStringVar2, ItemId_GetItem(show->secretBaseSecrets.item)->name); + StringCopy(gStringVar2, ItemId_GetName(show->secretBaseSecrets.item)); sTVShowState = show->secretBaseSecrets.savedState; break; case 20: |