implement team points and member ranking

This commit is contained in:
Martin Michelsen
2023-11-25 23:12:09 -08:00
parent 1cd0092a41
commit 6af0527498
5 changed files with 99 additions and 11 deletions
+5 -5
View File
@@ -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)
+27
View File
@@ -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;
+1
View File
@@ -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;
+42 -1
View File
@@ -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
View File
@@ -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);
}