pokeemerald/src/item.c
2025-06-23 10:04:44 +02:00

1038 lines
29 KiB
C

#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;
}