summaryrefslogtreecommitdiff
path: root/src/shop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shop.c')
-rw-r--r--src/shop.c1251
1 files changed, 1251 insertions, 0 deletions
diff --git a/src/shop.c b/src/shop.c
new file mode 100644
index 000000000..87dbbeb97
--- /dev/null
+++ b/src/shop.c
@@ -0,0 +1,1251 @@
+#include "global.h"
+#include "shop.h"
+#include "decompress.h"
+#include "field_fadetransition.h"
+#include "field_weather.h"
+#include "item_menu.h"
+#include "main.h"
+#include "menu.h"
+#include "menu_helpers.h"
+#include "money.h"
+#include "palette.h"
+#include "script.h"
+#include "sound.h"
+#include "sprite.h"
+#include "strings.h"
+#include "task.h"
+#include "tv.h"
+#include "scanline_effect.h"
+#include "event_object_movement.h"
+#include "field_player_avatar.h"
+#include "fieldmap.h"
+#include "item.h"
+#include "decoration.h"
+#include "constants/items.h"
+#include "constants/songs.h"
+#include "overworld.h"
+#include "decoration_inventory.h"
+#include "field_camera.h"
+#include "ewram.h"
+
+extern bool8 SellMenu_QuantityRoller(u8, u8);
+
+extern u8 gBuyMenuFrame_Gfx[];
+extern u16 gBuyMenuFrame_Tilemap[];
+extern u16 gMenuMoneyPal[16];
+
+static void Shop_DisplayPriceInList(int firstItemId, int lastItemId, bool32 hasControlCode);
+static void Shop_PrintItemDescText(void);
+static void Task_ReturnToBuyMenu(u8);
+static void Task_ExitBuyMenu(u8);
+static void Task_ExitBuyMenuDoFade(u8);
+static void Task_UpdatePurchaseHistory(u8);
+static void Task_HandleShopMenuBuy(u8 taskId);
+static void Task_HandleShopMenuSell(u8 taskId);
+static void Task_HandleShopMenuQuit(u8 taskId);
+static void Task_DoItemPurchase(u8 taskId);
+static void Task_CancelItemPurchase(u8 taskId);
+static void Task_DoBuySellMenu(u8);
+static void Shop_FadeAndRunBuySellCallback(u8);
+static void BuyMenuDrawGraphics(void);
+static void sub_80B3240(void);
+static void DrawFirstMartScrollIndicators(void);
+static void Shop_DrawViewport(void);
+static void Shop_InitMenus(int, int);
+static void Shop_PrintItemDesc(void);
+static void Shop_DoCursorAction(u8);
+static void Shop_LoadViewportObjects(void);
+static void Shop_AnimViewportObjects(void);
+
+// iwram
+static struct MartInfo gMartInfo;
+
+// ewram
+EWRAM_DATA u32 gMartTotalCost = 0;
+EWRAM_DATA s16 gMartViewportObjects[16][4] = {0};
+EWRAM_DATA struct ItemSlot gMartPurchaseHistory[3] = {0};
+EWRAM_DATA u8 gMartPurchaseHistoryId = 0;
+
+EWRAM_DATA u8 gUnknown_02038731 = 0; // This really should be in fldeff_escalator, but being in a new file aligns the ewram, which doesnt match the ROM.
+
+// rodata
+static const struct MenuAction2 sBuySellQuitMenuActions[] =
+{
+ { MartText_Buy, Task_HandleShopMenuBuy },
+ { MartText_Sell, Task_HandleShopMenuSell },
+ { MartText_Quit2, Task_HandleShopMenuQuit },
+};
+
+static const u8 gMartBuySellOptionList[] = {SHOP_BUY, SHOP_SELL, SHOP_EXIT};
+static const u8 gMartBuyNoSellOptionList[] = {SHOP_BUY, SHOP_EXIT};
+
+static const u16 gUnusedMartArray[] = {0x2, 0x3, 0x4, 0xD, 0x121, 0xE, 0xE, 0xE, 0xE, 0xE, 0xE, 0x0, 0x0};
+
+static const struct YesNoFuncTable sShopPurchaseYesNoFuncs[] =
+{
+ Task_DoItemPurchase,
+ Task_CancelItemPurchase
+};
+
+static u8 CreateShopMenu(u8 martType)
+{
+ ScriptContext2_Enable();
+ gMartInfo.martType = martType;
+ gMartInfo.cursor = 0;
+
+ if (martType == MART_TYPE_0)
+ {
+ gMartInfo.numChoices = 2;
+ Menu_DrawStdWindowFrame(0, 0, 10, 7);
+ Menu_PrintItemsReordered(1, 1, 3, sBuySellQuitMenuActions, gMartBuySellOptionList);
+ }
+ else
+ {
+ gMartInfo.numChoices = 1;
+ Menu_DrawStdWindowFrame(0, 0, 10, 5);
+ Menu_PrintItemsReordered(1, 1, 2, sBuySellQuitMenuActions, gMartBuyNoSellOptionList);
+ }
+ InitMenu(0, 1, 1, gMartInfo.numChoices + 1, 0, 9); // add 1 for cancel
+
+ return CreateTask(Task_DoBuySellMenu, 8);
+}
+
+static void SetShopMenuCallback(void *callbackPtr)
+{
+ gMartInfo.callback = callbackPtr;
+}
+
+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_DoBuySellMenu(u8 taskId)
+{
+ const u8 taskIdConst = taskId; // why is a local const needed to match?
+
+ if (gMain.newAndRepeatedKeys & DPAD_UP)
+ {
+ if (gMartInfo.cursor) // can move cursor up?
+ {
+ PlaySE(SE_SELECT);
+ gMartInfo.cursor = Menu_MoveCursor(-1);
+ }
+ }
+ else if (gMain.newAndRepeatedKeys & DPAD_DOWN)
+ {
+ if (gMartInfo.cursor != gMartInfo.numChoices) // can move cursor down?
+ {
+ PlaySE(SE_SELECT);
+ gMartInfo.cursor = Menu_MoveCursor(1);
+ }
+ }
+ else if (gMain.newKeys & A_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+ if (gMartInfo.martType == MART_TYPE_0)
+ sBuySellQuitMenuActions[gMartBuySellOptionList[gMartInfo.cursor]].func(taskIdConst);
+ else
+ sBuySellQuitMenuActions[gMartBuyNoSellOptionList[gMartInfo.cursor]].func(taskIdConst);
+ }
+ else if (gMain.newKeys & B_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+ Task_HandleShopMenuQuit(taskIdConst);
+ }
+}
+
+static void Task_HandleShopMenuBuy(u8 taskId)
+{
+ gTasks[taskId].data[8] = (u32)BuyMenuDrawGraphics >> 16;
+ gTasks[taskId].data[9] = (u32)BuyMenuDrawGraphics;
+ gTasks[taskId].func = Shop_FadeAndRunBuySellCallback;
+ FadeScreen(1, 0);
+}
+
+static void Task_HandleShopMenuSell(u8 taskId)
+{
+ gTasks[taskId].data[8] = (u32)ItemMenu_LoadSellMenu >> 16;
+ gTasks[taskId].data[9] = (u32)ItemMenu_LoadSellMenu;
+ gTasks[taskId].func = Shop_FadeAndRunBuySellCallback;
+ FadeScreen(1, 0);
+}
+
+static void Task_HandleShopMenuQuit(u8 taskId)
+{
+ Menu_DestroyCursor();
+ Menu_EraseWindowRect(0, 0, 11, 8);
+ sub_80BE3BC();
+ ScriptContext2_Disable();
+ DestroyTask(taskId);
+
+ if (gMartInfo.callback)
+ gMartInfo.callback(); // run the callback if it exists.
+}
+
+static void Shop_FadeAndRunBuySellCallback(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ SetMainCallback2((void *)((u16)gTasks[taskId].data[8] << 16 | (u16)gTasks[taskId].data[9]));
+ DestroyTask(taskId);
+ }
+}
+
+static void ReturnToShopMenuAfterExitingSellMenu(u8 taskId)
+{
+ CreateShopMenu(gMartInfo.martType);
+ DestroyTask(taskId);
+}
+
+static void Task_ReturnToMartMenu(u8 taskId)
+{
+ if (IsWeatherNotFadingIn() == 1)
+ {
+ if (gMartInfo.martType == MART_TYPE_2)
+ DisplayItemMessageOnField(taskId, gOtherText_CanIHelpYou, ReturnToShopMenuAfterExitingSellMenu, 0);
+ else
+ DisplayItemMessageOnField(taskId, gOtherText_AnythingElse, ReturnToShopMenuAfterExitingSellMenu, 0);
+ }
+}
+
+void Shop_FadeReturnToMartMenu(void)
+{
+ pal_fill_black();
+ CreateTask(Task_ReturnToMartMenu, 0x8);
+}
+
+void Shop_RunExitSellMenuTask(u8 taskId)
+{
+ Task_ReturnToMartMenu(taskId);
+}
+
+// unused
+void Shop_LoadExitSellMenuTask(u8 taskId)
+{
+ gTasks[taskId].func = Task_ReturnToMartMenu;
+}
+
+static void MainCB2(void)
+{
+ AnimateSprites();
+ BuildOamBuffer();
+ RunTasks();
+ UpdatePaletteFade();
+}
+
+static void VBlankCB(void)
+{
+ LoadOam();
+ ProcessSpriteCopyRequests();
+ TransferPlttBuffer();
+ DmaCopy16Defvars(3, gBGTilemapBuffers[1], (void *)(VRAM + 0xE800), 0x800);
+ DmaCopy16Defvars(3, gBGTilemapBuffers[2], (void *)(VRAM + 0xE000), 0x800);
+ DmaCopy16Defvars(3, gBGTilemapBuffers[3], (void *)(VRAM + 0xF000), 0x800);
+}
+
+static void BuyMenuDrawGraphics(void)
+{
+ ClearVideoCallbacks();
+ ScanlineEffect_Stop();
+ REG_BG1HOFS = 0;
+ REG_BG1VOFS = 0;
+ REG_BG2HOFS = 0;
+ REG_BG2VOFS = 0;
+ REG_BG3HOFS = 0;
+ REG_BG3VOFS = 0;
+ gPaletteFade.bufferTransferDisabled = 1;
+
+ /*
+ THEORY: This seemingly useless loop is required in order to match this
+ function without hacks. The reason is because it alters the 0 optimization
+ of a later assignment into using 2 different 0s instead of the same register.
+ It is speculated that at some point Game Freak insert an artificial
+ breakpoint here in order to look at the contents of OAM before it is cleared,
+ possibly because a programmer made a mistake in shop.c which corrupted its
+ contents. There may have been a macro here which at one point idled on the
+ while(1) but was changed to 0 for release due to a define somewhere. A
+ while(0) also matches, but it is more correct to use do {} while(0) as it
+ was a fix to prevent compiler warnings on older compilers.
+ */
+ do {} while(0);
+
+ DmaFill32Defvars(3, 0, (void*)OAM, OAM_SIZE);
+ LZDecompressVram(gBuyMenuFrame_Gfx, (void*)(VRAM + 0x7C00));
+ LZDecompressWram(gBuyMenuFrame_Tilemap, ewram18000_2);
+ LoadCompressedPalette(gMenuMoneyPal, 0xC0, sizeof(gMenuMoneyPal));
+ FreeAllSpritePalettes();
+ ResetPaletteFade();
+ ResetSpriteData();
+ ResetTasks();
+ Text_LoadWindowTemplate(&gWindowTemplate_81E6DFC);
+ InitMenuWindow(&gWindowTemplate_81E6DFC);
+ Shop_DrawViewport();
+ gMartInfo.cursor = 0;
+ gMartInfo.choicesAbove = 0;
+ Menu_EraseWindowRect(0, 0, 0x20, 0x20);
+ OpenMoneyWindow(gSaveBlock1.money, 0, 0);
+ Shop_InitMenus(0, 7);
+ Shop_PrintItemDesc();
+ DrawFirstMartScrollIndicators();
+ CreateTask(Shop_DoCursorAction, 0x8);
+ sub_80B3240();
+ BeginNormalPaletteFade(0xFFFFFFFF, 0, 0x10, 0, 0);
+ gPaletteFade.bufferTransferDisabled = 0;
+ SetVBlankCallback(VBlankCB);
+ SetMainCallback2(MainCB2);
+}
+
+static void sub_80B3240(void)
+{
+ u16 colors[2] = {RGB(14, 15, 16), RGB_WHITE};
+
+ LoadPalette(&colors[1], 0xD1, sizeof colors[1]);
+ LoadPalette(&colors[0], 0xD8, sizeof colors[0]);
+}
+
+static void DrawFirstMartScrollIndicators(void)
+{
+ ClearVerticalScrollIndicatorPalettes();
+
+ if (gMartInfo.itemCount > 7)
+ {
+ CreateVerticalScrollIndicators(TOP_ARROW, 172, 12);
+ CreateVerticalScrollIndicators(BOTTOM_ARROW, 172, 148);
+ SetVerticalScrollIndicators(TOP_ARROW, INVISIBLE);
+ }
+}
+
+static void Shop_TryDrawVerticalScrollIndicators(void)
+{
+ if (gMartInfo.choicesAbove == 0)
+ SetVerticalScrollIndicators(TOP_ARROW, INVISIBLE);
+ else
+ SetVerticalScrollIndicators(TOP_ARROW, VISIBLE);
+
+ if (gMartInfo.choicesAbove + 7 >= gMartInfo.itemCount)
+ SetVerticalScrollIndicators(BOTTOM_ARROW, INVISIBLE);
+ else
+ SetVerticalScrollIndicators(BOTTOM_ARROW, VISIBLE);
+}
+
+// what is the point of this function? the tiles always get overwritten by BuyMenuDrawTextboxBG.
+static void BuyMenuDrawTextboxBG_Old(u16 *array, s16 offset1, s16 offset2)
+{
+ array[offset1 + offset2] = 0xC3E1;
+ array[offset1 + offset2 + 1] = 0xC3E1;
+}
+
+static void BuyMenuDrawMapMetatileLayer(u16 *array, s16 offset1, s16 offset2, u16 *array2)
+{
+ // This function draws a whole 2x2 metatile.
+ array[offset1 + offset2] = array2[0]; // top left
+ array[offset1 + offset2 + 1] = array2[1]; // top right
+ array[offset1 + offset2 + 32] = array2[2]; // bottom left
+ array[offset1 + offset2 + 33] = array2[3]; // bottom right
+}
+
+static void BuyMenuDrawMapMetatile(int var1, int var2, u16 *var3, s32 var4)
+{
+ u8 tempVar4 = var4;
+ s16 offset1 = var1 * 2;
+ s16 offset2 = (var2 * 0x40) + 0x40;
+
+ switch (tempVar4)
+ {
+ case 0:
+ BuyMenuDrawMapMetatileLayer(gBGTilemapBuffers[2], offset1, offset2, var3);
+ BuyMenuDrawMapMetatileLayer(gBGTilemapBuffers[1], offset1, offset2, var3 + 4);
+ break;
+ case 1:
+ BuyMenuDrawMapMetatileLayer(gBGTilemapBuffers[3], offset1, offset2, var3);
+ BuyMenuDrawMapMetatileLayer(gBGTilemapBuffers[2], offset1, offset2, var3 + 4);
+ break;
+ case 2:
+ BuyMenuDrawMapMetatileLayer(gBGTilemapBuffers[3], offset1, offset2, var3);
+ BuyMenuDrawMapMetatileLayer(gBGTilemapBuffers[1], offset1, offset2, var3 + 4);
+ break;
+ }
+}
+
+// used to draw the border tiles around the viewport.
+static void BuyMenuDrawMapPartialMetatile(s16 var1, int var2, u16 *var3)
+{
+ s16 offset1 = var1 * 2;
+ s16 offset2 = (var2 * 0x40) + 0x40;
+
+ BuyMenuDrawMapMetatileLayer(gBGTilemapBuffers[3], offset1, offset2, var3);
+ BuyMenuDrawMapMetatileLayer(gBGTilemapBuffers[2], offset1, offset2, var3 + 4);
+}
+
+static void Shop_DrawViewportTiles(void)
+{
+ s16 facingX;
+ s16 facingY;
+ s16 x;
+ s16 y;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&facingX, &facingY);
+ facingX -= 3;
+ facingY -= 3;
+
+ for (y = 0; y < 6; y++)
+ {
+ for (x = 0; x < 7; x++)
+ {
+ u16 metatileId = MapGridGetMetatileIdAt(facingX + x, facingY + y);
+
+ if (y != 5 && x != 6)
+ {
+ s32 r3 = MapGridGetMetatileLayerTypeAt(facingX + x, facingY + y);
+
+ if (metatileId < 512)
+ BuyMenuDrawMapMetatile(x, y, (u16 *)gMapHeader.mapData->primaryTileset->metatiles + metatileId * 8, r3);
+ else
+ BuyMenuDrawMapMetatile(x, y, (u16 *)gMapHeader.mapData->secondaryTileset->metatiles + (metatileId - 512) * 8, r3);
+ }
+ else
+ {
+ if (metatileId < 512)
+ BuyMenuDrawMapPartialMetatile(x, y, (u16 *)gMapHeader.mapData->primaryTileset->metatiles + metatileId * 8);
+ else
+ BuyMenuDrawMapPartialMetatile(x, y, (u16 *)gMapHeader.mapData->secondaryTileset->metatiles + (metatileId - 512) * 8);
+ }
+
+ if (y == 0 && x != 0 && x != 6)
+ BuyMenuDrawTextboxBG_Old(gBGTilemapBuffers[1], x * 2, 64);
+ }
+ }
+}
+
+static void Shop_DrawViewport(void)
+{
+ ClearBGTilemapBuffers();
+ Shop_LoadViewportObjects();
+ Shop_AnimViewportObjects();
+ Shop_DrawViewportTiles();
+}
+
+static void Shop_LoadViewportObjects(void)
+{
+ s16 facingX;
+ s16 facingY;
+ u8 playerHeight;
+ u8 y;
+ u8 x;
+ u8 r8 = 0;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&facingX, &facingY);
+ playerHeight = PlayerGetZCoord();
+ for (y = 0; y < 16; y++)
+ gMartViewportObjects[y][MAP_OBJ_ID] = 16;
+ for (y = 0; y < 5; y++)
+ {
+ for (x = 0; x < 7; x++)
+ {
+ u8 mapObjId = GetFieldObjectIdByXYZ(facingX - 3 + x, facingY - 2 + y, playerHeight);
+
+ if (mapObjId != 16)
+ {
+ gMartViewportObjects[r8][MAP_OBJ_ID] = mapObjId;
+ gMartViewportObjects[r8][X_COORD] = x;
+ gMartViewportObjects[r8][Y_COORD] = y;
+ if (gMapObjects[mapObjId].mapobj_unk_18 == 1)
+ gMartViewportObjects[r8][ANIM_NUM] = 0;
+ if (gMapObjects[mapObjId].mapobj_unk_18 == 2)
+ gMartViewportObjects[r8][ANIM_NUM] = 1;
+ if (gMapObjects[mapObjId].mapobj_unk_18 == 3)
+ gMartViewportObjects[r8][ANIM_NUM] = 2;
+ if (gMapObjects[mapObjId].mapobj_unk_18 == 4)
+ gMartViewportObjects[r8][ANIM_NUM] = 3;
+ r8++;
+ }
+ }
+ }
+}
+
+static void Shop_AnimViewportObjects(void)
+{
+ u8 i;
+
+ for (i = 0; i < 16; i++) // max objects?
+ {
+ if (gMartViewportObjects[i][MAP_OBJ_ID] == 16)
+ continue;
+
+ StartSpriteAnim(&gSprites[AddPseudoFieldObject(
+ gMapObjects[gMartViewportObjects[i][MAP_OBJ_ID]].graphicsId,
+ SpriteCallbackDummy,
+ (u16)gMartViewportObjects[i][X_COORD] * 16 + 8,
+ (u16)gMartViewportObjects[i][Y_COORD] * 16 + 32,
+ 2)],
+ gMartViewportObjects[i][ANIM_NUM]);
+ }
+}
+
+static void BuyMenuDrawTextboxBG(void)
+{
+ s16 i;
+
+ for (i = 0; i < 0x400; i++)
+ {
+ if (ewram18000[i] != 0)
+ gBGTilemapBuffers[1][i] = ewram18000[i] + 0xC3E0;
+ }
+}
+
+static void Shop_InitMenus(int firstItemId, int lastItemId)
+{
+ BuyMenuDrawTextboxBG();
+ Shop_DisplayPriceInList(firstItemId, lastItemId, 0);
+ InitMenu(0, 0xE, 0x2, 0x8, gMartInfo.cursor, 0xF);
+}
+
+// after printing the item quantity and price, restore the textbox tiles before the Yes/No prompt.
+static void BuyMenuDrawTextboxBG_Restore(void)
+{
+ u16 i, j;
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 14; j++)
+ gBGTilemapBuffers[1][32 * (i + 12) + j] = ewram18300[32 * i + j] + 0xC3E0;
+}
+
+static void Shop_PrintItemDesc(void)
+{
+ Shop_PrintItemDescText();
+}
+
+#define tItemCount data[1]
+
+static void Shop_DisplayPriceInCheckoutWindow(u8 taskId)
+{
+ u16 itemListIndex = gMartInfo.choicesAbove + gMartInfo.cursor;
+ u16 itemId = gMartInfo.itemList[itemListIndex];
+ u32 price = (ItemId_GetPrice(itemId) >> GetPriceReduction(1));
+
+ PrintMoneyAmount(gTasks[taskId].tItemCount * price, 6, 6, 11);
+ gStringVar1[0] = EXT_CTRL_CODE_BEGIN;
+ gStringVar1[1] = 0x14;
+ gStringVar1[2] = 0x6;
+ ConvertIntToDecimalStringN(&gStringVar1[3], gTasks[taskId].tItemCount, 1, 2);
+ Menu_PrintText(gOtherText_xString1, 1, 11);
+ sub_80A3FA0(gBGTilemapBuffers[1], 1, 11, 12, 2, 0xC3E1);
+}
+
+static void Shop_DisplayNormalPriceInList(u16 itemId, u8 var2, bool32 hasControlCode)
+{
+ u8 *stringPtr = gStringVar1;
+
+ if (hasControlCode)
+ {
+ stringPtr[0] = EXT_CTRL_CODE_BEGIN;
+ stringPtr[1] = 0x1;
+ stringPtr[2] = 0x2;
+ stringPtr += 3;
+ }
+
+ CopyItemName(itemId, stringPtr);
+
+ sub_8072A18(&gStringVar1[0], 0x70, var2 << 3, 0x58, 0x1);
+ stringPtr = gStringVar1;
+
+ if (hasControlCode)
+ stringPtr = &gStringVar1[3];
+
+ GetMoneyAmountText(stringPtr, (ItemId_GetPrice(itemId) >> GetPriceReduction(1)), 0x4);
+ Menu_PrintTextPixelCoords(&gStringVar1[0], 0xCA, var2 << 3, 1);
+}
+
+static void Shop_DisplayDecorationPriceInList(u16 itemId, u8 var2, bool32 hasControlCode)
+{
+ u8 *stringPtr = gStringVar1;
+
+ if (hasControlCode)
+ {
+ stringPtr[0] = EXT_CTRL_CODE_BEGIN;
+ stringPtr[1] = 0x1;
+ stringPtr[2] = 0x2;
+ stringPtr += 3;
+ }
+
+ StringCopy(stringPtr, gDecorations[itemId].name);
+ sub_8072A18(&gStringVar1[0], 0x70, var2 << 3, 0x58, 0x1);
+ stringPtr = gStringVar1;
+
+ if (hasControlCode)
+ stringPtr = &gStringVar1[3];
+
+ // some names are the maximum string length for a shop item. Because there is no room for
+ // a 6 character price (including the currency), a sprite is instead used for anything that
+ // is the maximum decoration price in order to fit it on screen.
+ if (gDecorations[itemId].price == 10000)
+ {
+ Draw10000Sprite(0x19, var2, hasControlCode);
+ }
+ else
+ {
+ GetMoneyAmountText(stringPtr, gDecorations[itemId].price, 0x4);
+ Menu_PrintTextPixelCoords(&gStringVar1[0], 0xCA, var2 << 3, 0x1);
+ }
+}
+
+static void Shop_DisplayPriceInList(int firstItemId, int lastItemId, bool32 hasControlCode)
+{
+ u8 i;
+
+ for (i = firstItemId; i <= lastItemId && gMartInfo.choicesAbove + i < gMartInfo.itemCount; i++)
+ {
+ if (gMartInfo.martType == MART_TYPE_0)
+ Shop_DisplayNormalPriceInList(gMartInfo.itemList[gMartInfo.choicesAbove + i], (i << 1) + 2, hasControlCode);
+ else
+ Shop_DisplayDecorationPriceInList(gMartInfo.itemList[gMartInfo.choicesAbove + i], (i << 1) + 2, hasControlCode);
+ }
+
+ if (i != 8 && gMartInfo.choicesAbove + i == gMartInfo.itemCount)
+ {
+ Menu_BlankWindowRect(0xE, (i << 1) + 2, 0x1C, (i << 1) + 3);
+ Menu_PrintText(gOtherText_CancelNoTerminator, 0xE, (i << 1) + 2);
+ }
+}
+
+static void Shop_PrintItemDescText(void)
+{
+ if (gMartInfo.choicesAbove + gMartInfo.cursor != gMartInfo.itemCount)
+ {
+ if (gMartInfo.martType == MART_TYPE_0)
+ {
+ sub_8072AB0(ItemId_GetDescription(gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]),
+ 0x4, 0x68, 0x68, 0x30, 0);
+ }
+ else
+ {
+ sub_8072AB0(gDecorations[gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]].description,
+ 0x4, 0x68, 0x68, 0x30, 0);
+ }
+ }
+ else
+ {
+ sub_8072AB0(gOtherText_QuitShopping, 0x4, 0x68, 0x68, 0x30, 0);
+ }
+}
+
+static void Shop_DoPremierBallCheck(u8 taskId)
+{
+ if (gMain.newKeys & A_BUTTON || gMain.newKeys & B_BUTTON)
+ {
+ Shop_DisplayPriceInList(gMartInfo.cursor, gMartInfo.cursor, 0);
+ PlaySE(SE_SELECT);
+
+ if (gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor] == ITEM_POKE_BALL && gTasks[taskId].tItemCount >= 10 && AddBagItem(ITEM_PREMIER_BALL, 1) == TRUE)
+ DisplayItemMessageOnField(taskId, gOtherText_FreePremierBall, Task_ReturnToBuyMenu, 0xC3E1);
+ else
+ Task_ReturnToBuyMenu(taskId);
+ }
+}
+
+static void Shop_DoItemTransaction(u8 taskId)
+{
+ IncrementGameStat(GAME_STAT_SHOPPED);
+ RemoveMoney(&gSaveBlock1.money, gMartTotalCost);
+ PlaySE(SE_REGI);
+ UpdateMoneyWindow(gSaveBlock1.money, 0, 0);
+ gTasks[taskId].func = Shop_DoPremierBallCheck;
+}
+
+static void Shop_DoPricePrintAndReturnToBuyMenu(u8 taskId)
+{
+ Shop_DisplayPriceInList(gMartInfo.cursor, gMartInfo.cursor, 0);
+ Task_ReturnToBuyMenu(taskId);
+}
+
+static void Task_DoItemPurchase(u8 taskId)
+{
+ Menu_EraseWindowRect(0x7, 0x8, 0xD, 0xD);
+ sub_80A3FA0(gBGTilemapBuffers[1], 8, 9, 4, 4, 0);
+ BuyMenuDrawTextboxBG_Restore();
+ Shop_DrawViewportTiles();
+
+ if (IsEnoughMoney(gSaveBlock1.money, gMartTotalCost))
+ {
+ if (gMartInfo.martType == MART_TYPE_0)
+ {
+ if (AddBagItem(gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor], gTasks[taskId].tItemCount))
+ {
+ DisplayItemMessageOnField(taskId, gOtherText_HereYouGo, Shop_DoItemTransaction, 0xC3E1);
+ Task_UpdatePurchaseHistory(taskId);
+ }
+ else
+ {
+ DisplayItemMessageOnField(taskId, gOtherText_NoRoomFor, Shop_DoPricePrintAndReturnToBuyMenu, 0xC3E1);
+ }
+ }
+ else // a normal mart is only type 0, so types 1 and 2 are decoration marts.
+ {
+ if (IsThereStorageSpaceForDecoration(gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]))
+ {
+ if (gMartInfo.martType == MART_TYPE_1)
+ DisplayItemMessageOnField(taskId, gOtherText_HereYouGo2, Shop_DoItemTransaction, 0xC3E1);
+ else
+ DisplayItemMessageOnField(taskId, gOtherText_HereYouGo3, Shop_DoItemTransaction, 0xC3E1);
+ }
+ else
+ {
+ StringExpandPlaceholders(gStringVar4, gOtherText_SpaceForIsFull);
+ DisplayItemMessageOnField(taskId, gStringVar4, Shop_DoPricePrintAndReturnToBuyMenu, 0xC3E1);
+ }
+ }
+ }
+ else
+ {
+ DisplayItemMessageOnField(taskId, gOtherText_NotEnoughMoney, Shop_DoPricePrintAndReturnToBuyMenu, 0xC3E1);
+ }
+}
+
+static void Shop_DoYesNoPurchase(u8 taskId)
+{
+ DisplayYesNoMenu(7, 8, 1);
+ sub_80A3FA0(gBGTilemapBuffers[1], 8, 9, 4, 4, 0xC3E1);
+ DoYesNoFuncWithChoice(taskId, sShopPurchaseYesNoFuncs);
+}
+
+static void Task_CancelItemPurchase(u8 taskId)
+{
+ Shop_DisplayPriceInList(gMartInfo.cursor, gMartInfo.cursor, 0);
+ Menu_EraseWindowRect(0x7, 0x8, 0xD, 0xD);
+ sub_80A3FA0(gBGTilemapBuffers[1], 0x8, 0x9, 0x4, 0x4, 0);
+ Task_ReturnToBuyMenu(taskId);
+}
+
+static void Shop_PrintPrice(u8 taskId)
+{
+ if (SellMenu_QuantityRoller(taskId, gMartInfo.curItemCount) == TRUE)
+ Shop_DisplayPriceInCheckoutWindow(taskId);
+
+ if (gMain.newKeys & A_BUTTON)
+ {
+ gMartTotalCost = (ItemId_GetPrice(gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]) >> GetPriceReduction(1)) * gTasks[taskId].tItemCount; // set total cost of your purchase.
+ Menu_EraseWindowRect(0, 0xA, 0xD, 0xD);
+ sub_80A3FA0(gBGTilemapBuffers[1], 0x1, 0xB, 0xC, 0x2, 0);
+ BuyMenuDrawTextboxBG_Restore();
+ Shop_DrawViewportTiles();
+ CopyItemName(gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor], gStringVar1);
+ ConvertIntToDecimalStringN(gStringVar2, gTasks[taskId].tItemCount, 0, 0x2);
+ ConvertIntToDecimalStringN(gStringVar3, gMartTotalCost, 0, 0x8);
+ StringExpandPlaceholders(gStringVar4, gOtherText_ThatWillBe);
+ DisplayItemMessageOnField(taskId, gStringVar4, Shop_DoYesNoPurchase, 0xC3E1);
+ }
+ else if (gMain.newKeys & B_BUTTON)
+ {
+ Shop_DisplayPriceInList(gMartInfo.cursor, gMartInfo.cursor, 0);
+ Task_ReturnToBuyMenu(taskId);
+ }
+}
+
+// set the item count in the mart info to the maximum allowed by the player's budget.
+static void Shop_UpdateCurItemCountToMax(u8 taskId)
+{
+ u16 var;
+
+ gTasks[taskId].tItemCount = 1;
+ Menu_DrawStdWindowFrame(0, 0xA, 0xD, 0xD);
+ Shop_DisplayPriceInCheckoutWindow(taskId);
+
+ var = gSaveBlock1.money / (ItemId_GetPrice(gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]) >> GetPriceReduction(1));
+ if (var > 99)
+ gMartInfo.curItemCount = 99;
+ else
+ gMartInfo.curItemCount = var;
+
+ gTasks[taskId].func = Shop_PrintPrice;
+}
+
+#ifdef NONMATCHING
+static void Shop_MoveItemListUp(void)
+{
+ u16 *r1;
+ u16 *r2;
+ register u8 *r10 asm("r10");
+ s32 i;
+ s32 j;
+ struct Window *r8 = &gMenuWindow;
+
+ r1 = r8->tilemap;
+ r1 += 0x1EF;
+ r2 = r1;
+ r2 += 64;
+ r10 = r8->tileData;
+
+ for (i = 0; i < 14; i++)
+ {
+ for (j = 0; j < 15; j++)
+ {
+ if ((r1[j] & 0x3FF) <= r8->tileDataStartOffset + 1)
+ r2[j] = r8->tileDataStartOffset + 1;
+ else
+ r2[j] = r1[j] + 0x3C;
+ }
+
+ r1 -= 32;
+ r2 -= 32;
+ }
+
+ {
+ u8 *r1 = r10 + 0x3A20;
+ u8 *r2 = r1 + 0x780;
+ for (i = 0; i < 14; i++)
+ {
+ DmaCopy16(3, r1, r2, 0x1E0);
+ r2 -= 0x3C0;
+ r1 -= 0x3C0;
+ }
+ }
+}
+#else
+__attribute__((naked))
+static void Shop_MoveItemListUp(void)
+{
+ asm(".syntax unified\n\
+ 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\
+ ldr r0, _080B4020 @ =gMenuWindow\n\
+ mov r8, r0\n\
+ ldr r1, [r0, 0x28]\n\
+ ldr r3, _080B4024 @ =0x000003de\n\
+ adds r1, r3\n\
+ adds r2, r1, 0\n\
+ adds r2, 0x80\n\
+ ldr r7, [r0, 0x24]\n\
+ mov r10, r7\n\
+ ldr r0, _080B4028 @ =0x000003ff\n\
+ mov r9, r0\n\
+ movs r6, 0xD\n\
+_080B3FAC:\n\
+ adds r3, r2, 0\n\
+ subs r3, 0x40\n\
+ str r3, [sp]\n\
+ movs r7, 0x40\n\
+ negs r7, r7\n\
+ adds r7, r1\n\
+ mov r12, r7\n\
+ adds r3, r2, 0\n\
+ adds r4, r1, 0\n\
+ movs r5, 0xE\n\
+_080B3FC0:\n\
+ ldrh r2, [r4]\n\
+ mov r1, r9\n\
+ ands r1, r2\n\
+ mov r7, r8\n\
+ ldrh r0, [r7, 0x1A]\n\
+ adds r0, 0x1\n\
+ cmp r1, r0\n\
+ ble _080B3FD4\n\
+ adds r0, r2, 0\n\
+ adds r0, 0x3C\n\
+_080B3FD4:\n\
+ strh r0, [r3]\n\
+ adds r3, 0x2\n\
+ adds r4, 0x2\n\
+ subs r5, 0x1\n\
+ cmp r5, 0\n\
+ bge _080B3FC0\n\
+ ldr r2, [sp]\n\
+ mov r1, r12\n\
+ subs r6, 0x1\n\
+ cmp r6, 0\n\
+ bge _080B3FAC\n\
+ ldr r1, _080B402C @ =0x00003a20\n\
+ add r1, r10\n\
+ movs r0, 0xF0\n\
+ lsls r0, 3\n\
+ adds r2, r1, r0\n\
+ ldr r3, _080B4030 @ =0x040000d4\n\
+ ldr r5, _080B4034 @ =0x800000f0\n\
+ ldr r4, _080B4038 @ =0xfffffc40\n\
+ movs r6, 0xD\n\
+_080B3FFC:\n\
+ str r1, [r3]\n\
+ str r2, [r3, 0x4]\n\
+ str r5, [r3, 0x8]\n\
+ ldr r0, [r3, 0x8]\n\
+ adds r2, r4\n\
+ adds r1, r4\n\
+ subs r6, 0x1\n\
+ cmp r6, 0\n\
+ bge _080B3FFC\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 {r0}\n\
+ bx r0\n\
+ .align 2, 0\n\
+_080B4020: .4byte gMenuWindow\n\
+_080B4024: .4byte 0x000003de\n\
+_080B4028: .4byte 0x000003ff\n\
+_080B402C: .4byte 0x00003a20\n\
+_080B4030: .4byte 0x040000d4\n\
+_080B4034: .4byte 0x800000f0\n\
+_080B4038: .4byte 0xfffffc40\n\
+ .syntax divided");
+}
+#endif
+
+#ifdef NONMATCHING
+static void Shop_MoveItemListDown(void)
+{
+ u16 *r1;
+ u16 *r2;
+ u8 *r10;
+ s32 i;
+ s32 j;
+ struct Window *r8 = &gMenuWindow;
+
+ r1 = r8->tilemap;
+ r1 += 0x4F;
+ r2 = r1;
+ r2 += 64;
+ r10 = r8->tileData;
+
+ for (i = 0; i < 14; i++)
+ {
+ for (j = 0; j < 15; j++)
+ {
+ if ((r1[j] & 0x3FF) <= r8->tileDataStartOffset + 1)
+ r2[j] = r8->tileDataStartOffset + 1;
+ else
+ r2[j] = r1[j] + 0x3C;
+ }
+
+ r1 += 32;
+ r2 += 32;
+ }
+
+ {
+ register u8 *r1 asm("r1") = r10 + 0x960;
+ register u8 *r2 asm("r2") = r1;
+
+ r1 += 0x780;
+ for (i = 0; i < 14; i++)
+ {
+ DmaCopy16(3, r1, r2, 0x1E0);
+ r1 += 0x3C0;
+ r2 += 0x3C0;
+ }
+ }
+}
+#else
+__attribute__((naked))
+static void Shop_MoveItemListDown(void)
+{
+ asm(".syntax unified\n\
+ 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\
+ ldr r0, _080B40D8 @ =gMenuWindow\n\
+ mov r8, r0\n\
+ ldr r2, [r0, 0x28]\n\
+ adds r1, r2, 0\n\
+ adds r1, 0x9E\n\
+ adds r2, r1, 0\n\
+ adds r1, 0x80\n\
+ ldr r3, [r0, 0x24]\n\
+ mov r10, r3\n\
+ ldr r7, _080B40DC @ =0x000003ff\n\
+ mov r9, r7\n\
+ movs r6, 0xD\n\
+_080B4060:\n\
+ adds r0, r2, 0\n\
+ adds r0, 0x40\n\
+ str r0, [sp]\n\
+ movs r3, 0x40\n\
+ adds r3, r1\n\
+ mov r12, r3\n\
+ adds r3, r2, 0\n\
+ adds r4, r1, 0\n\
+ movs r5, 0xE\n\
+_080B4072:\n\
+ ldrh r2, [r4]\n\
+ mov r1, r9\n\
+ ands r1, r2\n\
+ mov r7, r8\n\
+ ldrh r0, [r7, 0x1A]\n\
+ adds r0, 0x1\n\
+ cmp r1, r0\n\
+ ble _080B4086\n\
+ adds r0, r2, 0\n\
+ subs r0, 0x3C\n\
+_080B4086:\n\
+ strh r0, [r3]\n\
+ adds r3, 0x2\n\
+ adds r4, 0x2\n\
+ subs r5, 0x1\n\
+ cmp r5, 0\n\
+ bge _080B4072\n\
+ ldr r2, [sp]\n\
+ mov r1, r12\n\
+ subs r6, 0x1\n\
+ cmp r6, 0\n\
+ bge _080B4060\n\
+ movs r1, 0x96\n\
+ lsls r1, 4\n\
+ add r1, r10\n\
+ adds r2, r1, 0\n\
+ movs r0, 0xF0\n\
+ lsls r0, 3\n\
+ adds r1, r0\n\
+ ldr r3, _080B40E0 @ =0x040000d4\n\
+ ldr r5, _080B40E4 @ =0x800000f0\n\
+ movs r4, 0xF0\n\
+ lsls r4, 2\n\
+ movs r6, 0xD\n\
+_080B40B4:\n\
+ str r1, [r3]\n\
+ str r2, [r3, 0x4]\n\
+ str r5, [r3, 0x8]\n\
+ ldr r0, [r3, 0x8]\n\
+ adds r2, r4\n\
+ adds r1, r4\n\
+ subs r6, 0x1\n\
+ cmp r6, 0\n\
+ bge _080B40B4\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 {r0}\n\
+ bx r0\n\
+ .align 2, 0\n\
+_080B40D8: .4byte gMenuWindow\n\
+_080B40DC: .4byte 0x000003ff\n\
+_080B40E0: .4byte 0x040000d4\n\
+_080B40E4: .4byte 0x800000f0\n\
+ .syntax divided");
+}
+#endif
+
+static void Shop_DoCursorAction(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ if ((gMain.newAndRepeatedKeys & DPAD_ANY) == DPAD_UP) // only up can be pressed
+ {
+ if (gMartInfo.cursor == 0)
+ {
+ if (gMartInfo.choicesAbove == 0) // if there are no choices above, dont bother
+ return;
+
+ PlaySE(SE_SELECT);
+ gMartInfo.choicesAbove--; // since cursor is at the top and there are choices above the top, scroll the menu up by updating choicesAbove.
+ Shop_MoveItemListUp();
+ Shop_DisplayPriceInList(0, 0, 0);
+ Shop_PrintItemDescText();
+ Shop_TryDrawVerticalScrollIndicators();
+ }
+ else // if the cursor is not 0, choicesAbove cannot be updated yet since the cursor is at the top of the menu, so update cursor.
+ {
+ PlaySE(SE_SELECT);
+ gMartInfo.cursor = Menu_MoveCursor(-1); // move cursor up
+ Shop_PrintItemDescText();
+ }
+ }
+ else if ((gMain.newAndRepeatedKeys & DPAD_ANY) == DPAD_DOWN) // only down can be pressed
+ {
+ if (gMartInfo.cursor == 7) // are you at the bottom of the menu?
+ {
+ if (gMartInfo.choicesAbove + gMartInfo.cursor == gMartInfo.itemCount) // are you at cancel?
+ return;
+
+ PlaySE(SE_SELECT);
+ gMartInfo.choicesAbove++;
+ Shop_MoveItemListDown();
+ Shop_DisplayPriceInList(7, 7, 0);
+ Shop_PrintItemDescText();
+ Shop_TryDrawVerticalScrollIndicators();
+ }
+ else if (gMartInfo.cursor != gMartInfo.itemCount)
+ {
+ PlaySE(SE_SELECT);
+ gMartInfo.cursor = Menu_MoveCursor(1);
+ Shop_PrintItemDescText();
+ }
+ }
+ else if (gMain.newKeys & A_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+
+ if (gMartInfo.choicesAbove + gMartInfo.cursor != gMartInfo.itemCount) // did you not hit CANCEL?
+ {
+ PauseVerticalScrollIndicator(TOP_ARROW);
+ PauseVerticalScrollIndicator(BOTTOM_ARROW);
+ SetVerticalScrollIndicators(BOTTOM_ARROW, INVISIBLE);
+ Shop_DisplayPriceInList(gMartInfo.cursor, gMartInfo.cursor, 1);
+ Menu_DestroyCursor();
+ Menu_EraseWindowRect(0, 0xC, 0xD, 0x13);
+
+ if (gMartInfo.martType == MART_TYPE_0)
+ {
+ gMartTotalCost = (ItemId_GetPrice(gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]) >> GetPriceReduction(1)); // set 1x price
+ if (!IsEnoughMoney(gSaveBlock1.money, gMartTotalCost))
+ {
+ DisplayItemMessageOnField(taskId, gOtherText_NotEnoughMoney, Shop_DoPricePrintAndReturnToBuyMenu, 0xC3E1); // tail merge
+ }
+ else // _080B42BA
+ {
+ CopyItemName(gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor], gStringVar1);
+ StringExpandPlaceholders(gStringVar4, gOtherText_HowManyYouWant);
+ DisplayItemMessageOnField(taskId, gStringVar4, Shop_UpdateCurItemCountToMax, 0xC3E1);
+ }
+ }
+ else // _080B428C
+ {
+ gMartTotalCost = gDecorations[gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]].price;
+
+ if (!IsEnoughMoney(gSaveBlock1.money, gMartTotalCost))
+ {
+ DisplayItemMessageOnField(taskId, gOtherText_NotEnoughMoney, Shop_DoPricePrintAndReturnToBuyMenu, 0xC3E1); // tail merge
+ }
+ else
+ {
+ StringCopy(gStringVar1, gDecorations[gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]].name);
+ ConvertIntToDecimalStringN(gStringVar2, gMartTotalCost, 0, 0x8);
+
+ if (gMartInfo.martType == MART_TYPE_1)
+ StringExpandPlaceholders(gStringVar4, gOtherText_ThatWillBe2);
+ else
+ StringExpandPlaceholders(gStringVar4, gOtherText_ThatWillBe3);
+ DisplayItemMessageOnField(taskId, gStringVar4, Shop_DoYesNoPurchase, 0xC3E1);
+ }
+ }
+ }
+ else
+ {
+ Task_ExitBuyMenu(taskId);
+ }
+ }
+ else if (gMain.newKeys & B_BUTTON) // go back to buy/sell/exit menu
+ {
+ PlaySE(SE_SELECT);
+ Task_ExitBuyMenu(taskId);
+ }
+ }
+}
+
+static void Task_ReturnToBuyMenu(u8 taskId)
+{
+ Menu_EraseWindowRect(0, 0xE, 0x1D, 0x13);
+ Menu_EraseWindowRect(0, 0xA, 0xD, 0xD);
+ sub_80A3FA0(gBGTilemapBuffers[1], 0x1, 0xB, 0xC, 0x2, 0);
+ Shop_DrawViewportTiles();
+ Shop_InitMenus(6, 7);
+ Shop_PrintItemDesc();
+ StartVerticalScrollIndicators(TOP_ARROW);
+ StartVerticalScrollIndicators(BOTTOM_ARROW);
+ Shop_TryDrawVerticalScrollIndicators();
+ gTasks[taskId].func = Shop_DoCursorAction;
+}
+
+static void Task_ExitBuyMenu(u8 taskId)
+{
+ gFieldCallback = Shop_FadeReturnToMartMenu;
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ gTasks[taskId].func = Task_ExitBuyMenuDoFade;
+}
+
+static void Task_ExitBuyMenuDoFade(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ CloseMoneyWindow(0, 0);
+ BuyMenuFreeMemory();
+ SetMainCallback2(c2_exit_to_overworld_2_switch);
+ DestroyTask(taskId);
+ }
+}
+
+// Task_UpdatePurchaseHistory
+static void Task_UpdatePurchaseHistory(u8 taskId)
+{
+ u16 i;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (gMartPurchaseHistory[i].itemId == gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor]
+ && gMartPurchaseHistory[i].quantity != 0)
+ {
+ if (gMartPurchaseHistory[i].quantity + gTasks[taskId].tItemCount > 255)
+ gMartPurchaseHistory[i].quantity = 255;
+ else
+ gMartPurchaseHistory[i].quantity += gTasks[taskId].tItemCount;
+ return;
+ }
+ }
+
+ if (gMartPurchaseHistoryId < 3)
+ {
+ gMartPurchaseHistory[gMartPurchaseHistoryId].itemId = gMartInfo.itemList[gMartInfo.choicesAbove + gMartInfo.cursor];
+ gMartPurchaseHistory[gMartPurchaseHistoryId].quantity = gTasks[taskId].tItemCount;
+ gMartPurchaseHistoryId++;
+ }
+}
+
+#undef tItemCount
+
+static void ClearItemPurchases(void)
+{
+ gMartPurchaseHistoryId = 0;
+ ClearItemSlots(gMartPurchaseHistory, 3);
+}
+
+void Shop_CreatePokemartMenu(u16 *itemList)
+{
+ CreateShopMenu(MART_TYPE_0);
+ SetShopItemsForSale(itemList);
+ ClearItemPurchases();
+ SetShopMenuCallback(EnableBothScriptContexts);
+}
+
+void Shop_CreateDecorationShop1Menu(u16 *itemList)
+{
+ CreateShopMenu(MART_TYPE_1);
+ SetShopItemsForSale(itemList);
+ SetShopMenuCallback(EnableBothScriptContexts);
+}
+
+void Shop_CreateDecorationShop2Menu(u16 *itemList)
+{
+ CreateShopMenu(MART_TYPE_2);
+ SetShopItemsForSale(itemList);
+ SetShopMenuCallback(EnableBothScriptContexts);
+}
+
+#if DEBUG
+
+void debug_sub_80C2818(void)
+{
+ CreateShopMenu(MART_TYPE_0);
+ SetShopItemsForSale(gUnusedMartArray);
+ SetShopMenuCallback(NULL);
+}
+
+#endif