allow overriding stack sizes
This commit is contained in:
+78
-52
@@ -1385,9 +1385,10 @@ static void on_player_drop_item(shared_ptr<Client> c, uint8_t command, uint8_t f
|
||||
return;
|
||||
}
|
||||
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item_id, 0, c->version());
|
||||
auto item = p->remove_item(cmd.item_id, 0, *s->item_stack_limits(c->version()));
|
||||
l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -1444,12 +1445,13 @@ static void on_create_inventory_item_t(shared_ptr<Client> c, uint8_t command, ui
|
||||
return;
|
||||
}
|
||||
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
auto p = c->character();
|
||||
ItemData item = cmd.item_data;
|
||||
item.decode_for_version(c->version());
|
||||
l->on_item_id_generated_externally(item.id);
|
||||
p->add_item(item, c->version());
|
||||
p->add_item(item, *s->item_stack_limits(c->version()));
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
auto s = c->require_server_state();
|
||||
@@ -1516,13 +1518,15 @@ static void on_drop_partial_stack_bb(shared_ptr<Client> c, uint8_t command, uint
|
||||
auto l = c->require_lobby();
|
||||
if (l->base_version == Version::BB_V4) {
|
||||
const auto& cmd = check_size_t<G_SplitStackedItem_BB_6xC3>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
|
||||
if (!l->is_game() || (cmd.header.client_id != c->lobby_client_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version());
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, limits);
|
||||
|
||||
// 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
|
||||
@@ -1534,7 +1538,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, c->version());
|
||||
p->add_item(item, limits);
|
||||
|
||||
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);
|
||||
@@ -1569,7 +1573,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, c->version());
|
||||
p->add_item(item, *s->item_stack_limits(c->version()));
|
||||
|
||||
size_t price = s->item_parameter_table(c->version())->price_for_item(item);
|
||||
p->remove_meseta(price, c->version() != Version::BB_V4);
|
||||
@@ -1696,6 +1700,7 @@ static void on_pick_up_item_generic(
|
||||
// logic here instead of forwarding the 6x5A to the leader.
|
||||
|
||||
auto p = c->character();
|
||||
auto s = c->require_server_state();
|
||||
auto fi = l->remove_item(floor, item_id, c->lobby_client_id);
|
||||
if (!fi->visible_to_client(c->lobby_client_id)) {
|
||||
l->log.warning("Player %hu requests to pick up %08" PRIX32 ", but is it not visible to them; dropping command",
|
||||
@@ -1705,7 +1710,7 @@ static void on_pick_up_item_generic(
|
||||
}
|
||||
|
||||
try {
|
||||
p->add_item(fi->data, c->version());
|
||||
p->add_item(fi->data, *s->item_stack_limits(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",
|
||||
@@ -1721,7 +1726,6 @@ static void on_pick_up_item_generic(
|
||||
c->print_inventory(stderr);
|
||||
}
|
||||
|
||||
auto s = c->require_server_state();
|
||||
for (size_t z = 0; z < 12; z++) {
|
||||
auto lc = l->clients[z];
|
||||
if ((!lc) || (!is_request && (lc == c))) {
|
||||
@@ -1821,8 +1825,8 @@ static void on_feed_mag(
|
||||
return;
|
||||
}
|
||||
|
||||
auto l = c->require_lobby();
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
auto p = c->character();
|
||||
|
||||
size_t mag_index = p->inventory.find_item(cmd.mag_item_id);
|
||||
@@ -1843,7 +1847,7 @@ static void on_feed_mag(
|
||||
// remove the fed item here, but on other versions, we allow the following
|
||||
// 6x29 command to do that.
|
||||
if (c->version() == Version::BB_V4) {
|
||||
p->remove_item(cmd.fed_item_id, 1, c->version());
|
||||
p->remove_item(cmd.fed_item_id, 1, *s->item_stack_limits(c->version()));
|
||||
}
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -1984,7 +1988,8 @@ 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());
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
auto item = p->remove_item(cmd.item_id, cmd.item_amount, limits);
|
||||
// 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
|
||||
@@ -1992,7 +1997,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, c->version());
|
||||
bank.add_item(item, limits);
|
||||
send_destroy_item_to_lobby(c, cmd.item_id, cmd.item_amount, true);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -2019,9 +2024,10 @@ 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, c->version());
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
auto item = bank.remove_item(cmd.item_id, cmd.item_amount, limits);
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(item, c->version());
|
||||
p->add_item(item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -2841,26 +2847,29 @@ void on_adjust_player_meseta_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* da
|
||||
p->disp.stats.meseta += cmd.amount;
|
||||
}
|
||||
} else if (cmd.amount > 0) {
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
|
||||
ItemData item;
|
||||
item.data1[0] = 0x04;
|
||||
item.data2d = cmd.amount.load();
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(item, c->version());
|
||||
p->add_item(item, *s->item_stack_limits(c->version()));
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
}
|
||||
|
||||
void on_item_reward_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* data, size_t size) {
|
||||
const auto& cmd = check_size_t<G_ItemRewardRequest_BB_6xCA>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
auto l = c->require_lobby();
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
|
||||
ItemData item;
|
||||
item = cmd.item_data;
|
||||
item.enforce_min_stack_size(c->version());
|
||||
item.enforce_min_stack_size(limits);
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
c->character()->add_item(item, c->version());
|
||||
c->character()->add_item(item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
|
||||
@@ -2885,7 +2894,8 @@ 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());
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, limits);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
auto name = s->describe_item(c->version(), item, false);
|
||||
@@ -2904,7 +2914,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->version());
|
||||
target_c->current_bank().add_item(item, limits);
|
||||
item_sent = true;
|
||||
} catch (const runtime_error&) {
|
||||
}
|
||||
@@ -2917,7 +2927,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, c->version());
|
||||
p->add_item(item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
}
|
||||
@@ -2943,7 +2953,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());
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, *s->item_stack_limits(c->version()));
|
||||
|
||||
size_t points = s->item_parameter_table(Version::BB_V4)->get_item_team_points(item);
|
||||
s->team_index->add_member_points(c->license->serial_number, points);
|
||||
@@ -2971,7 +2981,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());
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, *s->item_stack_limits(c->version()));
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
auto name = s->describe_item(c->version(), item, false);
|
||||
@@ -3075,7 +3085,8 @@ 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->version());
|
||||
auto s = c->require_server_state();
|
||||
c->character()->add_item(c->bb_identify_result, *s->item_stack_limits(c->version()));
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, c->bb_identify_result);
|
||||
c->bb_identify_result.clear();
|
||||
|
||||
@@ -3092,7 +3103,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());
|
||||
auto item = p->remove_item(cmd.item_id, cmd.amount, *s->item_stack_limits(c->version()));
|
||||
size_t price = (s->item_parameter_table(c->version())->price_for_item(item) >> 3) * cmd.amount;
|
||||
p->add_meseta(price);
|
||||
|
||||
@@ -3111,10 +3122,12 @@ static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* da
|
||||
auto l = c->require_lobby();
|
||||
if (l->base_version == Version::BB_V4) {
|
||||
const auto& cmd = check_size_t<G_BuyShopItem_BB_6xB7>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
|
||||
ItemData item;
|
||||
item = c->bb_shop_contents.at(cmd.shop_type).at(cmd.item_index);
|
||||
if (item.is_stackable(c->version())) {
|
||||
if (item.is_stackable(limits)) {
|
||||
item.data1[5] = cmd.amount;
|
||||
} else if (cmd.amount != 1) {
|
||||
throw runtime_error("item is not stackable");
|
||||
@@ -3127,7 +3140,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, c->version());
|
||||
p->add_item(item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item, true);
|
||||
|
||||
if (l->log.should_log(LogLevel::INFO)) {
|
||||
@@ -3375,20 +3388,22 @@ static void on_quest_exchange_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, vo
|
||||
(l->base_version == Version::BB_V4) &&
|
||||
l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS)) {
|
||||
const auto& cmd = check_size_t<G_ExchangeItemInQuest_BB_6xD5>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
|
||||
try {
|
||||
auto p = c->character();
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
|
||||
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, c->version());
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 1, limits);
|
||||
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(c->version());
|
||||
new_item.enforce_min_stack_size(limits);
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item, c->version());
|
||||
p->add_item(new_item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
send_quest_function_call(c, cmd.success_function_id);
|
||||
@@ -3404,12 +3419,13 @@ static void on_wrap_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* data,
|
||||
auto l = c->require_lobby();
|
||||
if (l->is_game() && (l->base_version == Version::BB_V4)) {
|
||||
const auto& cmd = check_size_t<G_WrapItem_BB_6xD6>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
|
||||
auto p = c->character();
|
||||
auto item = p->remove_item(cmd.item.id, 1, c->version());
|
||||
auto item = p->remove_item(cmd.item.id, 1, *s->item_stack_limits(c->version()));
|
||||
send_destroy_item_to_lobby(c, item.id, 1);
|
||||
item.wrap(c->version());
|
||||
p->add_item(item, c->version());
|
||||
item.wrap(*s->item_stack_limits(c->version()));
|
||||
p->add_item(item, *s->item_stack_limits(c->version()));
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
}
|
||||
@@ -3418,20 +3434,22 @@ static void on_photon_drop_exchange_for_item_bb(shared_ptr<Client> c, uint8_t, u
|
||||
auto l = c->require_lobby();
|
||||
if (l->is_game() && (l->base_version == Version::BB_V4)) {
|
||||
const auto& cmd = check_size_t<G_PaganiniPhotonDropExchange_BB_6xD7>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
|
||||
try {
|
||||
auto p = c->character();
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
|
||||
size_t found_index = p->inventory.find_item_by_primary_identifier(0x03100000);
|
||||
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()));
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 0, limits);
|
||||
send_destroy_item_to_lobby(c, found_item.id, found_item.stack_size(limits));
|
||||
|
||||
// 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(c->version());
|
||||
new_item.enforce_min_stack_size(limits);
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item, c->version());
|
||||
p->add_item(new_item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
send_quest_function_call(c, cmd.success_function_id);
|
||||
@@ -3447,6 +3465,8 @@ static void on_photon_drop_exchange_for_s_rank_special_bb(shared_ptr<Client> c,
|
||||
auto l = c->require_lobby();
|
||||
if (l->is_game() && (l->base_version == Version::BB_V4)) {
|
||||
const auto& cmd = check_size_t<G_AddSRankWeaponSpecial_BB_6xD8>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
|
||||
try {
|
||||
auto p = c->character();
|
||||
@@ -3459,13 +3479,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, c->version());
|
||||
auto payment_item = p->remove_item(p->inventory.items[payment_item_index].data.id, cost, limits);
|
||||
send_destroy_item_to_lobby(c, payment_item.id, cost);
|
||||
|
||||
auto item = p->remove_item(cmd.item_id, 1, c->version());
|
||||
auto item = p->remove_item(cmd.item_id, 1, limits);
|
||||
send_destroy_item_to_lobby(c, item.id, cost);
|
||||
item.data1[2] = cmd.special_type;
|
||||
p->add_item(item, c->version());
|
||||
p->add_item(item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
|
||||
send_quest_function_call(c, cmd.success_function_id);
|
||||
@@ -3495,6 +3515,7 @@ static void on_secret_lottery_ticket_exchange_bb(shared_ptr<Client> c, uint8_t,
|
||||
}
|
||||
|
||||
if (slt_index >= 0) {
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
uint32_t slt_item_id = p->inventory.items[slt_index].data.id;
|
||||
|
||||
G_ExchangeItemInQuest_BB_6xDB exchange_cmd;
|
||||
@@ -3506,14 +3527,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);
|
||||
|
||||
p->remove_item(slt_item_id, 1, c->version());
|
||||
p->remove_item(slt_item_id, 1, limits);
|
||||
|
||||
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(c->version());
|
||||
item.enforce_min_stack_size(limits);
|
||||
item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(item, c->version());
|
||||
p->add_item(item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
|
||||
}
|
||||
|
||||
@@ -3537,9 +3558,10 @@ static void on_photon_crystal_exchange_bb(shared_ptr<Client> c, uint8_t, uint8_t
|
||||
auto l = c->require_lobby();
|
||||
if (l->is_game() && (l->base_version == Version::BB_V4) && l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS)) {
|
||||
check_size_t<G_ExchangePhotonCrystals_BB_6xDF>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
auto p = c->character();
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x03100200);
|
||||
auto item = p->remove_item(p->inventory.items[index].data.id, 1, c->version());
|
||||
auto item = p->remove_item(p->inventory.items[index].data.id, 1, *s->item_stack_limits(c->version()));
|
||||
send_destroy_item_to_lobby(c, item.id, 1);
|
||||
}
|
||||
}
|
||||
@@ -3565,7 +3587,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(c->version());
|
||||
item.enforce_min_stack_size(*s->item_stack_limits(c->version()));
|
||||
}
|
||||
|
||||
item.id = l->generate_item_id(0xFF);
|
||||
@@ -3588,8 +3610,9 @@ static void on_quest_F95F_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
|
||||
throw runtime_error("invalid result index");
|
||||
}
|
||||
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x03100400); // Photon Ticket
|
||||
auto ticket_item = p->remove_item(p->inventory.items[index].data.id, result.first, c->version());
|
||||
auto ticket_item = p->remove_item(p->inventory.items[index].data.id, result.first, limits);
|
||||
// TODO: Shouldn't we send a 6x29 here? Check if this causes desync in an
|
||||
// actual game
|
||||
|
||||
@@ -3601,9 +3624,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(c->version());
|
||||
new_item.enforce_min_stack_size(limits);
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item, c->version());
|
||||
p->add_item(new_item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
S_GallonPlanResult_BB_25 out_cmd;
|
||||
@@ -3667,7 +3690,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, c->version());
|
||||
p->add_item(item, *s->item_stack_limits(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);
|
||||
@@ -3686,10 +3709,12 @@ static void on_momoka_item_exchange_bb(shared_ptr<Client> c, uint8_t, uint8_t, v
|
||||
auto l = c->require_lobby();
|
||||
if (l->is_game() && (l->base_version == Version::BB_V4) && l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS)) {
|
||||
const auto& cmd = check_size_t<G_MomokaItemExchange_BB_6xD9>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
auto p = c->character();
|
||||
try {
|
||||
const auto& limits = *s->item_stack_limits(c->version());
|
||||
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, c->version());
|
||||
auto found_item = p->remove_item(p->inventory.items[found_index].data.id, 1, limits);
|
||||
|
||||
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);
|
||||
@@ -3699,9 +3724,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(c->version());
|
||||
new_item.enforce_min_stack_size(limits);
|
||||
new_item.id = l->generate_item_id(c->lobby_client_id);
|
||||
p->add_item(new_item, c->version());
|
||||
p->add_item(new_item, limits);
|
||||
send_create_inventory_item_to_lobby(c, c->lobby_client_id, new_item);
|
||||
|
||||
send_command(c, 0x23, 0x00);
|
||||
@@ -3716,6 +3741,7 @@ static void on_upgrade_weapon_attribute_bb(shared_ptr<Client> c, uint8_t, uint8_
|
||||
auto l = c->require_lobby();
|
||||
if (l->is_game() && (l->base_version == Version::BB_V4) && l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS)) {
|
||||
const auto& cmd = check_size_t<G_UpgradeWeaponAttribute_BB_6xDA>(data, size);
|
||||
auto s = c->require_server_state();
|
||||
auto p = c->character();
|
||||
try {
|
||||
size_t item_index = p->inventory.find_item(cmd.item_id);
|
||||
@@ -3724,10 +3750,10 @@ static void on_upgrade_weapon_attribute_bb(shared_ptr<Client> c, uint8_t, uint8_
|
||||
uint32_t payment_primary_identifier = cmd.payment_type ? 0x03100100 : 0x03100000;
|
||||
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(c->version()) < cmd.payment_count) {
|
||||
if (payment_item.stack_size(*s->item_stack_limits(c->version())) < cmd.payment_count) {
|
||||
throw runtime_error("not enough payment items present");
|
||||
}
|
||||
p->remove_item(payment_item.id, cmd.payment_count, c->version());
|
||||
p->remove_item(payment_item.id, cmd.payment_count, *s->item_stack_limits(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