#include "global.h" #include "item.h" #include "berry.h" #include "constants/items.h" #include "string_util.h" #include "text.h" #include "event_data.h" #include "malloc.h" #include "secret_base.h" #include "item_menu.h" // These constants are used in gItems enum { POCKET_NONE, POCKET_ITEMS, POCKET_POKE_BALLS, POCKET_TM_HM, POCKET_BERRIES, POCKET_KEY_ITEMS, }; extern void ApplyNewEncryptionKeyToHword(u16 *hword, u32 newKey); extern bool8 InBattlePyramid(void); extern const u8 gText_PokeBalls[]; extern const u8 gText_Berries[]; extern const u8 gText_Berry[]; extern const struct Item gItems[]; // this file's functions static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count); static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count); static bool8 AddPyramidBagItem(u16 itemId, u16 count); static bool8 RemovePyramidBagItem(u16 itemId, u16 count); // code u16 GetBagItemQuantity(u16 *quantity) { return gSaveBlock2Ptr->encryptionKey ^ *quantity; } void SetBagItemQuantity(u16 *quantity, u16 newValue) { *quantity = newValue ^ gSaveBlock2Ptr->encryptionKey; } u16 GetPCItemQuantity(u16 *quantity) { return *quantity; } void SetPCItemQuantity(u16 *quantity, u16 newValue) { *quantity = newValue; } void ApplyNewEncryptionKeyToBagItems(u32 newKey) { u32 pocket, item; for (pocket = 0; pocket < POCKETS_COUNT; pocket++) { for (item = 0; item < gBagPockets[pocket].capacity; item++) ApplyNewEncryptionKeyToHword(&(gBagPockets[pocket].itemSlots[item].quantity), newKey); } } void ApplyNewEncryptionKeyToBagItems_(u32 newKey) // really GF? { ApplyNewEncryptionKeyToBagItems(newKey); } void SetBagItemsPointers(void) { gBagPockets[ITEMS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_Items; gBagPockets[ITEMS_POCKET].capacity = BAG_ITEMS_COUNT; gBagPockets[KEYITEMS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_KeyItems; gBagPockets[KEYITEMS_POCKET].capacity = BAG_KEYITEMS_COUNT; gBagPockets[BALLS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_PokeBalls; gBagPockets[BALLS_POCKET].capacity = BAG_POKEBALLS_COUNT; gBagPockets[TMHM_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_TMHM; gBagPockets[TMHM_POCKET].capacity = BAG_TMHM_COUNT; gBagPockets[BERRIES_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_Berries; gBagPockets[BERRIES_POCKET].capacity = BAG_BERRIES_COUNT; } void CopyItemName(u16 itemId, u8 *string) { StringCopy(string, ItemId_GetName(itemId)); } void CopyItemNameHandlePlural(u16 itemId, u8 *string, u32 quantity) { if (itemId == ITEM_POKE_BALL) { if (quantity < 2) StringCopy(string, ItemId_GetName(ITEM_POKE_BALL)); else StringCopy(string, gText_PokeBalls); } else { if (itemId >= ITEM_CHERI_BERRY && itemId <= ITEM_ENIGMA_BERRY) GetBerryCountString(string, gBerries[itemId - ITEM_CHERI_BERRY].name, quantity); else StringCopy(string, ItemId_GetName(itemId)); } } void GetBerryCountString(u8 *dst, const u8 *berryName, u32 quantity) { 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); } bool8 IsBagPocketNonEmpty(u8 pocket) { u8 i; for (i = 0; i < gBagPockets[pocket - 1].capacity; i++) { if (gBagPockets[pocket - 1].itemSlots[i].itemId != 0) return TRUE; } return FALSE; } bool8 CheckBagHasItem(u16 itemId, u16 count) { u8 i; u8 pocket; if (ItemId_GetPocket(itemId) == 0) return FALSE; 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 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? 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? if (count == 0) return TRUE; } } return FALSE; } bool8 HasAtLeastOneBerry(void) { u16 i; for (i = FIRST_BERRY_INDEX; i < ITEM_BRIGHT_POWDER; i++) { if (CheckBagHasItem(i, 1) == TRUE) { gSpecialVar_Result = TRUE; return TRUE; } } gSpecialVar_Result = FALSE; return FALSE; } #ifdef NONMATCHING // Refuses to match. bool8 CheckBagHasSpace(u16 itemId, u16 count) { u8 i; if (ItemId_GetPocket(itemId) == POCKET_NONE) return FALSE; if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE) { return CheckPyramidBagHasSpace(itemId, count); } else { u8 pocket; u16 slotCapacity; u16 ownedCount; 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) { 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++) { 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; } } 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; } } u8 GetPocketByItemId(u16 itemId) { return ItemId_GetPocket(itemId); } void ClearItemSlots(struct ItemSlot *itemSlots, u8 itemCount) { u16 i; for (i = 0; i < itemCount; 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) { ownedCount = GetPCItemQuantity(&newItems[i].quantity); if (ownedCount + count <= 999) { 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; } } } // 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; } static 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; } } extern u16 gUnknown_0203CF30[]; static 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; }