diff --git a/src/Player.cc b/src/Player.cc index 10b0716a..ac4f4d11 100644 --- a/src/Player.cc +++ b/src/Player.cc @@ -540,7 +540,7 @@ PlayerBankItem::PlayerBankItem() PlayerBankItem::PlayerBankItem(const PlayerInventoryItem& src) : data(src.data), - amount(combine_item_to_max.count(this->data.primary_identifier()) ? this->data.data1[5] : 1), + amount(stack_size_for_item(this->data)), show_flags(1) { } @@ -569,9 +569,8 @@ void SavedPlayerDataBB::add_item(const PlayerInventoryItem& item) { } // Handle combinable items - try { - uint32_t combine_max = combine_item_to_max.at(pid); - + size_t combine_max = stack_size_for_item(item.data); + if (combine_max > 1) { // Get the item index if there's already a stack of the same item in the // player's inventory size_t y; @@ -589,7 +588,7 @@ void SavedPlayerDataBB::add_item(const PlayerInventoryItem& item) { } return; } - } catch (const out_of_range&) { } + } // If we get here, then it's not meseta and not a combine item, so it needs to // go into an empty inventory slot @@ -611,9 +610,8 @@ void PlayerBank::add_item(const PlayerBankItem& item) { return; } - try { - uint32_t combine_max = combine_item_to_max.at(pid); - + size_t combine_max = stack_size_for_item(item.data); + if (combine_max > 1) { size_t y; for (y = 0; y < this->num_items; y++) { if (this->items[y].data.primary_identifier() == item.data.primary_identifier()) { @@ -629,7 +627,7 @@ void PlayerBank::add_item(const PlayerBankItem& item) { this->items[y].amount = this->items[y].data.data1[5]; return; } - } catch (const out_of_range&) { } + } if (this->num_items >= 200) { throw runtime_error("bank is full"); @@ -663,8 +661,8 @@ PlayerInventoryItem SavedPlayerDataBB::remove_item( // then create a new item and reduce the amount of the existing stack. Note // that passing amount == 0 means to remove the entire stack, so this only // applies if amount is nonzero. - if (amount && (amount < inventory_item.data.data1[5]) && - combine_item_to_max.count(inventory_item.data.primary_identifier())) { + if (amount && (stack_size_for_item(inventory_item.data) > 1) && + (amount < inventory_item.data.data1[5])) { ret = inventory_item; ret.data.data1[5] = amount; ret.data.id = 0xFFFFFFFF; @@ -700,8 +698,8 @@ PlayerBankItem PlayerBank::remove_item(uint32_t item_id, uint32_t amount) { size_t index = this->find_item(item_id); auto& bank_item = this->items[index]; - if (amount && (amount < bank_item.data.data1[5]) && - combine_item_to_max.count(bank_item.data.primary_identifier())) { + if (amount && (stack_size_for_item(bank_item.data) > 1) && + (amount < bank_item.data.data1[5])) { ret = bank_item; ret.data.data1[5] = amount; ret.amount = amount; diff --git a/src/RareItemSet.hh b/src/RareItemSet.hh index 62ca43c2..a779cb6c 100644 --- a/src/RareItemSet.hh +++ b/src/RareItemSet.hh @@ -10,6 +10,10 @@ struct RareItemDrop { } __attribute__((packed)); struct RareItemSet { + // TODO: It looks like this structure can actually vary. We see the offsets + // 0194 and 01B2 in the unused section, along with the value 1E (number of box + // rares). In PSOGC, these all appear to be the same size/format, but that's + // probably not strictly required to be the case. // 0x280 in size; describes one difficulty, section ID, and episode RareItemDrop rares[0x65]; // 0000 - 0194 in file uint8_t box_areas[0x1E]; // 0194 - 01B2 in file diff --git a/src/StaticGameData.cc b/src/StaticGameData.cc index 5cce8ed2..c01a76a7 100644 --- a/src/StaticGameData.cc +++ b/src/StaticGameData.cc @@ -253,24 +253,25 @@ uint8_t npc_for_name(const u16string& name) { -const unordered_map combine_item_to_max({ - {0x030000, 10}, - {0x030001, 10}, - {0x030002, 10}, - {0x030100, 10}, - {0x030101, 10}, - {0x030102, 10}, - {0x030300, 10}, - {0x030400, 10}, - {0x030500, 10}, - {0x030600, 10}, - {0x030601, 10}, - {0x030700, 10}, - {0x030800, 10}, - {0x031000, 99}, - {0x031001, 99}, - {0x031002, 99}, -}); +size_t stack_size_for_item(uint8_t data0, uint8_t data1) { + if (data0 == 4) { + return 999999; + } + if (data0 == 3) { + if ((data1 < 9) && (data1 != 2)) { + return 10; + } else if (data1 == 0x10) { + return 99; + } + } + return 1; +} + +size_t stack_size_for_item(const ItemData& item) { + return stack_size_for_item(item.data1[0], item.data1[1]); +} + + const unordered_map name_for_weapon_special({ {0x00, nullptr}, @@ -1592,7 +1593,7 @@ string name_for_item(const ItemData& item, bool include_color_codes) { // For tools, add the amount (if applicable) } else if (item.data1[0] == 0x03) { - if (combine_item_to_max.count(primary_identifier)) { + if (stack_size_for_item(item) > 1) { ret_tokens.emplace_back(string_printf("x%hhu", item.data1[5])); } } diff --git a/src/StaticGameData.hh b/src/StaticGameData.hh index 1d0facd6..73927905 100644 --- a/src/StaticGameData.hh +++ b/src/StaticGameData.hh @@ -8,7 +8,9 @@ -extern const std::unordered_map combine_item_to_max; +size_t stack_size_for_item(uint8_t data0, uint8_t data1); +size_t stack_size_for_item(const ItemData& item); + extern const std::unordered_map name_for_weapon_special; extern const std::unordered_map name_for_s_rank_special; extern const std::unordered_map name_for_primary_identifier;