implement most remaining BB team functions

This commit is contained in:
Martin Michelsen
2023-11-29 11:35:15 -08:00
parent 556360c993
commit 9ea84d7101
14 changed files with 557 additions and 263 deletions
+44 -94
View File
@@ -4528,23 +4528,27 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
try {
added_c = s->find_client(nullptr, cmd.guild_card_number);
} catch (const out_of_range&) {
send_lobby_message_box(c, "Player is offline");
send_command(c, 0x04EA, 0x00000006);
}
if (added_c) {
auto added_c_team = added_c->team();
if (added_c_team) {
send_lobby_message_box(c, "Player is already\nin another team");
} else if (!added_c->config.check_flag(Client::Flag::ACCEPTED_TEAM_INVITATION)) {
send_lobby_message_box(c, "Player did not accept\nteam invitation");
send_command(c, 0x04EA, 0x00000001);
send_command(added_c, 0x04EA, 0x00000001);
} else if (!team->can_add_member()) {
// Send "team is full" error
send_command(c, 0x04EA, 0x00000005);
send_command(added_c, 0x04EA, 0x00000005);
} else {
added_c->license->bb_team_id = team->team_id;
added_c->license->save();
added_c->config.clear_flag(Client::Flag::ACCEPTED_TEAM_INVITATION);
s->team_index->add_member(
team->team_id,
added_c->license->serial_number,
added_c->game_data.character()->disp.name.decode(added_c->language()));
send_update_team_metadata_for_client(added_c);
send_team_membership_info(added_c);
@@ -4623,8 +4627,7 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
auto team = c->team();
if (team && team->members.at(c->license->serial_number).check_flag(TeamIndex::Team::Member::Flag::IS_MASTER)) {
const auto& cmd = check_size_t<C_SetTeamFlag_BB_0FEA>(data);
team->flag_data.reset(new parray<le_uint16_t, 0x20 * 0x20>(cmd.flag_data));
team->save_flag();
s->team_index->set_flag_data(team->team_id, cmd.flag_data);
for (const auto& it : team->members) {
try {
auto member_c = s->find_client(nullptr, it.second.serial_number);
@@ -4660,37 +4663,29 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
throw runtime_error("this command cannot be used to modify your own permissions");
}
auto& this_m = team->members.at(c->license->serial_number);
if (!this_m.check_flag(TeamIndex::Team::Member::Flag::IS_MASTER)) {
break;
}
auto& other_m = team->members.at(cmd.guild_card_number);
// The client only sends this command with flag = 0x00, 0x30, or 0x40
bool send_updates_for_this_m = false;
bool send_updates_for_other_m = false;
switch (flag) {
case 0x00: // Demote member
if (other_m.check_flag(TeamIndex::Team::Member::Flag::IS_LEADER)) {
other_m.clear_flag(TeamIndex::Team::Member::Flag::IS_LEADER);
if (s->team_index->demote_leader(c->license->serial_number, cmd.guild_card_number)) {
send_command(c, 0x11EA, 0x00000000);
send_updates_for_other_m = true;
} else {
send_command(c, 0x11EA, 0x00000005);
}
break;
case 0x30: // Promote member
if (!other_m.check_flag(TeamIndex::Team::Member::Flag::IS_LEADER) && team->can_promote_leader()) {
other_m.set_flag(TeamIndex::Team::Member::Flag::IS_LEADER);
if (s->team_index->promote_leader(c->license->serial_number, cmd.guild_card_number)) {
send_command(c, 0x11EA, 0x00000000);
send_updates_for_other_m = true;
} else {
send_command(c, 0x11EA, 0x00000005);
}
break;
case 0x40: // Transfer master
this_m.clear_flag(TeamIndex::Team::Member::Flag::IS_MASTER);
this_m.set_flag(TeamIndex::Team::Member::Flag::IS_LEADER);
other_m.clear_flag(TeamIndex::Team::Member::Flag::IS_LEADER);
other_m.set_flag(TeamIndex::Team::Member::Flag::IS_MASTER);
s->team_index->change_master(c->license->serial_number, cmd.guild_card_number);
send_command(c, 0x11EA, 0x00000000);
send_updates_for_this_m = true;
send_updates_for_other_m = true;
break;
@@ -4705,8 +4700,8 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
if (send_updates_for_other_m) {
try {
auto other_c = s->find_client(nullptr, cmd.guild_card_number);
send_update_team_metadata_for_client(c);
send_team_membership_info(c);
send_update_team_metadata_for_client(other_c);
send_team_membership_info(other_c);
} catch (const out_of_range&) {
}
}
@@ -4720,83 +4715,37 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
send_all_nearby_team_metadatas_to_client(c, false);
break;
case 0x18EA: // Ranking information
send_team_rank_info(c);
send_intra_team_ranking(c);
break;
case 0x19EA: {
S_TeamRewardList_BB_19EA cmd = {0};
send_command_t(c, 0x19EA, 0x00000000, cmd);
break;
}
case 0x1AEA: // Get team rewards available for purchase
send_team_rewards_available_for_purchase(c);
case 0x19EA: // List purchased team rewards
case 0x1AEA: // List team rewards available for purchase
send_team_reward_list(c, (command == 0x19EA));
break;
case 0x1BEA: { // Buy team reward
auto team = c->team();
if (team) {
check_size_v(data.size(), 0); // No data should be sent
bool should_send_update_reward_flags = false;
switch (flag) {
case TeamRewardMenuItemID::TEAM_FLAG:
team->set_reward_flag(TeamIndex::Team::RewardFlag::TEAM_FLAG);
should_send_update_reward_flags = true;
break;
case TeamRewardMenuItemID::DRESSING_ROOM:
team->set_reward_flag(TeamIndex::Team::RewardFlag::DRESSING_ROOM);
should_send_update_reward_flags = true;
break;
case TeamRewardMenuItemID::MEMBERS_20_LEADERS_3:
if (team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_20_LEADERS_3) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_40_LEADERS_5) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_70_LEADERS_8) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_100_LEADERS_10)) {
throw runtime_error("team size upgrades purchased out of order");
}
team->set_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_20_LEADERS_3);
should_send_update_reward_flags = true;
break;
case TeamRewardMenuItemID::MEMBERS_40_LEADERS_5:
if (!team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_20_LEADERS_3) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_40_LEADERS_5) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_70_LEADERS_8) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_100_LEADERS_10)) {
throw runtime_error("team size upgrades purchased out of order");
}
team->set_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_40_LEADERS_5);
should_send_update_reward_flags = true;
break;
case TeamRewardMenuItemID::MEMBERS_70_LEADERS_8:
if (!team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_20_LEADERS_3) ||
!team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_40_LEADERS_5) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_70_LEADERS_8) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_100_LEADERS_10)) {
throw runtime_error("team size upgrades purchased out of order");
}
team->set_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_70_LEADERS_8);
should_send_update_reward_flags = true;
break;
case TeamRewardMenuItemID::MEMBERS_100_LEADERS_10:
if (!team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_20_LEADERS_3) ||
!team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_40_LEADERS_5) ||
!team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_70_LEADERS_8) ||
team->check_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_100_LEADERS_10)) {
throw runtime_error("team size upgrades purchased out of order");
}
team->set_reward_flag(TeamIndex::Team::RewardFlag::MEMBERS_100_LEADERS_10);
should_send_update_reward_flags = true;
break;
// TODO: Implement all the following cases
// case POINT_OF_DISASTER:
// case TOYS_TWILIGHT:
// case COMMANDER_BLADE:
// case UNION_GUARD:
// case TEAM_POINTS_500:
// case TEAM_POINTS_1000:
// case TEAM_POINTS_5000:
// case TEAM_POINTS_10000:
default:
throw runtime_error("incorrect team reward ID");
const auto& reward = s->team_index->reward_definitions().at(flag);
for (const auto& key : reward.prerequisite_keys) {
if (!team->has_reward(key)) {
throw runtime_error("not all prerequisite rewards have been purchased");
}
}
if (should_send_update_reward_flags) {
if (reward.is_unique && team->has_reward(reward.key)) {
throw runtime_error("team reward already purchased");
}
if (!reward.reward_item.empty()) {
// TODO: How do we do this? Do we just send a 6xBE in the lobby?
// (Once this is figured out, don't forget to move this block to after
// the reward is actually purchased)
throw runtime_error("team reward items are not implemented");
}
s->team_index->buy_reward(team->team_id, reward.key, reward.team_points, reward.reward_flag);
if (reward.reward_flag != TeamIndex::Team::RewardFlag::NONE) {
for (const auto& it : team->members) {
try {
auto member_c = s->find_client(nullptr, it.second.serial_number);
@@ -4809,7 +4758,8 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
break;
}
case 0x1CEA:
throw runtime_error("team subcommand is not yet implemented");
send_cross_team_ranking(c);
break;
default:
throw runtime_error("invalid team command");
}