implement team points and member ranking
This commit is contained in:
@@ -3363,16 +3363,16 @@ struct S_TeamInfoForPlayer_BB_13EA_15EA_Entry {
|
||||
// No arguments (C->S)
|
||||
|
||||
struct S_TeamRankingInformation_BB_18EA {
|
||||
/* 0000 */ le_uint32_t unknown_a1 = 0;
|
||||
/* 0000 */ le_uint32_t ranking_points = 0;
|
||||
/* 0004 */ le_uint32_t unknown_a2 = 0;
|
||||
/* 0008 */ le_uint32_t unknown_a3 = 0;
|
||||
/* 0008 */ le_uint32_t points_remaining = 0;
|
||||
/* 000C */ le_uint32_t num_entries = 1;
|
||||
struct Entry {
|
||||
/* 00 */ le_uint32_t unknown_a1 = 0;
|
||||
/* 00 */ le_uint32_t rank = 0;
|
||||
/* 04 */ le_uint32_t privilege_level = 0;
|
||||
/* 08 */ le_uint32_t guild_card_number = 0;
|
||||
/* 0C */ pstring<TextEncoding::UTF16, 0x10> player_name;
|
||||
/* 2C */ le_uint32_t unknown_a2 = 0;
|
||||
/* 2C */ le_uint32_t points = 0;
|
||||
/* 30 */
|
||||
} __packed__;
|
||||
// Variable-length field:
|
||||
@@ -5612,7 +5612,7 @@ struct G_ItemTransferRequest_BB_6xCB {
|
||||
struct G_ExchangeItemForTeamPoints_BB_6xCC {
|
||||
G_ClientIDHeader header;
|
||||
le_uint32_t item_id = 0;
|
||||
le_uint32_t unknown_a2 = 0;
|
||||
le_uint32_t amount = 0;
|
||||
} __packed__;
|
||||
|
||||
// 6xCD: Transfer master (BB)
|
||||
|
||||
@@ -610,6 +610,33 @@ uint32_t ItemParameterTable::get_item_id(const ItemData& item) const {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ItemParameterTable::get_item_team_points(const ItemData& item) const {
|
||||
switch (item.data1[0]) {
|
||||
case 0:
|
||||
return this->get_weapon(item.data1[1], item.data1[2]).base.team_points;
|
||||
case 1:
|
||||
if (item.data1[1] == 3) {
|
||||
return this->get_unit(item.data1[2]).base.team_points;
|
||||
} else if ((item.data1[1] == 1) || (item.data1[1] == 2)) {
|
||||
return this->get_armor_or_shield(item.data1[1], item.data1[2]).base.team_points;
|
||||
}
|
||||
throw runtime_error("invalid item");
|
||||
case 2:
|
||||
return this->get_mag(item.data1[1]).base.team_points;
|
||||
case 3:
|
||||
if (item.data1[1] == 2) {
|
||||
return this->get_tool(2, item.data1[4]).base.team_points;
|
||||
} else {
|
||||
return this->get_tool(item.data1[1], item.data1[2]).base.team_points;
|
||||
}
|
||||
throw logic_error("this should be impossible");
|
||||
case 4:
|
||||
throw runtime_error("item is meseta and therefore has no definition");
|
||||
default:
|
||||
throw runtime_error("invalid item");
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ItemParameterTable::get_item_base_stars(const ItemData& item) const {
|
||||
if (item.data1[0] == 2) {
|
||||
return (item.data1[1] >= this->first_rare_mag_index) ? 12 : 0;
|
||||
|
||||
@@ -324,6 +324,7 @@ public:
|
||||
uint8_t get_weapon_v1_replacement(uint8_t data1_1) const;
|
||||
|
||||
uint32_t get_item_id(const ItemData& item) const;
|
||||
uint32_t get_item_team_points(const ItemData& item) const;
|
||||
uint8_t get_item_base_stars(const ItemData& item) const;
|
||||
uint8_t get_item_adjusted_stars(const ItemData& item) const;
|
||||
bool is_item_rare(const ItemData& item) const;
|
||||
|
||||
@@ -2075,6 +2075,47 @@ void on_item_reward_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, const voi
|
||||
send_create_inventory_item(c, item);
|
||||
}
|
||||
|
||||
void on_exchange_item_for_team_points_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
const auto& cmd = check_size_t<G_ExchangeItemForTeamPoints_BB_6xCC>(data, size);
|
||||
|
||||
auto team = c->team();
|
||||
if (!team) {
|
||||
throw runtime_error("player is not in a team");
|
||||
}
|
||||
auto l = c->require_lobby();
|
||||
if (!l->is_game()) {
|
||||
return;
|
||||
}
|
||||
if (cmd.header.client_id != c->lobby_client_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (l->base_version != Version::BB_V4) {
|
||||
throw runtime_error("item tracking not enabled in BB game");
|
||||
}
|
||||
if (!l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||
throw runtime_error("item tracking not enabled in BB game");
|
||||
}
|
||||
|
||||
auto s = c->require_server_state();
|
||||
auto p = c->game_data.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);
|
||||
team->members.at(c->license->serial_number).points += points;
|
||||
|
||||
auto name = s->describe_item(c->version(), item, false);
|
||||
l->log.info("Player %hhu exchanged inventory item %hu:%08" PRIX32 " (%s) for %zu team points",
|
||||
c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), points);
|
||||
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
|
||||
string name = s->describe_item(c->version(), item, true);
|
||||
send_text_message_printf(c, "$C5EX/PT %08" PRIX32 "\n%s\n$C5+%zuPT", cmd.item_id.load(), name.c_str(), points);
|
||||
}
|
||||
p->print_inventory(stderr, c->version(), s->item_name_index);
|
||||
|
||||
forward_subcommand(c, command, flag, data, size);
|
||||
}
|
||||
|
||||
static void on_destroy_inventory_item(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
|
||||
const auto& cmd = check_size_t<G_DeleteInventoryItem_6x29>(data, size);
|
||||
|
||||
@@ -2914,7 +2955,7 @@ subcommand_handler_t subcommand_handlers[0x100] = {
|
||||
/* 6xC9 */ on_meseta_reward_request_bb,
|
||||
/* 6xCA */ on_item_reward_request_bb,
|
||||
/* 6xCB */ nullptr,
|
||||
/* 6xCC */ nullptr,
|
||||
/* 6xCC */ on_exchange_item_for_team_points_bb,
|
||||
/* 6xCD */ nullptr,
|
||||
/* 6xCE */ nullptr,
|
||||
/* 6xCF */ on_battle_restart_bb,
|
||||
|
||||
+24
-5
@@ -3272,13 +3272,13 @@ static S_TeamInfoForPlayer_BB_13EA_15EA_Entry team_metadata_for_client(shared_pt
|
||||
auto team = c->team();
|
||||
S_TeamInfoForPlayer_BB_13EA_15EA_Entry cmd;
|
||||
cmd.lobby_client_id = c->lobby_client_id;
|
||||
cmd.guild_card_number = c->license->serial_number;
|
||||
cmd.guild_card_number2 = c->license->serial_number;
|
||||
cmd.player_name = c->game_data.character()->disp.name;
|
||||
if (team) {
|
||||
cmd.guild_card_number = c->license->serial_number;
|
||||
cmd.team_id = team->team_id;
|
||||
cmd.privilege_level = team->members.at(c->license->serial_number).privilege_level();
|
||||
cmd.team_name.encode(team->name);
|
||||
cmd.guild_card_number2 = c->license->serial_number;
|
||||
cmd.player_name = c->game_data.character()->disp.name;
|
||||
if (team->flag_data) {
|
||||
cmd.flag_data = *team->flag_data;
|
||||
}
|
||||
@@ -3338,11 +3338,30 @@ void send_team_rank_info(std::shared_ptr<Client> c) {
|
||||
throw runtime_error("client is not in a team");
|
||||
}
|
||||
|
||||
vector<const TeamIndex::Team::Member*> members;
|
||||
for (const auto& it : team->members) {
|
||||
members.emplace_back(&it.second);
|
||||
}
|
||||
auto rank_fn = +[](const TeamIndex::Team::Member* a, const TeamIndex::Team::Member* b) {
|
||||
return a->points > b->points;
|
||||
};
|
||||
sort(members.begin(), members.end(), rank_fn);
|
||||
|
||||
S_TeamRankingInformation_BB_18EA cmd;
|
||||
cmd.num_entries = team->num_members();
|
||||
cmd.points_remaining = 0;
|
||||
|
||||
vector<S_TeamRankingInformation_BB_18EA::Entry> entries;
|
||||
// TODO: FIll in entries here
|
||||
for (size_t z = 0; z < members.size(); z++) {
|
||||
const auto* m = members[z];
|
||||
cmd.ranking_points += m->points;
|
||||
auto& e = entries.emplace_back();
|
||||
e.rank = z + 1;
|
||||
e.privilege_level = m->privilege_level();
|
||||
e.guild_card_number = m->serial_number;
|
||||
e.player_name.encode(m->name);
|
||||
e.points = m->points;
|
||||
}
|
||||
cmd.num_entries = entries.size();
|
||||
|
||||
send_command_t_vt(c, 0x18EA, 0x00000000, cmd, entries);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user