fix tool item stackability on 11/2000
This commit is contained in:
+3
-3
@@ -480,7 +480,7 @@ void ItemCreator::set_item_unidentified_flag_if_not_challenge(ItemData& item) co
|
||||
|
||||
void ItemCreator::set_tool_item_amount_to_1(ItemData& item) const {
|
||||
if (item.data1[0] == 0x03) {
|
||||
item.set_tool_item_amount(1);
|
||||
item.set_tool_item_amount(this->version, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1686,7 +1686,7 @@ ItemCreator::DropResult ItemCreator::on_specialized_box_item_drop(
|
||||
return res;
|
||||
}
|
||||
|
||||
ItemData ItemCreator::base_item_for_specialized_box(uint32_t def0, uint32_t def1, uint32_t def2) {
|
||||
ItemData ItemCreator::base_item_for_specialized_box(uint32_t def0, uint32_t def1, uint32_t def2) const {
|
||||
ItemData item;
|
||||
item.data1[0] = (def0 >> 0x18) & 0x0F;
|
||||
item.data1[1] = (def0 >> 0x10) + ((item.data1[0] == 0x00) || (item.data1[0] == 0x01));
|
||||
@@ -1715,7 +1715,7 @@ ItemData ItemCreator::base_item_for_specialized_box(uint32_t def0, uint32_t def1
|
||||
if (item.data1[1] == 0x02) {
|
||||
item.data1[4] = def0 & 0xFF;
|
||||
}
|
||||
item.set_tool_item_amount(1);
|
||||
item.set_tool_item_amount(this->version, 1);
|
||||
break;
|
||||
case 0x04:
|
||||
item.data2d = ((def1 >> 0x10) & 0xFFFF) * 10;
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public:
|
||||
void set_monster_destroyed(uint16_t entity_id);
|
||||
void set_box_destroyed(uint16_t entity_id);
|
||||
|
||||
static ItemData base_item_for_specialized_box(uint32_t def0, uint32_t def1, uint32_t def2);
|
||||
ItemData base_item_for_specialized_box(uint32_t def0, uint32_t def1, uint32_t def2) const;
|
||||
|
||||
std::vector<ItemData> generate_armor_shop_contents(size_t player_level);
|
||||
std::vector<ItemData> generate_tool_shop_contents(size_t player_level);
|
||||
|
||||
+18
-18
@@ -84,7 +84,7 @@ uint32_t ItemData::primary_identifier() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool ItemData::is_wrapped() const {
|
||||
bool ItemData::is_wrapped(Version version) const {
|
||||
switch (this->data1[0]) {
|
||||
case 0:
|
||||
case 1:
|
||||
@@ -92,7 +92,7 @@ bool ItemData::is_wrapped() const {
|
||||
case 2:
|
||||
return this->data2[2] & 0x40;
|
||||
case 3:
|
||||
return !this->is_stackable() && (this->data1[3] & 0x40);
|
||||
return !this->is_stackable(version) && (this->data1[3] & 0x40);
|
||||
case 4:
|
||||
return false;
|
||||
default:
|
||||
@@ -100,7 +100,7 @@ bool ItemData::is_wrapped() const {
|
||||
}
|
||||
}
|
||||
|
||||
void ItemData::wrap() {
|
||||
void ItemData::wrap(Version version) {
|
||||
switch (this->data1[0]) {
|
||||
case 0:
|
||||
case 1:
|
||||
@@ -110,7 +110,7 @@ void ItemData::wrap() {
|
||||
this->data2[2] |= 0x40;
|
||||
break;
|
||||
case 3:
|
||||
if (!this->is_stackable()) {
|
||||
if (!this->is_stackable(version)) {
|
||||
this->data1[3] |= 0x40;
|
||||
}
|
||||
break;
|
||||
@@ -121,7 +121,7 @@ void ItemData::wrap() {
|
||||
}
|
||||
}
|
||||
|
||||
void ItemData::unwrap() {
|
||||
void ItemData::unwrap(Version version) {
|
||||
switch (this->data1[0]) {
|
||||
case 0:
|
||||
case 1:
|
||||
@@ -131,7 +131,7 @@ void ItemData::unwrap() {
|
||||
this->data2[2] &= 0xBF;
|
||||
break;
|
||||
case 3:
|
||||
if (!this->is_stackable()) {
|
||||
if (!this->is_stackable(version)) {
|
||||
this->data1[3] &= 0xBF;
|
||||
}
|
||||
break;
|
||||
@@ -142,23 +142,23 @@ void ItemData::unwrap() {
|
||||
}
|
||||
}
|
||||
|
||||
bool ItemData::is_stackable() const {
|
||||
return this->max_stack_size() > 1;
|
||||
bool ItemData::is_stackable(Version version) const {
|
||||
return this->max_stack_size(version) > 1;
|
||||
}
|
||||
|
||||
size_t ItemData::stack_size() const {
|
||||
if (max_stack_size_for_item(this->data1[0], this->data1[1]) > 1) {
|
||||
size_t ItemData::stack_size(Version version) const {
|
||||
if (max_stack_size_for_item(version, this->data1[0], this->data1[1]) > 1) {
|
||||
return this->data1[5];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t ItemData::max_stack_size() const {
|
||||
return max_stack_size_for_item(this->data1[0], this->data1[1]);
|
||||
size_t ItemData::max_stack_size(Version version) const {
|
||||
return max_stack_size_for_item(version, this->data1[0], this->data1[1]);
|
||||
}
|
||||
|
||||
void ItemData::enforce_min_stack_size() {
|
||||
if (this->stack_size() == 0) {
|
||||
void ItemData::enforce_min_stack_size(Version version) {
|
||||
if (this->stack_size(version) == 0) {
|
||||
this->data1[5] = 1;
|
||||
}
|
||||
}
|
||||
@@ -502,12 +502,12 @@ void ItemData::set_sealed_item_kill_count(uint16_t v) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ItemData::get_tool_item_amount() const {
|
||||
return this->is_stackable() ? this->data1[5] : 1;
|
||||
uint8_t ItemData::get_tool_item_amount(Version version) const {
|
||||
return this->is_stackable(version) ? this->data1[5] : 1;
|
||||
}
|
||||
|
||||
void ItemData::set_tool_item_amount(uint8_t amount) {
|
||||
if (this->is_stackable()) {
|
||||
void ItemData::set_tool_item_amount(Version version, uint8_t amount) {
|
||||
if (this->is_stackable(version)) {
|
||||
this->data1[5] = amount;
|
||||
} else if (this->data1[0] == 0x03) {
|
||||
this->data1[5] = 0x00;
|
||||
|
||||
+9
-9
@@ -140,14 +140,14 @@ struct ItemData { // 0x14 bytes
|
||||
std::string hex() const;
|
||||
uint32_t primary_identifier() const;
|
||||
|
||||
bool is_wrapped() const;
|
||||
void wrap();
|
||||
void unwrap();
|
||||
bool is_wrapped(Version version) const;
|
||||
void wrap(Version version);
|
||||
void unwrap(Version version);
|
||||
|
||||
bool is_stackable() const;
|
||||
size_t stack_size() const;
|
||||
size_t max_stack_size() const;
|
||||
void enforce_min_stack_size();
|
||||
bool is_stackable(Version version) const;
|
||||
size_t stack_size(Version version) const;
|
||||
size_t max_stack_size(Version version) const;
|
||||
void enforce_min_stack_size(Version version);
|
||||
|
||||
static bool is_common_consumable(uint32_t primary_identifier);
|
||||
bool is_common_consumable() const;
|
||||
@@ -166,8 +166,8 @@ struct ItemData { // 0x14 bytes
|
||||
|
||||
uint16_t get_sealed_item_kill_count() const;
|
||||
void set_sealed_item_kill_count(uint16_t v);
|
||||
uint8_t get_tool_item_amount() const;
|
||||
void set_tool_item_amount(uint8_t amount);
|
||||
uint8_t get_tool_item_amount(Version version) const;
|
||||
void set_tool_item_amount(Version version, uint8_t amount);
|
||||
int16_t get_armor_or_shield_defense_bonus() const;
|
||||
void set_armor_or_shield_defense_bonus(int16_t bonus);
|
||||
int16_t get_common_armor_evasion_bonus() const;
|
||||
|
||||
@@ -21,9 +21,11 @@ using namespace std;
|
||||
// };
|
||||
|
||||
ItemNameIndex::ItemNameIndex(
|
||||
Version version,
|
||||
std::shared_ptr<const ItemParameterTable> item_parameter_table,
|
||||
const std::vector<std::string>& name_coll)
|
||||
: item_parameter_table(item_parameter_table) {
|
||||
: version(version),
|
||||
item_parameter_table(item_parameter_table) {
|
||||
|
||||
auto find_items_1d = [&](uint64_t data1, size_t position) -> size_t {
|
||||
ItemData item(data1, 0);
|
||||
@@ -176,7 +178,7 @@ std::string ItemNameIndex::describe_item(
|
||||
// flags in a different location.
|
||||
if (((item.data1[1] == 0x01) && (item.data1[4] & 0x40)) ||
|
||||
((item.data1[0] == 0x02) && (item.data2[2] & 0x40)) ||
|
||||
((item.data1[0] == 0x03) && !item.is_stackable() && (item.data1[3] & 0x40))) {
|
||||
((item.data1[0] == 0x03) && !item.is_stackable(this->version) && (item.data1[3] & 0x40))) {
|
||||
ret_tokens.emplace_back("Wrapped");
|
||||
}
|
||||
|
||||
@@ -359,7 +361,7 @@ std::string ItemNameIndex::describe_item(
|
||||
|
||||
// For tools, add the amount (if applicable)
|
||||
} else if (item.data1[0] == 0x03) {
|
||||
if (item.max_stack_size() > 1) {
|
||||
if (item.max_stack_size(this->version) > 1) {
|
||||
ret_tokens.emplace_back(string_printf("x%hhu", item.data1[5]));
|
||||
}
|
||||
}
|
||||
@@ -401,7 +403,7 @@ ItemData ItemNameIndex::parse_item_description(const std::string& desc) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.enforce_min_stack_size();
|
||||
ret.enforce_min_stack_size(this->version);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -635,7 +637,7 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
|
||||
ret.data2[2] |= 0x40;
|
||||
}
|
||||
} else if (ret.data1[0] == 0x03) {
|
||||
if (ret.max_stack_size() > 1) {
|
||||
if (ret.max_stack_size(this->version) > 1) {
|
||||
if (starts_with(desc, "x")) {
|
||||
ret.data1[5] = stoul(desc.substr(1), nullptr, 10);
|
||||
} else {
|
||||
@@ -646,7 +648,7 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
|
||||
}
|
||||
|
||||
if (is_wrapped) {
|
||||
if (ret.is_stackable()) {
|
||||
if (ret.is_stackable(this->version)) {
|
||||
throw runtime_error("stackable items cannot be wrapped");
|
||||
} else {
|
||||
ret.data1[3] |= 0x40;
|
||||
|
||||
@@ -19,7 +19,10 @@ public:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
ItemNameIndex(std::shared_ptr<const ItemParameterTable> pmt, const std::vector<std::string>& name_coll);
|
||||
ItemNameIndex(
|
||||
Version version,
|
||||
std::shared_ptr<const ItemParameterTable> pmt,
|
||||
const std::vector<std::string>& name_coll);
|
||||
|
||||
inline size_t entry_count() const {
|
||||
return this->primary_identifier_index.size();
|
||||
@@ -38,6 +41,7 @@ public:
|
||||
private:
|
||||
ItemData parse_item_description_phase(const std::string& description, bool skip_special) const;
|
||||
|
||||
Version version;
|
||||
std::shared_ptr<const ItemParameterTable> item_parameter_table;
|
||||
|
||||
std::unordered_map<uint32_t, std::shared_ptr<const ItemMetadata>> primary_identifier_index;
|
||||
|
||||
+3
-3
@@ -111,9 +111,9 @@ void player_use_item(shared_ptr<Client> c, size_t item_index, shared_ptr<PSOLFGE
|
||||
}
|
||||
armor.data.data1[5]++;
|
||||
|
||||
} else if (item.data.is_wrapped()) {
|
||||
} else if (item.data.is_wrapped(c->version())) {
|
||||
// Unwrap present
|
||||
item.data.unwrap();
|
||||
item.data.unwrap(c->version());
|
||||
should_delete_item = false;
|
||||
|
||||
} else if (item_identifier == 0x003300) {
|
||||
@@ -250,7 +250,7 @@ void player_use_item(shared_ptr<Client> c, size_t item_index, shared_ptr<PSOLFGE
|
||||
if (should_delete_item) {
|
||||
// Allow overdrafting meseta if the client is not BB, since the server isn't
|
||||
// informed when meseta is added or removed from the bank.
|
||||
player->remove_item(item.data.id, 1, !is_v4(c->version()));
|
||||
player->remove_item(item.data.id, 1, c->version());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@ PlayerRecordsBB_Challenge::operator PlayerRecordsV3_Challenge<false>() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PlayerBank::add_item(const ItemData& item) {
|
||||
void PlayerBank::add_item(const ItemData& item, Version version) {
|
||||
uint32_t pid = item.primary_identifier();
|
||||
|
||||
if (pid == MESETA_IDENTIFIER) {
|
||||
@@ -461,7 +461,7 @@ void PlayerBank::add_item(const ItemData& item) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t combine_max = item.max_stack_size();
|
||||
size_t combine_max = item.max_stack_size(version);
|
||||
if (combine_max > 1) {
|
||||
size_t y;
|
||||
for (y = 0; y < this->num_items; y++) {
|
||||
@@ -486,17 +486,17 @@ void PlayerBank::add_item(const ItemData& item) {
|
||||
}
|
||||
auto& last_item = this->items[this->num_items];
|
||||
last_item.data = item;
|
||||
last_item.amount = (item.max_stack_size() > 1) ? item.data1[5] : 1;
|
||||
last_item.amount = (item.max_stack_size(version) > 1) ? item.data1[5] : 1;
|
||||
last_item.present = 1;
|
||||
this->num_items++;
|
||||
}
|
||||
|
||||
ItemData PlayerBank::remove_item(uint32_t item_id, uint32_t amount) {
|
||||
ItemData PlayerBank::remove_item(uint32_t item_id, uint32_t amount, Version version) {
|
||||
size_t index = this->find_item(item_id);
|
||||
auto& bank_item = this->items[index];
|
||||
|
||||
ItemData ret;
|
||||
if (amount && (bank_item.data.stack_size() > 1) && (amount < bank_item.data.data1[5])) {
|
||||
if (amount && (bank_item.data.stack_size(version) > 1) && (amount < bank_item.data.data1[5])) {
|
||||
ret = bank_item.data;
|
||||
ret.data1[5] = amount;
|
||||
bank_item.data.data1[5] -= amount;
|
||||
|
||||
@@ -100,8 +100,8 @@ struct PlayerBank {
|
||||
/* 0008 */ parray<PlayerBankItem, 200> items;
|
||||
/* 12C8 */
|
||||
|
||||
void add_item(const ItemData& item);
|
||||
ItemData remove_item(uint32_t item_id, uint32_t amount);
|
||||
void add_item(const ItemData& item, Version version);
|
||||
ItemData remove_item(uint32_t item_id, uint32_t amount, Version version);
|
||||
size_t find_item(uint32_t item_id);
|
||||
|
||||
void sort();
|
||||
|
||||
@@ -3671,7 +3671,7 @@ static void on_DF_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string& d
|
||||
? p->challenge_records.ep2_online_award_state
|
||||
: p->challenge_records.ep1_online_award_state;
|
||||
award_state.rank_award_flags |= cmd.rank_bitmask;
|
||||
p->add_item(cmd.item);
|
||||
p->add_item(cmd.item, c->version());
|
||||
l->on_item_id_generated_externally(cmd.item.id);
|
||||
string desc = s->describe_item(Version::BB_V4, cmd.item, false);
|
||||
l->log.info("(Challenge mode) Item awarded to player %hhu: %s", c->lobby_client_id, desc.c_str());
|
||||
@@ -4543,9 +4543,9 @@ static void on_D2_V3_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
auto to_p = to_c->character();
|
||||
auto from_p = from_c->character();
|
||||
for (const auto& trade_item : from_c->pending_item_trade->items) {
|
||||
size_t amount = trade_item.stack_size();
|
||||
size_t amount = trade_item.stack_size(from_c->version());
|
||||
|
||||
auto item = from_p->remove_item(trade_item.id, amount, false);
|
||||
auto item = from_p->remove_item(trade_item.id, amount, from_c->version());
|
||||
// This is a special case: when the trade is executed, the client
|
||||
// deletes the traded items from its own inventory automatically, so we
|
||||
// should NOT send the 6x29 to that client; we should only send it to
|
||||
@@ -4557,7 +4557,7 @@ static void on_D2_V3_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
}
|
||||
}
|
||||
|
||||
to_p->add_item(trade_item);
|
||||
to_p->add_item(trade_item, to_c->version());
|
||||
send_create_inventory_item_to_lobby(to_c, to_c->lobby_client_id, item);
|
||||
}
|
||||
send_command(to_c, 0xD3, 0x00);
|
||||
@@ -4991,7 +4991,7 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
|
||||
}
|
||||
}
|
||||
if (!reward.reward_item.empty()) {
|
||||
c->current_bank().add_item(reward.reward_item);
|
||||
c->current_bank().add_item(reward.reward_item, c->version());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+51
-51
@@ -1376,7 +1376,7 @@ static void on_player_drop_item(shared_ptr<Client> c, uint8_t command, uint8_t f
|
||||
|
||||
auto l = c->require_lobby();
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item_id, 0, c->version() != Version::BB_V4);
|
||||
auto item = p->remove_item(cmd.item_id, 0, c->version());
|
||||
l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -1438,7 +1438,7 @@ static void on_create_inventory_item_t(shared_ptr<Client> c, uint8_t command, ui
|
||||
ItemData item = cmd.item_data;
|
||||
item.decode_for_version(c->version());
|
||||
l->on_item_id_generated_externally(item.id);
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
auto s = c->require_server_state();
|
||||
@@ -1511,7 +1511,7 @@ static void on_drop_partial_stack_bb(shared_ptr<Client> c, uint8_t command, uint
|
||||
}
|
||||
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version());
|
||||
|
||||
// If a stack was split, the original item still exists, so the dropped item
|
||||
// needs a new ID. remove_item signals this by returning an item with an ID
|
||||
@@ -1523,7 +1523,7 @@ static void on_drop_partial_stack_bb(shared_ptr<Client> c, uint8_t command, uint
|
||||
// PSOBB sends a 6x29 command after it receives the 6x5D, so we need to add
|
||||
// the item back to the player's inventory to correct for this (it will get
|
||||
// removed again by the 6x29 handler)
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
|
||||
l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F);
|
||||
send_drop_stacked_item_to_lobby(l, item, cmd.floor, cmd.x, cmd.z);
|
||||
@@ -1558,7 +1558,7 @@ static void on_buy_shop_item(shared_ptr<Client> c, uint8_t command, uint8_t flag
|
||||
item.data2d = 0; // Clear the price field
|
||||
item.decode_for_version(c->version());
|
||||
l->on_item_id_generated_externally(item.id);
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
|
||||
size_t price = s->item_parameter_table(c->version())->price_for_item(item);
|
||||
p->remove_meseta(price, c->version() != Version::BB_V4);
|
||||
@@ -1674,7 +1674,7 @@ static void on_pick_up_item_generic(
|
||||
}
|
||||
|
||||
try {
|
||||
p->add_item(fi->data);
|
||||
p->add_item(fi->data, c->version());
|
||||
} catch (const out_of_range&) {
|
||||
// Inventory is full; put the item back where it was
|
||||
l->log.warning("Player %hu requests to pick up %08" PRIX32 ", but their inventory is full; dropping command",
|
||||
@@ -1811,8 +1811,8 @@ static void on_feed_mag(
|
||||
// a 6x29 immediately after to destroy the fed item. So on BB, we should
|
||||
// remove the fed item here, but on other versions, we allow the following
|
||||
// 6x29 command to do that.
|
||||
if (l->base_version == Version::BB_V4) {
|
||||
p->remove_item(cmd.fed_item_id, 1, false);
|
||||
if (c->version() == Version::BB_V4) {
|
||||
p->remove_item(cmd.fed_item_id, 1, c->version());
|
||||
}
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -1899,7 +1899,7 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
|
||||
}
|
||||
|
||||
} else { // Deposit item
|
||||
auto item = p->remove_item(cmd.item_id, cmd.item_amount, c->version() != Version::BB_V4);
|
||||
auto item = p->remove_item(cmd.item_id, cmd.item_amount, c->version());
|
||||
// If a stack was split, the bank item retains the same item ID as the
|
||||
// inventory item. This is annoying but doesn't cause any problems
|
||||
// because we always generate a new item ID when withdrawing from the
|
||||
@@ -1907,7 +1907,7 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
|
||||
if (item.id == 0xFFFFFFFF) {
|
||||
item.id = cmd.item_id;
|
||||
}
|
||||
bank.add_item(item);
|
||||
bank.add_item(item, c->version());
|
||||
send_destroy_item_to_lobby(c, cmd.item_id, cmd.item_amount, true);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -1934,9 +1934,9 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
|
||||
}
|
||||
|
||||
} else { // Take item
|
||||
auto item = bank.remove_item(cmd.item_id, cmd.item_amount);
|
||||
auto item = bank.remove_item(cmd.item_id, cmd.item_amount, c->version());
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -2659,7 +2659,7 @@ void on_adjust_player_meseta_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* da
|
||||
item.data1[0] = 0x04;
|
||||
item.data2d = cmd.amount.load();
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
}
|
||||
@@ -2670,9 +2670,9 @@ void on_item_reward_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* dat
|
||||
|
||||
ItemData item;
|
||||
item = cmd.item_data;
|
||||
item.enforce_min_stack_size();
|
||||
item.enforce_min_stack_size(c->version());
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
c->character()->add_item(item);
|
||||
c->character()->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
|
||||
@@ -2699,7 +2699,7 @@ void on_transfer_item_via_mail_message_bb(shared_ptr<Client> c, uint8_t command,
|
||||
|
||||
auto s = c->require_server_state();
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version());
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
auto name = s->describe_item(c->version(), item, false);
|
||||
@@ -2718,7 +2718,7 @@ void on_transfer_item_via_mail_message_bb(shared_ptr<Client> c, uint8_t command,
|
||||
(target_c->character(false) != nullptr) &&
|
||||
!target_c->config.check_flag(Client::Flag::AT_BANK_COUNTER)) {
|
||||
try {
|
||||
target_c->current_bank().add_item(item);
|
||||
target_c->current_bank().add_item(item, target_c->version());
|
||||
item_sent = true;
|
||||
} catch (const runtime_error&) {
|
||||
}
|
||||
@@ -2730,7 +2730,7 @@ void on_transfer_item_via_mail_message_bb(shared_ptr<Client> c, uint8_t command,
|
||||
send_command(c, 0x16EA, 0x00000000);
|
||||
// If the item failed to send, add it back to the sender's inventory
|
||||
item.id = l->generate_item_id(0xFF);
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
}
|
||||
@@ -2756,7 +2756,7 @@ void on_exchange_item_for_team_points_bb(shared_ptr<Client> c, uint8_t command,
|
||||
|
||||
auto s = c->require_server_state();
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version());
|
||||
|
||||
size_t points = s->item_parameter_table_v4->get_item_team_points(item);
|
||||
s->team_index->add_member_points(c->license->serial_number, points);
|
||||
@@ -2784,7 +2784,7 @@ static void on_destroy_inventory_item(shared_ptr<Client> c, uint8_t command, uin
|
||||
|
||||
auto s = c->require_server_state();
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version());
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
auto name = s->describe_item(c->version(), item, false);
|
||||
@@ -2876,7 +2876,7 @@ static void on_accept_identify_item_bb(shared_ptr<Client> c, uint8_t command, ui
|
||||
if (c->bb_identify_result.id != cmd.item_id) {
|
||||
throw runtime_error("accepted item ID does not match previous identify request");
|
||||
}
|
||||
c->character()->add_item(c->bb_identify_result);
|
||||
c->character()->add_item(c->bb_identify_result, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, c->bb_identify_result);
|
||||
c->bb_identify_result.clear();
|
||||
|
||||
@@ -2893,7 +2893,7 @@ static void on_sell_item_at_shop_bb(shared_ptr<Client> c, uint8_t command, uint8
|
||||
|
||||
auto s = c->require_server_state();
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version());
|
||||
size_t price = (s->item_parameter_table(c->version())->price_for_item(item) >> 3) * cmd.amount;
|
||||
p->add_meseta(price);
|
||||
|
||||
@@ -2915,7 +2915,7 @@ static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* da
|
||||
|
||||
ItemData item;
|
||||
item = c->bb_shop_contents.at(cmd.shop_type).at(cmd.item_index);
|
||||
if (item.is_stackable()) {
|
||||
if (item.is_stackable(c->version())) {
|
||||
item.data1[5] = cmd.amount;
|
||||
} else if (cmd.amount != 1) {
|
||||
throw runtime_error("item is not stackable");
|
||||
@@ -2928,7 +2928,7 @@ static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* da
|
||||
|
||||
item.id = cmd.shop_item_id;
|
||||
l->on_item_id_generated_externally(item.id);
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item, true);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -3031,15 +3031,15 @@ static void on_quest_exchange_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, vo
|
||||
auto p = c->character();
|
||||
|
||||
size_t found_index = p->inventory.find_item_by_primary_identifier(cmd.find_item.primary_identifier());
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 1, false);
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 1, c->version());
|
||||
send_destroy_item_to_lobby(c, found_item.id, 1);
|
||||
|
||||
// TODO: We probably should use an allow-list here to prevent the client
|
||||
// from creating arbitrary items if cheat mode is disabled.
|
||||
ItemData new_item = cmd.replace_item;
|
||||
new_item.enforce_min_stack_size();
|
||||
new_item.enforce_min_stack_size(c->version());
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item);
|
||||
p->add_item(new_item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
send_quest_function_call(c, cmd.success_function_id);
|
||||
@@ -3057,10 +3057,10 @@ static void on_wrap_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* data,
|
||||
const auto& cmd = check_size_t<G_WrapItem_BB_6xD6>(data, size);
|
||||
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item.id, 1, false);
|
||||
auto item = p->remove_item(cmd.item.id, 1, c->version());
|
||||
send_destroy_item_to_lobby(c, item.id, 1);
|
||||
item.wrap();
|
||||
p->add_item(item);
|
||||
item.wrap(c->version());
|
||||
p->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
}
|
||||
@@ -3074,15 +3074,15 @@ static void on_photon_drop_exchange_for_item_bb(shared_ptr<Client> c, uint8_t, u
|
||||
auto p = c->character();
|
||||
|
||||
size_t found_index = p->inventory.find_item_by_primary_identifier(0x031000);
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 0, false);
|
||||
send_destroy_item_to_lobby(c, found_item.id, found_item.stack_size());
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 0, c->version());
|
||||
send_destroy_item_to_lobby(c, found_item.id, found_item.stack_size(c->version()));
|
||||
|
||||
// TODO: We probably should use an allow-list here to prevent the client
|
||||
// from creating arbitrary items if cheat mode is disabled.
|
||||
ItemData new_item = cmd.new_item;
|
||||
new_item.enforce_min_stack_size();
|
||||
new_item.enforce_min_stack_size(c->version());
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item);
|
||||
p->add_item(new_item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
send_quest_function_call(c, cmd.success_function_id);
|
||||
@@ -3110,13 +3110,13 @@ static void on_photon_drop_exchange_for_s_rank_special_bb(shared_ptr<Client> c,
|
||||
// consistent in case of error
|
||||
p->inventory.find_item(cmd.item_id);
|
||||
|
||||
auto payment_item = p->remove_item(p->inventory.items[payment_item_index].data.id, cost, false);
|
||||
auto payment_item = p->remove_item(p->inventory.items[payment_item_index].data.id, cost, c->version());
|
||||
send_destroy_item_to_lobby(c, payment_item.id, cost);
|
||||
|
||||
auto item = p->remove_item(cmd.item_id, 1, false);
|
||||
auto item = p->remove_item(cmd.item_id, 1, c->version());
|
||||
send_destroy_item_to_lobby(c, item.id, cost);
|
||||
item.data1[2] = cmd.special_type;
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
|
||||
send_quest_function_call(c, cmd.success_function_id);
|
||||
@@ -3157,14 +3157,14 @@ static void on_secret_lottery_ticket_exchange_bb(shared_ptr<Client> c, uint8_t,
|
||||
exchange_cmd.amount = 1;
|
||||
send_command_t(c, 0x60, 0x00, exchange_cmd);
|
||||
|
||||
send_destroy_item_to_lobby(c, slt_item_id, 1);
|
||||
p->remove_item(slt_item_id, 1, c->version());
|
||||
|
||||
ItemData item = (s->secret_lottery_results.size() == 1)
|
||||
? s->secret_lottery_results[0]
|
||||
: s->secret_lottery_results[l->random_crypt->next() % s->secret_lottery_results.size()];
|
||||
item.enforce_min_stack_size();
|
||||
item.enforce_min_stack_size(c->version());
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
|
||||
@@ -3190,7 +3190,7 @@ static void on_photon_crystal_exchange_bb(shared_ptr<Client> c, uint8_t, uint8_t
|
||||
check_size_t<G_ExchangePhotonCrystals_BB_6xDF>(data, size);
|
||||
auto p = c->character();
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x031002);
|
||||
auto item = p->remove_item(p->inventory.items[index].data.id, 1, false);
|
||||
auto item = p->remove_item(p->inventory.items[index].data.id, 1, c->version());
|
||||
send_destroy_item_to_lobby(c, item.id, 1);
|
||||
}
|
||||
}
|
||||
@@ -3216,7 +3216,7 @@ static void on_quest_F95E_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
|
||||
} else if (item.data1[0] == 0x00) {
|
||||
item.data1[4] |= 0x80; // Unidentified
|
||||
} else {
|
||||
item.enforce_min_stack_size();
|
||||
item.enforce_min_stack_size(c->version());
|
||||
}
|
||||
|
||||
item.id = l->generate_item_id(0xFF);
|
||||
@@ -3240,7 +3240,7 @@ static void on_quest_F95F_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
|
||||
}
|
||||
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x031004); // Photon Ticket
|
||||
auto ticket_item = p->remove_item(p->inventory.items[index].data.id, result.first, false);
|
||||
auto ticket_item = p->remove_item(p->inventory.items[index].data.id, result.first, c->version());
|
||||
// TODO: Shouldn't we send a 6x29 here? Check if this causes desync in an
|
||||
// actual game
|
||||
|
||||
@@ -3252,9 +3252,9 @@ static void on_quest_F95F_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
|
||||
send_command_t(c, 0x60, 0x00, cmd_6xDB);
|
||||
|
||||
ItemData new_item = result.second;
|
||||
new_item.enforce_min_stack_size();
|
||||
new_item.enforce_min_stack_size(c->version());
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item);
|
||||
p->add_item(new_item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
S_GallonPlanResult_BB_25 out_cmd;
|
||||
@@ -3318,7 +3318,7 @@ static void on_quest_F960_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
|
||||
send_command_t(c, 0x60, 0x00, cmd_6xE3);
|
||||
|
||||
try {
|
||||
p->add_item(item);
|
||||
p->add_item(item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
if (c->log.should_log(LogLevel::INFO)) {
|
||||
string name = s->describe_item(c->version(), item, false);
|
||||
@@ -3340,7 +3340,7 @@ static void on_momoka_item_exchange_bb(shared_ptr<Client> c, uint8_t, uint8_t, v
|
||||
auto p = c->character();
|
||||
try {
|
||||
size_t found_index = p->inventory.find_item_by_primary_identifier(cmd.find_item.primary_identifier());
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 1, false);
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 1, c->version());
|
||||
|
||||
G_ExchangeItemInQuest_BB_6xDB cmd_6xDB = {{0xDB, 0x04, c->lobby_client_id}, 1, found_item.id, 1};
|
||||
send_command_t(c, 0x60, 0x00, cmd_6xDB);
|
||||
@@ -3350,9 +3350,9 @@ static void on_momoka_item_exchange_bb(shared_ptr<Client> c, uint8_t, uint8_t, v
|
||||
// TODO: We probably should use an allow-list here to prevent the client
|
||||
// from creating arbitrary items if cheat mode is disabled.
|
||||
ItemData new_item = cmd.replace_item;
|
||||
new_item.enforce_min_stack_size();
|
||||
new_item.enforce_min_stack_size(c->version());
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item);
|
||||
p->add_item(new_item, c->version());
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
send_command(c, 0x23, 0x00);
|
||||
@@ -3375,10 +3375,10 @@ static void on_upgrade_weapon_attribute_bb(shared_ptr<Client> c, uint8_t, uint8_
|
||||
uint32_t payment_primary_identifier = cmd.payment_type ? 0x031001 : 0x031000;
|
||||
size_t payment_index = p->inventory.find_item_by_primary_identifier(payment_primary_identifier);
|
||||
auto& payment_item = p->inventory.items[payment_index].data;
|
||||
if (payment_item.stack_size() < cmd.payment_count) {
|
||||
if (payment_item.stack_size(c->version()) < cmd.payment_count) {
|
||||
throw runtime_error("not enough payment items present");
|
||||
}
|
||||
p->remove_item(payment_item.id, cmd.payment_count, false);
|
||||
p->remove_item(payment_item.id, cmd.payment_count, c->version());
|
||||
send_destroy_item_to_lobby(c, payment_item.id, cmd.payment_count);
|
||||
|
||||
uint8_t attribute_amount = 0;
|
||||
|
||||
@@ -396,7 +396,7 @@ PSOBBCharacterFile::SymbolChatEntry PSOBBCharacterFile::DefaultSymbolChatEntry::
|
||||
|
||||
// TODO: Eliminate duplication between this function and the parallel function
|
||||
// in PlayerBank
|
||||
void PSOBBCharacterFile::add_item(const ItemData& item) {
|
||||
void PSOBBCharacterFile::add_item(const ItemData& item, Version version) {
|
||||
uint32_t pid = item.primary_identifier();
|
||||
|
||||
// Annoyingly, meseta is in the disp data, not in the inventory struct. If the
|
||||
@@ -407,7 +407,7 @@ void PSOBBCharacterFile::add_item(const ItemData& item) {
|
||||
}
|
||||
|
||||
// Handle combinable items
|
||||
size_t combine_max = item.max_stack_size();
|
||||
size_t combine_max = item.max_stack_size(version);
|
||||
if (combine_max > 1) {
|
||||
// Get the item index if there's already a stack of the same item in the
|
||||
// player's inventory
|
||||
@@ -444,13 +444,13 @@ void PSOBBCharacterFile::add_item(const ItemData& item) {
|
||||
|
||||
// TODO: Eliminate code duplication between this function and the parallel
|
||||
// function in PlayerBank
|
||||
ItemData PSOBBCharacterFile::remove_item(uint32_t item_id, uint32_t amount, bool allow_meseta_overdraft) {
|
||||
ItemData PSOBBCharacterFile::remove_item(uint32_t item_id, uint32_t amount, Version version) {
|
||||
ItemData ret;
|
||||
|
||||
// If we're removing meseta (signaled by an invalid item ID), then create a
|
||||
// meseta item.
|
||||
if (item_id == 0xFFFFFFFF) {
|
||||
this->remove_meseta(amount, allow_meseta_overdraft);
|
||||
this->remove_meseta(amount, !is_v4(version));
|
||||
ret.data1[0] = 0x04;
|
||||
ret.data2d = amount;
|
||||
return ret;
|
||||
@@ -464,7 +464,7 @@ ItemData PSOBBCharacterFile::remove_item(uint32_t item_id, uint32_t amount, bool
|
||||
// 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 && (inventory_item.data.stack_size() > 1) &&
|
||||
if (amount && (inventory_item.data.stack_size(version) > 1) &&
|
||||
(amount < inventory_item.data.data1[5])) {
|
||||
if (is_equipped) {
|
||||
throw runtime_error("character has a combine item equipped");
|
||||
|
||||
@@ -231,8 +231,8 @@ struct PSOBBCharacterFile {
|
||||
const PlayerDispDataBBPreview& preview,
|
||||
std::shared_ptr<const LevelTable> level_table);
|
||||
|
||||
void add_item(const ItemData& item);
|
||||
ItemData remove_item(uint32_t item_id, uint32_t amount, bool allow_meseta_overdraft);
|
||||
void add_item(const ItemData& item, Version version);
|
||||
ItemData remove_item(uint32_t item_id, uint32_t amount, Version version);
|
||||
void add_meseta(uint32_t amount);
|
||||
void remove_meseta(uint32_t amount, bool allow_overdraft);
|
||||
|
||||
|
||||
+18
-11
@@ -1146,25 +1146,25 @@ shared_ptr<ItemNameIndex> ServerState::create_item_name_index_for_version(
|
||||
Version version, shared_ptr<const ItemParameterTable> pmt, shared_ptr<const TextIndex> text_index) {
|
||||
switch (version) {
|
||||
case Version::DC_NTE:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::DC_NTE, 0, 2));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::DC_NTE, 0, 2));
|
||||
case Version::DC_V1_11_2000_PROTOTYPE:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::DC_V1_11_2000_PROTOTYPE, 1, 2));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::DC_V1_11_2000_PROTOTYPE, 1, 2));
|
||||
case Version::DC_V1:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::DC_V1, 1, 2));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::DC_V1, 1, 2));
|
||||
case Version::DC_V2:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::DC_V2, 1, 3));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::DC_V2, 1, 3));
|
||||
case Version::PC_NTE:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::PC_NTE, 1, 3));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::PC_NTE, 1, 3));
|
||||
case Version::PC_V2:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::PC_V2, 1, 3));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::PC_V2, 1, 3));
|
||||
case Version::GC_NTE:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::GC_NTE, 1, 0));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::GC_NTE, 1, 0));
|
||||
case Version::GC_V3:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::GC_V3, 1, 0));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::GC_V3, 1, 0));
|
||||
case Version::XB_V3:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::XB_V3, 1, 0));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::XB_V3, 1, 0));
|
||||
case Version::BB_V4:
|
||||
return make_shared<ItemNameIndex>(pmt, text_index->get(Version::BB_V4, 1, 1));
|
||||
return make_shared<ItemNameIndex>(version, pmt, text_index->get(Version::BB_V4, 1, 1));
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1180,12 +1180,19 @@ void ServerState::load_item_name_indexes() {
|
||||
auto pc_v2_index = create_item_name_index_for_version(
|
||||
Version::PC_V2, this->item_parameter_table(Version::PC_V2), this->text_index);
|
||||
this->set_item_name_index(Version::DC_NTE, pc_v2_index);
|
||||
this->set_item_name_index(Version::DC_V1_11_2000_PROTOTYPE, pc_v2_index);
|
||||
this->set_item_name_index(Version::DC_V1, pc_v2_index);
|
||||
this->set_item_name_index(Version::DC_V2, pc_v2_index);
|
||||
this->set_item_name_index(Version::PC_NTE, pc_v2_index);
|
||||
this->set_item_name_index(Version::PC_V2, pc_v2_index);
|
||||
|
||||
// All tools are stackable on 11/2000, so make a separate index (still using
|
||||
// V2 data) with the correct version
|
||||
auto dc_112000_index = make_shared<ItemNameIndex>(
|
||||
Version::DC_V1_11_2000_PROTOTYPE,
|
||||
this->item_parameter_table(Version::PC_V2),
|
||||
this->text_index->get(Version::PC_V2, 1, 3));
|
||||
this->set_item_name_index(Version::DC_V1_11_2000_PROTOTYPE, dc_112000_index);
|
||||
|
||||
auto gc_v3_index = create_item_name_index_for_version(
|
||||
Version::GC_V3, this->item_parameter_table(Version::GC_V3), this->text_index);
|
||||
this->set_item_name_index(Version::GC_NTE, gc_v3_index);
|
||||
|
||||
@@ -493,12 +493,15 @@ uint8_t language_code_for_char(char language_char) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t max_stack_size_for_item(uint8_t data0, uint8_t data1) {
|
||||
size_t max_stack_size_for_item(Version version, uint8_t data0, uint8_t data1) {
|
||||
if (data0 == 4) {
|
||||
return 999999;
|
||||
}
|
||||
if (data0 == 3) {
|
||||
if ((data1 < 9) && (data1 != 2)) {
|
||||
if (version == Version::DC_V1_11_2000_PROTOTYPE) {
|
||||
// All tool items are stackable up to x10 on this version
|
||||
return 10;
|
||||
} else if ((data1 < 9) && (data1 != 2)) {
|
||||
return 10;
|
||||
} else if (data1 == 0x10) {
|
||||
return 99;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "FileContentsCache.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
enum class Episode {
|
||||
NONE = 0,
|
||||
@@ -32,7 +33,7 @@ enum class GameMode {
|
||||
const char* name_for_mode(GameMode mode);
|
||||
const char* abbreviation_for_mode(GameMode mode);
|
||||
|
||||
size_t max_stack_size_for_item(uint8_t data0, uint8_t data1);
|
||||
size_t max_stack_size_for_item(Version version, uint8_t data0, uint8_t data1);
|
||||
|
||||
extern const std::vector<std::string> tech_id_to_name;
|
||||
extern const std::unordered_map<std::string, uint8_t> name_to_tech_id;
|
||||
|
||||
Reference in New Issue
Block a user