diff options
Diffstat (limited to 'src/server/game/Loot/Loot.cpp')
-rw-r--r-- | src/server/game/Loot/Loot.cpp | 666 |
1 files changed, 143 insertions, 523 deletions
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp index 8f086facb80..3c5e976245e 100644 --- a/src/server/game/Loot/Loot.cpp +++ b/src/server/game/Loot/Loot.cpp @@ -126,6 +126,75 @@ void LootItem::AddAllowedLooter(const Player* player) allowedGUIDs.insert(player->GetGUID()); } +Optional<LootSlotType> LootItem::GetUiTypeForPlayer(Player const* player, Loot const& loot) const +{ + if (is_looted) + return {}; + + if (allowedGUIDs.find(player->GetGUID()) == allowedGUIDs.end()) + return {}; + + if (freeforall) + { + if (std::unique_ptr<NotNormalLootItemList> const* ffaItems = Trinity::Containers::MapGetValuePtr(loot.GetPlayerFFAItems(), player->GetGUID())) + { + auto ffaItemItr = std::find_if(ffaItems->get()->begin(), ffaItems->get()->end(), [&](NotNormalLootItem const& ffaItem) + { + return ffaItem.LootListId == LootListId; + }); + if (ffaItemItr != ffaItems->get()->end() && !ffaItemItr->is_looted) + return loot.GetLootMethod() == FREE_FOR_ALL ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT; + } + return {}; + } + + if (needs_quest && !follow_loot_rules) + return loot.GetLootMethod() == FREE_FOR_ALL ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT; + + switch (loot.GetLootMethod()) + { + case FREE_FOR_ALL: + return LOOT_SLOT_TYPE_OWNER; + case ROUND_ROBIN: + if (!loot.roundRobinPlayer.IsEmpty() && loot.roundRobinPlayer != player->GetGUID()) + return {}; + + return LOOT_SLOT_TYPE_ALLOW_LOOT; + case MASTER_LOOT: + if (is_underthreshold) + { + if (!loot.roundRobinPlayer.IsEmpty() && loot.roundRobinPlayer != player->GetGUID()) + return {}; + + return LOOT_SLOT_TYPE_ALLOW_LOOT; + } + + return loot.GetLootMasterGUID() == player->GetGUID() ? LOOT_SLOT_TYPE_MASTER : LOOT_SLOT_TYPE_LOCKED; + case GROUP_LOOT: + case NEED_BEFORE_GREED: + if (is_underthreshold) + if (!loot.roundRobinPlayer.IsEmpty() && loot.roundRobinPlayer != player->GetGUID()) + return {}; + + if (is_blocked) + return LOOT_SLOT_TYPE_ROLL_ONGOING; + + if (rollWinnerGUID.IsEmpty()) // all passed + return LOOT_SLOT_TYPE_ALLOW_LOOT; + + if (rollWinnerGUID == player->GetGUID()) + return LOOT_SLOT_TYPE_OWNER; + + return {}; + case PERSONAL_LOOT: + return LOOT_SLOT_TYPE_OWNER; + default: + break; + } + + return {}; +} + // // ------- Loot Roll ------- // @@ -286,7 +355,7 @@ void LootRoll::SendLootRollWon(ObjectGuid const& targetGuid, int32 rollNumber, R void LootRoll::FillPacket(WorldPackets::Loot::LootItemData& lootItem) const { lootItem.Quantity = m_lootItem->count; - lootItem.LootListID = m_lootListId + 1; + lootItem.LootListID = m_lootItem->LootListId; lootItem.CanTradeToTapList = m_lootItem->allowedGUIDs.size() > 1; lootItem.Loot.Initialize(*m_lootItem); } @@ -324,7 +393,6 @@ bool LootRoll::TryToStart(Map* map, Loot& loot, uint32 lootListId, uint16 enchan m_lootItem = &loot.items[lootListId]; m_loot = &loot; - m_lootListId = lootListId; m_lootItem->is_blocked = true; // block the item while rolling uint32 playerCount = 0; @@ -426,7 +494,7 @@ bool LootRoll::UpdateRoll() bool LootRoll::IsLootItem(ObjectGuid const& lootObject, uint32 lootListId) const { - return m_loot->GetGUID() == lootObject && m_lootListId == lootListId; + return m_loot->GetGUID() == lootObject && m_lootItem->LootListId == lootListId; } /** @@ -518,8 +586,7 @@ void LootRoll::Finish(RollVoteMap::const_iterator winnerItr) loot.FillLoot(disenchant->ID, LootTemplates_Disenchant, player, true, false, LOOT_MODE_DEFAULT, ItemContext::NONE); if (!loot.AutoStore(player, NULL_BAG, NULL_SLOT, true)) { - uint32 maxSlot = loot.GetMaxSlotInLootFor(player); - for (uint32 i = 0; i < maxSlot; ++i) + for (uint32 i = 0; i < loot.items.size(); ++i) if (LootItem* disenchantLoot = loot.LootItemInSlot(i, player)) player->SendItemRetrievalMail(disenchantLoot->itemid, disenchantLoot->count, disenchantLoot->context); } @@ -527,7 +594,7 @@ void LootRoll::Finish(RollVoteMap::const_iterator winnerItr) m_loot->NotifyItemRemoved(m_lootItem->LootListId, m_map); } else - player->StoreLootItem(m_loot->GetOwnerGUID(), m_lootListId, m_loot); + player->StoreLootItem(m_loot->GetOwnerGUID(), m_lootItem->LootListId, m_loot); } } m_isStarted = false; @@ -551,25 +618,14 @@ Loot::~Loot() void Loot::clear() { - for (NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.begin(); itr != PlayerQuestItems.end(); ++itr) - delete itr->second; - PlayerQuestItems.clear(); - - for (NotNormalLootItemMap::const_iterator itr = PlayerFFAItems.begin(); itr != PlayerFFAItems.end(); ++itr) - delete itr->second; PlayerFFAItems.clear(); - for (NotNormalLootItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.begin(); itr != PlayerNonQuestNonFFAConditionalItems.end(); ++itr) - delete itr->second; - PlayerNonQuestNonFFAConditionalItems.clear(); - for (ObjectGuid playerGuid : PlayersLooting) if (Player* player = ObjectAccessor::FindConnectedPlayer(playerGuid)) player->GetSession()->DoLootRelease(this); PlayersLooting.clear(); items.clear(); - quest_items.clear(); gold = 0; unlootedCount = 0; roundRobinPlayer.Clear(); @@ -598,47 +654,19 @@ void Loot::NotifyLootList(Map const* map) const allowedLooter->SendDirectMessage(lootList.GetRawPacket()); } -void Loot::NotifyItemRemoved(uint8 lootIndex, Map const* map) +void Loot::NotifyItemRemoved(uint8 lootListId, Map const* map) { // notify all players that are looting this that the item was removed // convert the index to the slot the player sees for (auto itr = PlayersLooting.begin(); itr != PlayersLooting.end();) { - if (Player* player = ObjectAccessor::GetPlayer(map, *itr)) - { - player->SendNotifyLootItemRemoved(GetGUID(), GetOwnerGUID(), lootIndex); - ++itr; - } - else - itr = PlayersLooting.erase(itr); - } -} + LootItem const& item = items[lootListId]; + if (item.GetAllowedLooters().find(*itr) == item.GetAllowedLooters().end()) + continue; -void Loot::NotifyQuestItemRemoved(uint8 questIndex, Map const* map) -{ - // when a free for all questitem is looted - // all players will get notified of it being removed - // (other questitems can be looted by each group member) - // bit inefficient but isn't called often - for (auto itr = PlayersLooting.begin(); itr != PlayersLooting.end();) - { if (Player* player = ObjectAccessor::GetPlayer(map, *itr)) { - NotNormalLootItemMap::const_iterator pq = PlayerQuestItems.find(player->GetGUID()); - if (pq != PlayerQuestItems.end() && pq->second) - { - // find where/if the player has the given item in it's vector - NotNormalLootItemList& pql = *pq->second; - - uint8 j; - for (j = 0; j < pql.size(); ++j) - if (pql[j].index == questIndex) - break; - - if (j < pql.size()) - player->SendNotifyLootItemRemoved(GetGUID(), GetOwnerGUID(), items.size() + j); - } - + player->SendNotifyLootItemRemoved(GetGUID(), GetOwnerGUID(), lootListId); ++itr; } else @@ -675,8 +703,7 @@ void Loot::OnLootOpened(Map* map, ObjectGuid looter) if (Player* allowedLooter = ObjectAccessor::GetPlayer(map, allowedLooterGuid)) maxEnchantingSkill = std::max(maxEnchantingSkill, allowedLooter->GetSkillValue(SKILL_ENCHANTING)); - uint32 lootListId = 0; - for (; lootListId < items.size(); ++lootListId) + for (uint32 lootListId = 0; lootListId < items.size(); ++lootListId) { LootItem& item = items[lootListId]; if (!item.is_blocked) @@ -686,17 +713,6 @@ void Loot::OnLootOpened(Map* map, ObjectGuid looter) if (!itr->second.TryToStart(map, *this, lootListId, maxEnchantingSkill)) _rolls.erase(itr); } - - for (; lootListId - items.size() < quest_items.size(); ++lootListId) - { - LootItem& item = quest_items[lootListId - items.size()]; - if (!item.is_blocked) - continue; - - auto&& [itr, inserted] = _rolls.try_emplace(lootListId); - if (!itr->second.TryToStart(map, *this, lootListId, maxEnchantingSkill)) - _rolls.erase(itr); - } } else if (_lootMethod == MASTER_LOOT) { @@ -746,9 +762,8 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo _itemContext = context; items.reserve(MAX_NR_LOOT_ITEMS); - quest_items.reserve(MAX_NR_QUEST_ITEMS); - tab->Process(*this, store.IsRatesAllowed(), lootMode, 0, lootOwner); // Processing is done there, callback via Loot::AddItem() + tab->Process(*this, store.IsRatesAllowed(), lootMode, 0); // Processing is done there, callback via Loot::AddItem() // Setting access rights for group loot case Group const* group = lootOwner->GetGroup(); @@ -761,8 +776,11 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo if (player->IsAtGroupRewardDistance(lootOwner)) FillNotNormalLootFor(player); - auto processLootItem = [&](LootItem& item) + for (LootItem& item : items) { + if (!item.follow_loot_rules || item.freeforall) + continue; + if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid)) { if (proto->GetQuality() < uint32(group->GetLootThreshold())) @@ -783,22 +801,6 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo } } } - }; - - for (LootItem& item : items) - { - if (item.freeforall) - continue; - - processLootItem(item); - } - - for (LootItem& item : quest_items) - { - if (!item.follow_loot_rules) - continue; - - processLootItem(item); } } // ... for personal loot @@ -809,7 +811,7 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo } // Inserts the item into the loot (called by LootTemplate processors) -void Loot::AddItem(LootStoreItem const& item, Player const* player) +void Loot::AddItem(LootStoreItem const& item) { ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid); if (!proto) @@ -818,65 +820,38 @@ void Loot::AddItem(LootStoreItem const& item, Player const* player) uint32 count = urand(item.mincount, item.maxcount); uint32 stacks = count / proto->GetMaxStackSize() + ((count % proto->GetMaxStackSize()) ? 1 : 0); - std::vector<LootItem>& lootItems = item.needs_quest ? quest_items : items; - uint32 limit = item.needs_quest ? MAX_NR_QUEST_ITEMS : MAX_NR_LOOT_ITEMS; - - for (uint32 i = 0; i < stacks && lootItems.size() < limit; ++i) + for (uint32 i = 0; i < stacks && items.size() < MAX_NR_LOOT_ITEMS; ++i) { LootItem generatedLoot(item); generatedLoot.context = _itemContext; generatedLoot.count = std::min(count, proto->GetMaxStackSize()); - generatedLoot.LootListId = lootItems.size(); + generatedLoot.LootListId = items.size(); if (_itemContext != ItemContext::NONE) { std::set<uint32> bonusListIDs = sDB2Manager.GetDefaultItemBonusTree(generatedLoot.itemid, _itemContext); generatedLoot.BonusListIDs.insert(generatedLoot.BonusListIDs.end(), bonusListIDs.begin(), bonusListIDs.end()); } - lootItems.push_back(generatedLoot); + items.push_back(generatedLoot); count -= proto->GetMaxStackSize(); - - // In some cases, a dropped item should be visible/lootable only for some players in group - bool canSeeItemInLootWindow = false; - if (Group const* group = player->GetGroup()) - { - for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) - if (Player const* member = itr->GetSource()) - if (generatedLoot.AllowedForPlayer(member)) - canSeeItemInLootWindow = true; - } - else if (generatedLoot.AllowedForPlayer(player)) - canSeeItemInLootWindow = true; - - if (!canSeeItemInLootWindow) - continue; - - // non-conditional one-player only items are counted here, - // free for all items are counted in FillFFALoot(), - // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot() - if (!item.needs_quest && item.conditions.empty() && !proto->HasFlag(ITEM_FLAG_MULTI_DROP)) - ++unlootedCount; } } bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool createdByPlayer) { bool allLooted = true; - uint32 max_slot = GetMaxSlotInLootFor(player); - for (uint32 i = 0; i < max_slot; ++i) + for (uint32 i = 0; i < items.size(); ++i) { - NotNormalLootItem* qitem = nullptr; NotNormalLootItem* ffaitem = nullptr; - NotNormalLootItem* conditem = nullptr; - LootItem* lootItem = LootItemInSlot(i, player, &qitem, &ffaitem, &conditem); + LootItem* lootItem = LootItemInSlot(i, player, &ffaitem); if (!lootItem || lootItem->is_looted) continue; if (!lootItem->AllowedForPlayer(player)) continue; - if (!qitem && lootItem->is_blocked) + if (lootItem->is_blocked) continue; // dont allow protected item to be looted by someone else @@ -896,12 +871,8 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool continue; } - if (qitem) - qitem->is_looted = true; - else if (ffaitem) + if (ffaitem) ffaitem->is_looted = true; - else if (conditem) - conditem->is_looted = true; if (!lootItem->freeforall) lootItem->is_looted = true; @@ -916,70 +887,33 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool return allLooted; } -LootItem const* Loot::GetItemInSlot(uint32 lootSlot) const +LootItem const* Loot::GetItemInSlot(uint32 lootListId) const { - if (lootSlot < items.size()) - return &items[lootSlot]; - - lootSlot -= uint32(items.size()); - if (lootSlot < quest_items.size()) - return &quest_items[lootSlot]; + if (lootListId < items.size()) + return &items[lootListId]; return nullptr; } -LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, NotNormalLootItem* *qitem, NotNormalLootItem* *ffaitem, NotNormalLootItem* *conditem) +LootItem* Loot::LootItemInSlot(uint32 lootListId, Player const* player, NotNormalLootItem** ffaItem) { - LootItem* item = nullptr; - bool is_looted = true; - if (lootSlot >= items.size()) - { - uint32 questSlot = lootSlot - items.size(); - NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID()); - if (itr != PlayerQuestItems.end() && questSlot < itr->second->size()) - { - NotNormalLootItem* qitem2 = &(*itr->second)[questSlot]; - if (qitem) - *qitem = qitem2; - item = &quest_items[qitem2->index]; - is_looted = qitem2->is_looted; - } - } - else + LootItem* item = &items[lootListId]; + bool is_looted = item->is_looted; + + if (item->freeforall) { - item = &items[lootSlot]; - is_looted = item->is_looted; - if (item->freeforall) + auto itr = PlayerFFAItems.find(player->GetGUID()); + if (itr != PlayerFFAItems.end()) { - NotNormalLootItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUID()); - if (itr != PlayerFFAItems.end()) + for (NotNormalLootItem& notNormalLootItem : *itr->second) { - for (NotNormalLootItemList::const_iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter) - if (iter->index == lootSlot) - { - NotNormalLootItem* ffaitem2 = (NotNormalLootItem*)&(*iter); - if (ffaitem) - *ffaitem = ffaitem2; - is_looted = ffaitem2->is_looted; - break; - } - } - } - else if (!item->conditions.empty()) - { - NotNormalLootItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUID()); - if (itr != PlayerNonQuestNonFFAConditionalItems.end()) - { - for (NotNormalLootItemList::const_iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter) + if (notNormalLootItem.LootListId == lootListId) { - if (iter->index == lootSlot) - { - NotNormalLootItem* conditem2 = (NotNormalLootItem*)&(*iter); - if (conditem) - *conditem = conditem2; - is_looted = conditem2->is_looted; - break; - } + is_looted = notNormalLootItem.is_looted; + if (ffaItem) + *ffaItem = ¬NormalLootItem; + + break; } } } @@ -991,12 +925,6 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, NotNormalLootIte return item; } -uint32 Loot::GetMaxSlotInLootFor(Player* player) const -{ - NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID()); - return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0); -} - // return true if there is any item that is lootable for any player (not quest item, FFA or conditional) bool Loot::hasItemForAll() const { @@ -1005,7 +933,7 @@ bool Loot::hasItemForAll() const return true; for (LootItem const& item : items) - if (!item.is_looted && !item.freeforall && item.conditions.empty()) + if (!item.is_looted && item.follow_loot_rules && !item.freeforall && item.conditions.empty()) return true; return false; } @@ -1013,43 +941,19 @@ bool Loot::hasItemForAll() const // return true if there is any FFA, quest or conditional item for the player. bool Loot::hasItemFor(Player const* player) const { - NotNormalLootItemMap const& lootPlayerQuestItems = GetPlayerQuestItems(); - NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUID()); - if (q_itr != lootPlayerQuestItems.end()) - { - NotNormalLootItemList* q_list = q_itr->second; - for (NotNormalLootItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi) - { - const LootItem &item = quest_items[qi->index]; - if (!qi->is_looted && !item.is_looted) - return true; - } - } - - NotNormalLootItemMap const& lootPlayerFFAItems = GetPlayerFFAItems(); - NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUID()); - if (ffa_itr != lootPlayerFFAItems.end()) - { - NotNormalLootItemList* ffa_list = ffa_itr->second; - for (NotNormalLootItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi) - { - const LootItem &item = items[fi->index]; - if (!fi->is_looted && !item.is_looted) - return true; - } - } + // quest items + for (LootItem const& lootItem : items) + if (!lootItem.is_looted && !lootItem.follow_loot_rules && lootItem.GetAllowedLooters().find(player->GetGUID()) != lootItem.GetAllowedLooters().end()) + return true; - NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems(); - NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUID()); - if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end()) + if (std::unique_ptr<NotNormalLootItemList> const* ffaItems = Trinity::Containers::MapGetValuePtr(GetPlayerFFAItems(), player->GetGUID())) { - NotNormalLootItemList* conditional_list = nn_itr->second; - for (NotNormalLootItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci) + bool hasFfaItem = std::any_of(ffaItems->get()->begin(), ffaItems->get()->end(), [&](NotNormalLootItem const& ffaItem) { - const LootItem &item = items[ci->index]; - if (!ci->is_looted && !item.is_looted) - return true; - } + return !ffaItem.is_looted; + }); + if (hasFfaItem) + return true; } return false; @@ -1067,223 +971,21 @@ bool Loot::hasOverThresholdItem() const return false; } -void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* viewer, PermissionTypes permission) const +void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player const* viewer) const { - if (permission == NONE_PERMISSION) - return; - packet.Coins = gold; - switch (permission) - { - case GROUP_PERMISSION: - case MASTER_PERMISSION: - case RESTRICTED_PERMISSION: - { - // if you are not the round-robin group looter, you can only see - // blocked rolled items and quest items, and !ffa items - for (uint8 i = 0; i < items.size(); ++i) - { - if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer)) - { - uint8 slot_type; - - if (items[i].is_blocked) // for ML & restricted is_blocked = !is_underthreshold - { - switch (permission) - { - case GROUP_PERMISSION: - slot_type = LOOT_SLOT_TYPE_ROLL_ONGOING; - break; - case MASTER_PERMISSION: - { - if (viewer->GetGroup() && viewer->GetGroup()->GetMasterLooterGuid() == viewer->GetGUID()) - slot_type = LOOT_SLOT_TYPE_MASTER; - else - slot_type = LOOT_SLOT_TYPE_LOCKED; - break; - } - case RESTRICTED_PERMISSION: - slot_type = LOOT_SLOT_TYPE_LOCKED; - break; - default: - continue; - } - } - else if (roundRobinPlayer.IsEmpty() || viewer->GetGUID() == roundRobinPlayer || !items[i].is_underthreshold) - { - // no round robin owner or he has released the loot - // or it IS the round robin group owner - // => item is lootable - slot_type = LOOT_SLOT_TYPE_ALLOW_LOOT; - } - else if (!items[i].rollWinnerGUID.IsEmpty()) - { - if (items[i].rollWinnerGUID == viewer->GetGUID()) - slot_type = LOOT_SLOT_TYPE_OWNER; - else - continue; - } - else - // item shall not be displayed. - continue; - - WorldPackets::Loot::LootItemData lootItem; - lootItem.LootListID = i + 1; - lootItem.UIType = slot_type; - lootItem.Quantity = items[i].count; - lootItem.Loot.Initialize(items[i]); - packet.Items.push_back(lootItem); - } - } - break; - } - case ROUND_ROBIN_PERMISSION: - { - for (uint8 i = 0; i < items.size(); ++i) - { - if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer)) - { - if (!roundRobinPlayer.IsEmpty() && viewer->GetGUID() != roundRobinPlayer) - // item shall not be displayed. - continue; - - WorldPackets::Loot::LootItemData lootItem; - lootItem.LootListID = i + 1; - lootItem.UIType = LOOT_SLOT_TYPE_ALLOW_LOOT; - lootItem.Quantity = items[i].count; - lootItem.Loot.Initialize(items[i]); - packet.Items.push_back(lootItem); - } - } - break; - } - case ALL_PERMISSION: - case OWNER_PERMISSION: - { - for (uint8 i = 0; i < items.size(); ++i) - { - if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer)) - { - WorldPackets::Loot::LootItemData lootItem; - lootItem.LootListID = i + 1; - lootItem.UIType = permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT; - lootItem.Quantity = items[i].count; - lootItem.Loot.Initialize(items[i]); - packet.Items.push_back(lootItem); - } - } - break; - } - default: - return; - } - - LootSlotType slotType = permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT; - NotNormalLootItemMap const& lootPlayerQuestItems = GetPlayerQuestItems(); - NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(viewer->GetGUID()); - if (q_itr != lootPlayerQuestItems.end()) - { - NotNormalLootItemList const& q_list = *q_itr->second; - for (std::size_t i = 0; i < q_list.size(); ++i) - { - NotNormalLootItem const& qi = q_list[i]; - LootItem const& item = quest_items[qi.index]; - if (!qi.is_looted && !item.is_looted) - { - WorldPackets::Loot::LootItemData lootItem; - lootItem.LootListID = items.size() + i + 1; - lootItem.Quantity = item.count; - lootItem.Loot.Initialize(item); - - if (item.follow_loot_rules) - { - switch (permission) - { - case MASTER_PERMISSION: - lootItem.UIType = LOOT_SLOT_TYPE_MASTER; - break; - case RESTRICTED_PERMISSION: - lootItem.UIType = item.is_blocked ? LOOT_SLOT_TYPE_LOCKED : LOOT_SLOT_TYPE_ALLOW_LOOT; - break; - case GROUP_PERMISSION: - case ROUND_ROBIN_PERMISSION: - if (!item.is_blocked) - lootItem.UIType = LOOT_SLOT_TYPE_ALLOW_LOOT; - else - lootItem.UIType = LOOT_SLOT_TYPE_ROLL_ONGOING; - break; - default: - lootItem.UIType = slotType; - break; - } - } - else - lootItem.UIType = slotType; - - packet.Items.push_back(lootItem); - } - } - } - - NotNormalLootItemMap const& lootPlayerFFAItems = GetPlayerFFAItems(); - NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(viewer->GetGUID()); - if (ffa_itr != lootPlayerFFAItems.end()) - { - NotNormalLootItemList* ffa_list = ffa_itr->second; - for (NotNormalLootItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi) - { - LootItem const& item = items[fi->index]; - if (!fi->is_looted && !item.is_looted) - { - WorldPackets::Loot::LootItemData lootItem; - lootItem.LootListID = fi->index + 1; - lootItem.UIType = slotType; - lootItem.Quantity = item.count; - lootItem.Loot.Initialize(item); - packet.Items.push_back(lootItem); - } - } - } - - NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems(); - NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(viewer->GetGUID()); - if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end()) + for (LootItem const& item : items) { - NotNormalLootItemList* conditional_list = nn_itr->second; - for (NotNormalLootItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci) - { - LootItem const& item = items[ci->index]; - if (!ci->is_looted && !item.is_looted) - { - WorldPackets::Loot::LootItemData lootItem; - lootItem.LootListID = ci->index + 1; - lootItem.Quantity = item.count; - lootItem.Loot.Initialize(item); - - switch (permission) - { - case MASTER_PERMISSION: - lootItem.UIType = LOOT_SLOT_TYPE_MASTER; - break; - case RESTRICTED_PERMISSION: - lootItem.UIType = item.is_blocked ? LOOT_SLOT_TYPE_LOCKED : LOOT_SLOT_TYPE_ALLOW_LOOT; - break; - case GROUP_PERMISSION: - case ROUND_ROBIN_PERMISSION: - if (!item.is_blocked) - lootItem.UIType = LOOT_SLOT_TYPE_ALLOW_LOOT; - else - lootItem.UIType = LOOT_SLOT_TYPE_ROLL_ONGOING; - break; - default: - lootItem.UIType = slotType; - break; - } + Optional<LootSlotType> uiType = item.GetUiTypeForPlayer(viewer, *this); + if (!uiType) + continue; - packet.Items.push_back(lootItem); - } - } + WorldPackets::Loot::LootItemData& lootItem = packet.Items.emplace_back(); + lootItem.LootListID = item.LootListId; + lootItem.UIType = *uiType; + lootItem.Quantity = item.count; + lootItem.Loot.Initialize(item); } } @@ -1303,111 +1005,29 @@ void Loot::FillNotNormalLootFor(Player const* player) ObjectGuid plguid = player->GetGUID(); _allowedLooters.insert(plguid); - NotNormalLootItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid); - if (qmapitr == PlayerQuestItems.end()) - FillQuestLoot(player); - - qmapitr = PlayerFFAItems.find(plguid); - if (qmapitr == PlayerFFAItems.end()) - FillFFALoot(player); - - qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid); - if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end()) - FillNonQuestNonFFAConditionalLoot(player); -} - -NotNormalLootItemList* Loot::FillFFALoot(Player const* player) -{ - NotNormalLootItemList* ql = new NotNormalLootItemList(); + std::unique_ptr<NotNormalLootItemList> ffaItems = std::make_unique<NotNormalLootItemList>(); - for (uint8 i = 0; i < items.size(); ++i) - { - LootItem &item = items[i]; - if (!item.is_looted && item.freeforall && item.AllowedForPlayer(player)) - { - ql->push_back(NotNormalLootItem(i)); - ++unlootedCount; - } - } - if (ql->empty()) + for (LootItem& item : items) { - delete ql; - return nullptr; - } - - PlayerFFAItems[player->GetGUID()] = ql; - return ql; -} - -NotNormalLootItemList* Loot::FillQuestLoot(Player const* player) -{ - if (items.size() == MAX_NR_LOOT_ITEMS) - return nullptr; - - NotNormalLootItemList* ql = new NotNormalLootItemList(); + if (!item.AllowedForPlayer(player)) + continue; - for (uint8 i = 0; i < quest_items.size(); ++i) - { - LootItem &item = quest_items[i]; + item.AddAllowedLooter(player); - if (!item.is_looted && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() && ((GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || GetLootMethod() != MASTER_LOOT)))) + if (item.freeforall) { - item.AddAllowedLooter(player); - - ql->push_back(NotNormalLootItem(i)); - - // quest items get blocked when they first appear in a - // player's quest vector - // - // increase once if one looter only, looter-times if free for all - if (item.freeforall || !item.is_blocked) - ++unlootedCount; - if (!player->GetGroup() || (GetLootMethod() != GROUP_LOOT && GetLootMethod() != ROUND_ROBIN)) - item.is_blocked = true; - - if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS) - break; + ffaItems->emplace_back(item.LootListId); + ++unlootedCount; } - } - if (ql->empty()) - { - delete ql; - return nullptr; - } - - PlayerQuestItems[player->GetGUID()] = ql; - return ql; -} - -NotNormalLootItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player const* player) -{ - NotNormalLootItemList* ql = new NotNormalLootItemList(); - - for (uint8 i = 0; i < items.size(); ++i) - { - LootItem &item = items[i]; - if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player))) + else if (!item.is_counted) { - item.AddAllowedLooter(player); - if (!item.conditions.empty()) - { - ql->push_back(NotNormalLootItem(i)); - if (!item.is_counted) - { - ++unlootedCount; - item.is_counted = true; - } - } + item.is_counted = true; + ++unlootedCount; } } - if (ql->empty()) - { - delete ql; - return nullptr; - } - PlayerNonQuestNonFFAConditionalItems[player->GetGUID()] = ql; - return ql; + if (!ffaItems->empty()) + PlayerFFAItems[player->GetGUID()] = std::move(ffaItems); } // |