aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp150
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Handlers/LootHandler.cpp15
-rw-r--r--src/server/game/Loot/Loot.cpp666
-rw-r--r--src/server/game/Loot/Loot.h48
-rw-r--r--src/server/game/Loot/LootMgr.cpp16
-rw-r--r--src/server/game/Loot/LootMgr.h2
-rw-r--r--src/server/game/Mails/Mail.cpp3
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp19
9 files changed, 203 insertions, 718 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 58bbc90a40c..b56b414981d 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -8794,7 +8794,6 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
m_session->DoLootReleaseAll();
Loot* loot;
- PermissionTypes permission = ALL_PERMISSION;
TC_LOG_DEBUG("loot", "Player::SendLoot: Player: '%s' (%s), Loot: %s",
GetName().c_str(), GetGUID().ToString().c_str(), guid.ToString().c_str());
@@ -8884,30 +8883,6 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
go->SetLootState(GO_ACTIVATED, this);
}
-
- if (go->getLootState() == GO_ACTIVATED)
- {
- if (Group* group = GetGroup())
- {
- switch (loot->GetLootMethod())
- {
- case MASTER_LOOT:
- permission = group->GetMasterLooterGuid() == GetGUID() ? MASTER_PERMISSION : RESTRICTED_PERMISSION;
- break;
- case FREE_FOR_ALL:
- permission = ALL_PERMISSION;
- break;
- case ROUND_ROBIN:
- permission = ROUND_ROBIN_PERMISSION;
- break;
- default:
- permission = GROUP_PERMISSION;
- break;
- }
- }
- else
- permission = ALL_PERMISSION;
- }
}
else if (guid.IsItem())
{
@@ -8919,8 +8894,6 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
return;
}
- permission = OWNER_PERMISSION;
-
loot = item->GetLootForPlayer(this);
// If item doesn't already have loot, attempt to load it. If that
@@ -8966,11 +8939,6 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
}
loot = bones->GetLootForPlayer(this);
-
- if (bones->lootRecipient && bones->lootRecipient != this)
- permission = NONE_PERMISSION;
- else
- permission = OWNER_PERMISSION;
}
else
{
@@ -9008,7 +8976,6 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
const uint32 a = urand(0, creature->GetLevel() / 2);
const uint32 b = urand(0, GetLevel() / 2);
loot->gold = uint32(10 * (a + b) * sWorld->getRate(RATE_DROP_MONEY));
- permission = OWNER_PERMISSION;
}
else
{
@@ -9039,76 +9006,37 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
if (loot->loot_type == LOOT_SKINNING)
{
loot_type = LOOT_SKINNING;
- permission = creature->GetLootRecipientGUID() == GetGUID() ? OWNER_PERMISSION : NONE_PERMISSION;
}
else if (loot_type == LOOT_SKINNING)
{
loot->clear();
loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true);
- permission = OWNER_PERMISSION;
// Set new loot recipient
creature->SetLootRecipient(this, false);
}
- // set group rights only for loot_type != LOOT_SKINNING
- else
- {
- if (creature->GetLootRecipientGroup())
- {
- Group* group = GetGroup();
- if (group == creature->GetLootRecipientGroup())
- {
- switch (loot->GetLootMethod())
- {
- case MASTER_LOOT:
- permission = group->GetMasterLooterGuid() == GetGUID() ? MASTER_PERMISSION : RESTRICTED_PERMISSION;
- break;
- case FREE_FOR_ALL:
- permission = ALL_PERMISSION;
- break;
- case ROUND_ROBIN:
- permission = ROUND_ROBIN_PERMISSION;
- break;
- default:
- permission = GROUP_PERMISSION;
- break;
- }
- }
- else
- permission = NONE_PERMISSION;
- }
- else if (creature->GetLootRecipient() == this)
- permission = OWNER_PERMISSION;
- else
- permission = NONE_PERMISSION;
- }
}
}
- if (permission != NONE_PERMISSION)
- {
- if (!guid.IsItem() && !aeLooting)
- SetLootGUID(guid);
+ if (!guid.IsItem() && !aeLooting)
+ SetLootGUID(guid);
- WorldPackets::Loot::LootResponse packet;
- packet.Owner = guid;
- packet.LootObj = loot->GetGUID();
- packet._LootMethod = loot->GetLootMethod();
- packet.AcquireReason = GetLootTypeForClient(loot_type);
- packet.Acquired = true; // false == No Loot (this too^^)
- packet.AELooting = aeLooting;
- loot->BuildLootResponse(packet, this, permission);
- SendDirectMessage(packet.Write());
+ WorldPackets::Loot::LootResponse packet;
+ packet.Owner = guid;
+ packet.LootObj = loot->GetGUID();
+ packet._LootMethod = loot->GetLootMethod();
+ packet.AcquireReason = GetLootTypeForClient(loot_type);
+ packet.Acquired = true; // false == No Loot (this too^^)
+ packet.AELooting = aeLooting;
+ loot->BuildLootResponse(packet, this);
+ SendDirectMessage(packet.Write());
- // add 'this' player as one of the players that are looting 'loot'
- loot->OnLootOpened(GetMap(), GetGUID());
- m_AELootView[loot->GetGUID()] = loot;
+ // add 'this' player as one of the players that are looting 'loot'
+ loot->OnLootOpened(GetMap(), GetGUID());
+ m_AELootView[loot->GetGUID()] = loot;
- if (loot_type == LOOT_CORPSE && !guid.IsItem())
- SetUnitFlag(UNIT_FLAG_LOOTING);
- }
- else
- SendLootError(loot ? loot->GetGUID() : ObjectGuid::Empty, guid, LOOT_ERROR_DIDNT_KILL);
+ if (loot_type == LOOT_CORPSE && !guid.IsItem())
+ SetUnitFlag(UNIT_FLAG_LOOTING);
}
void Player::SendLootError(ObjectGuid const& lootObj, ObjectGuid const& owner, LootError error) const
@@ -9128,12 +9056,12 @@ void Player::SendNotifyLootMoneyRemoved(ObjectGuid lootObj) const
SendDirectMessage(packet.Write());
}
-void Player::SendNotifyLootItemRemoved(ObjectGuid lootObj, ObjectGuid owner, uint8 lootSlot) const
+void Player::SendNotifyLootItemRemoved(ObjectGuid lootObj, ObjectGuid owner, uint8 lootListId) const
{
WorldPackets::Loot::LootRemoved packet;
packet.LootObj = lootObj;
packet.Owner = owner;
- packet.LootListID = lootSlot + 1;
+ packet.LootListID = lootListId;
SendDirectMessage(packet.Write());
}
@@ -18179,7 +18107,6 @@ bool Player::isAllowedToLoot(const Creature* creature) const
{
case PERSONAL_LOOT: /// @todo implement personal loot (http://wow.gamepedia.com/Loot#Personal_Loot)
return false;
- case MASTER_LOOT:
case FREE_FOR_ALL:
return true;
case ROUND_ROBIN:
@@ -18189,10 +18116,11 @@ bool Player::isAllowedToLoot(const Creature* creature) const
return true;
return loot->hasItemFor(this);
+ case MASTER_LOOT:
case GROUP_LOOT:
case NEED_BEFORE_GREED:
// may only loot if the player is the loot roundrobin player
- // or item over threshold (so roll(s) can be launched)
+ // or item over threshold (so roll(s) can be launched or to preview master looted items)
// or if there are free/quest/conditional item for the player
if (loot->roundRobinPlayer.IsEmpty() || loot->roundRobinPlayer == GetGUID())
return true;
@@ -26025,11 +25953,9 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons
void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot* loot, AELootResult* aeResult/* = nullptr*/)
{
- NotNormalLootItem* qitem = nullptr;
- NotNormalLootItem* ffaitem = nullptr;
- NotNormalLootItem* conditem = nullptr;
+ NotNormalLootItem* ffaItem = nullptr;
- LootItem* item = loot->LootItemInSlot(lootSlot, this, &qitem, &ffaitem, &conditem);
+ LootItem* item = loot->LootItemInSlot(lootSlot, this, &ffaItem);
if (!item || item->is_looted)
{
@@ -26043,8 +25969,7 @@ void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot*
return;
}
- // questitems use the blocked field for other purposes
- if (!qitem && item->is_blocked)
+ if (item->is_blocked)
{
SendLootReleaseAll();
return;
@@ -26063,31 +25988,14 @@ void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot*
{
Item* newitem = StoreNewItem(dest, item->itemid, true, item->randomBonusListId, item->GetAllowedLooters(), item->context, item->BonusListIDs);
- if (qitem)
- {
- qitem->is_looted = true;
- //freeforall is 1 if everyone's supposed to get the quest item.
- if (item->freeforall || loot->GetPlayerQuestItems().size() == 1)
- SendNotifyLootItemRemoved(loot->GetGUID(), loot->GetOwnerGUID(), lootSlot);
- else
- loot->NotifyQuestItemRemoved(qitem->index, GetMap());
- }
- else
+ if (ffaItem)
{
- if (ffaitem)
- {
- //freeforall case, notify only one player of the removal
- ffaitem->is_looted = true;
- SendNotifyLootItemRemoved(loot->GetGUID(), loot->GetOwnerGUID(), lootSlot);
- }
- else
- {
- //not freeforall, notify everyone
- if (conditem)
- conditem->is_looted = true;
- loot->NotifyItemRemoved(lootSlot, GetMap());
- }
+ //freeforall case, notify only one player of the removal
+ ffaItem->is_looted = true;
+ SendNotifyLootItemRemoved(loot->GetGUID(), loot->GetOwnerGUID(), lootSlot);
}
+ else //not freeforall, notify everyone
+ loot->NotifyItemRemoved(lootSlot, GetMap());
//if only one person is supposed to loot the item, then set it to looted
if (!item->freeforall)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index ce1d2c586f5..4ad0f6af647 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2355,7 +2355,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SendLootError(ObjectGuid const& lootObj, ObjectGuid const& owner, LootError error) const;
void SendLootRelease(ObjectGuid guid) const;
void SendLootReleaseAll() const;
- void SendNotifyLootItemRemoved(ObjectGuid lootObj, ObjectGuid owner, uint8 lootSlot) const;
+ void SendNotifyLootItemRemoved(ObjectGuid lootObj, ObjectGuid owner, uint8 lootListId) const;
void SendNotifyLootMoneyRemoved(ObjectGuid lootObj) const;
/*********************************************************/
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index d14810c2b32..a367e18da8e 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -107,7 +107,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p
}
}
- player->StoreLootItem(lguid, req.LootListID - 1, loot, aeResultPtr);
+ player->StoreLootItem(lguid, req.LootListID, loot, aeResultPtr);
// If player is removing the last LootItem, delete the empty container.
if (loot->isLooted() && lguid.IsItem())
@@ -413,15 +413,14 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem
if (!loot || loot->GetLootMethod() != MASTER_LOOT)
return;
- uint8 slotid = req.LootListID - 1;
- if (slotid >= loot->items.size() + loot->quest_items.size())
+ if (req.LootListID >= loot->items.size())
{
- TC_LOG_DEBUG("loot", "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)",
- GetPlayer()->GetName().c_str(), slotid, (unsigned long)loot->items.size());
+ TC_LOG_DEBUG("loot", "MasterLootItem: Player %s might be using a hack! (slot %d, size " SZFMTD ")",
+ GetPlayer()->GetName().c_str(), req.LootListID, loot->items.size());
return;
}
- LootItem& item = slotid >= loot->items.size() ? loot->quest_items[slotid - loot->items.size()] : loot->items[slotid];
+ LootItem& item = loot->items[req.LootListID];
ItemPosCountVec dest;
InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count);
@@ -446,7 +445,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem
item.count = 0;
item.is_looted = true;
- loot->NotifyItemRemoved(slotid, GetPlayer()->GetMap());
+ loot->NotifyItemRemoved(req.LootListID, GetPlayer()->GetMap());
--loot->unlootedCount;
}
@@ -461,7 +460,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem
void WorldSession::HandleLootRoll(WorldPackets::Loot::LootRoll& packet)
{
- LootRoll* lootRoll = GetPlayer()->GetLootRoll(packet.LootObj, packet.LootListID - 1);
+ LootRoll* lootRoll = GetPlayer()->GetLootRoll(packet.LootObj, packet.LootListID);
if (!lootRoll)
return;
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 = &notNormalLootItem;
+
+ 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);
}
//
diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h
index a75862f05dc..a966a4df4dd 100644
--- a/src/server/game/Loot/Loot.h
+++ b/src/server/game/Loot/Loot.h
@@ -26,6 +26,7 @@
#include "ObjectGuid.h"
#include "Optional.h"
#include "SharedDefines.h"
+#include <memory>
#include <unordered_map>
#include <vector>
@@ -80,9 +81,6 @@ enum RollMask
};
#define MAX_NR_LOOT_ITEMS 18
-// note: the client cannot show more than 16 items total
-#define MAX_NR_QUEST_ITEMS 32
-// unrelated to the number of quest items shown, just for reserve
enum LootMethod : uint8
{
@@ -94,17 +92,6 @@ enum LootMethod : uint8
PERSONAL_LOOT = 5
};
-enum PermissionTypes
-{
- ALL_PERMISSION = 0,
- GROUP_PERMISSION = 1,
- MASTER_PERMISSION = 2,
- RESTRICTED_PERMISSION = 3,
- ROUND_ROBIN_PERMISSION = 4,
- OWNER_PERMISSION = 5,
- NONE_PERMISSION = 6
-};
-
enum LootType : uint8
{
LOOT_NONE = 0,
@@ -203,23 +190,24 @@ struct TC_GAME_API LootItem
bool AllowedForPlayer(Player const* player, bool isGivenByMasterLooter = false) const;
void AddAllowedLooter(Player const* player);
GuidSet const& GetAllowedLooters() const { return allowedGUIDs; }
+ Optional<LootSlotType> GetUiTypeForPlayer(Player const* player, Loot const& loot) const;
};
struct NotNormalLootItem
{
- uint8 index; // position in quest_items or items;
+ uint8 LootListId;
bool is_looted;
NotNormalLootItem()
- : index(0), is_looted(false) { }
+ : LootListId(0), is_looted(false) { }
NotNormalLootItem(uint8 _index, bool _islooted = false)
- : index(_index), is_looted(_islooted) { }
+ : LootListId(_index), is_looted(_islooted) { }
};
typedef std::vector<NotNormalLootItem> NotNormalLootItemList;
typedef std::vector<LootItem> LootItemList;
-typedef std::unordered_map<ObjectGuid, NotNormalLootItemList*> NotNormalLootItemMap;
+typedef std::unordered_map<ObjectGuid, std::unique_ptr<NotNormalLootItemList>> NotNormalLootItemMap;
//=====================================================
@@ -235,7 +223,7 @@ class LootRoll
public:
using RollVoteMap = std::unordered_map<ObjectGuid, PlayerRollVote>;
- LootRoll() : m_map(nullptr), m_isStarted(false), m_lootItem(nullptr), m_loot(nullptr), m_lootListId(0), m_voteMask(), m_endTime(TimePoint::min()) { }
+ LootRoll() : m_map(nullptr), m_isStarted(false), m_lootItem(nullptr), m_loot(nullptr), m_voteMask(), m_endTime(TimePoint::min()) { }
~LootRoll();
LootRoll(LootRoll const&) = delete;
@@ -263,19 +251,15 @@ private:
bool m_isStarted;
LootItem* m_lootItem;
Loot* m_loot;
- uint32 m_lootListId;
RollMask m_voteMask;
TimePoint m_endTime;
};
struct TC_GAME_API Loot
{
- NotNormalLootItemMap const& GetPlayerQuestItems() const { return PlayerQuestItems; }
NotNormalLootItemMap const& GetPlayerFFAItems() const { return PlayerFFAItems; }
- NotNormalLootItemMap const& GetPlayerNonQuestNonFFAConditionalItems() const { return PlayerNonQuestNonFFAConditionalItems; }
std::vector<LootItem> items;
- std::vector<LootItem> quest_items;
uint32 gold;
uint8 unlootedCount;
ObjectGuid roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released.
@@ -301,8 +285,7 @@ struct TC_GAME_API Loot
bool isLooted() const { return gold == 0 && unlootedCount == 0; }
void NotifyLootList(Map const* map) const;
- void NotifyItemRemoved(uint8 lootIndex, Map const* map);
- void NotifyQuestItemRemoved(uint8 questIndex, Map const* map);
+ void NotifyItemRemoved(uint8 lootListId, Map const* map);
void NotifyMoneyRemoved(Map const* map);
void OnLootOpened(Map* map, ObjectGuid looter);
void AddLooter(ObjectGuid GUID) { PlayersLooting.insert(GUID); }
@@ -312,33 +295,26 @@ struct TC_GAME_API Loot
bool FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError = false, uint16 lootMode = LOOT_MODE_DEFAULT, ItemContext context = ItemContext::NONE);
// Inserts the item into the loot (called by LootTemplate processors)
- void AddItem(LootStoreItem const& item, Player const* player);
+ void AddItem(LootStoreItem const& item);
bool AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast = false, bool createdByPlayer = false);
- LootItem const* GetItemInSlot(uint32 lootSlot) const;
- LootItem* LootItemInSlot(uint32 lootslot, Player* player, NotNormalLootItem** qitem = nullptr, NotNormalLootItem** ffaitem = nullptr, NotNormalLootItem** conditem = nullptr);
- uint32 GetMaxSlotInLootFor(Player* player) const;
+ LootItem const* GetItemInSlot(uint32 lootListId) const;
+ LootItem* LootItemInSlot(uint32 lootListId, Player const* player, NotNormalLootItem** ffaItem = nullptr);
bool hasItemForAll() const;
bool hasItemFor(Player const* player) const;
bool hasOverThresholdItem() const;
// Builds data for SMSG_LOOT_RESPONSE
- void BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* viewer, PermissionTypes permission = ALL_PERMISSION) const;
+ void BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player const* viewer) const;
void Update();
private:
-
void FillNotNormalLootFor(Player const* player);
- NotNormalLootItemList* FillFFALoot(Player const* player);
- NotNormalLootItemList* FillQuestLoot(Player const* player);
- NotNormalLootItemList* FillNonQuestNonFFAConditionalLoot(Player const* player);
GuidSet PlayersLooting;
- NotNormalLootItemMap PlayerQuestItems;
NotNormalLootItemMap PlayerFFAItems;
- NotNormalLootItemMap PlayerNonQuestNonFFAConditionalItems;
// Loot GUID
ObjectGuid _guid;
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index b37d22f10eb..506b26b59ef 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -87,7 +87,7 @@ class LootTemplate::LootGroup // A set of loot def
bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
bool HasQuestDropForPlayer(Player const* player) const;
// The same for active quests of the player
- void Process(Loot& loot, uint16 lootMode, Player const* player) const; // Rolls an item from the group (if any) and adds the item to the loot
+ void Process(Loot& loot, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
float TotalChance() const; // Overall chance for the group
@@ -443,10 +443,10 @@ void LootTemplate::LootGroup::CopyConditions(ConditionContainer /*conditions*/)
}
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
-void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode, Player const* player) const
+void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const
{
if (LootStoreItem const* item = Roll(loot, lootMode))
- loot.AddItem(*item, player);
+ loot.AddItem(*item);
}
// Overall chance for the group without equal chanced items
@@ -563,7 +563,7 @@ void LootTemplate::CopyConditions(LootItem* li) const
}
// Rolls for every item in the template and adds the rolled items the the loot
-void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId, Player const* player) const
+void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId) const
{
if (groupId) // Group reference uses own processing of the group
{
@@ -573,7 +573,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId
if (!Groups[groupId - 1])
return;
- Groups[groupId - 1]->Process(loot, lootMode, player);
+ Groups[groupId - 1]->Process(loot, lootMode);
return;
}
@@ -595,16 +595,16 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId
uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
- Referenced->Process(loot, rate, lootMode, item->groupid, player);
+ Referenced->Process(loot, rate, lootMode, item->groupid);
}
else // Plain entries (not a reference, not grouped)
- loot.AddItem(*item, player); // Chance is already checked, just add
+ loot.AddItem(*item); // Chance is already checked, just add
}
// Now processing groups
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
if (LootGroup* group = *i)
- group->Process(loot, lootMode, player);
+ group->Process(loot, lootMode);
}
// True if template includes at least 1 quest drop entry
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index b6161aed051..5fcd3f28ed6 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -108,7 +108,7 @@ class TC_GAME_API LootTemplate
// Adds an entry to the group (at loading stage)
void AddEntry(LootStoreItem* item);
// Rolls for every item in the template and adds the rolled items the the loot
- void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId, Player const* player) const;
+ void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId) const;
void CopyConditions(ConditionContainer const& conditions);
void CopyConditions(LootItem* li) const;
diff --git a/src/server/game/Mails/Mail.cpp b/src/server/game/Mails/Mail.cpp
index fecbd220ce0..c8b10f410f0 100644
--- a/src/server/game/Mails/Mail.cpp
+++ b/src/server/game/Mails/Mail.cpp
@@ -118,8 +118,7 @@ void MailDraft::prepareItems(Player* receiver, CharacterDatabaseTransaction tran
// can be empty
mailLoot.FillLoot(m_mailTemplateId, LootTemplates_Mail, receiver, true, true, LOOT_MODE_DEFAULT, ItemContext::NONE);
- uint32 max_slot = mailLoot.GetMaxSlotInLootFor(receiver);
- for (uint32 i = 0; m_items.size() < MAX_MAIL_ITEMS && i < max_slot; ++i)
+ for (uint32 i = 0; m_items.size() < MAX_MAIL_ITEMS && i < mailLoot.items.size(); ++i)
{
if (LootItem* lootitem = mailLoot.LootItemInSlot(i, receiver))
{
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 9fcf544b0ec..9340b0f292f 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -1183,7 +1183,7 @@ public:
for (auto it = pair.second->cbegin(); it != pair.second->cend(); ++it)
{
- LootItem const& item = items[it->index];
+ LootItem const& item = items[it->LootListId];
if (!(it->is_looted) && !item.is_looted)
_ShowLootEntry(handler, item.itemid, item.count, true);
}
@@ -1216,11 +1216,6 @@ public:
for (LootItem const& item : loot->items)
if (!item.is_looted)
_ShowLootEntry(handler, item.itemid, item.count);
-
- handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Quest items", loot->quest_items.size());
- for (LootItem const& item : loot->quest_items)
- if (!item.is_looted)
- _ShowLootEntry(handler, item.itemid, item.count);
}
else
{
@@ -1229,23 +1224,11 @@ public:
if (!item.is_looted && !item.freeforall && item.conditions.empty())
_ShowLootEntry(handler, item.itemid, item.count);
- if (!loot->GetPlayerQuestItems().empty())
- {
- handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "Per-player quest items");
- _IterateNotNormalLootMap(handler, loot->GetPlayerQuestItems(), loot->quest_items);
- }
-
if (!loot->GetPlayerFFAItems().empty())
{
handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "FFA items per allowed player");
_IterateNotNormalLootMap(handler, loot->GetPlayerFFAItems(), loot->items);
}
-
- if (!loot->GetPlayerNonQuestNonFFAConditionalItems().empty())
- {
- handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "Per-player conditional items");
- _IterateNotNormalLootMap(handler, loot->GetPlayerNonQuestNonFFAConditionalItems(), loot->items);
- }
}
return true;