mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-17 12:07:38 +01:00
1103 lines
28 KiB
C
1103 lines
28 KiB
C
#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"
|
|
#include "strings.h"
|
|
#include "load_save.h"
|
|
#include "battle_pyramid_bag.h"
|
|
|
|
extern bool8 InBattlePyramid(void);
|
|
extern u16 gUnknown_0203CF30[];
|
|
extern const struct Item gItems[];
|
|
|
|
// this file's functions
|
|
static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count);
|
|
static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count);
|
|
|
|
// EWRAM variables
|
|
EWRAM_DATA struct BagPocket gBagPockets[POCKETS_COUNT] = {0};
|
|
|
|
// code
|
|
static u16 GetBagItemQuantity(u16 *quantity)
|
|
{
|
|
return gSaveBlock2Ptr->encryptionKey ^ *quantity;
|
|
}
|
|
|
|
static void SetBagItemQuantity(u16 *quantity, u16 newValue)
|
|
{
|
|
*quantity = newValue ^ gSaveBlock2Ptr->encryptionKey;
|
|
}
|
|
|
|
static u16 GetPCItemQuantity(u16 *quantity)
|
|
{
|
|
return *quantity;
|
|
}
|
|
|
|
static 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 *dst)
|
|
{
|
|
StringCopy(dst, ItemId_GetName(itemId));
|
|
}
|
|
|
|
void CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity)
|
|
{
|
|
if (itemId == ITEM_POKE_BALL)
|
|
{
|
|
if (quantity < 2)
|
|
StringCopy(dst, ItemId_GetName(ITEM_POKE_BALL));
|
|
else
|
|
StringCopy(dst, gText_PokeBalls);
|
|
}
|
|
else
|
|
{
|
|
if (itemId >= ITEM_CHERI_BERRY && itemId <= ITEM_ENIGMA_BERRY)
|
|
GetBerryCountString(dst, gBerries[itemId - ITEM_CHERI_BERRY].name, quantity);
|
|
else
|
|
StringCopy(dst, 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
|
|
NAKED
|
|
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;
|
|
SWAP(*a, *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->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode];
|
|
u8 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode];
|
|
|
|
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];
|
|
u8 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode];
|
|
|
|
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;
|
|
}
|
|
|
|
bool8 AddPyramidBagItem(u16 itemId, u16 count)
|
|
{
|
|
u16 i;
|
|
|
|
u16 *items = gSaveBlock2Ptr->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode];
|
|
u8 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode];
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
bool8 RemovePyramidBagItem(u16 itemId, u16 count)
|
|
{
|
|
u16 i;
|
|
|
|
u16 *items = gSaveBlock2Ptr->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode];
|
|
u8 *quantities = gSaveBlock2Ptr->frontier.pyramidBag.quantity[gSaveBlock2Ptr->frontier.lvlMode];
|
|
|
|
i = gPyramidBagCursorData.cursorPosition + gPyramidBagCursorData.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(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 >= ITEMS_COUNT)
|
|
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;
|
|
}
|