#include "global.h" #include "item.h" #include "berry.h" #include "pokeball.h" #include "string_util.h" #include "text.h" #include "event_data.h" #include "malloc.h" #include "secret_base.h" #include "item_menu.h" #include "party_menu.h" #include "strings.h" #include "load_save.h" #include "item_use.h" #include "battle_pyramid.h" #include "battle_pyramid_bag.h" #include "graphics.h" #include "constants/battle.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/item_effects.h" #include "constants/hold_effects.h" static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count); static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count); static const u8 *GetItemPluralName(u16); static bool32 DoesItemHavePluralName(u16); EWRAM_DATA struct BagPocket gBagPockets[POCKETS_COUNT] = {0}; #include "data/pokemon/item_effects.h" #include "data/items.h" static inline u16 GetBagItemIdPocket(struct BagPocket *pocket, u32 pocketPos) { return pocket->itemSlots[pocketPos].itemId; } static inline u16 GetBagItemQuantityPocket(struct BagPocket *pocket, u32 pocketPos) { return gSaveBlock2Ptr->encryptionKey ^ pocket->itemSlots[pocketPos].quantity; } static inline void SetBagItemIdPocket(struct BagPocket *pocket, u32 pocketPos, u16 itemId) { pocket->itemSlots[pocketPos].itemId = itemId; } static inline void SetBagItemQuantityPocket(struct BagPocket *pocket, u32 pocketPos, u16 newValue) { pocket->itemSlots[pocketPos].quantity = newValue ^ gSaveBlock2Ptr->encryptionKey; } u16 GetBagItemId(enum Pocket pocketId, u32 pocketPos) { return GetBagItemIdPocket(&gBagPockets[pocketId], pocketPos); } u16 GetBagItemQuantity(enum Pocket pocketId, u32 pocketPos) { return GetBagItemQuantityPocket(&gBagPockets[pocketId], pocketPos); } static void SetBagItemId(enum Pocket pocketId, u32 pocketPos, u16 itemId) { SetBagItemIdPocket(&gBagPockets[pocketId], pocketPos, itemId); } void SetBagItemQuantity(enum Pocket pocketId, u32 pocketPos, u16 newValue) { SetBagItemQuantityPocket(&gBagPockets[pocketId], pocketPos, newValue); } static u16 GetPCItemQuantity(u16 *quantity) { return *quantity; } static void SetPCItemQuantity(u16 *quantity, u16 newValue) { *quantity = newValue; } void ApplyNewEncryptionKeyToBagItems(u32 newKey) { enum Pocket pocketId; u32 item; for (pocketId = 0; pocketId < POCKETS_COUNT; pocketId++) { for (item = 0; item < gBagPockets[pocketId].capacity; item++) ApplyNewEncryptionKeyToHword(&(gBagPockets[pocketId].itemSlots[item].quantity), newKey); } } void SetBagItemsPointers(void) { gBagPockets[POCKET_ITEMS].itemSlots = gSaveBlock1Ptr->bag.items; gBagPockets[POCKET_ITEMS].capacity = BAG_ITEMS_COUNT; gBagPockets[POCKET_KEY_ITEMS].itemSlots = gSaveBlock1Ptr->bag.keyItems; gBagPockets[POCKET_KEY_ITEMS].capacity = BAG_KEYITEMS_COUNT; gBagPockets[POCKET_POKE_BALLS].itemSlots = gSaveBlock1Ptr->bag.pokeBalls; gBagPockets[POCKET_POKE_BALLS].capacity = BAG_POKEBALLS_COUNT; gBagPockets[POCKET_TM_HM].itemSlots = gSaveBlock1Ptr->bag.TMsHMs; gBagPockets[POCKET_TM_HM].capacity = BAG_TMHM_COUNT; gBagPockets[POCKET_BERRIES].itemSlots = gSaveBlock1Ptr->bag.berries; gBagPockets[POCKET_BERRIES].capacity = BAG_BERRIES_COUNT; } u8 *CopyItemName(u16 itemId, u8 *dst) { return StringCopy(dst, GetItemName(itemId)); } const u8 sText_s[] =_("s"); u8 *CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity) { if (quantity == 1) { return StringCopy(dst, GetItemName(itemId)); } else if (DoesItemHavePluralName(itemId)) { return StringCopy(dst, GetItemPluralName(itemId)); } else { u8 *end = StringCopy(dst, GetItemName(itemId)); return StringCopy(end, sText_s); } } bool8 IsBagPocketNonEmpty(enum Pocket pocketId) { u8 i; for (i = 0; i < gBagPockets[pocketId].capacity; i++) { if (GetBagItemId(pocketId, i) != 0) return TRUE; } return FALSE; } bool8 CheckBagHasItem(u16 itemId, u16 count) { u8 i; enum Pocket pocketId; if (GetItemPocket(itemId) >= POCKETS_COUNT) return FALSE; if (InBattlePyramid() || FlagGet(FLAG_STORING_ITEMS_IN_PYRAMID_BAG) == TRUE) return CheckPyramidBagHasItem(itemId, count); pocketId = GetItemPocket(itemId); // Check for item slots that contain the item for (i = 0; i < gBagPockets[pocketId].capacity; i++) { if (GetBagItemId(pocketId, i) == itemId) { u16 quantity; // Does this item slot contain enough of the item? quantity = GetBagItemQuantity(pocketId, i); 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 <= LAST_BERRY_INDEX; i++) { if (CheckBagHasItem(i, 1) == TRUE) { gSpecialVar_Result = TRUE; return TRUE; } } gSpecialVar_Result = FALSE; return FALSE; } bool8 HasAtLeastOnePokeBall(void) { u16 ballId; for (ballId = BALL_STRANGE; ballId < POKEBALL_COUNT; ballId++) { if (CheckBagHasItem(ballId, 1) == TRUE) return TRUE; } return FALSE; } bool8 CheckBagHasSpace(u16 itemId, u16 count) { if (GetItemPocket(itemId) >= POCKETS_COUNT) return FALSE; if (InBattlePyramid() || FlagGet(FLAG_STORING_ITEMS_IN_PYRAMID_BAG) == TRUE) return CheckPyramidBagHasSpace(itemId, count); return GetFreeSpaceForItemInBag(itemId) >= count; } u32 GetFreeSpaceForItemInBag(u16 itemId) { u8 i; enum Pocket pocketId = GetItemPocket(itemId); u16 ownedCount; u32 spaceForItem = 0; if (GetItemPocket(itemId) >= POCKETS_COUNT) return 0; // Check space in any existing item slots that already contain this item for (i = 0; i < gBagPockets[pocketId].capacity; i++) { if (GetBagItemId(pocketId, i) == itemId) { ownedCount = GetBagItemQuantity(pocketId, i); spaceForItem += max(0, MAX_BAG_ITEM_CAPACITY - ownedCount); } else if (GetBagItemId(pocketId, i) == ITEM_NONE) { spaceForItem += MAX_BAG_ITEM_CAPACITY; } } return spaceForItem; } static inline u32 PrepareTempPocket(struct BagPocket *tempPocket, enum Pocket pocketId) { u32 size = gBagPockets[pocketId].capacity * sizeof(struct ItemSlot); tempPocket->itemSlots = AllocZeroed(size); tempPocket->capacity = gBagPockets[pocketId].capacity; memcpy(tempPocket->itemSlots, gBagPockets[pocketId].itemSlots, size); return size; } static inline void ClearTempPocket(struct BagPocket *pocket) { Free(pocket->itemSlots); Free(pocket); } static inline void RestorePocketAndClearTempPocket(struct BagPocket *tempPocket, enum Pocket pocketId, u32 pocketSize) { memcpy(gBagPockets[pocketId].itemSlots, tempPocket->itemSlots, pocketSize); ClearTempPocket(tempPocket); } bool8 AddBagItem(u16 itemId, u16 count) { u8 i; if (GetItemPocket(itemId) >= POCKETS_COUNT) return FALSE; // check Battle Pyramid Bag if (InBattlePyramid() || FlagGet(FLAG_STORING_ITEMS_IN_PYRAMID_BAG) == TRUE) { return AddPyramidBagItem(itemId, count); } else { u16 ownedCount; enum Pocket pocketId = GetItemPocket(itemId); struct BagPocket *tempPocket = AllocZeroed(sizeof(struct BagPocket)); u32 pocketSize = PrepareTempPocket(tempPocket, pocketId); for (i = 0; i < gBagPockets[pocketId].capacity; i++) { if (GetBagItemIdPocket(tempPocket, i) == itemId) { ownedCount = GetBagItemQuantityPocket(tempPocket, i); // check if won't exceed max slot capacity if (ownedCount + count <= MAX_BAG_ITEM_CAPACITY) { // successfully added to already existing item's count SetBagItemQuantityPocket(tempPocket, i, ownedCount + count); RestorePocketAndClearTempPocket(tempPocket, pocketId, pocketSize); return TRUE; } else { // try creating another instance of the item if possible if (pocketId == POCKET_TM_HM || pocketId == POCKET_BERRIES) { ClearTempPocket(tempPocket); return FALSE; } else { count -= MAX_BAG_ITEM_CAPACITY - ownedCount; SetBagItemQuantityPocket(tempPocket, i, MAX_BAG_ITEM_CAPACITY); // don't create another instance of the item if it's at max slot capacity and count is equal to 0 if (count == 0) { break; } } } } } // 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 < gBagPockets[pocketId].capacity; i++) { if (GetBagItemIdPocket(tempPocket, i) == ITEM_NONE) { SetBagItemIdPocket(tempPocket, i, itemId); if (count > MAX_BAG_ITEM_CAPACITY) { // try creating a new slot with max capacity if duplicates are possible if (pocketId == POCKET_TM_HM || pocketId == POCKET_BERRIES) { ClearTempPocket(tempPocket); return FALSE; } count -= MAX_BAG_ITEM_CAPACITY; SetBagItemQuantityPocket(tempPocket, i, MAX_BAG_ITEM_CAPACITY); } else { // created a new slot and added quantity SetBagItemQuantityPocket(tempPocket, i, count); count = 0; break; } } } if (count > 0) { ClearTempPocket(tempPocket); return FALSE; } } RestorePocketAndClearTempPocket(tempPocket, pocketId, pocketSize); return TRUE; } } bool8 RemoveBagItem(u16 itemId, u16 count) { u8 i; u16 totalQuantity = 0; if (GetItemPocket(itemId) >= POCKETS_COUNT || itemId == ITEM_NONE) return FALSE; // check Battle Pyramid Bag if (InBattlePyramid() || FlagGet(FLAG_STORING_ITEMS_IN_PYRAMID_BAG) == TRUE) { return RemovePyramidBagItem(itemId, count); } else { u16 ownedCount, firstStackIndex = 0; enum Pocket pocketId = GetItemPocket(itemId); for (i = 0; i < gBagPockets[pocketId].capacity; i++) { if (GetBagItemId(pocketId, i) == itemId) { if (totalQuantity == 0) firstStackIndex = i; totalQuantity += GetBagItemQuantity(pocketId, i); } } if (totalQuantity < count) return FALSE; // We don't have enough of the item if (CurMapIsSecretBase() == TRUE) { VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_BAG); VarSet(VAR_SECRET_BASE_LAST_ITEM_USED, itemId); } for (i = firstStackIndex; i < gBagPockets[pocketId].capacity; i++) { if (GetBagItemId(pocketId, i) == itemId) { ownedCount = GetBagItemQuantity(pocketId, i); if (ownedCount >= count) { SetBagItemQuantity(pocketId, i, ownedCount - count); count = 0; } else { count -= ownedCount; SetBagItemQuantity(pocketId, i, 0); } if (GetBagItemQuantity(pocketId, i) == 0) SetBagItemId(pocketId, i, ITEM_NONE); if (count == 0) return TRUE; } } return TRUE; } } 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 <= MAX_PC_ITEM_CAPACITY) { SetPCItemQuantity(&newItems[i].quantity, ownedCount + count); memcpy(gSaveBlock1Ptr->pcItems, newItems, sizeof(gSaveBlock1Ptr->pcItems)); Free(newItems); return TRUE; } count += ownedCount - MAX_PC_ITEM_CAPACITY; SetPCItemQuantity(&newItems[i].quantity, MAX_PC_ITEM_CAPACITY); 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) { 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; } } static void SwapItemSlots(enum Pocket pocketId, u32 pocketPosA, u16 pocketPosB) { struct ItemSlot *itemA = &gBagPockets[pocketId].itemSlots[pocketPosA], *itemB = &gBagPockets[pocketId].itemSlots[pocketPosB], temp; SWAP(*itemA, *itemB, temp); } void CompactItemsInBagPocket(enum Pocket pocketId) { u16 i, j; for (i = 0; i < gBagPockets[pocketId].capacity - 1; i++) { for (j = i + 1; j < gBagPockets[pocketId].capacity; j++) { if (GetBagItemQuantity(pocketId, i) == 0) SwapItemSlots(pocketId, i, j); } } } void SortBerriesOrTMHMs(enum Pocket pocketId) { u16 i, j; for (i = 0; i < gBagPockets[pocketId].capacity - 1; i++) { for (j = i + 1; j < gBagPockets[pocketId].capacity; j++) { if (GetBagItemQuantity(pocketId, i) != 0 || GetBagItemId(pocketId, i) != ITEM_NONE) { if (GetBagItemQuantity(pocketId, j) == 0 || GetBagItemId(pocketId, j) == ITEM_NONE) continue; if (GetBagItemId(pocketId, i) <= GetBagItemId(pocketId, j)) continue; } SwapItemSlots(pocketId, i, j); } } } void MoveItemSlotInPocket(enum Pocket pocketId, u32 from, u32 to) { if (from != to) { u32 i; s8 shift = -1; struct BagPocket *pocket = &gBagPockets[pocketId]; // Record the values at "from" u16 fromItemId = GetBagItemIdPocket(pocket, from), fromQuantity = GetBagItemQuantityPocket(pocket, from); // Shuffle items between "to" and "from" if (to > from) { to--; shift = 1; } for (i = from; i == to - shift; i += shift) { SetBagItemIdPocket(pocket, i, GetBagItemIdPocket(pocket, i + shift)); SetBagItemQuantityPocket(pocket, i, GetBagItemQuantityPocket(pocket, i + shift)); } // Move the saved "from" to "to" SetBagItemIdPocket(pocket, to, fromItemId); SetBagItemQuantityPocket(pocket, to, fromQuantity); } } void MoveItemSlotInPC(struct ItemSlot *itemSlots, u32 from, u32 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) { CpuFastFill(0, &gSaveBlock1Ptr->bag, sizeof(struct Bag)); } u16 CountTotalItemQuantityInBag(u16 itemId) { u16 i; u16 ownedCount = 0; enum Pocket pocketId = GetItemPocket(itemId); for (i = 0; i < gBagPockets[pocketId].capacity; i++) { if (GetBagItemId(pocketId, i) == itemId) ownedCount += GetBagItemQuantity(pocketId, i); } return ownedCount; } static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count) { u8 i; u16 *items = gSaveBlock2Ptr->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode]; #if MAX_PYRAMID_BAG_ITEM_CAPACITY > 255 u16 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode]; #else u8 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode]; #endif 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->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode]; #if MAX_PYRAMID_BAG_ITEM_CAPACITY > 255 u16 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode]; #else u8 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode]; #endif for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++) { if (items[i] == itemId || items[i] == ITEM_NONE) { if (quantities[i] + count <= MAX_PYRAMID_BAG_ITEM_CAPACITY) return TRUE; count = (quantities[i] + count) - MAX_PYRAMID_BAG_ITEM_CAPACITY; if (count == 0) return TRUE; } } return FALSE; } bool8 AddPyramidBagItem(u16 itemId, u16 count) { u16 i; u16 *items = gSaveBlock2Ptr->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode]; u16 *newItems = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(*newItems)); #if MAX_PYRAMID_BAG_ITEM_CAPACITY > 255 u16 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode]; u16 *newQuantities = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(*newQuantities)); #else u8 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode]; u8 *newQuantities = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(*newQuantities)); #endif memcpy(newItems, items, PYRAMID_BAG_ITEMS_COUNT * sizeof(*newItems)); memcpy(newQuantities, quantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(*newQuantities)); for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++) { if (newItems[i] == itemId && newQuantities[i] < MAX_PYRAMID_BAG_ITEM_CAPACITY) { newQuantities[i] += count; if (newQuantities[i] > MAX_PYRAMID_BAG_ITEM_CAPACITY) { count = newQuantities[i] - MAX_PYRAMID_BAG_ITEM_CAPACITY; newQuantities[i] = MAX_PYRAMID_BAG_ITEM_CAPACITY; } 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] > MAX_PYRAMID_BAG_ITEM_CAPACITY) { count = newQuantities[i] - MAX_PYRAMID_BAG_ITEM_CAPACITY; newQuantities[i] = MAX_PYRAMID_BAG_ITEM_CAPACITY; } else { count = 0; } if (count == 0) break; } } } if (count == 0) { memcpy(items, newItems, PYRAMID_BAG_ITEMS_COUNT * sizeof(*items)); memcpy(quantities, newQuantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(*quantities)); Free(newItems); Free(newQuantities); return TRUE; } else { Free(newItems); Free(newQuantities); return FALSE; } } bool8 RemovePyramidBagItem(u16 itemId, u16 count) { u16 i; u16 *items = gSaveBlock2Ptr->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode]; #if MAX_PYRAMID_BAG_ITEM_CAPACITY > 255 u16 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode]; #else u8 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode]; #endif i = gPyramidBagMenuState.cursorPosition + gPyramidBagMenuState.scrollPosition; 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(*newItems)); #if MAX_PYRAMID_BAG_ITEM_CAPACITY > 255 u16 *newQuantities = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(*newQuantities)); #else u8 *newQuantities = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(*newQuantities)); #endif memcpy(newItems, items, PYRAMID_BAG_ITEMS_COUNT * sizeof(*newItems)); memcpy(newQuantities, quantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(*newQuantities)); 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(*items)); memcpy(quantities, newQuantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(*quantities)); Free(newItems); Free(newQuantities); return TRUE; } else { Free(newItems); Free(newQuantities); return FALSE; } } } static u16 SanitizeItemId(u16 itemId) { if (itemId >= ITEMS_COUNT) return ITEM_NONE; else return itemId; } const u8 *GetItemName(u16 itemId) { return gItemsInfo[SanitizeItemId(itemId)].name; } u32 GetItemPrice(u16 itemId) { return gItemsInfo[SanitizeItemId(itemId)].price; } static bool32 DoesItemHavePluralName(u16 itemId) { return (gItemsInfo[SanitizeItemId(itemId)].pluralName[0] != '\0'); } static const u8 *GetItemPluralName(u16 itemId) { return gItemsInfo[SanitizeItemId(itemId)].pluralName; } const u8 *GetItemEffect(u32 itemId) { if (itemId == ITEM_ENIGMA_BERRY_E_READER) #if FREE_ENIGMA_BERRY == FALSE return gSaveBlock1Ptr->enigmaBerry.itemEffect; #else return 0; #endif //FREE_ENIGMA_BERRY else return gItemsInfo[SanitizeItemId(itemId)].effect; } u32 GetItemHoldEffect(u32 itemId) { return gItemsInfo[SanitizeItemId(itemId)].holdEffect; } u32 GetItemHoldEffectParam(u32 itemId) { return gItemsInfo[SanitizeItemId(itemId)].holdEffectParam; } const u8 *GetItemDescription(u16 itemId) { return gItemsInfo[SanitizeItemId(itemId)].description; } u8 GetItemImportance(u16 itemId) { return gItemsInfo[SanitizeItemId(itemId)].importance; } u8 GetItemConsumability(u16 itemId) { return !gItemsInfo[SanitizeItemId(itemId)].notConsumed; } enum Pocket GetItemPocket(u16 itemId) { return gItemsInfo[SanitizeItemId(itemId)].pocket; } u8 GetItemType(u16 itemId) { return gItemsInfo[SanitizeItemId(itemId)].type; } ItemUseFunc GetItemFieldFunc(u16 itemId) { return gItemsInfo[SanitizeItemId(itemId)].fieldUseFunc; } // Returns an item's battle effect script ID. u8 GetItemBattleUsage(u16 itemId) { u16 item = SanitizeItemId(itemId); // Handle E-Reader berries. if (item == ITEM_ENIGMA_BERRY_E_READER) { switch (GetItemEffectType(gSpecialVar_ItemId)) { case ITEM_EFFECT_X_ITEM: return EFFECT_ITEM_INCREASE_STAT; case ITEM_EFFECT_HEAL_HP: return EFFECT_ITEM_RESTORE_HP; case ITEM_EFFECT_CURE_POISON: case ITEM_EFFECT_CURE_SLEEP: case ITEM_EFFECT_CURE_BURN: case ITEM_EFFECT_CURE_FREEZE_FROSTBITE: case ITEM_EFFECT_CURE_PARALYSIS: case ITEM_EFFECT_CURE_ALL_STATUS: case ITEM_EFFECT_CURE_CONFUSION: case ITEM_EFFECT_CURE_INFATUATION: return EFFECT_ITEM_CURE_STATUS; case ITEM_EFFECT_HEAL_PP: return EFFECT_ITEM_RESTORE_PP; default: return 0; } } else return gItemsInfo[item].battleUsage; } u32 GetItemSecondaryId(u32 itemId) { return gItemsInfo[SanitizeItemId(itemId)].secondaryId; } u32 GetItemFlingPower(u32 itemId) { return gItemsInfo[SanitizeItemId(itemId)].flingPower; } u32 GetItemStatus1Mask(u16 itemId) { const u8 *effect = GetItemEffect(itemId); switch (effect[3]) { case ITEM3_PARALYSIS: return STATUS1_PARALYSIS; case ITEM3_FREEZE: return STATUS1_FREEZE | STATUS1_FROSTBITE; case ITEM3_BURN: return STATUS1_BURN; case ITEM3_POISON: return STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER; case ITEM3_SLEEP: return STATUS1_SLEEP; case ITEM3_STATUS_ALL: return STATUS1_ANY | STATUS1_TOXIC_COUNTER; } return 0; } u32 GetItemStatus2Mask(u16 itemId) { const u8 *effect = GetItemEffect(itemId); if (effect[3] & ITEM3_STATUS_ALL) return STATUS2_INFATUATION | STATUS2_CONFUSION; else if (effect[0] & ITEM0_INFATUATION) return STATUS2_INFATUATION; else if (effect[3] & ITEM3_CONFUSION) return STATUS2_CONFUSION; else return 0; } u32 GetItemSellPrice(u32 itemId) { return GetItemPrice(itemId) / ITEM_SELL_FACTOR; }