Bag refactor 2 (#7166)
This commit is contained in:
parent
cb606cee6a
commit
7d5a949b71
2
Makefile
2
Makefile
@ -124,7 +124,7 @@ ARMCC := $(PREFIX)gcc
|
||||
PATH_ARMCC := PATH="$(PATH)" $(ARMCC)
|
||||
CC1 := $(shell $(PATH_ARMCC) --print-prog-name=cc1) -quiet
|
||||
|
||||
override CFLAGS += -mthumb -mthumb-interwork -O$(O_LEVEL) -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init
|
||||
override CFLAGS += -mthumb -mthumb-interwork -O$(O_LEVEL) -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init -Wnonnull
|
||||
|
||||
ifneq ($(LTO),0)
|
||||
ifneq ($(TEST),1)
|
||||
|
||||
@ -11,7 +11,7 @@ enum Pocket
|
||||
POCKETS_COUNT,
|
||||
};
|
||||
|
||||
#define POCKET_NONE POCKETS_COUNT
|
||||
#define POCKET_DUMMY POCKETS_COUNT
|
||||
|
||||
#define REPEL_LURE_MASK (1 << 15)
|
||||
#define IS_LAST_USED_LURE(var) (var & REPEL_LURE_MASK)
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#define ALIGNED(n) __attribute__((aligned(n)))
|
||||
#define PACKED __attribute__((packed))
|
||||
#define TRANSPARENT __attribute__ ((__transparent_union__))
|
||||
#define NONNULL __attribute__((__nonnull__))
|
||||
|
||||
#define SOUND_INFO_PTR (*(struct SoundInfo **)0x3007FF0)
|
||||
#define INTR_CHECK (*(u16 *)0x3007FF8)
|
||||
|
||||
@ -68,7 +68,8 @@ struct Item
|
||||
struct ALIGNED(2) BagPocket
|
||||
{
|
||||
struct ItemSlot *itemSlots;
|
||||
u16 capacity;
|
||||
u16 capacity:10;
|
||||
enum Pocket id:6;
|
||||
};
|
||||
|
||||
struct TmHmIndexKey
|
||||
@ -135,35 +136,42 @@ static inline u16 GetTMHMMoveId(enum TMHMIndex index)
|
||||
return gTMHMItemMoveIds[index].moveId;
|
||||
}
|
||||
|
||||
enum SortPocket
|
||||
{
|
||||
SORT_NONE,
|
||||
SORT_POCKET_BY_ITEM_ID,
|
||||
SORT_POCKET_TM_HM,
|
||||
};
|
||||
|
||||
void GetBagItemIdAndQuantity(enum Pocket pocketId, u32 pocketPos, u16 *itemId, u16 *quantity);
|
||||
u16 GetBagItemId(enum Pocket pocketId, u32 pocketPos);
|
||||
u16 GetBagItemQuantity(enum Pocket pocketId, u32 pocketPos);
|
||||
void SetBagItemQuantity(enum Pocket pocketId, u32 pocketPos, u16 newValue);
|
||||
void ApplyNewEncryptionKeyToBagItems(u32 newKey);
|
||||
void SetBagItemsPointers(void);
|
||||
u8 *CopyItemName(u16 itemId, u8 *dst);
|
||||
u8 *CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity);
|
||||
bool8 IsBagPocketNonEmpty(enum Pocket pocketId);
|
||||
bool8 CheckBagHasItem(u16 itemId, u16 count);
|
||||
bool8 HasAtLeastOneBerry(void);
|
||||
bool8 HasAtLeastOnePokeBall(void);
|
||||
bool8 CheckBagHasSpace(u16 itemId, u16 count);
|
||||
bool32 IsBagPocketNonEmpty(enum Pocket pocketId);
|
||||
bool32 CheckBagHasItem(u16 itemId, u16 count);
|
||||
bool32 HasAtLeastOneBerry(void);
|
||||
bool32 HasAtLeastOnePokeBall(void);
|
||||
bool32 CheckBagHasSpace(u16 itemId, u16 count);
|
||||
u32 GetFreeSpaceForItemInBag(u16 itemId);
|
||||
bool8 AddBagItem(u16 itemId, u16 count);
|
||||
bool8 RemoveBagItem(u16 itemId, u16 count);
|
||||
bool32 AddBagItem(u16 itemId, u16 count);
|
||||
bool32 RemoveBagItem(u16 itemId, u16 count);
|
||||
u8 CountUsedPCItemSlots(void);
|
||||
bool8 CheckPCHasItem(u16 itemId, u16 count);
|
||||
bool8 AddPCItem(u16 itemId, u16 count);
|
||||
bool32 CheckPCHasItem(u16 itemId, u16 count);
|
||||
bool32 AddPCItem(u16 itemId, u16 count);
|
||||
void RemovePCItem(u8 index, u16 count);
|
||||
void CompactPCItems(void);
|
||||
void SwapRegisteredBike(void);
|
||||
void CompactItemsInBagPocket(enum Pocket pocketId);
|
||||
void SortBerriesOrTMHMs(enum Pocket pocketId);
|
||||
void SortPocket(enum Pocket pocketId, enum SortPocket sortPocket);
|
||||
void MoveItemSlotInPocket(enum Pocket pocketId, u32 from, u32 to);
|
||||
void MoveItemSlotInPC(struct ItemSlot *itemSlots, u32 from, u32 to);
|
||||
void ClearBag(void);
|
||||
u16 CountTotalItemQuantityInBag(u16 itemId);
|
||||
bool8 AddPyramidBagItem(u16 itemId, u16 count);
|
||||
bool8 RemovePyramidBagItem(u16 itemId, u16 count);
|
||||
bool32 AddPyramidBagItem(u16 itemId, u16 count);
|
||||
bool32 RemovePyramidBagItem(u16 itemId, u16 count);
|
||||
const u8 *GetItemName(u16 itemId);
|
||||
u32 GetItemPrice(u16 itemId);
|
||||
const u8 *GetItemEffect(u32 itemId);
|
||||
|
||||
719
src/item.c
719
src/item.c
@ -21,10 +21,19 @@
|
||||
#include "constants/item_effects.h"
|
||||
#include "constants/hold_effects.h"
|
||||
|
||||
static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count);
|
||||
static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count);
|
||||
#define DUMMY_PC_BAG_POCKET \
|
||||
{ \
|
||||
.id = POCKET_DUMMY, \
|
||||
.capacity = PC_ITEMS_COUNT, \
|
||||
.itemSlots = gSaveBlock1Ptr->pcItems, \
|
||||
}
|
||||
|
||||
static bool32 CheckPyramidBagHasItem(u16 itemId, u16 count);
|
||||
static bool32 CheckPyramidBagHasSpace(u16 itemId, u16 count);
|
||||
static const u8 *GetItemPluralName(u16);
|
||||
static bool32 DoesItemHavePluralName(u16);
|
||||
static void BagPocket_GetSetSlotDataGeneric(struct BagPocket *pocket, u32 pocketPos, u16 *itemId, u16 *quantity, bool32 isSetting);
|
||||
static void BagPocket_GetSetSlotDataPC(struct BagPocket *pocket, u32 pocketPos, u16 *itemId, u16 *quantity, bool32 isSetting);
|
||||
|
||||
EWRAM_DATA struct BagPocket gBagPockets[POCKETS_COUNT] = {0};
|
||||
|
||||
@ -52,54 +61,71 @@ const struct TmHmIndexKey gTMHMItemMoveIds[NUM_ALL_MACHINES + 1] =
|
||||
#undef UNPACK_TM_ITEM_ID
|
||||
#undef UNPACK_HM_ITEM_ID
|
||||
|
||||
static inline u16 GetBagItemIdPocket(struct BagPocket *pocket, u32 pocketPos)
|
||||
static void (*const sBagPocket_GetSetSlotDataFuncs[])(struct BagPocket *pocket, u32 pocketPos, u16 *itemId, u16 *quantity, bool32 isSetting) =
|
||||
{
|
||||
return pocket->itemSlots[pocketPos].itemId;
|
||||
[POCKET_ITEMS] = BagPocket_GetSetSlotDataGeneric,
|
||||
[POCKET_KEY_ITEMS] = BagPocket_GetSetSlotDataGeneric,
|
||||
[POCKET_POKE_BALLS] = BagPocket_GetSetSlotDataGeneric,
|
||||
[POCKET_TM_HM] = BagPocket_GetSetSlotDataGeneric,
|
||||
[POCKET_BERRIES] = BagPocket_GetSetSlotDataGeneric,
|
||||
[POCKET_DUMMY] = BagPocket_GetSetSlotDataPC,
|
||||
};
|
||||
|
||||
static void NONNULL BagPocket_GetSetSlotDataGeneric(struct BagPocket *pocket, u32 pocketPos, u16 *itemId, u16 *quantity, bool32 isSetting)
|
||||
{
|
||||
if (isSetting)
|
||||
{
|
||||
pocket->itemSlots[pocketPos].itemId = *quantity ? *itemId : ITEM_NONE; // Sets to zero if quantity is zero
|
||||
pocket->itemSlots[pocketPos].quantity = *quantity ^ gSaveBlock2Ptr->encryptionKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
*itemId = pocket->itemSlots[pocketPos].itemId;
|
||||
*quantity = pocket->itemSlots[pocketPos].quantity ^ gSaveBlock2Ptr->encryptionKey;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 GetBagItemQuantityPocket(struct BagPocket *pocket, u32 pocketPos)
|
||||
static void NONNULL BagPocket_GetSetSlotDataPC(struct BagPocket *pocket, u32 pocketPos, u16 *itemId, u16 *quantity, bool32 isSetting)
|
||||
{
|
||||
return gSaveBlock2Ptr->encryptionKey ^ pocket->itemSlots[pocketPos].quantity;
|
||||
if (isSetting)
|
||||
{
|
||||
pocket->itemSlots[pocketPos].itemId = *quantity ? *itemId : ITEM_NONE; // Sets to zero if quantity is zero
|
||||
pocket->itemSlots[pocketPos].quantity = *quantity;
|
||||
}
|
||||
else
|
||||
{
|
||||
*itemId = pocket->itemSlots[pocketPos].itemId;
|
||||
*quantity = pocket->itemSlots[pocketPos].quantity;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SetBagItemIdPocket(struct BagPocket *pocket, u32 pocketPos, u16 itemId)
|
||||
static inline void NONNULL BagPocket_GetSlotData(struct BagPocket *pocket, u32 pocketPos, u16 *itemId, u16 *quantity)
|
||||
{
|
||||
pocket->itemSlots[pocketPos].itemId = itemId;
|
||||
sBagPocket_GetSetSlotDataFuncs[pocket->id](pocket, pocketPos, itemId, quantity, FALSE);
|
||||
}
|
||||
|
||||
static inline void SetBagItemQuantityPocket(struct BagPocket *pocket, u32 pocketPos, u16 newValue)
|
||||
static inline void NONNULL BagPocket_SetSlotData(struct BagPocket *pocket, u32 pocketPos, u16 *itemId, u16 *quantity)
|
||||
{
|
||||
pocket->itemSlots[pocketPos].quantity = newValue ^ gSaveBlock2Ptr->encryptionKey;
|
||||
sBagPocket_GetSetSlotDataFuncs[pocket->id](pocket, pocketPos, itemId, quantity, TRUE);
|
||||
}
|
||||
|
||||
void GetBagItemIdAndQuantity(enum Pocket pocketId, u32 pocketPos, u16 *itemId, u16 *quantity)
|
||||
{
|
||||
BagPocket_GetSlotData(&gBagPockets[pocketId], pocketPos, itemId, quantity);
|
||||
}
|
||||
|
||||
u16 GetBagItemId(enum Pocket pocketId, u32 pocketPos)
|
||||
{
|
||||
return GetBagItemIdPocket(&gBagPockets[pocketId], pocketPos);
|
||||
u16 itemId, quantity;
|
||||
BagPocket_GetSlotData(&gBagPockets[pocketId], pocketPos, &itemId, &quantity);
|
||||
return itemId;
|
||||
}
|
||||
|
||||
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;
|
||||
u16 itemId, quantity;
|
||||
BagPocket_GetSlotData(&gBagPockets[pocketId], pocketPos, &itemId, &quantity);
|
||||
return quantity;
|
||||
}
|
||||
|
||||
void ApplyNewEncryptionKeyToBagItems(u32 newKey)
|
||||
@ -117,18 +143,23 @@ void SetBagItemsPointers(void)
|
||||
{
|
||||
gBagPockets[POCKET_ITEMS].itemSlots = gSaveBlock1Ptr->bag.items;
|
||||
gBagPockets[POCKET_ITEMS].capacity = BAG_ITEMS_COUNT;
|
||||
gBagPockets[POCKET_ITEMS].id = POCKET_ITEMS;
|
||||
|
||||
gBagPockets[POCKET_KEY_ITEMS].itemSlots = gSaveBlock1Ptr->bag.keyItems;
|
||||
gBagPockets[POCKET_KEY_ITEMS].capacity = BAG_KEYITEMS_COUNT;
|
||||
gBagPockets[POCKET_KEY_ITEMS].id = POCKET_KEY_ITEMS;
|
||||
|
||||
gBagPockets[POCKET_POKE_BALLS].itemSlots = gSaveBlock1Ptr->bag.pokeBalls;
|
||||
gBagPockets[POCKET_POKE_BALLS].capacity = BAG_POKEBALLS_COUNT;
|
||||
gBagPockets[POCKET_POKE_BALLS].id = POCKET_POKE_BALLS;
|
||||
|
||||
gBagPockets[POCKET_TM_HM].itemSlots = gSaveBlock1Ptr->bag.TMsHMs;
|
||||
gBagPockets[POCKET_TM_HM].capacity = BAG_TMHM_COUNT;
|
||||
gBagPockets[POCKET_TM_HM].id = POCKET_TM_HM;
|
||||
|
||||
gBagPockets[POCKET_BERRIES].itemSlots = gSaveBlock1Ptr->bag.berries;
|
||||
gBagPockets[POCKET_BERRIES].capacity = BAG_BERRIES_COUNT;
|
||||
gBagPockets[POCKET_BERRIES].id = POCKET_BERRIES;
|
||||
}
|
||||
|
||||
u8 *CopyItemName(u16 itemId, u8 *dst)
|
||||
@ -155,68 +186,56 @@ u8 *CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity)
|
||||
}
|
||||
}
|
||||
|
||||
bool8 IsBagPocketNonEmpty(enum Pocket pocketId)
|
||||
bool32 IsBagPocketNonEmpty(enum Pocket pocketId)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < gBagPockets[pocketId].capacity; i++)
|
||||
{
|
||||
if (GetBagItemId(pocketId, i) != 0)
|
||||
if (GetBagItemId(pocketId, i) != ITEM_NONE)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool8 CheckBagHasItem(u16 itemId, u16 count)
|
||||
static bool32 NONNULL BagPocket_CheckHasItem(struct BagPocket *pocket, u16 itemId, u16 count)
|
||||
{
|
||||
u8 i;
|
||||
enum Pocket pocketId;
|
||||
u16 tempItemId, tempQuantity;
|
||||
|
||||
// Check for item slots that contain the item
|
||||
for (u32 i = 0; i < pocket->capacity && count > 0; i++)
|
||||
{
|
||||
BagPocket_GetSlotData(pocket, i, &tempItemId, &tempQuantity);
|
||||
if (tempItemId == itemId)
|
||||
count -= min(count, tempQuantity);
|
||||
}
|
||||
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
bool32 CheckBagHasItem(u16 itemId, u16 count)
|
||||
{
|
||||
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;
|
||||
|
||||
return BagPocket_CheckHasItem(&gBagPockets[GetItemPocket(itemId)], itemId, count);
|
||||
}
|
||||
|
||||
bool8 HasAtLeastOneBerry(void)
|
||||
bool32 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;
|
||||
|
||||
for (u32 i = FIRST_BERRY_INDEX; i <= LAST_BERRY_INDEX && gSpecialVar_Result == FALSE; i++)
|
||||
gSpecialVar_Result = CheckBagHasItem(i, 1);
|
||||
|
||||
return gSpecialVar_Result;
|
||||
}
|
||||
|
||||
bool8 HasAtLeastOnePokeBall(void)
|
||||
bool32 HasAtLeastOnePokeBall(void)
|
||||
{
|
||||
u16 ballId;
|
||||
|
||||
for (ballId = BALL_STRANGE; ballId < POKEBALL_COUNT; ballId++)
|
||||
for (u32 ballId = BALL_STRANGE; ballId < POKEBALL_COUNT; ballId++)
|
||||
{
|
||||
if (CheckBagHasItem(ballId, 1) == TRUE)
|
||||
return TRUE;
|
||||
@ -224,7 +243,7 @@ bool8 HasAtLeastOnePokeBall(void)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool8 CheckBagHasSpace(u16 itemId, u16 count)
|
||||
bool32 CheckBagHasSpace(u16 itemId, u16 count)
|
||||
{
|
||||
if (GetItemPocket(itemId) >= POCKETS_COUNT)
|
||||
return FALSE;
|
||||
@ -235,335 +254,250 @@ bool8 CheckBagHasSpace(u16 itemId, u16 count)
|
||||
return GetFreeSpaceForItemInBag(itemId) >= count;
|
||||
}
|
||||
|
||||
u32 GetFreeSpaceForItemInBag(u16 itemId)
|
||||
static u32 NONNULL BagPocket_GetFreeSpaceForItem(struct BagPocket *pocket, u16 itemId)
|
||||
{
|
||||
u8 i;
|
||||
enum Pocket pocketId = GetItemPocket(itemId);
|
||||
u16 ownedCount;
|
||||
u32 spaceForItem = 0;
|
||||
|
||||
if (GetItemPocket(itemId) >= POCKETS_COUNT)
|
||||
return 0;
|
||||
u16 tempItemId, tempQuantity;
|
||||
|
||||
// Check space in any existing item slots that already contain this item
|
||||
for (i = 0; i < gBagPockets[pocketId].capacity; i++)
|
||||
for (u32 i = 0; i < pocket->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;
|
||||
}
|
||||
BagPocket_GetSlotData(pocket, i, &tempItemId, &tempQuantity);
|
||||
if (tempItemId == ITEM_NONE || tempItemId == itemId)
|
||||
spaceForItem += (tempItemId ? (MAX_BAG_ITEM_CAPACITY - tempQuantity) : MAX_BAG_ITEM_CAPACITY);
|
||||
}
|
||||
|
||||
return spaceForItem;
|
||||
}
|
||||
|
||||
static inline u32 PrepareTempPocket(struct BagPocket *tempPocket, enum Pocket pocketId)
|
||||
u32 GetFreeSpaceForItemInBag(u16 itemId)
|
||||
{
|
||||
u32 size = gBagPockets[pocketId].capacity * sizeof(struct ItemSlot);
|
||||
tempPocket->itemSlots = AllocZeroed(size);
|
||||
tempPocket->capacity = gBagPockets[pocketId].capacity;
|
||||
memcpy(tempPocket->itemSlots, gBagPockets[pocketId].itemSlots, size);
|
||||
if (GetItemPocket(itemId) >= POCKETS_COUNT)
|
||||
return 0;
|
||||
|
||||
return size;
|
||||
return BagPocket_GetFreeSpaceForItem(&gBagPockets[GetItemPocket(itemId)], itemId);
|
||||
}
|
||||
|
||||
static inline void ClearTempPocket(struct BagPocket *pocket)
|
||||
static inline bool32 NONNULL CheckSlotAndUpdateCount(struct BagPocket *pocket, u16 itemId, u32 pocketPos, u32 *nextPocketPos, u16 *count, u16 *tempPocketSlotQuantities)
|
||||
{
|
||||
Free(pocket->itemSlots);
|
||||
Free(pocket);
|
||||
u16 tempItemId, tempQuantity;
|
||||
BagPocket_GetSlotData(pocket, pocketPos, &tempItemId, &tempQuantity);
|
||||
if (tempItemId == ITEM_NONE || tempItemId == itemId)
|
||||
{
|
||||
// The quantity already at the slot - zero if an empty slot
|
||||
if (!tempItemId)
|
||||
tempQuantity = 0;
|
||||
|
||||
// Record slot quantity in tempPocketSlotQuantities, adjust count
|
||||
tempPocketSlotQuantities[pocketPos] = min(MAX_BAG_ITEM_CAPACITY, *count + tempQuantity);
|
||||
*count -= min(*count, MAX_BAG_ITEM_CAPACITY - tempQuantity);
|
||||
|
||||
// Set the starting index for the next loop to set items (shifted by one)
|
||||
if (!*nextPocketPos)
|
||||
*nextPocketPos = pocketPos + 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline void RestorePocketAndClearTempPocket(struct BagPocket *tempPocket, enum Pocket pocketId, u32 pocketSize)
|
||||
static bool32 NONNULL BagPocket_AddItem(struct BagPocket *pocket, u16 itemId, u16 count)
|
||||
{
|
||||
memcpy(gBagPockets[pocketId].itemSlots, tempPocket->itemSlots, pocketSize);
|
||||
ClearTempPocket(tempPocket);
|
||||
u32 itemLookupIndex, itemAddIndex = 0;
|
||||
|
||||
// First, check that there is a free slot for this item
|
||||
u16 *tempPocketSlotQuantities = AllocZeroed(sizeof(u16) * pocket->capacity);
|
||||
|
||||
switch (pocket->id)
|
||||
{
|
||||
case POCKET_TM_HM:
|
||||
case POCKET_BERRIES:
|
||||
for (itemLookupIndex = 0; itemLookupIndex < pocket->capacity && count > 0; itemLookupIndex++)
|
||||
{
|
||||
// Check if we found a slot to store the item but weren't able to reduce count to 0
|
||||
// This means that we have more than one stack's worth, which isn't allowed in these pockets
|
||||
if (CheckSlotAndUpdateCount(pocket, itemId, itemLookupIndex, &itemAddIndex, &count, tempPocketSlotQuantities) && count > 0)
|
||||
{
|
||||
Free(tempPocketSlotQuantities);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (itemLookupIndex = 0; itemLookupIndex < pocket->capacity && count > 0; itemLookupIndex++)
|
||||
CheckSlotAndUpdateCount(pocket, itemId, itemLookupIndex, &itemAddIndex, &count, tempPocketSlotQuantities);
|
||||
}
|
||||
|
||||
// If the count is still greater than zero, clearly we have not found enough slots for this...
|
||||
// Otherwise, we have found slots - update the actual pockets with the updated quantities
|
||||
if (count == 0)
|
||||
{
|
||||
for (--itemAddIndex; itemAddIndex < itemLookupIndex; itemAddIndex++)
|
||||
{
|
||||
if (tempPocketSlotQuantities[itemAddIndex] > 0)
|
||||
BagPocket_SetSlotData(pocket, itemAddIndex, &itemId, &tempPocketSlotQuantities[itemAddIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
Free(tempPocketSlotQuantities);
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
bool8 AddBagItem(u16 itemId, u16 count)
|
||||
bool32 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;
|
||||
}
|
||||
return BagPocket_AddItem(&gBagPockets[GetItemPocket(itemId)], itemId, count);
|
||||
}
|
||||
|
||||
bool8 RemoveBagItem(u16 itemId, u16 count)
|
||||
static bool32 NONNULL BagPocket_RemoveItem(struct BagPocket *pocket, u16 itemId, u16 count)
|
||||
{
|
||||
u8 i;
|
||||
u16 totalQuantity = 0;
|
||||
u32 itemLookupIndex, itemRemoveIndex = 0, totalQuantity = 0;
|
||||
u16 tempItemId, tempQuantity;
|
||||
u16 *tempPocketSlotQuantities = AllocZeroed(sizeof(u16) * pocket->capacity);
|
||||
|
||||
if (GetItemPocket(itemId) >= POCKETS_COUNT || itemId == ITEM_NONE)
|
||||
return FALSE;
|
||||
|
||||
// check Battle Pyramid Bag
|
||||
if (InBattlePyramid() || FlagGet(FLAG_STORING_ITEMS_IN_PYRAMID_BAG) == TRUE)
|
||||
for (itemLookupIndex = 0; itemLookupIndex < pocket->capacity && totalQuantity < count; itemLookupIndex++)
|
||||
{
|
||||
return RemovePyramidBagItem(itemId, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 ownedCount, firstStackIndex = 0;
|
||||
enum Pocket pocketId = GetItemPocket(itemId);
|
||||
|
||||
for (i = 0; i < gBagPockets[pocketId].capacity; i++)
|
||||
BagPocket_GetSlotData(pocket, itemLookupIndex, &tempItemId, &tempQuantity);
|
||||
if (tempItemId == itemId)
|
||||
{
|
||||
if (GetBagItemId(pocketId, i) == itemId)
|
||||
{
|
||||
if (totalQuantity == 0)
|
||||
firstStackIndex = i;
|
||||
totalQuantity += GetBagItemQuantity(pocketId, i);
|
||||
}
|
||||
// Index for the next loop - where we should start removing items
|
||||
if (!itemRemoveIndex)
|
||||
itemRemoveIndex = itemLookupIndex + 1;
|
||||
|
||||
// Gather quantities (+ 1 to tempPocketSlotQuantities so that even if setting to 0 we know which indices to target)
|
||||
totalQuantity += tempQuantity;
|
||||
tempPocketSlotQuantities[itemLookupIndex] = (tempQuantity <= count ? 0 : tempQuantity - count) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalQuantity < count)
|
||||
return FALSE; // We don't have enough of the item
|
||||
|
||||
if (totalQuantity >= count) // We 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++)
|
||||
// Update the quantities correctly with the items removed
|
||||
for (--itemRemoveIndex; itemRemoveIndex < itemLookupIndex; itemRemoveIndex++)
|
||||
{
|
||||
if (GetBagItemId(pocketId, i) == itemId)
|
||||
if (tempPocketSlotQuantities[itemRemoveIndex] > 0)
|
||||
{
|
||||
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;
|
||||
tempPocketSlotQuantities[itemRemoveIndex]--; // Reverse the +1 shift
|
||||
BagPocket_SetSlotData(pocket, itemRemoveIndex, &itemId, &tempPocketSlotQuantities[itemRemoveIndex]);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Free(tempPocketSlotQuantities);
|
||||
return totalQuantity >= count;
|
||||
}
|
||||
|
||||
static s32 FindFreePCItemSlot(void)
|
||||
bool32 RemoveBagItem(u16 itemId, u16 count)
|
||||
{
|
||||
s8 i;
|
||||
if (GetItemPocket(itemId) >= POCKETS_COUNT || itemId == ITEM_NONE)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < PC_ITEMS_COUNT; i++)
|
||||
{
|
||||
if (gSaveBlock1Ptr->pcItems[i].itemId == ITEM_NONE)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
// check Battle Pyramid Bag
|
||||
if (InBattlePyramid() || FlagGet(FLAG_STORING_ITEMS_IN_PYRAMID_BAG) == TRUE)
|
||||
return RemovePyramidBagItem(itemId, count);
|
||||
|
||||
return BagPocket_RemoveItem(&gBagPockets[GetItemPocket(itemId)], itemId, count);
|
||||
}
|
||||
|
||||
u8 CountUsedPCItemSlots(void)
|
||||
static u8 NONNULL BagPocket_CountUsedItemSlots(struct BagPocket *pocket)
|
||||
{
|
||||
u8 usedSlots = 0;
|
||||
u8 i;
|
||||
u16 tempItemId, tempQuantity;
|
||||
|
||||
for (i = 0; i < PC_ITEMS_COUNT; i++)
|
||||
for (u32 i = 0; i < pocket->capacity; i++)
|
||||
{
|
||||
if (gSaveBlock1Ptr->pcItems[i].itemId != ITEM_NONE)
|
||||
BagPocket_GetSlotData(pocket, i, &tempItemId, &tempQuantity);
|
||||
if (tempItemId)
|
||||
usedSlots++;
|
||||
}
|
||||
return usedSlots;
|
||||
}
|
||||
|
||||
bool8 CheckPCHasItem(u16 itemId, u16 count)
|
||||
u8 CountUsedPCItemSlots(void)
|
||||
{
|
||||
u8 i;
|
||||
struct BagPocket dummyPocket = DUMMY_PC_BAG_POCKET;
|
||||
return BagPocket_CountUsedItemSlots(&dummyPocket);
|
||||
}
|
||||
|
||||
for (i = 0; i < PC_ITEMS_COUNT; i++)
|
||||
static bool32 NONNULL BagPocket_CheckPocketForItemCount(struct BagPocket *pocket, u16 itemId, u16 count)
|
||||
{
|
||||
u16 tempItemId, tempQuantity;
|
||||
|
||||
for (u32 i = 0; i < pocket->capacity; i++)
|
||||
{
|
||||
if (gSaveBlock1Ptr->pcItems[i].itemId == itemId && GetPCItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity) >= count)
|
||||
BagPocket_GetSlotData(pocket, i, &tempItemId, &tempQuantity);
|
||||
if (tempItemId == itemId && tempQuantity >= count)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool8 AddPCItem(u16 itemId, u16 count)
|
||||
bool32 CheckPCHasItem(u16 itemId, u16 count)
|
||||
{
|
||||
u8 i;
|
||||
s8 freeSlot;
|
||||
u16 ownedCount;
|
||||
struct ItemSlot *newItems;
|
||||
struct BagPocket dummyPocket = DUMMY_PC_BAG_POCKET;
|
||||
return BagPocket_CheckPocketForItemCount(&dummyPocket, itemId, count);
|
||||
}
|
||||
|
||||
// Copy PC items
|
||||
newItems = AllocZeroed(sizeof(gSaveBlock1Ptr->pcItems));
|
||||
memcpy(newItems, gSaveBlock1Ptr->pcItems, sizeof(gSaveBlock1Ptr->pcItems));
|
||||
bool32 AddPCItem(u16 itemId, u16 count)
|
||||
{
|
||||
struct BagPocket dummyPocket = DUMMY_PC_BAG_POCKET;
|
||||
return BagPocket_AddItem(&dummyPocket, itemId, count);
|
||||
}
|
||||
|
||||
// Use any item slots that already contain this item
|
||||
for (i = 0; i < PC_ITEMS_COUNT; i++)
|
||||
static void NONNULL BagPocket_CompactItems(struct BagPocket *pocket)
|
||||
{
|
||||
u16 itemId, quantity, zero = 0, slotCursor = 0;
|
||||
for (u32 i = 0; i < pocket->capacity; i++)
|
||||
{
|
||||
if (newItems[i].itemId == itemId)
|
||||
BagPocket_GetSlotData(pocket, i, &itemId, &quantity);
|
||||
if (itemId == ITEM_NONE)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (!slotCursor)
|
||||
slotCursor = i + 1;
|
||||
}
|
||||
else if (slotCursor > 0)
|
||||
{
|
||||
BagPocket_SetSlotData(pocket, slotCursor - 1, &itemId, &quantity);
|
||||
BagPocket_SetSlotData(pocket, i, &zero, &zero);
|
||||
slotCursor++;
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
struct BagPocket dummyPocket = DUMMY_PC_BAG_POCKET;
|
||||
|
||||
// Get id, quantity at slot
|
||||
u16 tempItemId, tempQuantity;
|
||||
BagPocket_GetSlotData(&dummyPocket, index, &tempItemId, &tempQuantity);
|
||||
|
||||
// Remove quantity
|
||||
tempQuantity -= count;
|
||||
BagPocket_SetSlotData(&dummyPocket, index, &tempItemId, &tempQuantity);
|
||||
|
||||
// Compact if necessary
|
||||
if (tempQuantity == 0)
|
||||
BagPocket_CompactItems(&dummyPocket);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
struct BagPocket dummyPocket = DUMMY_PC_BAG_POCKET;
|
||||
BagPocket_CompactItems(&dummyPocket);
|
||||
}
|
||||
|
||||
void SwapRegisteredBike(void)
|
||||
@ -579,101 +513,80 @@ void SwapRegisteredBike(void)
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
BagPocket_CompactItems(&gBagPockets[pocketId]);
|
||||
}
|
||||
|
||||
for (i = 0; i < gBagPockets[pocketId].capacity - 1; i++)
|
||||
// Opens the possibility of sorting by other means e.g. ghoulslash's advanced sorting
|
||||
static inline bool32 ItemIndexCompare(u16 itemA, u16 itemB, enum SortPocket sortPocket)
|
||||
{
|
||||
switch (sortPocket)
|
||||
{
|
||||
for (j = i + 1; j < gBagPockets[pocketId].capacity; j++)
|
||||
case SORT_POCKET_BY_ITEM_ID:
|
||||
return itemA > itemB;
|
||||
case SORT_POCKET_TM_HM:
|
||||
return GetItemTMHMIndex(itemA) > GetItemTMHMIndex(itemB);
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void SortPocket(enum Pocket pocketId, enum SortPocket sortPocket)
|
||||
{
|
||||
u16 itemId_i, quantity_i, itemId_j, quantity_j;
|
||||
struct BagPocket *pocket = &gBagPockets[pocketId];
|
||||
|
||||
for (u32 i = 0; i < pocket->capacity - 1; i++)
|
||||
{
|
||||
BagPocket_GetSlotData(pocket, i, &itemId_i, &quantity_i);
|
||||
for (u32 j = i + 1; j < pocket->capacity; j++)
|
||||
{
|
||||
if (GetBagItemQuantity(pocketId, i) == 0)
|
||||
SwapItemSlots(pocketId, i, j);
|
||||
BagPocket_GetSlotData(pocket, j, &itemId_j, &quantity_j);
|
||||
if (itemId_j && (!itemId_i || ItemIndexCompare(itemId_i, itemId_j, sortPocket)))
|
||||
{
|
||||
BagPocket_SetSlotData(pocket, i, &itemId_j, &quantity_j);
|
||||
BagPocket_SetSlotData(pocket, j, &itemId_i, &quantity_i);
|
||||
itemId_i = itemId_j;
|
||||
quantity_i = quantity_j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SortBerriesOrTMHMs(enum Pocket pocketId)
|
||||
static inline void NONNULL BagPocket_MoveItemSlot(struct BagPocket *pocket, u32 from, u32 to)
|
||||
{
|
||||
u16 i, j;
|
||||
|
||||
for (i = 0; i < gBagPockets[pocketId].capacity - 1; i++)
|
||||
if (from != to)
|
||||
{
|
||||
for (j = i + 1; j < gBagPockets[pocketId].capacity; j++)
|
||||
s8 shift = (to > from) ? 1 : -1;
|
||||
if (to > from)
|
||||
to--;
|
||||
|
||||
// Record the values at "from"
|
||||
u16 fromItemId, fromQuantity, tempItemId, tempQuantity;
|
||||
BagPocket_GetSlotData(pocket, from, &fromItemId, &fromQuantity);
|
||||
|
||||
// Shuffle items between "to" and "from"
|
||||
for (u32 i = from; i == to - shift; i += shift)
|
||||
{
|
||||
if (GetBagItemQuantity(pocketId, i) != 0 || GetBagItemId(pocketId, i) != ITEM_NONE)
|
||||
{
|
||||
if (GetBagItemQuantity(pocketId, j) == 0 || GetBagItemId(pocketId, j) == ITEM_NONE)
|
||||
continue;
|
||||
if (pocketId == POCKET_BERRIES && GetBagItemId(pocketId, i) <= GetBagItemId(pocketId, j)) // To do
|
||||
continue;
|
||||
if (pocketId == POCKET_TM_HM && GetItemTMHMIndex(GetBagItemId(pocketId, i)) <= GetItemTMHMIndex(GetBagItemId(pocketId, j)))
|
||||
continue;
|
||||
}
|
||||
SwapItemSlots(pocketId, i, j);
|
||||
BagPocket_GetSlotData(pocket, i + shift, &tempItemId, &tempQuantity);
|
||||
BagPocket_SetSlotData(pocket, i, &tempItemId, &tempQuantity);
|
||||
}
|
||||
|
||||
// Move the saved "from" to "to"
|
||||
BagPocket_SetSlotData(pocket, to, &fromItemId, &fromQuantity);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
BagPocket_MoveItemSlot(&gBagPockets[pocketId], from, to);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
struct BagPocket dummyPocket = DUMMY_PC_BAG_POCKET;
|
||||
return BagPocket_MoveItemSlot(&dummyPocket, from, to);
|
||||
}
|
||||
|
||||
void ClearBag(void)
|
||||
@ -681,22 +594,26 @@ void ClearBag(void)
|
||||
CpuFastFill(0, &gSaveBlock1Ptr->bag, sizeof(struct Bag));
|
||||
}
|
||||
|
||||
u16 CountTotalItemQuantityInBag(u16 itemId)
|
||||
static inline u16 NONNULL BagPocket_CountTotalItemQuantity(struct BagPocket *pocket, u16 itemId)
|
||||
{
|
||||
u16 i;
|
||||
u16 ownedCount = 0;
|
||||
enum Pocket pocketId = GetItemPocket(itemId);
|
||||
u16 tempItemId, tempQuantity, ownedCount = 0;
|
||||
|
||||
for (i = 0; i < gBagPockets[pocketId].capacity; i++)
|
||||
for (u32 i = 0; i < pocket->capacity; i++)
|
||||
{
|
||||
if (GetBagItemId(pocketId, i) == itemId)
|
||||
ownedCount += GetBagItemQuantity(pocketId, i);
|
||||
BagPocket_GetSlotData(pocket, i, &tempItemId, &tempQuantity);
|
||||
if (tempItemId == itemId)
|
||||
ownedCount += tempQuantity;
|
||||
}
|
||||
|
||||
return ownedCount;
|
||||
}
|
||||
|
||||
static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count)
|
||||
u16 CountTotalItemQuantityInBag(u16 itemId)
|
||||
{
|
||||
return BagPocket_CountTotalItemQuantity(&gBagPockets[GetItemPocket(itemId)], itemId);
|
||||
}
|
||||
|
||||
static bool32 CheckPyramidBagHasItem(u16 itemId, u16 count)
|
||||
{
|
||||
u8 i;
|
||||
u16 *items = gSaveBlock2Ptr->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode];
|
||||
@ -722,7 +639,7 @@ static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count)
|
||||
static bool32 CheckPyramidBagHasSpace(u16 itemId, u16 count)
|
||||
{
|
||||
u8 i;
|
||||
u16 *items = gSaveBlock2Ptr->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode];
|
||||
@ -748,7 +665,7 @@ static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool8 AddPyramidBagItem(u16 itemId, u16 count)
|
||||
bool32 AddPyramidBagItem(u16 itemId, u16 count)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
@ -826,7 +743,7 @@ bool8 AddPyramidBagItem(u16 itemId, u16 count)
|
||||
}
|
||||
}
|
||||
|
||||
bool8 RemovePyramidBagItem(u16 itemId, u16 count)
|
||||
bool32 RemovePyramidBagItem(u16 itemId, u16 count)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
|
||||
@ -964,12 +964,11 @@ static void BagMenu_MoveCursorCallback(s32 itemIndex, bool8 onInit, struct ListM
|
||||
|
||||
static void BagMenu_ItemPrintCallback(u8 windowId, u32 itemIndex, u8 y)
|
||||
{
|
||||
u16 itemId;
|
||||
u16 itemQuantity;
|
||||
int offset;
|
||||
|
||||
if (itemIndex != LIST_CANCEL)
|
||||
{
|
||||
u16 itemId, itemQuantity;
|
||||
s32 offset;
|
||||
|
||||
if (gBagMenu->toSwapPos != NOT_SWAPPING)
|
||||
{
|
||||
// Swapping items, draw cursor at original item's location
|
||||
@ -979,8 +978,7 @@ static void BagMenu_ItemPrintCallback(u8 windowId, u32 itemIndex, u8 y)
|
||||
BagMenu_PrintCursorAtPos(y, COLORID_NONE);
|
||||
}
|
||||
|
||||
itemId = GetBagItemId(gBagPosition.pocket, itemIndex);
|
||||
itemQuantity = GetBagItemQuantity(gBagPosition.pocket, itemIndex);
|
||||
GetBagItemIdAndQuantity(gBagPosition.pocket, itemIndex, &itemId, &itemQuantity);
|
||||
|
||||
// Draw HM icon
|
||||
if (gBagPosition.pocket == POCKET_TM_HM && GetItemTMHMIndex(itemId) > NUM_TECHNICAL_MACHINES)
|
||||
@ -1133,8 +1131,10 @@ void UpdatePocketItemList(u8 pocketId)
|
||||
switch (pocketId)
|
||||
{
|
||||
case POCKET_TM_HM:
|
||||
SortPocket(pocketId, SORT_POCKET_TM_HM);
|
||||
break;
|
||||
case POCKET_BERRIES:
|
||||
SortBerriesOrTMHMs(pocketId);
|
||||
SortPocket(pocketId, SORT_POCKET_BY_ITEM_ID);
|
||||
break;
|
||||
default:
|
||||
CompactItemsInBagPocket(pocketId);
|
||||
@ -1287,8 +1287,7 @@ static void Task_BagMenu_HandleInput(u8 taskId)
|
||||
BagDestroyPocketScrollArrowPair();
|
||||
BagMenu_PrintCursor(tListTaskId, COLORID_GRAY_CURSOR);
|
||||
tListPosition = listPosition;
|
||||
tQuantity = GetBagItemQuantity(gBagPosition.pocket, listPosition);
|
||||
gSpecialVar_ItemId = GetBagItemId(gBagPosition.pocket, listPosition);
|
||||
GetBagItemIdAndQuantity(gBagPosition.pocket, listPosition, &gSpecialVar_ItemId, (u16*)&tQuantity);
|
||||
sContextMenuFuncs[gBagPosition.location](taskId);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ static const union AnimCmd *const sBagSpriteAnimTable[] =
|
||||
[POCKET_TM_HM] = sSpriteAnim_Bag_TMsHMs,
|
||||
[POCKET_BERRIES] = sSpriteAnim_Bag_Berries,
|
||||
[POCKET_KEY_ITEMS] = sSpriteAnim_Bag_KeyItems,
|
||||
[POCKET_NONE] = sSpriteAnim_Bag_Closed,
|
||||
[POCKET_DUMMY] = sSpriteAnim_Bag_Closed,
|
||||
};
|
||||
|
||||
static const union AffineAnimCmd sSpriteAffineAnim_BagNormal[] =
|
||||
@ -474,7 +474,7 @@ void SetBagVisualPocketId(u8 bagPocketId, bool8 isSwitchingPockets)
|
||||
sprite->y2 = -5;
|
||||
sprite->callback = SpriteCB_BagVisualSwitchingPockets;
|
||||
sprite->sPocketId = bagPocketId;
|
||||
StartSpriteAnim(sprite, POCKET_NONE);
|
||||
StartSpriteAnim(sprite, POCKET_DUMMY);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -426,7 +426,6 @@ static void Task_SacredAshDisplayHPRestored(u8);
|
||||
static void GiveItemOrMailToSelectedMon(u8);
|
||||
static void DisplayItemMustBeRemovedFirstMessage(u8);
|
||||
static void Task_SwitchItemsFromBagYesNo(u8);
|
||||
static void RemoveItemToGiveFromBag(u16);
|
||||
static void CB2_WriteMailToGiveMonFromBag(void);
|
||||
static void GiveItemToSelectedMon(u8);
|
||||
static void Task_UpdateHeldItemSpriteAndClosePartyMenu(u8);
|
||||
@ -6850,7 +6849,7 @@ static void GiveItemOrMailToSelectedMon(u8 taskId)
|
||||
{
|
||||
if (ItemIsMail(gPartyMenu.bagItem))
|
||||
{
|
||||
RemoveItemToGiveFromBag(gPartyMenu.bagItem);
|
||||
RemoveBagItem(gPartyMenu.bagItem, 1);
|
||||
sPartyMenuInternal->exitCallback = CB2_WriteMailToGiveMonFromBag;
|
||||
Task_ClosePartyMenu(taskId);
|
||||
}
|
||||
@ -6869,7 +6868,7 @@ static void GiveItemToSelectedMon(u8 taskId)
|
||||
item = gPartyMenu.bagItem;
|
||||
DisplayGaveHeldItemMessage(&gPlayerParty[gPartyMenu.slotId], item, FALSE, 1);
|
||||
GiveItemToMon(&gPlayerParty[gPartyMenu.slotId], item);
|
||||
RemoveItemToGiveFromBag(item);
|
||||
RemoveBagItem(item, 1);
|
||||
gTasks[taskId].func = Task_UpdateHeldItemSpriteAndClosePartyMenu;
|
||||
}
|
||||
}
|
||||
@ -6948,7 +6947,7 @@ static void Task_HandleSwitchItemsFromBagYesNoInput(u8 taskId)
|
||||
{
|
||||
case 0: // Yes, switch items
|
||||
item = gPartyMenu.bagItem;
|
||||
RemoveItemToGiveFromBag(item);
|
||||
RemoveBagItem(item, 1);
|
||||
if (AddBagItem(sPartyMenuItemId, 1) == FALSE)
|
||||
{
|
||||
ReturnGiveItemToBagOrPC(item);
|
||||
@ -6984,14 +6983,6 @@ static void DisplayItemMustBeRemovedFirstMessage(u8 taskId)
|
||||
gTasks[taskId].func = Task_UpdateHeldItemSpriteAndClosePartyMenu;
|
||||
}
|
||||
|
||||
static void RemoveItemToGiveFromBag(u16 item)
|
||||
{
|
||||
if (gPartyMenu.action == PARTY_ACTION_GIVE_PC_ITEM) // Unused, never occurs
|
||||
RemovePCItem(item, 1);
|
||||
else
|
||||
RemoveBagItem(item, 1);
|
||||
}
|
||||
|
||||
// Returns FALSE if there was no space to return the item
|
||||
// but there always should be, and the return is ignored in all uses
|
||||
static bool8 ReturnGiveItemToBagOrPC(u16 item)
|
||||
|
||||
14
test/bag.c
14
test/bag.c
@ -30,7 +30,7 @@ TEST("TMs and HMs are sorted correctly in the bag")
|
||||
additem ITEM_HM02;
|
||||
);
|
||||
|
||||
SortBerriesOrTMHMs(POCKET_TM_HM);
|
||||
SortPocket(POCKET_TM_HM, SORT_POCKET_TM_HM);
|
||||
|
||||
EXPECT_EQ(pocket->itemSlots[0].itemId, ITEM_TM01);
|
||||
EXPECT_EQ(pocket->itemSlots[1].itemId, ITEM_TM05);
|
||||
@ -67,7 +67,7 @@ TEST("Berries are sorted correctly in the bag")
|
||||
additem ITEM_CHERI_BERRY;
|
||||
);
|
||||
|
||||
SortBerriesOrTMHMs(POCKET_BERRIES);
|
||||
SortPocket(POCKET_BERRIES, SORT_POCKET_BY_ITEM_ID);
|
||||
|
||||
EXPECT_EQ(pocket->itemSlots[0].itemId, ITEM_CHERI_BERRY);
|
||||
EXPECT_EQ(pocket->itemSlots[1].itemId, ITEM_ORAN_BERRY);
|
||||
@ -102,11 +102,17 @@ TEST("Items are correctly compacted in the bag")
|
||||
);
|
||||
|
||||
EXPECT_EQ(pocket->itemSlots[0].itemId, ITEM_NUGGET);
|
||||
EXPECT_EQ(pocket->itemSlots[0].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[1].itemId, ITEM_BIG_NUGGET);
|
||||
EXPECT_EQ(pocket->itemSlots[1].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[2].itemId, ITEM_TINY_MUSHROOM);
|
||||
EXPECT_EQ(pocket->itemSlots[2].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[3].itemId, ITEM_BIG_MUSHROOM);
|
||||
EXPECT_EQ(pocket->itemSlots[3].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[4].itemId, ITEM_PEARL);
|
||||
EXPECT_EQ(pocket->itemSlots[4].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[5].itemId, ITEM_BIG_PEARL);
|
||||
EXPECT_EQ(pocket->itemSlots[5].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[6].itemId, ITEM_NONE);
|
||||
|
||||
// Try removing the small items, check that everything is compacted correctly
|
||||
@ -120,11 +126,13 @@ TEST("Items are correctly compacted in the bag")
|
||||
CompactItemsInBagPocket(POCKET_ITEMS);
|
||||
|
||||
EXPECT_EQ(pocket->itemSlots[0].itemId, ITEM_BIG_NUGGET);
|
||||
EXPECT_EQ(pocket->itemSlots[0].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[1].itemId, ITEM_BIG_MUSHROOM);
|
||||
EXPECT_EQ(pocket->itemSlots[1].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[2].itemId, ITEM_BIG_PEARL);
|
||||
EXPECT_EQ(pocket->itemSlots[2].quantity, 1);
|
||||
EXPECT_EQ(pocket->itemSlots[3].itemId, ITEM_NONE);
|
||||
EXPECT_EQ(pocket->itemSlots[4].itemId, ITEM_NONE);
|
||||
EXPECT_EQ(pocket->itemSlots[5].itemId, ITEM_NONE);
|
||||
EXPECT_EQ(pocket->itemSlots[6].itemId, ITEM_NONE);
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user