diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 6d32c5760..fc259e34a 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -662,6 +662,14 @@ namespace lfg if (isRaid && grp && (grp->isLFGGroup() || guid != grp->GetLeaderGUID())) return; + // Do not allow to change dungeon in the middle of a current dungeon + if (!isRaid && isContinue && grp->GetMembersCount() == 5) + { + dungeons.clear(); + dungeons.insert(GetDungeon(gguid)); + joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS; + } + // Can't join. Send result if (joinData.result != LFG_JOIN_OK) { @@ -1603,6 +1611,18 @@ namespace lfg _SaveToDB(gguid); + // Select a player inside to be teleported to + WorldLocation const* teleportLocation = nullptr; + for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next()) + { + Player* plr = itr->GetSource(); + if (plr && plr->GetMapId() == uint32(dungeon->map) && !proposal.isNew) + { + teleportLocation = plr; + break; + } + } + bool randomDungeon = false; // Teleport Player for (LfgGuidList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it) @@ -1610,6 +1630,16 @@ namespace lfg { if (player->GetGroup() != grp) // pussywizard: could not add because group was full (some shitness happened) continue; + + if (player->GetMapId() == uint32(dungeon->map)) + { + // Remove bind to that map + if (!sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUID(), dungeon->map, player->GetDungeonDifficulty())) + { + sInstanceSaveMgr->PlayerUnbindInstance(player->GetGUID(), dungeon->map, player->GetDungeonDifficulty(), true); + } + } + // Add the cooldown spell if queued for a random dungeon // xinef: add aura if ((randomDungeon || selectedRandomLfgDungeon(player->GetGUID())) && !player->HasAura(LFG_SPELL_DUNGEON_COOLDOWN)) @@ -1617,7 +1647,8 @@ namespace lfg randomDungeon = true; player->AddAura(LFG_SPELL_DUNGEON_COOLDOWN, player); } - TeleportPlayer(player, false); + + TeleportPlayer(player, false, teleportLocation); } if (randomDungeon) @@ -1952,7 +1983,7 @@ namespace lfg @param[in] out Teleport out (true) or in (false) @param[in] fromOpcode Function called from opcode handlers? (Default false) */ - void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*/) + void LFGMgr::TeleportPlayer(Player* player, bool out, WorldLocation const* teleportLocation /*= nullptr*/) { LFGDungeonData const* dungeon = nullptr; Group* group = player->GetGroup(); @@ -1986,7 +2017,7 @@ namespace lfg error = LFG_TELEPORTERROR_IN_VEHICLE; else if (player->GetCharmGUID()) error = LFG_TELEPORTERROR_CHARMING; - else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance + else { uint32 mapid = dungeon->map; float x = dungeon->x; @@ -1994,32 +2025,21 @@ namespace lfg float z = dungeon->z; float orientation = dungeon->o; - if (!fromOpcode) + if (teleportLocation) { - // Select a player inside to be teleported to - for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) - { - Player* plrg = itr->GetSource(); - if (plrg && plrg != player && plrg->GetMapId() == uint32(dungeon->map)) - { - mapid = plrg->GetMapId(); - x = plrg->GetPositionX(); - y = plrg->GetPositionY(); - z = plrg->GetPositionZ(); - orientation = plrg->GetOrientation(); - break; - } - } + teleportLocation->GetWorldLocation(mapid, x, y, z, orientation); } - if (!player->GetMap()->IsDungeon()) + if (!player->GetMap()->IsDungeon() || player->GetEntryPoint().GetMapId() == MAPID_INVALID) + { player->SetEntryPoint(); + } - if (!player->TeleportTo(mapid, x, y, z, orientation)) + if (!player->TeleportTo(mapid, x, y, z, orientation, 0, nullptr, mapid == player->GetMapId())) + { error = LFG_TELEPORTERROR_INVALID_LOCATION; + } } - else - error = LFG_TELEPORTERROR_INVALID_LOCATION; if (error != LFG_TELEPORTERROR_OK) player->GetSession()->SendLfgTeleportError(uint8(error)); diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index c8c253afe..7b289bd07 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -18,6 +18,7 @@ class Group; class Player; class Quest; +class WorldLocation; namespace lfg { @@ -500,7 +501,7 @@ namespace lfg /// Returns all random and seasonal dungeons for given level and expansion LfgDungeonSet GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion); /// Teleport a player to/from selected dungeon - void TeleportPlayer(Player* player, bool out, bool fromOpcode = false); + void TeleportPlayer(Player* player, bool out, WorldLocation const* teleportLocation = nullptr); /// Inits new proposal to boot a player void InitBoot(ObjectGuid gguid, ObjectGuid kicker, ObjectGuid victim, std::string const& reason); /// Updates player boot proposal with new player answer diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index e43080c14..e81768ad1 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -15,12 +15,15 @@ */ #include "Containers.h" +#include "DBCStores.h" #include "Group.h" +#include "InstanceScript.h" #include "LFGMgr.h" #include "LFGQueue.h" #include "Log.h" #include "ObjectDefines.h" #include "ObjectMgr.h" +#include "Player.h" #include "World.h" namespace lfg @@ -397,9 +400,8 @@ namespace lfg return LFG_COMPATIBLES_WITH_LESS_PLAYERS; } - ObjectGuid gguid = check.front(); proposal.queues = strGuids; - proposal.isNew = numLfgGroups != 1 || sLFGMgr->GetOldState(gguid) != LFG_STATE_DUNGEON; + proposal.isNew = numLfgGroups != 1 || sLFGMgr->GetOldState(proposal.group) != LFG_STATE_DUNGEON; if (!sLFGMgr->AllQueued(check)) // can't create proposal return LFG_COMPATIBILITY_PENDING; @@ -410,6 +412,7 @@ namespace lfg proposal.leader.Clear(); proposal.dungeonId = Acore::Containers::SelectRandomContainerElement(proposalDungeons); + uint32 completedEncounters = 0; bool leader = false; for (LfgRolesMap::const_iterator itRoles = proposalRoles.begin(); itRoles != proposalRoles.end(); ++itRoles) { @@ -429,8 +432,27 @@ namespace lfg data.group = proposalGroups.find(itRoles->first)->second; if (!proposal.isNew && data.group && data.group == proposal.group) // Player from existing group, autoaccept data.accept = LFG_ANSWER_AGREE; + + if (!completedEncounters && !proposal.isNew) + { + if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(proposal.dungeonId)) + { + if (Player* player = ObjectAccessor::FindConnectedPlayer(itRoles->first)) + { + if (player->GetMapId() == static_cast(dungeon->map)) + { + if (InstanceScript* instance = player->GetInstanceScript()) + { + completedEncounters = instance->GetCompletedEncounterMask(); + } + } + } + } + } } + proposal.encounters = completedEncounters; + for (uint8 i = 0; i < 5 && proposal.queues.guids[i]; ++i) RemoveFromQueue(proposal.queues.guids[i], true); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 0ab4fafde..01b8a1955 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -666,11 +666,49 @@ public: Relocate(x, y, z, o); } + void SetMapId(uint32 mapId) + { + m_mapId = mapId; + } + [[nodiscard]] uint32 GetMapId() const { return m_mapId; } + void GetWorldLocation(uint32& mapId, float& x, float& y) const + { + mapId = m_mapId; + x = m_positionX; + y = m_positionY; + } + + void GetWorldLocation(uint32& mapId, float& x, float& y, float& z) const + { + mapId = m_mapId; + x = m_positionX; + y = m_positionY; + z = m_positionZ; + } + + void GetWorldLocation(uint32& mapId, float& x, float& y, float& z, float& o) const + { + mapId = m_mapId; + x = m_positionX; + y = m_positionY; + z = m_positionZ; + o = m_orientation; + } + + void GetWorldLocation(WorldLocation* location) const + { + if (location) + { + location->Relocate(m_positionX, m_positionY, m_positionZ, m_orientation); + location->SetMapId(m_mapId); + } + } + [[nodiscard]] WorldLocation GetWorldLocation() const { return *this; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9c4280cb0..b43dbc723 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1277,7 +1277,7 @@ void Player::SendTeleportAckPacket() GetSession()->SendPacket(&data); } -bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options /*= 0*/, Unit* target /*= nullptr*/) +bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options /*= 0*/, Unit* target /*= nullptr*/, bool newInstance /*= false*/) { // for except kick by antispeedhack sScriptMgr->AnticheatSetSkipOnePacketForASH(this, true); @@ -1378,7 +1378,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!sScriptMgr->OnBeforePlayerTeleport(this, mapid, x, y, z, orientation, options, target)) return false; - if (GetMapId() == mapid) + if (GetMapId() == mapid && !newInstance) { //lets reset far teleport flag if it wasn't reset during chained teleports SetSemaphoreTeleportFar(0); @@ -1547,9 +1547,15 @@ bool Player::TeleportToEntryPoint() ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE); ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE); - if (m_entryPointData.joinPos.m_mapId == MAPID_INVALID) + WorldLocation loc = m_entryPointData.joinPos; + m_entryPointData.joinPos.m_mapId = MAPID_INVALID; + + if (loc.m_mapId == MAPID_INVALID) + { return TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); - return TeleportTo(m_entryPointData.joinPos); + } + + return TeleportTo(loc); } void Player::ProcessDelayedOperations() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e89adb2c7..87ad00cc1 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -992,7 +992,7 @@ public: return GetSession()->GetSessionDbLocaleIndex() == LOCALE_esES || GetSession()->GetSessionDbLocaleIndex() == LOCALE_esMX; } - bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0, Unit* target = nullptr); + bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0, Unit* target = nullptr, bool newInstance = false); bool TeleportTo(WorldLocation const& loc, uint32 options = 0, Unit* target = nullptr) { return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options, target); diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index 6f7dcf716..90e371fed 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -119,8 +119,19 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) } Group* group = GetPlayer()->GetGroup(); - if (group && (group->isBGGroup() || group->isBFGroup())) - group = GetPlayer()->GetOriginalGroup(); + if (group) + { + if (group->isLFGGroup() && group->IsLfgRandomInstance()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_TARGET_NOT_IN_INSTANCE_S); + return; + } + + if (group->isBGGroup() || group->isBFGroup()) + { + group = GetPlayer()->GetOriginalGroup(); + } + } Group* group2 = player->GetGroup(); if (group2 && (group2->isBGGroup() || group2->isBFGroup())) diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index a832dcd04..2948c33bb 100644 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -151,7 +151,7 @@ void WorldSession::HandleLfgTeleportOpcode(WorldPacket& recvData) recvData >> out; LOG_DEBUG("network", "CMSG_LFG_TELEPORT [%s] out: %u", GetPlayer()->GetGUID().ToString().c_str(), out ? 1 : 0); - sLFGMgr->TeleportPlayer(GetPlayer(), out, true); + sLFGMgr->TeleportPlayer(GetPlayer(), out); } void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*/)