fix tool item stackability on 11/2000
This commit is contained in:
+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;
|
||||
|
||||
Reference in New Issue
Block a user