diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/server/game/DungeonFinding/LFGMgr.cpp | 115 | ||||
-rwxr-xr-x | src/server/game/DungeonFinding/LFGMgr.h | 8 | ||||
-rwxr-xr-x | src/server/game/Entities/Player/Player.cpp | 96 | ||||
-rwxr-xr-x | src/server/game/Entities/Player/Player.h | 1 | ||||
-rwxr-xr-x | src/server/game/Groups/Group.cpp | 121 | ||||
-rwxr-xr-x | src/server/game/Groups/Group.h | 3 | ||||
-rw-r--r-- | src/server/game/Groups/GroupMgr.cpp | 8 | ||||
-rwxr-xr-x | src/server/game/Groups/GroupReference.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp | 14 | ||||
-rwxr-xr-x | src/server/game/Server/Protocol/Handlers/LFGHandler.cpp | 3 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_generic.cpp | 12 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.cpp | 4 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.h | 3 |
13 files changed, 339 insertions, 53 deletions
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index e0a16d4868b..0f146598a6e 100755 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -72,6 +72,54 @@ LFGMgr::~LFGMgr() delete it->second; } +void LFGMgr::_LoadFromDB(Field* fields, uint64 guid) +{ + if (!fields) + return; + + if (!IS_GROUP(guid)) + return; + + uint32 dungeon = fields[16].GetUInt32(); + + uint8 state = fields[17].GetUInt8(); + + if (!dungeon || !state) + return; + + SetDungeon(guid, dungeon); + + switch (state) + { + case LFG_STATE_DUNGEON: + case LFG_STATE_FINISHED_DUNGEON: + SetState(guid, (LfgState)state); + break; + default: + break; + } +} + +void LFGMgr::_SaveToDB(uint64 guid, uint32 db_guid) +{ + if (!IS_GROUP(guid)) + return; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA); + + stmt->setUInt32(0, db_guid); + + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LFG_DATA); + stmt->setUInt32(0, db_guid); + + stmt->setUInt32(1, GetDungeon(guid)); + stmt->setUInt32(2, GetState(guid)); + + CharacterDatabase.Execute(stmt); +} + /// Load rewards for completing dungeons void LFGMgr::LoadRewards() { @@ -245,7 +293,8 @@ void LFGMgr::Update(uint32 diff) UpdateProposal(m_lfgProposalId, guid, true); } else - currentQueue.push_back(frontguid); // Lfg group not found, add this group to the queue. + if (std::find(currentQueue.begin(), currentQueue.end(), frontguid) == currentQueue.end()) //already in queue? + currentQueue.push_back(frontguid); // Lfg group not found, add this group to the queue. firstNew.clear(); } } @@ -382,7 +431,10 @@ void LFGMgr::InitializeLockedDungeons(Player* player) else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player)) locktype = LFG_LOCKSTATUS_RAID_LOCKED; else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty))) - locktype = LFG_LOCKSTATUS_RAID_LOCKED; + { + if (!player->GetGroup() || !player->GetGroup()->isLFGGroup() || GetDungeon(player->GetGroup()->GetGUID(), true) != dungeon->ID || GetState(player->GetGroup()->GetGUID()) != LFG_STATE_DUNGEON) + locktype = LFG_LOCKSTATUS_RAID_LOCKED; + } else if (dungeon->minlevel > level) locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL; else if (dungeon->maxlevel < level) @@ -808,7 +860,7 @@ bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal) { uint64 guid = (*it); LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(guid); - if (itQueue == m_QueueInfoMap.end()) + if (itQueue == m_QueueInfoMap.end() || GetState(guid) != LFG_STATE_QUEUED) { sLog->outError("LFGMgr::CheckCompatibility: [" UI64FMTD "] is not queued but listed as queued!", (*it)); RemoveFromQueue(guid); @@ -923,6 +975,42 @@ bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal) if (numPlayers != MAXGROUPSIZE) { sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Compatibles but not match. Players(%u)", strGuids.c_str(), numPlayers); + uint8 Tanks_Needed = LFG_TANKS_NEEDED; + uint8 Healers_Needed = LFG_HEALERS_NEEDED; + uint8 Dps_Needed = LFG_DPS_NEEDED; + for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue) + { + LfgQueueInfo* queue = itQueue->second; + for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) + { + uint8 roles = itPlayer->second; + if ((roles & ROLE_TANK) && Tanks_Needed > 0) + --Tanks_Needed; + else if ((roles & ROLE_HEALER) && Healers_Needed > 0) + --Healers_Needed; + else if ((roles & ROLE_DAMAGE) && Dps_Needed > 0) + --Dps_Needed; + } + } + for (PlayerSet::const_iterator itPlayers = players.begin(); itPlayers != players.end(); ++itPlayers) + { + for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue) + { + LfgQueueInfo* queue = itQueue->second; + if (!queue) + continue; + + for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) + { + if (*itPlayers == ObjectAccessor::FindPlayer(itPlayer->first)) + { + queue->tanks = Tanks_Needed; + queue->healers = Healers_Needed; + queue->dps = Dps_Needed; + } + } + } + } return true; } sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) MATCH! Group formed", strGuids.c_str()); @@ -1078,6 +1166,11 @@ void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* } m_QueueInfoMap[gguid] = pqInfo; + if(GetState(gguid) != LFG_STATE_NONE) + { + LfgGuidList& currentQueue = m_currentQueue[team]; + currentQueue.push_front(gguid); + } AddToQueue(gguid, team); } @@ -1384,6 +1477,7 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) break; } } + m_teleport.push_back(pguid); grp->SetLfgRoles(pguid, pProposal->players[pguid]->role); SetState(pguid, LFG_STATE_DUNGEON); } @@ -1395,6 +1489,7 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) uint64 gguid = grp->GetGUID(); SetDungeon(gguid, dungeon->Entry()); SetState(gguid, LFG_STATE_DUNGEON); + _SaveToDB(gguid, grp->GetDbStoreId()); // Remove players/groups from Queue for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it) @@ -1509,7 +1604,9 @@ void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType t for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it) { uint64 guid = *it; - AddToQueue(guid, team); + LfgGuidList& currentQueue = m_currentQueue[team]; + currentQueue.push_front(guid); //Add GUID for high priority + AddToQueue(guid, team); //We have to add each GUID in newQueue to check for a new groups } delete pProposal; @@ -1921,6 +2018,16 @@ const std::string& LFGMgr::GetComment(uint64 guid) return m_Players[guid].GetComment(); } +bool LFGMgr::IsTeleported(uint64 pguid) +{ + if (std::find(m_teleport.begin(), m_teleport.end(), pguid) != m_teleport.end()) + { + m_teleport.remove(pguid); + return true; + } + return false; +} + const LfgDungeonSet& LFGMgr::GetSelectedDungeons(uint64 guid) { sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetSelectedDungeons: [" UI64FMTD "]", guid); diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 3e324f4b5f4..d10902b9553 100755 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -287,6 +287,9 @@ class LFGMgr void InitializeLockedDungeons(Player* player); + void _LoadFromDB(Field* fields, uint64 guid); + void _SaveToDB(uint64 guid, uint32 db_guid); + void SetComment(uint64 guid, const std::string& comment); const LfgLockMap& GetLockedDungeons(uint64 guid); LfgState GetState(uint64 guid); @@ -298,7 +301,9 @@ class LFGMgr void RemoveGroupData(uint64 guid); uint8 GetKicksLeft(uint64 gguid); uint8 GetVotesNeeded(uint64 gguid); + bool IsTeleported(uint64 pguid); void SetRoles(uint64 guid, uint8 roles); + void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons); private: @@ -306,10 +311,8 @@ class LFGMgr const std::string& GetComment(uint64 gguid); void RestoreState(uint64 guid); void SetDungeon(uint64 guid, uint32 dungeon); - void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons); void SetLockedDungeons(uint64 guid, const LfgLockMap& lock); void DecreaseKicksLeft(uint64 guid); - void NoExiste(uint8 lala); // Queue void AddToQueue(uint64 guid, uint8 queueId); @@ -352,6 +355,7 @@ class LFGMgr LfgGuidListMap m_currentQueue; ///< Ordered list. Used to find groups LfgGuidListMap m_newToQueue; ///< New groups to add to queue LfgCompatibleMap m_CompatibleMap; ///< Compatible dungeons + LfgGuidList m_teleport; ///< Players being teleported // Rolecheck - Proposal - Vote Kicks LfgRoleCheckMap m_RoleChecks; ///< Current Role checks LfgProposalMap m_Proposals; ///< Current Proposals diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 46f903ee71a..6a4b729e58a 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2305,9 +2305,14 @@ bool Player::TeleportToBGEntryPoint() if (m_bgData.joinPos.m_mapId == MAPID_INVALID) return false; + Group* group = GetGroup(); + if (group && group->isLFGGroup() && group->GetMembersCount() == 1) + group->Disband(); + else + ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE); + ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE); ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE); - ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE); return TeleportTo(m_bgData.joinPos); } @@ -7371,6 +7376,22 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) SendInitWorldStates(newZone, newArea); // only if really enters to new zone, not just area change, works strange... } + // group update + if (GetGroup()) + { + SetGroupUpdateFlag(GROUP_UPDATE_FULL); + Group* grp = GetGroup(); + if (GetSession() && grp->isLFGGroup() && sLFGMgr->IsTeleported(GetGUID())) + { + for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* tempplr = itr->getSource(); + if (tempplr) + GetSession()->SendNameQueryOpcode(tempplr->GetGUID()); + } + } + } + m_zoneUpdateId = newZone; m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; @@ -7458,10 +7479,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) // recent client version not send leave/join channel packets for built-in local channels UpdateLocalChannels(newZone); - // group update - if (GetGroup()) - SetGroupUpdateFlag(GROUP_UPDATE_FULL); - UpdateZoneDependentAuras(newZone); } @@ -11794,6 +11811,75 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const return EQUIP_ERR_ITEM_NOT_FOUND; } +InventoryResult Player::CanRollForItem(ItemTemplate const* proto) const +{ + if (!proto) + return EQUIP_ERR_ITEM_NOT_FOUND; + // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player + + const static uint32 item_weapon_skills[MAX_ITEM_SUBCLASS_WEAPON] = + { + SKILL_AXES, SKILL_2H_AXES, SKILL_BOWS, SKILL_GUNS, SKILL_MACES, + SKILL_2H_MACES, SKILL_POLEARMS, SKILL_SWORDS, SKILL_2H_SWORDS, 0, + SKILL_STAVES, 0, 0, SKILL_FIST_WEAPONS, 0, + SKILL_DAGGERS, SKILL_THROWN, SKILL_ASSASSINATION, SKILL_CROSSBOWS, SKILL_WANDS, + SKILL_FISHING + }; //Copy from function Item::GetSkill() + + if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0) + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + + if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell)) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + + if (proto->RequiredSkill != 0) + { + if (!GetSkillValue(proto->RequiredSkill)) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank) + return EQUIP_ERR_CANT_EQUIP_SKILL; + } + + uint8 _class = getClass(); + + if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + + if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass > ITEM_SUBCLASS_ARMOR_MISC && proto->SubClass < ITEM_SUBCLASS_ARMOR_BUCKLER && proto->InventoryType != INVTYPE_CLOAK) + { + if (_class == CLASS_WARRIOR || _class == CLASS_PALADIN || _class == CLASS_DEATH_KNIGHT) + { + if (getLevel() < 40) + { + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_PLATE) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + else if (_class == CLASS_HUNTER || _class == CLASS_SHAMAN) + { + if (getLevel() < 40) + { + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + + if (_class == CLASS_ROGUE || _class == CLASS_DRUID) + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + + if (_class == CLASS_MAGE || _class == CLASS_PRIEST || _class == CLASS_WARLOCK) + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_CLOTH) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + + return EQUIP_ERR_OK; +} + InventoryResult Player::CanUseAmmo(uint32 item) const { sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanUseAmmo item = %u", item); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index aa1d4e8185e..2b8ea7bbdc8 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1277,6 +1277,7 @@ class Player : public Unit, public GridObject<Player> bool HasItemTotemCategory(uint32 TotemCategory) const; InventoryResult CanUseItem(ItemTemplate const* pItem) const; InventoryResult CanUseAmmo(uint32 item) const; + InventoryResult CanRollForItem(ItemTemplate const* item) const; Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, int32 randomPropertyId = 0); Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, int32 randomPropertyId, AllowedLooterSet &allowedLooters); Item* StoreItem(ItemPosCountVec const& pos, Item* pItem, bool update); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 49472880edd..b2fb59ea993 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -190,6 +190,9 @@ void Group::LoadGroupFromDB(Field* fields) m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; else m_raidDifficulty = Difficulty(r_diff); + + if (m_groupType & GROUPTYPE_LFG) + sLFGMgr->_LoadFromDB(fields, GetGUID()); } void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup, uint8 roles) @@ -211,6 +214,14 @@ void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup, m_memberSlots.push_back(member); SubGroupCounterIncrease(subgroup); + + if (isLFGGroup()) + { + LfgDungeonSet Dungeons; + Dungeons.insert(sLFGMgr->GetDungeon(GetGUID())); + sLFGMgr->SetSelectedDungeons(member.guid, Dungeons); + sLFGMgr->SetState(member.guid, sLFGMgr->GetState(GetGUID())); + } } void Group::ConvertToLFG() @@ -441,7 +452,7 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV return m_memberSlots.size(); // remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG allow 1 member group) - if (GetMembersCount() > (isBGGroup() ? 1u : 2u)) + if (GetMembersCount() > ((isBGGroup() || isLFGGroup()) ? 1u : 2u)) { Player* player = ObjectAccessor::FindPlayer(guid); if (player) @@ -485,6 +496,8 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV CharacterDatabase.Execute(stmt); + DelinkMember(guid); + // Reevaluate group enchanter if the leaving player had enchanting skill or the player is offline if ((player && player->GetSkillValue(SKILL_ENCHANTING)) || !player) ResetMaxEnchantingLevel(); @@ -534,6 +547,20 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV } SendUpdate(); + + if (isLFGGroup() && GetMembersCount() == 1) + { + Player* Leader = ObjectAccessor::FindPlayer(GetLeaderGUID()); + LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(sLFGMgr->GetDungeon(GetGUID())); + if ((Leader && dungeon && Leader->isAlive() && Leader->GetMapId() != dungeon->map) || !dungeon) + { + Disband(); + return false; + } + } + + if (m_memberMgr.getSize() < ((isLFGGroup() || isBGGroup()) ? 1u : 2u)) + Disband(); return true; } @@ -673,6 +700,10 @@ void Group::Disband(bool hideDestroy /* = false */) CharacterDatabase.CommitTransaction(trans); ResetInstances(INSTANCE_RESET_GROUP_DISBAND, false, NULL); ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, NULL); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA); + stmt->setUInt32(0, m_dbStoreId); + CharacterDatabase.Execute(stmt); sGroupMgr->FreeGroupDbStoreId(this); } @@ -709,6 +740,28 @@ void Group::SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll &r) } } +void Group::SendLootStartRollToPlayer(uint32 CountDown, uint32 mapid, Player* p, bool NeedBlocked, const Roll &r) +{ + if (!p || !p->GetSession()) + return; + + WorldPacket data(SMSG_LOOT_START_ROLL, (8 + 4 + 4 + 4 + 4 + 4 + 4 + 1 )); + data << uint64(r.itemGUID); // guid of rolled item + data << uint32(mapid); // 3.3.3 mapid + data << uint32(r.totalPlayersRolling); // maybe the number of players rolling for it??? + data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for + data << uint32(r.itemRandomSuffix); // randomSuffix + data << uint32(r.itemRandomPropId); // item random property ID + data << uint32(r.itemCount); // items in stack + data << uint32(CountDown); // the countdown time to choose "need" or "greed" + uint8 VoteMask = r.rollVoteMask; + if (NeedBlocked) + VoteMask &= ~ROLL_FLAG_TYPE_NEED; + data << uint8(VoteMask); // roll type mask + + p->GetSession()->SendPacket(&data); +} + void Group::SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r) { WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1+1)); @@ -887,7 +940,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) } } -void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject) +void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) { ItemTemplate const* item; uint8 itemSlot = 0; @@ -902,7 +955,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject) if (item->Quality >= uint32(m_lootThreshold)) { uint64 newitemGUID = MAKE_NEW_GUID(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), 0, HIGHGUID_ITEM); - Roll* r=new Roll(newitemGUID, *i); + Roll* r = new Roll(newitemGUID, *i); for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -911,21 +964,17 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject) continue; bool allowedForPlayer = i->AllowedForPlayer(playerToRoll); - if (playerToRoll->CanUseItem(item) == EQUIP_ERR_OK && allowedForPlayer) + if (allowedForPlayer && playerToRoll->IsWithinDistInMap(lootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) { - if (playerToRoll->IsWithinDistInMap(pLootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) + r->totalPlayersRolling++; + if (playerToRoll->GetPassOnGroupLoot()) { - r->totalPlayersRolling++; - - if (playerToRoll->GetPassOnGroupLoot()) - { - r->playerVote[playerToRoll->GetGUID()] = PASS; - r->totalPass++; - // can't broadcast the pass now. need to wait until all rolling players are known. - } - else - r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; + r->playerVote[playerToRoll->GetGUID()] = PASS; + r->totalPass++; + // can't broadcast the pass now. need to wait until all rolling players are known. } + else + r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; } } @@ -941,25 +990,24 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject) loot->items[itemSlot].is_blocked = true; - // If there is any "auto pass", broadcast the pass now. - if (r->totalPass) + //Broadcast Pass and Send Rollstart + for (Roll::PlayerVote::const_iterator itr=r->playerVote.begin(); itr != r->playerVote.end(); ++itr) { - for (Roll::PlayerVote::const_iterator itr=r->playerVote.begin(); itr != r->playerVote.end(); ++itr) - { - Player* p = ObjectAccessor::FindPlayer(itr->first); - if (!p || !p->GetSession()) - continue; - - if (itr->second == PASS) - SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); - } + Player* p = ObjectAccessor::FindPlayer(itr->first); + if (!p || !p->GetSession()) + continue; + + if (itr->second == PASS) + SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); + if (p->CanRollForItem(item) == EQUIP_ERR_OK) + SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, false, *r); + else + SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, true, *r); } - SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); - RollId.push_back(r); - if (Creature* creature = pLootedObject->ToCreature()) + if (Creature* creature = lootedObject->ToCreature()) { creature->m_groupLootTimer = 60000; creature->lootingGroupLowGUID = GetLowGUID(); @@ -1242,9 +1290,7 @@ void Group::SendTargetIconList(WorldSession* session) void Group::SendUpdate() { for (member_witerator witr = m_memberSlots.begin(); witr != m_memberSlots.end(); ++witr) - { SendUpdateToPlayer(witr->guid, &(*witr)); - } } void Group::SendUpdateToPlayer(uint64 playerGUID, MemberSlot* slot) @@ -2118,8 +2164,19 @@ void Group::LinkMember(GroupReference* pRef) m_memberMgr.insertFirst(pRef); } -void Group::DelinkMember(GroupReference* /*pRef*/) const +void Group::DelinkMember(uint64 guid) { + GroupReference* ref = m_memberMgr.getFirst(); + while (ref) + { + GroupReference* nextRef = ref->next(); + if (ref->getSource()->GetGUID() == guid) + { + ref->unlink(); + break; + } + ref = nextRef; + } } Group::BoundInstancesMap& Group::GetBoundInstances(Difficulty difficulty) diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index bed112d5511..caa49125100 100755 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -273,6 +273,7 @@ class Group bool isRollLootActive() const; void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll &r); + void SendLootStartRollToPlayer(uint32 CountDown, uint32 mapid, Player* p, bool NeedBlocked, const Roll &r); void SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r); void SendLootRollWon(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r); void SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r); @@ -289,7 +290,7 @@ class Group void ResetMaxEnchantingLevel(); void LinkMember(GroupReference* pRef); - void DelinkMember(GroupReference* /*pRef*/) const; + void DelinkMember(uint64 guid); InstanceGroupBind* BindToInstance(InstanceSave* save, bool permanent, bool load = false); void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp index 412814a60d2..ae400852c73 100644 --- a/src/server/game/Groups/GroupMgr.cpp +++ b/src/server/game/Groups/GroupMgr.cpp @@ -119,10 +119,10 @@ void GroupMgr::LoadGroups() // Delete all groups with less than 2 members CharacterDatabase.DirectExecute("DELETE FROM groups WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)"); - // 0 1 2 3 4 5 6 7 8 9 - QueryResult result = CharacterDatabase.PQuery("SELECT leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6" - // 10 11 12 13 14 15 - ", icon7, icon8, groupType, difficulty, raiddifficulty, guid FROM groups ORDER BY guid ASC"); + // 0 1 2 3 4 5 6 7 8 9 + QueryResult result = CharacterDatabase.PQuery("SELECT g.leaderGuid, g.lootMethod, g.looterGuid, g.lootThreshold, g.icon1, g.icon2, g.icon3, g.icon4, g.icon5, g.icon6" + // 10 11 12 13 14 15 16 17 + ", g.icon7, g.icon8, g.groupType, g.difficulty, g.raiddifficulty, g.guid, lfg.dungeon, lfg.state FROM groups g LEFT JOIN lfg_data lfg ON lfg.guid = g.guid ORDER BY g.guid ASC"); if (!result) { sLog->outString(">> Loaded 0 group definitions. DB table `groups` is empty!"); diff --git a/src/server/game/Groups/GroupReference.cpp b/src/server/game/Groups/GroupReference.cpp index 4d5890aa4e6..68d85c5bce9 100755 --- a/src/server/game/Groups/GroupReference.cpp +++ b/src/server/game/Groups/GroupReference.cpp @@ -28,12 +28,12 @@ void GroupReference::targetObjectBuildLink() void GroupReference::targetObjectDestroyLink() { // called from unlink() - getTarget()->DelinkMember(this); + //getTarget()->DelinkMember(this); } void GroupReference::sourceObjectDestroyLink() { // called from invalidate() - getTarget()->DelinkMember(this); + //getTarget()->DelinkMember(this); } diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp index 35276bb1d0a..bd9668ce5b8 100644 --- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp @@ -43,6 +43,7 @@ #include "ScriptMgr.h" #include "Battleground.h" #include "AccountMgr.h" +#include "LFGMgr.h" class LoginQueryHolder : public SQLQueryHolder { @@ -196,7 +197,7 @@ bool LoginQueryHolder::Initialize() stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES); stmt->setUInt32(0, m_accountId); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES, stmt); - + return res; } @@ -892,6 +893,17 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) } } + if (Group* group = pCurrChar->GetGroup()) + { + if (group->isLFGGroup()) + { + LfgDungeonSet Dungeons; + Dungeons.insert(sLFGMgr->GetDungeon(group->GetGUID())); + sLFGMgr->SetSelectedDungeons(pCurrChar->GetGUID(), Dungeons); + sLFGMgr->SetState(pCurrChar->GetGUID(), sLFGMgr->GetState(group->GetGUID())); + } + } + if (!pCurrChar->GetMap()->AddPlayerToMap(pCurrChar) || !pCurrChar->CheckInstanceLoginValid()) { AreaTrigger const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId()); diff --git a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp index 52b4d4abbed..3c6bd28b5cb 100755 --- a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp @@ -48,7 +48,8 @@ void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMa void WorldSession::HandleLfgJoinOpcode(WorldPacket& recv_data) { if (!sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE) || - (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID())) + (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() && + (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) { recv_data.rfinish(); return; diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 38e5771ccca..3fb2c4f3319 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1445,7 +1445,17 @@ class spell_gen_luck_of_the_draw : public SpellScriptLoader if (GetUnitOwner()->GetTypeId() != TYPEID_PLAYER) return; - LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*(sLFGMgr->GetSelectedDungeons(GetUnitOwner()->GetGUID()).begin())); + const LfgDungeonSet dungeons = sLFGMgr->GetSelectedDungeons(GetUnitOwner()->GetGUID()); + LfgDungeonSet::const_iterator itr = dungeons.begin(); + + if (itr == dungeons.end()) + { + Remove(AURA_REMOVE_BY_DEFAULT); + return; + } + + + LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*itr); Group* group = GetUnitOwner()->ToPlayer()->GetGroup(); Map const* map = GetUnitOwner()->GetMap(); if (group && group->isLFGGroup()) diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index a24f17a8b76..24b99219f46 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -325,6 +325,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() // For loading and deleting expired auctions at startup PREPARE_STATEMENT(CHAR_SEL_EXPIRED_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid WHERE ah.time <= ?", CONNECTION_SYNCH) + + // LFG Data + PREPARE_STATEMENT(CHAR_INS_LFG_DATA, "INSERT INTO lfg_data (guid, dungeon, state) VALUES (?, ?, ?)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_DEL_LFG_DATA, "DELETE FROM lfg_data WHERE guid = ?", CONNECTION_ASYNC) // Player saving PREPARE_STATEMENT(CHAR_INS_CHARACTER, "INSERT INTO characters (guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index a239e274a54..18b488e055a 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -351,6 +351,9 @@ enum CharacterDatabaseStatements CHAR_DEL_CHARACTER_SOCIAL, CHAR_UPD_CHARACTER_SOCIAL_NOTE, CHAR_UPD_CHARACTER_POSITION, + + CHAR_INS_LFG_DATA, + CHAR_DEL_LFG_DATA, MAX_CHARACTERDATABASE_STATEMENTS, }; |