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: