factor ClientGameData into Client to reduce data duplication

This commit is contained in:
Martin Michelsen
2023-12-07 12:23:08 -08:00
parent 072ebe81bf
commit 6d16f8095a
25 changed files with 1123 additions and 1150 deletions
+68 -69
View File
@@ -13,7 +13,6 @@
#include "Loggers.hh"
#include "Map.hh"
#include "PSOProtocol.hh"
#include "Player.hh"
#include "SendCommands.hh"
#include "StaticGameData.hh"
#include "Text.hh"
@@ -324,7 +323,7 @@ static void on_sync_joining_player_item_state(shared_ptr<Client> c, uint8_t comm
}
auto* floor_items = reinterpret_cast<FloorItem*>(decompressed.data() + sizeof(G_SyncItemState_6x6D_Decompressed));
size_t target_num_items = target->game_data.character()->inventory.num_items;
size_t target_num_items = target->character()->inventory.num_items;
for (size_t z = 0; z < 12; z++) {
uint32_t client_next_id = decompressed_cmd->next_item_id_per_player[z];
uint32_t server_next_id = l->next_item_id[z];
@@ -549,12 +548,12 @@ static void on_send_guild_card(shared_ptr<Client> c, uint8_t command, uint8_t fl
case Version::DC_V1:
case Version::DC_V2: {
const auto& cmd = check_size_t<G_SendGuildCard_DC_6x06>(data, size);
c->game_data.character(true, false)->guild_card.description.encode(cmd.guild_card.description.decode(c->language()), c->language());
c->character(true, false)->guild_card.description.encode(cmd.guild_card.description.decode(c->language()), c->language());
break;
}
case Version::PC_V2: {
const auto& cmd = check_size_t<G_SendGuildCard_PC_6x06>(data, size);
c->game_data.character(true, false)->guild_card.description = cmd.guild_card.description;
c->character(true, false)->guild_card.description = cmd.guild_card.description;
break;
}
case Version::GC_NTE:
@@ -562,12 +561,12 @@ static void on_send_guild_card(shared_ptr<Client> c, uint8_t command, uint8_t fl
case Version::GC_EP3_TRIAL_EDITION:
case Version::GC_EP3: {
const auto& cmd = check_size_t<G_SendGuildCard_GC_6x06>(data, size);
c->game_data.character(true, false)->guild_card.description.encode(cmd.guild_card.description.decode(c->language()), c->language());
c->character(true, false)->guild_card.description.encode(cmd.guild_card.description.decode(c->language()), c->language());
break;
}
case Version::XB_V3: {
const auto& cmd = check_size_t<G_SendGuildCard_XB_6x06>(data, size);
c->game_data.character(true, false)->guild_card.description.encode(cmd.guild_card.description.decode(c->language()), c->language());
c->character(true, false)->guild_card.description.encode(cmd.guild_card.description.decode(c->language()), c->language());
break;
}
case Version::BB_V4:
@@ -651,7 +650,7 @@ static void on_word_select_t(shared_ptr<Client> c, uint8_t command, uint8_t, con
}
} catch (const exception& e) {
string name = c->game_data.character()->disp.name.decode(c->language());
string name = c->character()->disp.name.decode(c->language());
lc->log.warning("Untranslatable Word Select message: %s", e.what());
send_text_message_printf(lc, "$C4Untranslatable Word\nSelect message from\n%s", name.c_str());
}
@@ -720,7 +719,7 @@ static void on_player_died(shared_ptr<Client> c, uint8_t command, uint8_t flag,
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
try {
auto& inventory = c->game_data.character()->inventory;
auto& inventory = c->character()->inventory;
size_t mag_index = inventory.find_equipped_item(EquipSlot::MAG);
auto& data = inventory.items[mag_index].data;
data.data2[0] = max<int8_t>(static_cast<int8_t>(data.data2[0] - 5), 0);
@@ -874,7 +873,7 @@ static void on_player_drop_item(shared_ptr<Client> c, uint8_t command, uint8_t f
auto l = c->require_lobby();
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto p = c->game_data.character();
auto p = c->character();
auto item = p->remove_item(cmd.item_id, 0, c->version() != Version::BB_V4);
l->add_item(item, cmd.floor, cmd.x, cmd.z);
@@ -933,7 +932,7 @@ static void on_create_inventory_item_t(shared_ptr<Client> c, uint8_t command, ui
auto l = c->require_lobby();
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto p = c->game_data.character();
auto p = c->character();
ItemData item = cmd.item_data;
item.decode_for_version(c->version());
l->on_item_id_generated_externally(item.id);
@@ -992,7 +991,7 @@ static void on_drop_partial_stack_t(shared_ptr<Client> c, uint8_t command, uint8
string name = s->describe_item(c->version(), item, true);
send_text_message_printf(c, "$C5SPLIT %08" PRIX32 "\n%s", item.id.load(), name.c_str());
}
c->game_data.character()->print_inventory(stderr, c->version(), s->item_name_index);
c->character()->print_inventory(stderr, c->version(), s->item_name_index);
}
forward_subcommand_with_item_transcode_t(c, command, flag, cmd);
@@ -1021,7 +1020,7 @@ static void on_drop_partial_stack_bb(shared_ptr<Client> c, uint8_t command, uint
throw logic_error("item tracking not enabled in BB game");
}
auto p = c->game_data.character();
auto p = c->character();
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
// If a stack was split, the original item still exists, so the dropped item
@@ -1070,7 +1069,7 @@ static void on_buy_shop_item(shared_ptr<Client> c, uint8_t command, uint8_t flag
}
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto p = c->game_data.character();
auto p = c->character();
ItemData item = cmd.item_data;
item.data2d = 0; // Clear the price field
item.decode_for_version(c->version());
@@ -1169,7 +1168,7 @@ static void on_pick_up_item(shared_ptr<Client> c, uint8_t command, uint8_t flag,
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto s = c->require_server_state();
auto effective_p = effective_c->game_data.character();
auto effective_p = effective_c->character();
// It seems the client just plays it fast and loose with these commands.
// There can be multiple 6x5A (request to pick up item) commands in flight,
@@ -1238,7 +1237,7 @@ static void on_pick_up_item_request(shared_ptr<Client> c, uint8_t command, uint8
throw logic_error("item tracking not enabled in BB game");
}
auto p = c->game_data.character();
auto p = c->character();
auto item = l->remove_item(cmd.item_id);
p->add_item(item);
@@ -1268,7 +1267,7 @@ static void on_equip_item(shared_ptr<Client> c, uint8_t command, uint8_t flag, c
auto l = c->require_lobby();
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
EquipSlot slot = static_cast<EquipSlot>(cmd.equip_slot.load());
auto p = c->game_data.character();
auto p = c->character();
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 == Version::BB_V4) {
@@ -1287,7 +1286,7 @@ static void on_unequip_item(shared_ptr<Client> 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();
auto p = c->character();
p->inventory.unequip_item_id(cmd.item_id);
c->log.info("Unequipped item %08" PRIX32, cmd.item_id.load());
} else if (l->base_version == Version::BB_V4) {
@@ -1311,7 +1310,7 @@ static void on_use_item(
auto l = c->require_lobby();
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto s = c->require_server_state();
auto p = c->game_data.character();
auto p = c->character();
size_t index = p->inventory.find_item(cmd.item_id);
string name, colored_name;
{
@@ -1349,7 +1348,7 @@ static void on_feed_mag(
auto l = c->require_lobby();
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto s = c->require_server_state();
auto p = c->game_data.character();
auto p = c->character();
size_t mag_index = p->inventory.find_item(cmd.mag_item_id);
size_t fed_index = p->inventory.find_item(cmd.fed_item_id);
@@ -1404,21 +1403,21 @@ static void on_open_shop_bb_or_ep3_battle_subs(shared_ptr<Client> c, uint8_t com
}
auto s = c->require_server_state();
size_t level = c->game_data.character()->disp.stats.level + 1;
size_t level = c->character()->disp.stats.level + 1;
switch (cmd.shop_type) {
case 0:
c->game_data.shop_contents[0] = l->item_creator->generate_tool_shop_contents(level);
c->bb_shop_contents[0] = l->item_creator->generate_tool_shop_contents(level);
break;
case 1:
c->game_data.shop_contents[1] = l->item_creator->generate_weapon_shop_contents(level);
c->bb_shop_contents[1] = l->item_creator->generate_weapon_shop_contents(level);
break;
case 2:
c->game_data.shop_contents[2] = l->item_creator->generate_armor_shop_contents(level);
c->bb_shop_contents[2] = l->item_creator->generate_armor_shop_contents(level);
break;
default:
throw runtime_error("invalid shop type");
}
for (auto& item : c->game_data.shop_contents[cmd.shop_type]) {
for (auto& item : c->bb_shop_contents[cmd.shop_type]) {
item.id = 0xFFFFFFFF;
item.data2d = s->item_parameter_table_for_version(c->version())->price_for_item(item);
}
@@ -1452,8 +1451,8 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
throw logic_error("item tracking not enabled in BB game");
}
auto p = c->game_data.character();
auto& bank = c->game_data.current_bank();
auto p = c->character();
auto& bank = c->current_bank();
if (cmd.action == 0) { // Deposit
if (cmd.item_id == 0xFFFFFFFF) { // Deposit Meseta
if (cmd.meseta_amount > p->disp.stats.meseta) {
@@ -1484,7 +1483,7 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
string name = s->item_name_index->describe_item(Version::BB_V4, item);
l->log.info("Player %hu deposited item %08" PRIX32 " (x%hhu) (%s) in the bank",
c->lobby_client_id, cmd.item_id.load(), cmd.item_amount, name.c_str());
c->game_data.character()->print_inventory(stderr, c->version(), s->item_name_index);
c->character()->print_inventory(stderr, c->version(), s->item_name_index);
}
} else if (cmd.action == 1) { // Take
@@ -1511,7 +1510,7 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
string name = s->item_name_index->describe_item(Version::BB_V4, item);
l->log.info("Player %hu withdrew item %08" PRIX32 " (x%hhu) (%s) from the bank",
c->lobby_client_id, item.id.load(), cmd.item_amount, name.c_str());
c->game_data.character()->print_inventory(stderr, c->version(), s->item_name_index);
c->character()->print_inventory(stderr, c->version(), s->item_name_index);
}
} else if (cmd.action == 3) { // Leave bank counter
@@ -1532,7 +1531,7 @@ static void on_sort_inventory_bb(shared_ptr<Client> c, uint8_t, uint8_t, const v
throw logic_error("item tracking not enabled in BB game");
}
auto p = c->game_data.character();
auto p = c->character();
// Make sure the set of item IDs passed in by the client exactly matches the
// set of item IDs present in the inventory
@@ -1745,7 +1744,7 @@ static void on_set_quest_flag(shared_ptr<Client> c, uint8_t command, uint8_t fla
}
// TODO: Should we allow overlays here?
auto p = c->game_data.character(true, false);
auto p = c->character(true, false);
// The client explicitly checks for both 0 and 1 - any other value means no
// operation is performed.
@@ -1898,7 +1897,7 @@ static void on_charge_attack_bb(shared_ptr<Client> c, uint8_t command, uint8_t f
forward_subcommand(c, command, flag, data, size);
const auto& cmd = check_size_t<G_ChargeAttack_BB_6xC7>(data, size);
auto& disp = c->game_data.character()->disp;
auto& disp = c->character()->disp;
if (cmd.meseta_amount > disp.stats.meseta) {
disp.stats.meseta = 0;
} else {
@@ -1914,7 +1913,7 @@ static void on_level_up(shared_ptr<Client> c, uint8_t command, uint8_t flag, con
return;
}
auto p = c->game_data.character();
auto p = c->character();
p->disp.stats.char_stats.atp = cmd.atp;
p->disp.stats.char_stats.mst = cmd.mst;
p->disp.stats.char_stats.evp = cmd.evp;
@@ -1928,7 +1927,7 @@ static void on_level_up(shared_ptr<Client> c, uint8_t command, uint8_t flag, con
static void add_player_exp(shared_ptr<Client> c, uint32_t exp) {
auto s = c->require_server_state();
auto p = c->game_data.character();
auto p = c->character();
p->disp.stats.experience += exp;
send_give_experience(c, exp);
@@ -1963,7 +1962,7 @@ static void on_steal_exp_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void*
const auto& cmd = check_size_t<G_StealEXP_BB_6xC6>(data, size);
auto p = c->game_data.character();
auto p = c->character();
const auto& enemy = l->map->enemies.at(cmd.enemy_index);
const auto& inventory = p->inventory;
const auto& weapon = inventory.items[inventory.find_equipped_item(EquipSlot::WEAPON)];
@@ -2073,14 +2072,14 @@ static void on_enemy_exp_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, cons
(!cmd.is_killer == !is_killer) ? "" : "$C6!K$C5 ",
name_for_enum(e.type));
}
if (c->game_data.character()->disp.stats.level < 199) {
if (c->character()->disp.stats.level < 199) {
add_player_exp(c, player_exp);
}
}
}
// Update kill counts on unsealable items
auto& inventory = c->game_data.character()->inventory;
auto& inventory = c->character()->inventory;
for (size_t z = 0; z < inventory.num_items; z++) {
auto& item = inventory.items[z];
if ((item.flags & 0x08) &&
@@ -2093,7 +2092,7 @@ static void on_enemy_exp_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, cons
void on_meseta_reward_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void* data, size_t size) {
const auto& cmd = check_size_t<G_MesetaRewardRequest_BB_6xC9>(data, size);
auto p = c->game_data.character();
auto p = c->character();
if (cmd.amount < 0) {
if (-cmd.amount > static_cast<int32_t>(p->disp.stats.meseta.load())) {
p->disp.stats.meseta = 0;
@@ -2119,7 +2118,7 @@ void on_item_reward_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, const voi
ItemData item;
item = cmd.item_data;
item.id = l->generate_item_id(c->lobby_client_id);
c->game_data.character()->add_item(item);
c->character()->add_item(item);
send_create_inventory_item(c, item);
}
@@ -2148,7 +2147,7 @@ void on_transfer_item_via_mail_message_bb(shared_ptr<Client> c, uint8_t command,
forward_subcommand(c, command, flag, data, size);
auto s = c->require_server_state();
auto p = c->game_data.character();
auto p = c->character();
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
auto name = s->describe_item(c->version(), item, false);
@@ -2167,10 +2166,10 @@ void on_transfer_item_via_mail_message_bb(shared_ptr<Client> c, uint8_t command,
auto target_c = s->find_client(nullptr, cmd.target_guild_card_number);
if (target_c &&
(target_c->version() == Version::BB_V4) &&
(target_c->game_data.character(false) != nullptr) &&
(target_c->character(false) != nullptr) &&
!target_c->config.check_flag(Client::Flag::AT_BANK_COUNTER)) {
try {
target_c->game_data.current_bank().add_item(item);
target_c->current_bank().add_item(item);
item_sent = true;
} catch (const runtime_error&) {
}
@@ -2210,7 +2209,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->game_data.character();
auto p = c->character();
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
size_t points = s->item_parameter_table_v4->get_item_team_points(item);
@@ -2241,7 +2240,7 @@ static void on_destroy_inventory_item(shared_ptr<Client> c, uint8_t command, uin
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
auto s = c->require_server_state();
auto p = c->game_data.character();
auto p = c->character();
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hhu destroyed inventory item %hu:%08" PRIX32 " (%s)",
@@ -2293,7 +2292,7 @@ static void on_identify_item_bb(shared_ptr<Client> c, uint8_t command, uint8_t f
throw logic_error("received item identify subcommand without item creator present");
}
auto p = c->game_data.character();
auto p = c->character();
size_t x = p->inventory.find_item(cmd.item_id);
if (p->inventory.items[x].data.data1[0] != 0) {
throw runtime_error("non-weapon items cannot be unidentified");
@@ -2305,9 +2304,9 @@ static void on_identify_item_bb(shared_ptr<Client> c, uint8_t command, uint8_t f
// ID instead.
l->generate_item_id(c->lobby_client_id);
p->disp.stats.meseta -= 100;
c->game_data.identify_result = p->inventory.items[x].data;
c->game_data.identify_result.data1[4] &= 0x7F;
l->item_creator->apply_tekker_deltas(c->game_data.identify_result, p->disp.visual.section_id);
c->bb_identify_result = p->inventory.items[x].data;
c->bb_identify_result.data1[4] &= 0x7F;
l->item_creator->apply_tekker_deltas(c->bb_identify_result, p->disp.visual.section_id);
send_item_identify_result(c);
} else {
@@ -2324,15 +2323,15 @@ static void on_accept_identify_item_bb(shared_ptr<Client> c, uint8_t command, ui
throw logic_error("item tracking not enabled in BB game");
}
if (!c->game_data.identify_result.id || (c->game_data.identify_result.id == 0xFFFFFFFF)) {
if (!c->bb_identify_result.id || (c->bb_identify_result.id == 0xFFFFFFFF)) {
throw runtime_error("no identify result present");
}
if (c->game_data.identify_result.id != cmd.item_id) {
if (c->bb_identify_result.id != cmd.item_id) {
throw runtime_error("accepted item ID does not match previous identify request");
}
c->game_data.character()->add_item(c->game_data.identify_result);
send_create_inventory_item(c, c->game_data.identify_result);
c->game_data.identify_result.clear();
c->character()->add_item(c->bb_identify_result);
send_create_inventory_item(c, c->bb_identify_result);
c->bb_identify_result.clear();
} else {
forward_subcommand(c, command, flag, data, size);
@@ -2350,7 +2349,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->game_data.character();
auto p = c->character();
auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != Version::BB_V4);
size_t price = (s->item_parameter_table_for_version(c->version())->price_for_item(item) >> 3) * cmd.amount;
p->add_meseta(price);
@@ -2378,7 +2377,7 @@ static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, const vo
}
ItemData item;
item = c->game_data.shop_contents.at(cmd.shop_type).at(cmd.item_index);
item = c->bb_shop_contents.at(cmd.shop_type).at(cmd.item_index);
if (item.is_stackable()) {
item.data1[5] = cmd.amount;
} else if (cmd.amount != 1) {
@@ -2387,7 +2386,7 @@ static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, const vo
size_t price = item.data2d * cmd.amount;
item.data2d = 0;
auto p = c->game_data.character();
auto p = c->character();
p->remove_meseta(price, false);
item.id = l->generate_item_id(c->lobby_client_id);
@@ -2410,7 +2409,7 @@ static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, const vo
static void on_medical_center_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void*, size_t) {
auto l = c->require_lobby();
if (l->is_game() && (l->base_version == Version::BB_V4)) {
c->game_data.character()->remove_meseta(10, false);
c->character()->remove_meseta(10, false);
}
}
@@ -2436,8 +2435,8 @@ static void on_battle_restart_bb(shared_ptr<Client> c, uint8_t, uint8_t, const v
for (auto& lc : l->clients) {
if (lc) {
lc->game_data.delete_overlay();
lc->game_data.create_battle_overlay(new_rules, s->level_table);
lc->delete_overlay();
lc->create_battle_overlay(new_rules, s->level_table);
}
}
l->map->clear();
@@ -2462,7 +2461,7 @@ static void on_battle_level_up_bb(shared_ptr<Client> c, uint8_t, uint8_t, const
auto lc = l->clients.at(cmd.header.client_id);
if (lc) {
auto s = c->require_server_state();
auto lp = lc->game_data.character();
auto lp = lc->character();
uint32_t target_level = lp->disp.stats.level + cmd.num_levels;
uint32_t before_exp = lp->disp.stats.experience;
lp->disp.stats.advance_to_level(lp->disp.visual.char_class, target_level, s->level_table);
@@ -2502,7 +2501,7 @@ static void on_quest_exchange_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, co
const auto& cmd = check_size_t<G_ExchangeItemInQuest_BB_6xD5>(data, size);
try {
auto p = c->game_data.character();
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);
@@ -2529,7 +2528,7 @@ static void on_wrap_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void*
if (l->is_game() && (l->base_version == Version::BB_V4)) {
const auto& cmd = check_size_t<G_WrapItem_BB_6xD6>(data, size);
auto p = c->game_data.character();
auto p = c->character();
auto item = p->remove_item(cmd.item.id, 1, false);
send_destroy_item(c, item.id, 1);
item.wrap();
@@ -2544,7 +2543,7 @@ static void on_photon_drop_exchange_for_item_bb(shared_ptr<Client> c, uint8_t, u
const auto& cmd = check_size_t<G_PaganiniPhotonDropExchange_BB_6xD7>(data, size);
try {
auto p = c->game_data.character();
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);
@@ -2572,7 +2571,7 @@ static void on_photon_drop_exchange_for_s_rank_special_bb(shared_ptr<Client> c,
const auto& cmd = check_size_t<G_AddSRankWeaponSpecial_BB_6xD8>(data, size);
try {
auto p = c->game_data.character();
auto p = c->character();
static const array<uint8_t, 0x10> costs({60, 60, 20, 20, 30, 30, 30, 50, 40, 50, 40, 40, 50, 40, 40, 40});
uint8_t cost = costs.at(cmd.special_type);
@@ -2610,7 +2609,7 @@ static void on_secret_lottery_ticket_exchange_bb(shared_ptr<Client> c, uint8_t,
throw runtime_error("no secret lottery results are defined");
}
auto p = c->game_data.character();
auto p = c->character();
ssize_t slt_index = -1;
try {
slt_index = p->inventory.find_item_by_primary_identifier(0x031003); // Secret Lottery Ticket
@@ -2659,7 +2658,7 @@ 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 p = c->game_data.character();
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);
send_destroy_item(c, item.id, 1);
@@ -2701,7 +2700,7 @@ static void on_quest_F95F_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, cons
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_ExchangePhotonTickets_BB_6xE1>(data, size);
auto s = c->require_server_state();
auto p = c->game_data.character();
auto p = c->character();
const auto& result = s->quest_F95F_results.at(cmd.result_index);
if (result.second.empty()) {
@@ -2739,7 +2738,7 @@ static void on_momoka_item_exchange_bb(shared_ptr<Client> c, uint8_t, uint8_t, c
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 p = c->game_data.character();
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);
@@ -2768,7 +2767,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 p = c->game_data.character();
auto p = c->character();
try {
size_t item_index = p->inventory.find_item(cmd.item_id);
auto& item = p->inventory.items[item_index].data;
@@ -2819,7 +2818,7 @@ static void on_upgrade_weapon_attribute_bb(shared_ptr<Client> c, uint8_t, uint8_
static void on_write_quest_global_flag_bb(shared_ptr<Client> c, uint8_t, uint8_t, const void* data, size_t size) {
const auto& cmd = check_size_t<G_SetQuestGlobalFlag_BB_6xD2>(data, size);
c->game_data.character()->quest_global_flags[cmd.index] = cmd.value;
c->character()->quest_global_flags[cmd.index] = cmd.value;
}
////////////////////////////////////////////////////////////////////////////////