diff --git a/src/PlayerSubordinates.cc b/src/PlayerSubordinates.cc index a0766872..20d39d1d 100644 --- a/src/PlayerSubordinates.cc +++ b/src/PlayerSubordinates.cc @@ -572,8 +572,11 @@ bool PlayerInventory::has_equipped_item(EquipSlot slot) const { } } -void PlayerInventory::equip_item(uint32_t item_id, EquipSlot slot) { - size_t index = this->find_item(item_id); +void PlayerInventory::equip_item_id(uint32_t item_id, EquipSlot slot) { + this->equip_item_index(this->find_item(item_id), slot); +} + +void PlayerInventory::equip_item_index(size_t index, EquipSlot slot) { auto& item = this->items[index]; if (slot == EquipSlot::UNKNOWN) { @@ -594,8 +597,15 @@ void PlayerInventory::equip_item(uint32_t item_id, EquipSlot slot) { } } -void PlayerInventory::unequip_item(uint32_t item_id) { - size_t index = this->find_item(item_id); +void PlayerInventory::unequip_item_id(uint32_t item_id) { + this->unequip_item_index(this->find_item(item_id)); +} + +void PlayerInventory::unequip_item_slot(EquipSlot slot) { + this->unequip_item_index(this->find_equipped_item(slot)); +} + +void PlayerInventory::unequip_item_index(size_t index) { auto& item = this->items[index]; item.flags &= (~0x00000008); diff --git a/src/PlayerSubordinates.hh b/src/PlayerSubordinates.hh index 6c14795a..da59e2fe 100644 --- a/src/PlayerSubordinates.hh +++ b/src/PlayerSubordinates.hh @@ -76,8 +76,11 @@ struct PlayerInventory { size_t find_equipped_item(EquipSlot slot) const; bool has_equipped_item(EquipSlot slot) const; - void equip_item(uint32_t item_id, EquipSlot slot); - void unequip_item(uint32_t item_id); + void equip_item_id(uint32_t item_id, EquipSlot slot); + void equip_item_index(size_t index, EquipSlot slot); + void unequip_item_id(uint32_t item_id); + void unequip_item_slot(EquipSlot slot); + void unequip_item_index(size_t index); size_t remove_all_items_of_type(uint8_t data0, int16_t data1 = -1); diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index ce0c4248..99ab0568 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -1215,7 +1215,7 @@ static void on_equip_item(shared_ptr c, uint8_t command, uint8_t flag, c if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) { EquipSlot slot = static_cast(cmd.equip_slot.load()); auto p = c->game_data.character(); - p->inventory.equip_item(cmd.item_id, slot); + p->inventory.equip_item_id(cmd.item_id, slot); c->log.info("Equipped item %08" PRIX32, cmd.item_id.load()); } else if (l->base_version == GameVersion::BB) { throw logic_error("item tracking not enabled in BB game"); @@ -1234,7 +1234,7 @@ static void on_unequip_item(shared_ptr c, uint8_t command, uint8_t flag, auto l = c->require_lobby(); if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) { auto p = c->game_data.character(); - p->inventory.unequip_item(cmd.item_id); + p->inventory.unequip_item_id(cmd.item_id); c->log.info("Unequipped item %08" PRIX32, cmd.item_id.load()); } else if (l->base_version == GameVersion::BB) { throw logic_error("item tracking not enabled in BB game"); diff --git a/src/SaveFileFormats.cc b/src/SaveFileFormats.cc index fa13235c..461cb484 100644 --- a/src/SaveFileFormats.cc +++ b/src/SaveFileFormats.cc @@ -310,6 +310,7 @@ ItemData PSOBBCharacterFile::remove_item(uint32_t item_id, uint32_t amount, bool size_t index = this->inventory.find_item(item_id); auto& inventory_item = this->inventory.items[index]; + bool is_equipped = (inventory_item.flags & 0x00000008); // If the item is a combine item and are we removing less than we have of it, // then create a new item and reduce the amount of the existing stack. Note @@ -317,6 +318,9 @@ ItemData PSOBBCharacterFile::remove_item(uint32_t item_id, uint32_t amount, bool // applies if amount is nonzero. if (amount && (inventory_item.data.stack_size() > 1) && (amount < inventory_item.data.data1[5])) { + if (is_equipped) { + throw runtime_error("character has a combine item equipped"); + } ret = inventory_item.data; ret.data1[5] = amount; ret.id = 0xFFFFFFFF; @@ -327,6 +331,9 @@ ItemData PSOBBCharacterFile::remove_item(uint32_t item_id, uint32_t amount, bool // If we get here, then it's not meseta, and either it's not a combine item or // we're removing the entire stack. Delete the item from the inventory slot // and return the deleted item. + if (is_equipped) { + this->inventory.unequip_item_index(index); + } ret = inventory_item.data; this->inventory.num_items--; for (size_t x = index; x < this->inventory.num_items; x++) { @@ -425,7 +432,7 @@ void PSOBBCharacterFile::print_inventory(FILE* stream, GameVersion version, shar const auto& item = this->inventory.items[x]; auto name = name_index->describe_item(version, item.data); auto hex = item.data.hex(); - fprintf(stream, "[PlayerInventory] %2zu: %s (%s)\n", x, hex.c_str(), name.c_str()); + fprintf(stream, "[PlayerInventory] %2zu: [+%08" PRIX32 "] %s (%s)\n", x, item.flags.load(), hex.c_str(), name.c_str()); } }