diff options
author | garak <garakmon@gmail.com> | 2018-10-19 16:05:14 -0400 |
---|---|---|
committer | garak <garakmon@gmail.com> | 2018-10-19 16:05:14 -0400 |
commit | 38fcc46abb36df72512f4b532d1379dab1c13af6 (patch) | |
tree | df44258d7b5a65d2a75a146c7c01b6c683b023f9 /src/shop.c | |
parent | 901f3ff55715ec6bdeda5c711e7e73b4c38ab55a (diff) | |
parent | 95d8815721321f08714b97c59a97de3a59f1e0c7 (diff) |
Merge remote-tracking branch 'upstream/master' into pan-constants
Diffstat (limited to 'src/shop.c')
-rwxr-xr-x | src/shop.c | 1232 |
1 files changed, 1232 insertions, 0 deletions
diff --git a/src/shop.c b/src/shop.c new file mode 100755 index 000000000..510c9f4f7 --- /dev/null +++ b/src/shop.c @@ -0,0 +1,1232 @@ +#include "global.h" +#include "bg.h" +#include "data2.h" +#include "decompress.h" +#include "decoration.h" +#include "decoration_inventory.h" +#include "event_object_movement.h" +#include "field_player_avatar.h" +#include "field_screen.h" +#include "field_weather.h" +#include "fieldmap.h" +#include "gpu_regs.h" +#include "graphics.h" +#include "international_string_util.h" +#include "item.h" +#include "item_icon.h" +#include "item_menu.h" +#include "list_menu.h" +#include "main.h" +#include "malloc.h" +#include "menu.h" +#include "menu_helpers.h" +#include "money.h" +#include "overworld.h" +#include "palette.h" +#include "party_menu.h" +#include "scanline_effect.h" +#include "script.h" +#include "shop.h" +#include "sound.h" +#include "sprite.h" +#include "string_util.h" +#include "strings.h" +#include "text_window.h" +#include "tv.h" +#include "constants/items.h" +#include "constants/metatile_behaviors.h" +#include "constants/rgb.h" +#include "constants/songs.h" + +EWRAM_DATA struct MartInfo gMartInfo = {0}; +EWRAM_DATA struct ShopData *gShopDataPtr = NULL; +EWRAM_DATA struct ListMenuItem *gUnknown_02039F74 = NULL; +EWRAM_DATA u8 (*gUnknown_02039F78)[16] = {0}; +EWRAM_DATA u8 gMartPurchaseHistoryId = 0; +EWRAM_DATA struct ItemSlot gMartPurchaseHistory[3] = {0}; + +static void Task_ShopMenu(u8 taskId); +static void Task_HandleShopMenuQuit(u8 taskId); +static void CB2_InitBuyMenu(void); +static void Task_GoToBuyOrSellMenu(u8 taskId); +static void MapPostLoadHook_ReturnToShopMenu(void); +static void Task_ReturnToShopMenu(u8 taskId); +static void ShowShopMenuAfterExitingBuyOrSellMenu(u8 taskId); +static void BuyMenuDrawGraphics(void); +static void BuyMenuAddScrollIndicatorArrows(void); +static void Task_BuyMenu(u8 taskId); +static void BuyMenuBuildListMenuTemplate(void); +static void BuyMenuInitBgs(void); +static void BuyMenuInitWindows(void); +static void BuyMenuDecompressBgGraphics(void); +static void BuyMenuSetListEntry(struct ListMenuItem*, u16, u8*); +static void BuyMenuAddItemIcon(u16, u8); +static void BuyMenuRemoveItemIcon(u16, u8); +static void BuyMenuPrint(u8 windowId, const u8 *text, u8 x, u8 y, s8 speed, u8 colorSet); +static void BuyMenuDrawMapGraphics(void); +static void BuyMenuCopyMenuBgToBg1TilemapBuffer(void); +static void BuyMenuCollectEventObjectData(void); +static void BuyMenuDrawEventObjects(void); +static void BuyMenuDrawMapBg(void); +static bool8 BuyMenuCheckForOverlapWithMenuBg(int, int); +static void BuyMenuDrawMapMetatile(s16, s16, const u16*, u8); +static void BuyMenuDrawMapMetatileLayer(u16 *dest, s16 offset1, s16 offset2, const u16 *src); +static bool8 BuyMenuCheckIfEventObjectOverlapsMenuBg(s16 *); +static void ExitBuyMenu(u8 taskId); +static void Task_ExitBuyMenu(u8 taskId); +static void BuyMenuTryMakePurchase(u8 taskId); +static void BuyMenuReturnToItemList(u8 taskId); +static void Task_BuyHowManyDialogueInit(u8 taskId); +static void BuyMenuConfirmPurchase(u8 taskId); +static void BuyMenuPrintItemQuantityAndPrice(u8 taskId); +static void Task_BuyHowManyDialogueHandleInput(u8 taskId); +static void BuyMenuSubtractMoney(u8 taskId); +static void RecordItemPurchase(u8 taskId); +static void Task_ReturnToItemListAfterItemPurchase(u8 taskId); +static void Task_ReturnToItemListAfterDecorationPurchase(u8 taskId); +static void Task_HandleShopMenuBuy(u8 taskId); +static void Task_HandleShopMenuSell(u8 taskId); +static void BuyMenuPrintItemDescriptionAndShowItemIcon(int item, bool8 onInit, struct ListMenu *list); +static void BuyMenuPrintPriceInList(u8 windowId, int item, u8 y); + +static const struct YesNoFuncTable sShopPurchaseYesNoFuncs = +{ + BuyMenuTryMakePurchase, + BuyMenuReturnToItemList +}; + +static const struct MenuAction sShopMenuActions_BuySellQuit[] = +{ + { gText_ShopBuy, {.void_u8=Task_HandleShopMenuBuy} }, + { gText_ShopSell, {.void_u8=Task_HandleShopMenuSell} }, + { gText_ShopQuit, {.void_u8=Task_HandleShopMenuQuit} } +}; + +static const struct MenuAction sShopMenuActions_BuyQuit[] = +{ + { gText_ShopBuy, {.void_u8=Task_HandleShopMenuBuy} }, + { gText_ShopQuit, {.void_u8=Task_HandleShopMenuQuit} } +}; + +static const struct WindowTemplate sShopMenuWindowTemplates[] = +{ + { + .priority = 0, + .tilemapLeft = 2, + .tilemapTop = 1, + .width = 9, + .height = 6, + .paletteNum = 15, + .baseBlock = 0x0008, + }, + { + .priority = 0, + .tilemapLeft = 2, + .tilemapTop = 1, + .width = 9, + .height = 4, + .paletteNum = 15, + .baseBlock = 0x0008, + } +}; + +static const struct ListMenuTemplate sShopBuyMenuListTemplate = +{ + .items = NULL, + .moveCursorFunc = BuyMenuPrintItemDescriptionAndShowItemIcon, + .itemPrintFunc = BuyMenuPrintPriceInList, + .totalItems = 0, + .maxShowed = 0, + .windowId = 1, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 1, + .cursorPal = 2, + .fillValue = 0, + .cursorShadowPal = 3, + .lettersSpacing = 0, + .itemVerticalPadding = 0, + .scrollMultiple = LIST_NO_MULTIPLE_SCROLL, + .fontId = 7, + .cursorKind = 0 +}; + +static const struct BgTemplate sShopBuyMenuBgTemplates[] = +{ + { + .bg = 0, + .charBaseIndex = 2, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 0, + .baseTile = 0 + }, + { + .bg = 1, + .charBaseIndex = 0, + .mapBaseIndex = 30, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0 + }, + { + .bg = 2, + .charBaseIndex = 0, + .mapBaseIndex = 29, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0 + }, + { + .bg = 3, + .charBaseIndex = 0, + .mapBaseIndex = 28, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0 + } +}; + +static const struct WindowTemplate sShopBuyMenuWindowTemplates[] = +{ + { + .priority = 0, + .tilemapLeft = 1, + .tilemapTop = 1, + .width = 10, + .height = 2, + .paletteNum = 15, + .baseBlock = 0x001E, + }, + { + .priority = 0, + .tilemapLeft = 14, + .tilemapTop = 2, + .width = 15, + .height = 16, + .paletteNum = 15, + .baseBlock = 0x0032, + }, + { + .priority = 0, + .tilemapLeft = 0, + .tilemapTop = 13, + .width = 14, + .height = 6, + .paletteNum = 15, + .baseBlock = 0x0122, + }, + { + .priority = 0, + .tilemapLeft = 1, + .tilemapTop = 11, + .width = 12, + .height = 2, + .paletteNum = 15, + .baseBlock = 0x0176, + }, + { + .priority = 0, + .tilemapLeft = 18, + .tilemapTop = 11, + .width = 10, + .height = 2, + .paletteNum = 15, + .baseBlock = 0x018E, + }, + { + .priority = 0, + .tilemapLeft = 2, + .tilemapTop = 15, + .width = 27, + .height = 4, + .paletteNum = 15, + .baseBlock = 0x01A2, + }, + DUMMY_WIN_TEMPLATE +}; + +static const struct WindowTemplate sShopBuyMenuYesNoWindowTemplates = +{ + .priority = 0, + .tilemapLeft = 21, + .tilemapTop = 9, + .width = 5, + .height = 4, + .paletteNum = 15, + .baseBlock = 0x020E, +}; + +static const u8 sShopBuyMenuTextColors[][3] = +{ + {1, 2, 3}, + {0, 2, 3}, + {0, 3, 2} +}; + +static u8 CreateShopMenu(u8 martType) +{ + int numMenuItems; + + ScriptContext2_Enable(); + gMartInfo.martType = martType; + + if (martType == MART_TYPE_0) + { + struct WindowTemplate winTemplate; + winTemplate = sShopMenuWindowTemplates[0]; + winTemplate.width = GetMaxWidthInMenuTable(sShopMenuActions_BuySellQuit, ARRAY_COUNT(sShopMenuActions_BuySellQuit)); + gMartInfo.windowId = AddWindow(&winTemplate); + gMartInfo.menuActions = sShopMenuActions_BuySellQuit; + numMenuItems = ARRAY_COUNT(sShopMenuActions_BuySellQuit); + } + else + { + struct WindowTemplate winTemplate; + winTemplate = sShopMenuWindowTemplates[1]; + winTemplate.width = GetMaxWidthInMenuTable(sShopMenuActions_BuyQuit, ARRAY_COUNT(sShopMenuActions_BuyQuit)); + gMartInfo.windowId = AddWindow(&winTemplate); + gMartInfo.menuActions = sShopMenuActions_BuyQuit; + numMenuItems = ARRAY_COUNT(sShopMenuActions_BuyQuit); + } + + SetStandardWindowBorderStyle(gMartInfo.windowId, 0); + PrintMenuTable(gMartInfo.windowId, numMenuItems, gMartInfo.menuActions); + InitMenuInUpperLeftCornerPlaySoundWhenAPressed(gMartInfo.windowId, numMenuItems, 0); + PutWindowTilemap(gMartInfo.windowId); + CopyWindowToVram(gMartInfo.windowId, 1); + + return CreateTask(Task_ShopMenu, 8); +} + +static void SetShopMenuCallback(void (* callback)(void)) +{ + gMartInfo.callback = callback; +} + +static void SetShopItemsForSale(const u16 *items) +{ + u16 i = 0; + + gMartInfo.itemList = items; + gMartInfo.itemCount = 0; + + while (gMartInfo.itemList[i]) + { + gMartInfo.itemCount++; + i++; + } +} + +static void Task_ShopMenu(u8 taskId) +{ + s8 inputCode = Menu_ProcessInputNoWrapAround(); + switch (inputCode) + { + case LIST_B_PRESSED: + break; + case LIST_NOTHING_CHOSEN: + PlaySE(SE_SELECT); + Task_HandleShopMenuQuit(taskId); + break; + default: + gMartInfo.menuActions[inputCode].func.void_u8(taskId); + break; + } +} + +static void Task_HandleShopMenuBuy(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + data[8] = (u32)CB2_InitBuyMenu >> 16; + data[9] = (u32)CB2_InitBuyMenu; + gTasks[taskId].func = Task_GoToBuyOrSellMenu; + FadeScreen(1, 0); +} + +static void Task_HandleShopMenuSell(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + data[8] = (u32)CB2_GoToSellMenu >> 16; + data[9] = (u32)CB2_GoToSellMenu; + gTasks[taskId].func = Task_GoToBuyOrSellMenu; + FadeScreen(1, 0); +} + +void CB2_ExitSellMenu(void) +{ + gFieldCallback = MapPostLoadHook_ReturnToShopMenu; + SetMainCallback2(CB2_ReturnToField); +} + +static void Task_HandleShopMenuQuit(u8 taskId) +{ + sub_8198070(gMartInfo.windowId, 2); + RemoveWindow(gMartInfo.windowId); + SaveRecordedItemPurchasesForTVShow(); + ScriptContext2_Disable(); + DestroyTask(taskId); + + if (gMartInfo.callback) + gMartInfo.callback(); +} + +static void Task_GoToBuyOrSellMenu(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (!gPaletteFade.active) + { + DestroyTask(taskId); + SetMainCallback2((void *)((u16)data[8] << 16 | (u16)data[9])); + } +} + +static void MapPostLoadHook_ReturnToShopMenu(void) +{ + pal_fill_black(); + CreateTask(Task_ReturnToShopMenu, 8); +} + +static void Task_ReturnToShopMenu(u8 taskId) +{ + if (IsWeatherNotFadingIn() == TRUE) + { + if (gMartInfo.martType == MART_TYPE_2) + DisplayItemMessageOnField(taskId, gText_CanIHelpWithAnythingElse, ShowShopMenuAfterExitingBuyOrSellMenu); + else + DisplayItemMessageOnField(taskId, gText_AnythingElseICanHelp, ShowShopMenuAfterExitingBuyOrSellMenu); + } +} + +static void ShowShopMenuAfterExitingBuyOrSellMenu(u8 taskId) +{ + CreateShopMenu(gMartInfo.martType); + DestroyTask(taskId); +} + +static void CB2_BuyMenu(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + do_scheduled_bg_tilemap_copies_to_vram(); + UpdatePaletteFade(); +} + +static void VBlankCB_BuyMenu(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +#define tItemCount data[1] +#define tItemId data[5] +#define tListTaskId data[7] + +static void CB2_InitBuyMenu(void) +{ + u8 taskId; + + switch (gMain.state) + { + case 0: + SetVBlankHBlankCallbacksToNull(); + CpuFastFill(0, (void *)OAM, 0x400); + ScanlineEffect_Stop(); + reset_temp_tile_data_buffers(); + FreeAllSpritePalettes(); + ResetPaletteFade(); + ResetSpriteData(); + ResetTasks(); + clear_scheduled_bg_copies_to_vram(); + gShopDataPtr = AllocZeroed(sizeof(struct ShopData)); + gShopDataPtr->scrollIndicatorsTaskId = 0xFF; + gShopDataPtr->itemSpriteIds[0] = -1; + gShopDataPtr->itemSpriteIds[1] = -1; + BuyMenuBuildListMenuTemplate(); + BuyMenuInitBgs(); + FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 0x20, 0x20); + FillBgTilemapBufferRect_Palette0(1, 0, 0, 0, 0x20, 0x20); + FillBgTilemapBufferRect_Palette0(2, 0, 0, 0, 0x20, 0x20); + FillBgTilemapBufferRect_Palette0(3, 0, 0, 0, 0x20, 0x20); + BuyMenuInitWindows(); + BuyMenuDecompressBgGraphics(); + gMain.state++; + break; + case 1: + if (!free_temp_tile_data_buffers_if_possible()) + gMain.state++; + break; + default: + BuyMenuDrawGraphics(); + BuyMenuAddScrollIndicatorArrows(); + taskId = CreateTask(Task_BuyMenu, 8); + gTasks[taskId].tListTaskId = ListMenuInit(&gMultiuseListMenuTemplate, 0, 0); + BlendPalettes(0xFFFFFFFF, 0x10, RGB_BLACK); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0x10, 0, RGB_BLACK); + SetVBlankCallback(VBlankCB_BuyMenu); + SetMainCallback2(CB2_BuyMenu); + break; + } +} + +static void BuyMenuFreeMemory(void) +{ + Free(gShopDataPtr); + Free(gUnknown_02039F74); + Free(gUnknown_02039F78); + FreeAllWindowBuffers(); +} + +static void BuyMenuBuildListMenuTemplate(void) +{ + u16 i; + u16 itemCount; + + gUnknown_02039F74 = Alloc((gMartInfo.itemCount + 1) * sizeof(*gUnknown_02039F74)); + gUnknown_02039F78 = Alloc((gMartInfo.itemCount + 1) * sizeof(*gUnknown_02039F78)); + for (i = 0; i < gMartInfo.itemCount; i++) + BuyMenuSetListEntry(&gUnknown_02039F74[i], gMartInfo.itemList[i], gUnknown_02039F78[i]); + + StringCopy(gUnknown_02039F78[i], gText_Cancel2); + gUnknown_02039F74[i].name = gUnknown_02039F78[i]; + gUnknown_02039F74[i].id = -2; + + gMultiuseListMenuTemplate = sShopBuyMenuListTemplate; + gMultiuseListMenuTemplate.items = gUnknown_02039F74; + gMultiuseListMenuTemplate.totalItems = gMartInfo.itemCount + 1; + if (gMultiuseListMenuTemplate.totalItems > 8) + gMultiuseListMenuTemplate.maxShowed = 8; + else + gMultiuseListMenuTemplate.maxShowed = gMultiuseListMenuTemplate.totalItems; + + gShopDataPtr->itemsShowed = gMultiuseListMenuTemplate.maxShowed; +} + +static void BuyMenuSetListEntry(struct ListMenuItem *menuItem, u16 item, u8 *name) +{ + if (gMartInfo.martType == MART_TYPE_0) + CopyItemName(item, name); + else + StringCopy(name, gDecorations[item].name); + + menuItem->name = name; + menuItem->id = item; +} + +static void BuyMenuPrintItemDescriptionAndShowItemIcon(int item, bool8 onInit, struct ListMenu *list) +{ + const u8 *description; + if (onInit != TRUE) + PlaySE(SE_SELECT); + + if (item != -2) + BuyMenuAddItemIcon(item, gShopDataPtr->iconSlot); + else + BuyMenuAddItemIcon(-1, gShopDataPtr->iconSlot); + + BuyMenuRemoveItemIcon(item, gShopDataPtr->iconSlot ^ 1); + gShopDataPtr->iconSlot ^= 1; + if (item != -2) + { + if (gMartInfo.martType == MART_TYPE_0) + description = ItemId_GetDescription(item); + else + description = gDecorations[item].description; + } + else + { + description = gText_QuitShopping; + } + + FillWindowPixelBuffer(2, 0); + BuyMenuPrint(2, description, 3, 1, 0, 0); +} + +static void BuyMenuPrintPriceInList(u8 windowId, int item, u8 y) +{ + u8 x; + + if (item != -2) + { + if (gMartInfo.martType == MART_TYPE_0) + { + ConvertIntToDecimalStringN( + gStringVar1, + ItemId_GetPrice(item) >> GetPriceReduction(1), + STR_CONV_MODE_LEFT_ALIGN, + 5); + } + else + { + ConvertIntToDecimalStringN( + gStringVar1, + gDecorations[item].price, + STR_CONV_MODE_LEFT_ALIGN, + 5); + } + + StringExpandPlaceholders(gStringVar4, gText_PokedollarVar1); + x = GetStringRightAlignXOffset(7, gStringVar4, 0x78); + AddTextPrinterParameterized4(windowId, 7, x, y, 0, 0, sShopBuyMenuTextColors[1], -1, gStringVar4); + } +} + +static void BuyMenuAddScrollIndicatorArrows(void) +{ + if (gShopDataPtr->scrollIndicatorsTaskId == 0xFF && gMartInfo.itemCount + 1 > 8) + { + gShopDataPtr->scrollIndicatorsTaskId = AddScrollIndicatorArrowPairParameterized( + SCROLL_ARROW_UP, + 0xAC, + 0xC, + 0x94, + gMartInfo.itemCount - 7, + 2100, + 2100, + &gShopDataPtr->scrollOffset); + } +} + +static void BuyMenuRemoveScrollIndicatorArrows(void) +{ + if (gShopDataPtr->scrollIndicatorsTaskId != 0xFF) + { + RemoveScrollIndicatorArrowPair(gShopDataPtr->scrollIndicatorsTaskId); + gShopDataPtr->scrollIndicatorsTaskId = 0xFF; + } +} + +static void BuyMenuPrintCursor(u8 scrollIndicatorsTaskId, u8 colorSet) +{ + u8 y = ListMenuGetYCoordForPrintingArrowCursor(scrollIndicatorsTaskId); + BuyMenuPrint(1, gText_SelectorArrow2, 0, y, 0, colorSet); +} + +static void BuyMenuAddItemIcon(u16 item, u8 iconSlot) +{ + u8 spriteId; + u8 *spriteIdPtr = &gShopDataPtr->itemSpriteIds[iconSlot]; + if (*spriteIdPtr != 0xFF) + return; + + if (gMartInfo.martType == MART_TYPE_0 || item == 0xFFFF) + { + spriteId = AddItemIconSprite(iconSlot + 2110, iconSlot + 2110, item); + if (spriteId != MAX_SPRITES) + { + *spriteIdPtr = spriteId; + gSprites[spriteId].pos2.x = 24; + gSprites[spriteId].pos2.y = 88; + } + } + else + { + spriteId = AddDecorationIconObject(item, 20, 84, 1, iconSlot + 2110, iconSlot + 2110); + if (spriteId != MAX_SPRITES) + *spriteIdPtr = spriteId; + } +} + +static void BuyMenuRemoveItemIcon(u16 item, u8 iconSlot) +{ + u8 *spriteIdPtr = &gShopDataPtr->itemSpriteIds[iconSlot]; + if (*spriteIdPtr == 0xFF) + return; + + FreeSpriteTilesByTag(iconSlot + 2110); + FreeSpritePaletteByTag(iconSlot + 2110); + DestroySprite(&gSprites[*spriteIdPtr]); + *spriteIdPtr = 0xFF; +} + +static void BuyMenuInitBgs(void) +{ + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sShopBuyMenuBgTemplates, ARRAY_COUNT(sShopBuyMenuBgTemplates)); + SetBgTilemapBuffer(1, gShopDataPtr->tilemapBuffers[1]); + SetBgTilemapBuffer(2, gShopDataPtr->tilemapBuffers[3]); + SetBgTilemapBuffer(3, gShopDataPtr->tilemapBuffers[2]); + SetGpuReg(REG_OFFSET_BG0HOFS, 0); + SetGpuReg(REG_OFFSET_BG0VOFS, 0); + SetGpuReg(REG_OFFSET_BG1HOFS, 0); + SetGpuReg(REG_OFFSET_BG1VOFS, 0); + SetGpuReg(REG_OFFSET_BG2HOFS, 0); + SetGpuReg(REG_OFFSET_BG2VOFS, 0); + SetGpuReg(REG_OFFSET_BG3HOFS, 0); + SetGpuReg(REG_OFFSET_BG3VOFS, 0); + SetGpuReg(REG_OFFSET_BLDCNT, 0); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); + ShowBg(0); + ShowBg(1); + ShowBg(2); + ShowBg(3); +} + +static void BuyMenuDecompressBgGraphics(void) +{ + decompress_and_copy_tile_data_to_vram(1, gBuyMenuFrame_Gfx, 0x3A0, 0x3E3, 0); + LZDecompressWram(gBuyMenuFrame_Tilemap, gShopDataPtr->tilemapBuffers[0]); + LoadCompressedPalette(gMenuMoneyPal, 0xC0, 0x20); +} + +static void BuyMenuInitWindows(void) +{ + InitWindows(sShopBuyMenuWindowTemplates); + DeactivateAllTextPrinters(); + LoadUserWindowBorderGfx(0, 1, 0xD0); + LoadMessageBoxGfx(0, 0xA, 0xE0); + PutWindowTilemap(0); + PutWindowTilemap(1); + PutWindowTilemap(2); +} + +static void BuyMenuPrint(u8 windowId, const u8 *text, u8 x, u8 y, s8 speed, u8 colorSet) +{ + AddTextPrinterParameterized4(windowId, 1, x, y, 0, 0, sShopBuyMenuTextColors[colorSet], speed, text); +} + +static void BuyMenuDisplayMessage(u8 taskId, const u8 *text, TaskFunc callback) +{ + DisplayMessageAndContinueTask(taskId, 5, 10, 14, 1, GetPlayerTextSpeed(), text, callback); + schedule_bg_copy_tilemap_to_vram(0); +} + +static void BuyMenuDrawGraphics(void) +{ + BuyMenuDrawMapGraphics(); + BuyMenuCopyMenuBgToBg1TilemapBuffer(); + AddMoneyLabelObject(19, 11); + PrintMoneyAmountInMoneyBoxWithBorder(0, 1, 13, GetMoney(&gSaveBlock1Ptr->money)); + schedule_bg_copy_tilemap_to_vram(0); + schedule_bg_copy_tilemap_to_vram(1); + schedule_bg_copy_tilemap_to_vram(2); + schedule_bg_copy_tilemap_to_vram(3); +} + +static void BuyMenuDrawMapGraphics(void) +{ + BuyMenuCollectEventObjectData(); + BuyMenuDrawEventObjects(); + BuyMenuDrawMapBg(); +} + +static void BuyMenuDrawMapBg(void) +{ + s16 i; + s16 j; + s16 x; + s16 y; + const struct MapLayout *mapLayout; + u16 metatile; + u8 metatileLayerType; + + mapLayout = gMapHeader.mapLayout; + GetXYCoordsOneStepInFrontOfPlayer(&x, &y); + x -= 4; + y -= 4; + + for (j = 0; j < 10; j++) + { + for (i = 0; i < 15; i++) + { + metatile = MapGridGetMetatileIdAt(x + i, y + j); + if (BuyMenuCheckForOverlapWithMenuBg(i, j) == TRUE) + metatileLayerType = MapGridGetMetatileLayerTypeAt(x + i, y + j); + else + metatileLayerType = 1; + + if (metatile < NUM_METATILES_IN_PRIMARY) + { + BuyMenuDrawMapMetatile(i, j, (u16*)mapLayout->primaryTileset->metatiles + metatile * 8, metatileLayerType); + } + else + { + BuyMenuDrawMapMetatile(i, j, (u16*)mapLayout->secondaryTileset->metatiles + ((metatile - NUM_METATILES_IN_PRIMARY) * 8), metatileLayerType); + } + } + } +} + +static void BuyMenuDrawMapMetatile(s16 x, s16 y, const u16 *src, u8 metatileLayerType) +{ + u16 offset1 = x * 2; + u16 offset2 = y * 64; + + switch (metatileLayerType) + { + case 0: + BuyMenuDrawMapMetatileLayer(gShopDataPtr->tilemapBuffers[3], offset1, offset2, src); + BuyMenuDrawMapMetatileLayer(gShopDataPtr->tilemapBuffers[1], offset1, offset2, src + 4); + break; + case 1: + BuyMenuDrawMapMetatileLayer(gShopDataPtr->tilemapBuffers[2], offset1, offset2, src); + BuyMenuDrawMapMetatileLayer(gShopDataPtr->tilemapBuffers[3], offset1, offset2, src + 4); + break; + case 2: + BuyMenuDrawMapMetatileLayer(gShopDataPtr->tilemapBuffers[2], offset1, offset2, src); + BuyMenuDrawMapMetatileLayer(gShopDataPtr->tilemapBuffers[1], offset1, offset2, src + 4); + break; + } +} + +static void BuyMenuDrawMapMetatileLayer(u16 *dest, s16 offset1, s16 offset2, const u16 *src) +{ + // This function draws a whole 2x2 metatile. + dest[offset1 + offset2] = src[0]; // top left + dest[offset1 + offset2 + 1] = src[1]; // top right + dest[offset1 + offset2 + 32] = src[2]; // bottom left + dest[offset1 + offset2 + 33] = src[3]; // bottom right +} + +static void BuyMenuCollectEventObjectData(void) +{ + s16 facingX; + s16 facingY; + u8 y; + u8 x; + u8 r8 = 0; + + GetXYCoordsOneStepInFrontOfPlayer(&facingX, &facingY); + for (y = 0; y < 16; y++) + gShopDataPtr->viewportObjects[y][EVENT_OBJ_ID] = 16; + for (y = 0; y < 5; y++) + { + for (x = 0; x < 7; x++) + { + u8 eventObjId = GetEventObjectIdByXY(facingX - 4 + x, facingY - 2 + y); + + if (eventObjId != 16) + { + gShopDataPtr->viewportObjects[r8][EVENT_OBJ_ID] = eventObjId; + gShopDataPtr->viewportObjects[r8][X_COORD] = x; + gShopDataPtr->viewportObjects[r8][Y_COORD] = y; + gShopDataPtr->viewportObjects[r8][LAYER_TYPE] = MapGridGetMetatileLayerTypeAt(facingX - 4 + x, facingY - 2 + y); + + switch (gEventObjects[eventObjId].facingDirection) + { + case DIR_SOUTH: + gShopDataPtr->viewportObjects[r8][ANIM_NUM] = 0; + break; + case DIR_NORTH: + gShopDataPtr->viewportObjects[r8][ANIM_NUM] = 1; + break; + case DIR_WEST: + gShopDataPtr->viewportObjects[r8][ANIM_NUM] = 2; + break; + case DIR_EAST: + default: + gShopDataPtr->viewportObjects[r8][ANIM_NUM] = 3; + break; + } + r8++; + } + } + } +} + +static void BuyMenuDrawEventObjects(void) +{ + u8 i; + u8 spriteId; + const struct EventObjectGraphicsInfo *graphicsInfo; + + for (i = 0; i < 16; i++) // max objects? + { + if (gShopDataPtr->viewportObjects[i][EVENT_OBJ_ID] == 16) + continue; + + graphicsInfo = GetEventObjectGraphicsInfo(gEventObjects[gShopDataPtr->viewportObjects[i][EVENT_OBJ_ID]].graphicsId); + + spriteId = AddPseudoEventObject( + gEventObjects[gShopDataPtr->viewportObjects[i][EVENT_OBJ_ID]].graphicsId, + SpriteCallbackDummy, + (u16)gShopDataPtr->viewportObjects[i][X_COORD] * 16 + 8, + (u16)gShopDataPtr->viewportObjects[i][Y_COORD] * 16 + 48 - graphicsInfo->height / 2, + 2); + + if (BuyMenuCheckIfEventObjectOverlapsMenuBg(gShopDataPtr->viewportObjects[i]) == TRUE) + { + gSprites[spriteId].subspriteTableNum = 4; + gSprites[spriteId].subspriteMode = 1; + } + + StartSpriteAnim(&gSprites[spriteId], gShopDataPtr->viewportObjects[i][ANIM_NUM]); + } +} + +static bool8 BuyMenuCheckIfEventObjectOverlapsMenuBg(s16 *object) +{ + if (!BuyMenuCheckForOverlapWithMenuBg(object[X_COORD], object[Y_COORD] + 2) && object[LAYER_TYPE] != MB_SECRET_BASE_WALL) + { + return TRUE; + } + else + { + return FALSE; + } +} + +static void BuyMenuCopyMenuBgToBg1TilemapBuffer(void) +{ + s16 i; + u16 *dest = gShopDataPtr->tilemapBuffers[1]; + const u16 *src = gShopDataPtr->tilemapBuffers[0]; + + for (i = 0; i < 1024; i++) + { + if (src[i] != 0) + { + dest[i] = src[i] + 0xC3E3; + } + } +} + +static bool8 BuyMenuCheckForOverlapWithMenuBg(int x, int y) +{ + const u16 *metatile = gShopDataPtr->tilemapBuffers[0]; + int offset1 = x * 2; + int offset2 = y * 64; + + if (metatile[offset2 + offset1] == 0 && + metatile[offset2 + offset1 + 32] == 0 && + metatile[offset2 + offset1 + 1] == 0 && + metatile[offset2 + offset1 + 33] == 0) + { + return TRUE; + } + + return FALSE; +} + +static void Task_BuyMenu(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (!gPaletteFade.active) + { + s32 itemId = ListMenuHandleInputGetItemId(tListTaskId); + ListMenuGetScrollAndRow(tListTaskId, &gShopDataPtr->scrollOffset, &gShopDataPtr->selectedRow); + + switch (itemId) + { + case LIST_NOTHING_CHOSEN: + break; + case LIST_B_PRESSED: + PlaySE(SE_SELECT); + ExitBuyMenu(taskId); + break; + default: + PlaySE(SE_SELECT); + tItemId = itemId; + ClearWindowTilemap(2); + BuyMenuRemoveScrollIndicatorArrows(); + BuyMenuPrintCursor(tListTaskId, 2); + + if (gMartInfo.martType == MART_TYPE_0) + { + gShopDataPtr->totalCost = (ItemId_GetPrice(itemId) >> GetPriceReduction(1)); + } + else + { + gShopDataPtr->totalCost = gDecorations[itemId].price; + } + + if (!IsEnoughMoney(&gSaveBlock1Ptr->money, gShopDataPtr->totalCost)) + { + BuyMenuDisplayMessage(taskId, gText_YouDontHaveMoney, BuyMenuReturnToItemList); + } + else + { + if (gMartInfo.martType == MART_TYPE_0) + { + CopyItemName(itemId, gStringVar1); + if (ItemId_GetPocket(itemId) == POCKET_TM_HM) + { + StringCopy(gStringVar2, gMoveNames[ItemIdToBattleMoveId(itemId)]); + BuyMenuDisplayMessage(taskId, gText_Var1CertainlyHowMany2, Task_BuyHowManyDialogueInit); + } + else + { + BuyMenuDisplayMessage(taskId, gText_Var1CertainlyHowMany, Task_BuyHowManyDialogueInit); + } + } + else + { + StringCopy(gStringVar1, gDecorations[itemId].name); + ConvertIntToDecimalStringN(gStringVar2, gShopDataPtr->totalCost, STR_CONV_MODE_LEFT_ALIGN, 6); + + if (gMartInfo.martType == MART_TYPE_1) + StringExpandPlaceholders(gStringVar4, gText_Var1IsItThatllBeVar2); + else + StringExpandPlaceholders(gStringVar4, gText_YouWantedVar1ThatllBeVar2); + BuyMenuDisplayMessage(taskId, gStringVar4, BuyMenuConfirmPurchase); + } + } + break; + } + } +} + +static void Task_BuyHowManyDialogueInit(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + u16 quantityInBag = CountTotalItemQuantityInBag(tItemId); + u16 maxQuantity; + + SetWindowBorderStyle(3, FALSE, 1, 13); + ConvertIntToDecimalStringN(gStringVar1, quantityInBag, STR_CONV_MODE_RIGHT_ALIGN, 4); + StringExpandPlaceholders(gStringVar4, gText_InBagVar1); + BuyMenuPrint(3, gStringVar4, 0, 1, 0, 0); + tItemCount = 1; + SetWindowBorderStyle(4, FALSE, 1, 13); + BuyMenuPrintItemQuantityAndPrice(taskId); + schedule_bg_copy_tilemap_to_vram(0); + + maxQuantity = GetMoney(&gSaveBlock1Ptr->money) / gShopDataPtr->totalCost; + + if (maxQuantity > 99) + { + gShopDataPtr->maxQuantity = 99; + } + else + { + gShopDataPtr->maxQuantity = maxQuantity; + } + + gTasks[taskId].func = Task_BuyHowManyDialogueHandleInput; +} + +static void Task_BuyHowManyDialogueHandleInput(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (AdjustQuantityAccordingToDPadInput(&tItemCount, gShopDataPtr->maxQuantity) == TRUE) + { + gShopDataPtr->totalCost = (ItemId_GetPrice(tItemId) >> GetPriceReduction(1)) * tItemCount; + BuyMenuPrintItemQuantityAndPrice(taskId); + } + else + { + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + sub_8198070(4, 0); + sub_8198070(3, 0); + ClearWindowTilemap(4); + ClearWindowTilemap(3); + PutWindowTilemap(1); + CopyItemName(tItemId, gStringVar1); + ConvertIntToDecimalStringN(gStringVar2, tItemCount, STR_CONV_MODE_LEFT_ALIGN, 2); + ConvertIntToDecimalStringN(gStringVar3, gShopDataPtr->totalCost, STR_CONV_MODE_LEFT_ALIGN, 6); + BuyMenuDisplayMessage(taskId, gText_Var1AndYouWantedVar2, BuyMenuConfirmPurchase); + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + sub_8198070(4, 0); + sub_8198070(3, 0); + ClearWindowTilemap(4); + ClearWindowTilemap(3); + BuyMenuReturnToItemList(taskId); + } + } +} + +static void BuyMenuConfirmPurchase(u8 taskId) +{ + CreateYesNoMenuWithCallbacks(taskId, &sShopBuyMenuYesNoWindowTemplates, 1, 0, 0, 1, 13, &sShopPurchaseYesNoFuncs); +} + +static void BuyMenuTryMakePurchase(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + PutWindowTilemap(1); + + if (gMartInfo.martType == MART_TYPE_0) + { + if (AddBagItem(tItemId, tItemCount) == TRUE) + { + BuyMenuDisplayMessage(taskId, gText_HereYouGoThankYou, BuyMenuSubtractMoney); + RecordItemPurchase(taskId); + } + else + { + BuyMenuDisplayMessage(taskId, gText_NoMoreRoomForThis, BuyMenuReturnToItemList); + } + } + else + { + if (DecorationAdd(tItemId)) + { + if (gMartInfo.martType == MART_TYPE_1) + { + BuyMenuDisplayMessage(taskId, gText_ThankYouIllSendItHome, BuyMenuSubtractMoney); + } + else + { + BuyMenuDisplayMessage(taskId, gText_ThanksIllSendItHome, BuyMenuSubtractMoney); + } + } + else + { + BuyMenuDisplayMessage(taskId, gText_SpaceForVar1Full, BuyMenuReturnToItemList); + } + } +} + +static void BuyMenuSubtractMoney(u8 taskId) +{ + IncrementGameStat(GAME_STAT_SHOPPED); + RemoveMoney(&gSaveBlock1Ptr->money, gShopDataPtr->totalCost); + PlaySE(SE_REGI); + PrintMoneyAmountInMoneyBox(0, GetMoney(&gSaveBlock1Ptr->money), 0); + + if (gMartInfo.martType == MART_TYPE_0) + { + gTasks[taskId].func = Task_ReturnToItemListAfterItemPurchase; + } + else + { + gTasks[taskId].func = Task_ReturnToItemListAfterDecorationPurchase; + } +} + +static void Task_ReturnToItemListAfterItemPurchase(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + PlaySE(SE_SELECT); + if (tItemId == ITEM_POKE_BALL && tItemCount > 9 && AddBagItem(ITEM_PREMIER_BALL, 1) == TRUE) + { + BuyMenuDisplayMessage(taskId, gText_ThrowInPremierBall, BuyMenuReturnToItemList); + } + else + { + BuyMenuReturnToItemList(taskId); + } + } +} + +static void Task_ReturnToItemListAfterDecorationPurchase(u8 taskId) +{ + if (gMain.newKeys & (A_BUTTON | B_BUTTON)) + { + PlaySE(SE_SELECT); + BuyMenuReturnToItemList(taskId); + } +} + +static void BuyMenuReturnToItemList(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + sub_8197DF8(5, 0); + BuyMenuPrintCursor(tListTaskId, 1); + PutWindowTilemap(1); + PutWindowTilemap(2); + schedule_bg_copy_tilemap_to_vram(0); + BuyMenuAddScrollIndicatorArrows(); + gTasks[taskId].func = Task_BuyMenu; +} + +static void BuyMenuPrintItemQuantityAndPrice(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + FillWindowPixelBuffer(4, 0x11); + PrintMoneyAmount(4, 38, 1, gShopDataPtr->totalCost, TEXT_SPEED_FF); + ConvertIntToDecimalStringN(gStringVar1, tItemCount, 2, 2); + StringExpandPlaceholders(gStringVar4, gText_xVar1); + BuyMenuPrint(4, gStringVar4, 0, 1, 0, 0); +} + +static void ExitBuyMenu(u8 taskId) +{ + gFieldCallback = MapPostLoadHook_ReturnToShopMenu; + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, 0); + gTasks[taskId].func = Task_ExitBuyMenu; +} + +static void Task_ExitBuyMenu(u8 taskId) +{ + if (!gPaletteFade.active) + { + RemoveMoneyLabelObject(); + BuyMenuFreeMemory(); + SetMainCallback2(CB2_ReturnToField); + DestroyTask(taskId); + } +} + +static void ClearItemPurchases(void) +{ + gMartPurchaseHistoryId = 0; + memset(gMartPurchaseHistory, 0, sizeof(gMartPurchaseHistory)); +} + +static void RecordItemPurchase(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + u16 i; + + for (i = 0; i < 3; i++) + { + if (gMartPurchaseHistory[i].itemId == tItemId && gMartPurchaseHistory[i].quantity != 0) + { + if (gMartPurchaseHistory[i].quantity + tItemCount > 255) + { + gMartPurchaseHistory[i].quantity = 255; + } + else + { + gMartPurchaseHistory[i].quantity += tItemCount; + } + return; + } + } + + if (gMartPurchaseHistoryId < 3) + { + gMartPurchaseHistory[gMartPurchaseHistoryId].itemId = tItemId; + gMartPurchaseHistory[gMartPurchaseHistoryId].quantity = tItemCount; + gMartPurchaseHistoryId++; + } +} + +#undef tItemCount +#undef tItemId +#undef tListTaskId + +void CreatePokemartMenu(const u16 *itemsForSale) +{ + CreateShopMenu(MART_TYPE_0); + SetShopItemsForSale(itemsForSale); + ClearItemPurchases(); + SetShopMenuCallback(EnableBothScriptContexts); +} + +void CreateDecorationShop1Menu(const u16 *itemsForSale) +{ + CreateShopMenu(MART_TYPE_1); + SetShopItemsForSale(itemsForSale); + SetShopMenuCallback(EnableBothScriptContexts); +} + +void CreateDecorationShop2Menu(const u16 *itemsForSale) +{ + CreateShopMenu(MART_TYPE_2); + SetShopItemsForSale(itemsForSale); + SetShopMenuCallback(EnableBothScriptContexts); +} |