From 1d24432e47938bc9bcc3614f2137c30edb17c07f Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Tue, 8 Sep 2020 23:44:26 -0400 Subject: [PATCH] Truncate expedition members to max on creation This implements the new behavior from live's September 16, 2020 (test server's September 8, 2020) patch Expeditions can be created even when the client's group or raid exceeds the expedition's max player requirement. Members are added until the max player count is reached and the rest are ignored. Raid members are added ordered by their raid group number with ungrouped members having the lowest priority Rename expedition request method ValidateMembers to CanMembersJoin Change some expedition messages to System color (live changes) --- zone/expedition.cpp | 14 +++++++--- zone/expedition.h | 1 + zone/expedition_request.cpp | 55 +++++++++++++++++++++++++++++-------- zone/expedition_request.h | 4 ++- zone/raids.cpp | 13 +++++++++ zone/raids.h | 2 ++ 6 files changed, 72 insertions(+), 17 deletions(-) diff --git a/zone/expedition.cpp b/zone/expedition.cpp index a955a6661..27a3d9324 100644 --- a/zone/expedition.cpp +++ b/zone/expedition.cpp @@ -40,6 +40,8 @@ const char* const EXPEDITION_OTHER_BELONGS = "{} attempted to create an expedi const char* const DZADD_INVITE_WARNING = "Warning! You will be given replay timers for the following events if you enter %s:"; const char* const DZADD_INVITE_WARNING_TIMER = "%s - %sD:%sH:%sM"; const char* const KICKPLAYERS_EVERYONE = "Everyone"; +// message string 8312 added in September 08 2020 Test patch (used by both dz and shared tasks) +const char* const CREATE_NOT_ALL_ADDED = "Not all players in your {} were added to the {}. The {} can take a maximum of {} players, and your {} has {}."; const int32_t Expedition::REPLAY_TIMER_ID = -1; const int32_t Expedition::EVENT_TIMER_ID = 1; @@ -130,10 +132,14 @@ Expedition* Expedition::TryCreate( inserted.first->second->SendUpdatesToZoneMembers(); inserted.first->second->SendWorldExpeditionUpdate(ServerOP_ExpeditionCreate); // cache in other zones + inserted.first->second->SendLeaderMessage(request.GetLeaderClient(), + Chat::System, EXPEDITION_AVAILABLE, { request.GetExpeditionName() }); - inserted.first->second->SendLeaderMessage( - request.GetLeaderClient(), Chat::Yellow, EXPEDITION_AVAILABLE, { request.GetExpeditionName() } - ); + if (!request.GetNotAllAddedMessage().empty()) + { + Client::SendCrossZoneMessage(request.GetLeaderClient(), request.GetLeaderName(), + Chat::System, request.GetNotAllAddedMessage()); + } return inserted.first->second.get(); } @@ -889,7 +895,7 @@ bool Expedition::ConfirmLeaderCommand(Client* requester) if (leader.char_id != requester->CharacterID()) { - requester->MessageString(Chat::Red, EXPEDITION_NOT_LEADER, leader.name.c_str()); + requester->MessageString(Chat::System, EXPEDITION_NOT_LEADER, leader.name.c_str()); return false; } diff --git a/zone/expedition.h b/zone/expedition.h index 611ad6c0c..490fd1f44 100644 --- a/zone/expedition.h +++ b/zone/expedition.h @@ -38,6 +38,7 @@ class ServerPacket; extern const char* const DZ_YOU_NOT_ASSIGNED; extern const char* const EXPEDITION_OTHER_BELONGS; +extern const char* const CREATE_NOT_ALL_ADDED; enum class ExpeditionMemberStatus : uint8_t { diff --git a/zone/expedition_request.cpp b/zone/expedition_request.cpp index 474c1de08..5013d49a4 100644 --- a/zone/expedition_request.cpp +++ b/zone/expedition_request.cpp @@ -30,6 +30,8 @@ extern WorldServer worldserver; +constexpr char SystemName[] = "expedition"; + struct ExpeditionRequestConflict { std::string character_name; @@ -75,7 +77,7 @@ bool ExpeditionRequest::Validate(Client* requester) m_leader = m_requester; m_leader_id = m_requester->CharacterID(); m_leader_name = m_requester->GetName(); - requirements_met = ValidateMembers({m_leader_name}); + requirements_met = CanMembersJoin({m_leader_name}); } auto elapsed = benchmark.elapsed(); @@ -90,16 +92,34 @@ bool ExpeditionRequest::CanRaidRequest(Raid* raid) m_leader_name = raid->leadername; m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(raid->leadername); - std::vector member_names; - for (int i = 0; i < MAX_RAID_MEMBERS; ++i) + // live (as of September 16, 2020) supports creation even if raid count exceeds + // expedition max. members are added up to the max ordered by group number. + auto raid_members = raid->GetMembers(); + + if (raid_members.size() > m_max_players) { - if (raid->members[i].membername[0]) - { - member_names.emplace_back(raid->members[i].membername); - } + // stable_sort not needed, order within a raid group may not be what is displayed + std::sort(raid_members.begin(), raid_members.end(), + [&](const RaidMember& lhs, const RaidMember& rhs) { + if (m_leader_name == lhs.membername) { // leader always added first + return true; + } else if (m_leader_name == rhs.membername) { + return false; + } + return lhs.GroupNumber < rhs.GroupNumber; + }); + + m_not_all_added_msg = fmt::format(CREATE_NOT_ALL_ADDED, "raid", SystemName, + SystemName, m_max_players, "raid", raid_members.size()); } - return ValidateMembers(member_names); + std::vector member_names; + for (int i = 0; i < raid_members.size() && member_names.size() < m_max_players; ++i) + { + member_names.emplace_back(raid_members[i].membername); + } + + return CanMembersJoin(member_names); } bool ExpeditionRequest::CanGroupRequest(Group* group) @@ -109,20 +129,31 @@ bool ExpeditionRequest::CanGroupRequest(Group* group) { m_leader = group->GetLeader()->CastToClient(); } + // Group::GetLeaderName() is broken if group formed across zones, ask database instead m_leader_name = m_leader ? m_leader->GetName() : GetGroupLeaderName(group->GetID()); // group->GetLeaderName(); m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(m_leader_name.c_str()); std::vector member_names; + member_names.emplace_back(m_leader_name); // leader always added first + for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) { - if (group->membername[i][0]) + if (group->membername[i][0] && m_leader_name != group->membername[i]) { member_names.emplace_back(group->membername[i]); } } - return ValidateMembers(member_names); + if (member_names.size() > m_max_players) + { + m_not_all_added_msg = fmt::format(CREATE_NOT_ALL_ADDED, "group", SystemName, + SystemName, m_max_players, "group", member_names.size()); + + member_names.resize(m_max_players); + } + + return CanMembersJoin(member_names); } std::string ExpeditionRequest::GetGroupLeaderName(uint32_t group_id) @@ -132,7 +163,7 @@ std::string ExpeditionRequest::GetGroupLeaderName(uint32_t group_id) return std::string(leader_name_buffer); } -bool ExpeditionRequest::ValidateMembers(const std::vector& member_names) +bool ExpeditionRequest::CanMembersJoin(const std::vector& member_names) { if (member_names.empty()) { @@ -354,7 +385,7 @@ bool ExpeditionRequest::IsPlayerCountValidated(uint32_t member_count) { requirements_met = false; - SendLeaderMessage(Chat::Red, REQUIRED_PLAYER_COUNT, { + SendLeaderMessage(Chat::System, REQUIRED_PLAYER_COUNT, { fmt::format_int(member_count).str(), fmt::format_int(m_min_players).str(), fmt::format_int(m_max_players).str() diff --git a/zone/expedition_request.h b/zone/expedition_request.h index d0afb46c0..cf1151771 100644 --- a/zone/expedition_request.h +++ b/zone/expedition_request.h @@ -47,13 +47,14 @@ public: Client* GetLeaderClient() const { return m_leader; } uint32_t GetLeaderID() const { return m_leader_id; } const std::string& GetLeaderName() const { return m_leader_name; } + const std::string& GetNotAllAddedMessage() const { return m_not_all_added_msg; } uint32_t GetMinPlayers() const { return m_min_players; } uint32_t GetMaxPlayers() const { return m_max_players; } std::vector GetMembers() const { return m_members; } std::unordered_map GetLockouts() const { return m_lockouts; } private: - bool ValidateMembers(const std::vector& member_names); + bool CanMembersJoin(const std::vector& member_names); bool CanRaidRequest(Raid* raid); bool CanGroupRequest(Group* group); bool CheckMembersForConflicts(const std::vector& member_names); @@ -74,6 +75,7 @@ private: bool m_disable_messages = false; std::string m_expedition_name; std::string m_leader_name; + std::string m_not_all_added_msg; std::vector m_members; std::unordered_map m_lockouts; }; diff --git a/zone/raids.cpp b/zone/raids.cpp index 51c52d8d4..386eb70ac 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1849,3 +1849,16 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re } } } + +std::vector Raid::GetMembers() const +{ + std::vector raid_members; + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) + { + if (members[i].membername[0]) + { + raid_members.emplace_back(members[i]); + } + } + return raid_members; +} diff --git a/zone/raids.h b/zone/raids.h index 26ba90a02..1e771e03d 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -239,6 +239,8 @@ public: void QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required = true, bool ignore_sender = true, float distance = 0, bool group_only = true); + std::vector GetMembers() const; + RaidMember members[MAX_RAID_MEMBERS]; char leadername[64]; protected: