diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 630856b7a..c9e8a5896 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -898,7 +898,7 @@ void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, p->GetSession()->SendPacket(&data); } -void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll) +void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll, bool autoPass) { WorldPacket data(SMSG_LOOT_ROLL, (8 + 4 + 8 + 4 + 4 + 4 + 1 + 1 + 1)); data << sourceGuid; // guid of the item rolled @@ -909,7 +909,7 @@ void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rol data << uint32(roll.itemRandomPropId); // Item random property ID data << uint8(rollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number data << uint8(rollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll - data << uint8(0); // 1: "You automatically passed on: %s because you cannot loot that item." - Possibly used in need befor greed + data << uint8(autoPass); // 1: "You automatically passed on: %s because you cannot loot that item." for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr) { @@ -986,6 +986,23 @@ void Group::SendLooter(Creature* creature, Player* groupLooter) BroadcastPacket(&data, false); } +bool CanRollOnItem(LootItem const& item, Player const* player, Loot* loot) +{ + // Players can't roll on unique items if they already reached the maximum quantity of that item + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid); + if (!proto) + return false; + + uint32 itemCount = player->GetItemCount(item.itemid); + if ((proto->MaxCount > 0 && static_cast(itemCount) >= proto->MaxCount) || (player->CanEquipUniqueItem(proto) != EQUIP_ERR_OK)) + return false; + + if (!item.AllowedForPlayer(player, loot->sourceWorldObjectGUID)) + return false; + + return true; +} + void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) { std::vector::iterator i; @@ -1013,23 +1030,20 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); - if (!member) + if (!member || !member->GetSession()) continue; if (member->IsAtLootRewardDistance(pLootedObject)) { - if (i->AllowedForPlayer(member, loot->sourceWorldObjectGUID)) - { - r->totalPlayersRolling++; + r->totalPlayersRolling++; - if (member->GetPassOnGroupLoot()) - { - r->playerVote[member->GetGUID()] = PASS; - r->totalPass++; - // can't broadcast the pass now. need to wait until all rolling players are known. - } - else - r->playerVote[member->GetGUID()] = NOT_EMITED_YET; + RollVote vote = member->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET; + if (!CanRollOnItem(*i, member, loot)) + { + vote = PASS; + ++r->totalPass; } + + r->playerVote[member->GetGUID()] = vote; } } @@ -1052,23 +1066,28 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) continue; if (itr->second == PASS) - SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); + SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r, true); } } - SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); - - RollId.push_back(r); - - if (Creature* creature = pLootedObject->ToCreature()) + if (r->totalPass == r->totalPlayersRolling) + delete r; + else { - creature->m_groupLootTimer = 60000; - creature->lootingGroupLowGUID = GetGUID().GetCounter(); - } - else if (GameObject* go = pLootedObject->ToGameObject()) - { - go->m_groupLootTimer = 60000; - go->lootingGroupLowGUID = GetGUID().GetCounter(); + SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); + + RollId.push_back(r); + + if (Creature* creature = pLootedObject->ToCreature()) + { + creature->m_groupLootTimer = 60000; + creature->lootingGroupLowGUID = GetGUID().GetCounter(); + } + else if (GameObject* go = pLootedObject->ToGameObject()) + { + go->m_groupLootTimer = 60000; + go->lootingGroupLowGUID = GetGUID().GetCounter(); + } } } else @@ -1096,16 +1115,18 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); - if (!member) + if (!member || !member->GetSession()) continue; if (member->IsAtLootRewardDistance(pLootedObject)) { - if (i->AllowedForPlayer(member, loot->sourceWorldObjectGUID)) + RollVote vote = NOT_EMITED_YET; + if (!CanRollOnItem(*i, member, loot)) { - r->totalPlayersRolling++; - r->playerVote[member->GetGUID()] = NOT_EMITED_YET; + vote = PASS; + ++r->totalPass; } + r->playerVote[member->GetGUID()] = vote; } } @@ -1156,20 +1177,21 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* playerToRoll = itr->GetSource(); - if (!playerToRoll) + if (!playerToRoll || !playerToRoll->GetSession()) continue; - if (i->AllowedForPlayer(playerToRoll, loot->sourceWorldObjectGUID) && playerToRoll->IsAtLootRewardDistance(lootedObject)) + if (playerToRoll->IsAtGroupRewardDistance(lootedObject)) { r->totalPlayersRolling++; - if (playerToRoll->GetPassOnGroupLoot()) + + RollVote vote = playerToRoll->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET; + if (!CanRollOnItem(*i, playerToRoll, loot)) { - r->playerVote[playerToRoll->GetGUID()] = PASS; - r->totalPass++; - // can't broadcast the pass now. need to wait until all rolling players are known. + vote = 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()] = vote; } } @@ -1230,13 +1252,21 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* playerToRoll = itr->GetSource(); - if (!playerToRoll) + if (!playerToRoll || !playerToRoll->GetSession()) continue; - if (i->AllowedForPlayer(playerToRoll, loot->sourceWorldObjectGUID) && playerToRoll->IsAtLootRewardDistance(lootedObject)) + if (playerToRoll->IsAtGroupRewardDistance(lootedObject)) { r->totalPlayersRolling++; - r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; + + RollVote vote = playerToRoll->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET; + if (!CanRollOnItem(*i, playerToRoll, loot)) + { + vote = PASS; + r->totalPass++; // Can't broadcast the pass now. need to wait until all rolling players are known + } + + r->playerVote[playerToRoll->GetGUID()] = vote; } } diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 87317f376..f4afabf6f 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -286,7 +286,7 @@ public: bool isRollLootActive() const; void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll& r); void SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r); - void SendLootRoll(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r); + void SendLootRoll(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r, bool autoPass = false); void SendLootRollWon(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r); void SendLootAllPassed(Roll const& roll); void SendLooter(Creature* creature, Player* pLooter);