aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Loot/Loot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Loot/Loot.cpp')
-rw-r--r--src/server/game/Loot/Loot.cpp234
1 files changed, 165 insertions, 69 deletions
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp
index 85c831eed59..ab022379792 100644
--- a/src/server/game/Loot/Loot.cpp
+++ b/src/server/game/Loot/Loot.cpp
@@ -17,8 +17,8 @@
#include "Loot.h"
#include "Containers.h"
-#include "DatabaseEnv.h"
#include "DB2Stores.h"
+#include "DatabaseEnv.h"
#include "GameTime.h"
#include "Group.h"
#include "Item.h"
@@ -40,26 +40,26 @@
//
// Constructor, copies most fields from LootStoreItem and generates random count
-LootItem::LootItem(LootStoreItem const& li)
+LootItem::LootItem(LootStoreItem const& li) : itemid(li.itemid), conditions(li.conditions), needs_quest(li.needs_quest)
{
- itemid = li.itemid;
- LootListId = 0;
- conditions = li.conditions;
-
- ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid);
- freeforall = proto && proto->HasFlag(ITEM_FLAG_MULTI_DROP);
- follow_loot_rules = !li.needs_quest || (proto && proto->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES));
-
- needs_quest = li.needs_quest;
-
- randomBonusListId = GenerateItemRandomBonusListId(itemid);
- context = ItemContext::NONE;
- count = 0;
- is_looted = false;
- is_blocked = false;
- is_underthreshold = false;
- is_counted = false;
- rollWinnerGUID = ObjectGuid::Empty;
+ switch (li.type)
+ {
+ case LootStoreItem::Type::Item:
+ {
+ randomBonusListId = GenerateItemRandomBonusListId(itemid);
+ type = LootItemType::Item;
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid);
+ freeforall = proto && proto->HasFlag(ITEM_FLAG_MULTI_DROP);
+ follow_loot_rules = !li.needs_quest || (proto && proto->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES));
+ break;
+ }
+ case LootStoreItem::Type::Currency:
+ type = LootItemType::Currency;
+ freeforall = true;
+ break;
+ default:
+ break;
+ }
}
LootItem::LootItem(LootItem const&) = default;
@@ -71,10 +71,35 @@ LootItem::~LootItem() = default;
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot) const
{
- return AllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules, false, conditions);
+ switch (type)
+ {
+ case LootItemType::Item:
+ return ItemAllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules, false, conditions);
+ case LootItemType::Currency:
+ return CurrencyAllowedForPlayer(player, itemid, needs_quest, conditions);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool LootItem::AllowedForPlayer(Player const* player, LootStoreItem const& lootStoreItem, bool strictUsabilityCheck)
+{
+ switch (lootStoreItem.type)
+ {
+ case LootStoreItem::Type::Item:
+ return ItemAllowedForPlayer(player, nullptr, lootStoreItem.itemid, lootStoreItem.needs_quest,
+ !lootStoreItem.needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(lootStoreItem.itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
+ strictUsabilityCheck, lootStoreItem.conditions);
+ case LootStoreItem::Type::Currency:
+ return CurrencyAllowedForPlayer(player, lootStoreItem.itemid, lootStoreItem.needs_quest, lootStoreItem.conditions);
+ default:
+ break;
+ }
+ return false;
}
-bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck,
+bool LootItem::ItemAllowedForPlayer(Player const* player, Loot const* loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck,
ConditionsReference const& conditions)
{
// DB conditions check
@@ -128,14 +153,38 @@ bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot, uint32 i
return true;
}
-void LootItem::AddAllowedLooter(const Player* player)
+bool LootItem::CurrencyAllowedForPlayer(Player const* player, uint32 currencyId, bool needs_quest, ConditionsReference const& conditions)
+{
+ // DB conditions check
+ if (!conditions.Meets(player))
+ return false;
+
+ CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(currencyId);
+ if (!currency)
+ return false;
+
+ // not show loot for not own team
+ if (currency->GetFlags().HasFlag(CurrencyTypesFlags::IsHordeOnly) && player->GetTeam() != HORDE)
+ return false;
+
+ if (currency->GetFlags().HasFlag(CurrencyTypesFlags::IsAllianceOnly) && player->GetTeam() != ALLIANCE)
+ return false;
+
+ // check quest requirements
+ if (needs_quest && !player->HasQuestForCurrency(currencyId))
+ return false;
+
+ return true;
+}
+
+void LootItem::AddAllowedLooter(Player const* player)
{
allowedGUIDs.insert(player->GetGUID());
}
bool LootItem::HasAllowedLooter(ObjectGuid const& looter) const
{
- return allowedGUIDs.find(looter) != allowedGUIDs.end();
+ return allowedGUIDs.contains(looter);
}
Optional<LootSlotType> LootItem::GetUiTypeForPlayer(Player const* player, Loot const& loot) const
@@ -143,7 +192,7 @@ Optional<LootSlotType> LootItem::GetUiTypeForPlayer(Player const* player, Loot c
if (is_looted)
return {};
- if (allowedGUIDs.find(player->GetGUID()) == allowedGUIDs.end())
+ if (!allowedGUIDs.contains(player->GetGUID()))
return {};
if (freeforall)
@@ -604,7 +653,8 @@ void LootRoll::Finish(RollVoteMap::const_iterator winnerItr)
{
for (uint32 i = 0; i < loot.items.size(); ++i)
if (LootItem* disenchantLoot = loot.LootItemInSlot(i, player))
- player->SendItemRetrievalMail(disenchantLoot->itemid, disenchantLoot->count, disenchantLoot->context);
+ if (disenchantLoot->type == LootItemType::Item)
+ player->SendItemRetrievalMail(disenchantLoot->itemid, disenchantLoot->count, disenchantLoot->context);
}
else
m_loot->NotifyItemRemoved(m_lootItem->LootListId, m_map);
@@ -791,7 +841,7 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
for (LootItem& item : items)
{
- if (!item.follow_loot_rules || item.freeforall)
+ if (!item.follow_loot_rules || item.freeforall || item.type != LootItemType::Item)
continue;
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid))
@@ -826,23 +876,40 @@ 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)
{
- ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
- if (!proto)
- return;
+ switch (item.type)
+ {
+ case LootStoreItem::Type::Item:
+ {
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
+ if (!proto)
+ return;
- uint32 count = urand(item.mincount, item.maxcount);
- uint32 stacks = count / proto->GetMaxStackSize() + ((count % proto->GetMaxStackSize()) ? 1 : 0);
+ uint32 count = urand(item.mincount, item.maxcount);
+ uint32 stacks = count / proto->GetMaxStackSize() + ((count % proto->GetMaxStackSize()) ? 1 : 0);
- 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 = items.size();
- generatedLoot.BonusListIDs = ItemBonusMgr::GetBonusListsForItem(generatedLoot.itemid, _itemContext);
-
- items.push_back(generatedLoot);
- count -= proto->GetMaxStackSize();
+ 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 = items.size();
+ generatedLoot.BonusListIDs = ItemBonusMgr::GetBonusListsForItem(generatedLoot.itemid, _itemContext);
+
+ items.push_back(generatedLoot);
+ count -= proto->GetMaxStackSize();
+ }
+ break;
+ }
+ case LootStoreItem::Type::Currency:
+ {
+ LootItem generatedLoot(item);
+ generatedLoot.count = urand(item.mincount, item.maxcount);
+ generatedLoot.LootListId = items.size();
+ items.push_back(generatedLoot);
+ break;
+ }
+ default:
+ break;
}
}
@@ -867,17 +934,34 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool
if (!lootItem->rollWinnerGUID.IsEmpty() && lootItem->rollWinnerGUID != GetGUID())
continue;
- ItemPosCountVec dest;
- InventoryResult msg = player->CanStoreNewItem(bag, slot, dest, lootItem->itemid, lootItem->count);
- if (msg != EQUIP_ERR_OK && slot != NULL_SLOT)
- msg = player->CanStoreNewItem(bag, NULL_SLOT, dest, lootItem->itemid, lootItem->count);
- if (msg != EQUIP_ERR_OK && bag != NULL_BAG)
- msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, lootItem->itemid, lootItem->count);
- if (msg != EQUIP_ERR_OK)
+ switch (lootItem->type)
{
- player->SendEquipError(msg, nullptr, nullptr, lootItem->itemid);
- allLooted = false;
- continue;
+ case LootItemType::Item:
+ {
+ ItemPosCountVec dest;
+ InventoryResult msg = player->CanStoreNewItem(bag, slot, dest, lootItem->itemid, lootItem->count);
+ if (msg != EQUIP_ERR_OK && slot != NULL_SLOT)
+ msg = player->CanStoreNewItem(bag, NULL_SLOT, dest, lootItem->itemid, lootItem->count);
+ if (msg != EQUIP_ERR_OK && bag != NULL_BAG)
+ msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, lootItem->itemid, lootItem->count);
+ if (msg != EQUIP_ERR_OK)
+ {
+ player->SendEquipError(msg, nullptr, nullptr, lootItem->itemid);
+ allLooted = false;
+ continue;
+ }
+
+ if (Item* pItem = player->StoreNewItem(dest, lootItem->itemid, true, lootItem->randomBonusListId, GuidSet(), lootItem->context, &lootItem->BonusListIDs))
+ {
+ player->SendNewItem(pItem, lootItem->count, false, createdByPlayer, broadcast, GetDungeonEncounterId());
+ player->ApplyItemLootedSpell(pItem, true);
+ }
+
+ break;
+ }
+ case LootItemType::Currency:
+ player->ModifyCurrency(lootItem->itemid, lootItem->count, CurrencyGainSource::Loot);
+ break;
}
if (ffaitem)
@@ -887,10 +971,6 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool
lootItem->is_looted = true;
--unlootedCount;
-
- Item* pItem = player->StoreNewItem(dest, lootItem->itemid, true, lootItem->randomBonusListId, GuidSet(), lootItem->context, &lootItem->BonusListIDs);
- player->SendNewItem(pItem, lootItem->count, false, createdByPlayer, broadcast);
- player->ApplyItemLootedSpell(pItem, true);
}
return allLooted;
@@ -962,18 +1042,12 @@ bool Loot::hasItemFor(Player const* player) const
{
// quest items
for (LootItem const& lootItem : items)
- if (!lootItem.is_looted && !lootItem.follow_loot_rules && lootItem.GetAllowedLooters().find(player->GetGUID()) != lootItem.GetAllowedLooters().end())
+ if (!lootItem.is_looted && !lootItem.follow_loot_rules && lootItem.GetAllowedLooters().contains(player->GetGUID()))
return true;
if (NotNormalLootItemList const* ffaItems = Trinity::Containers::MapGetValuePtr(GetPlayerFFAItems(), player->GetGUID()))
- {
- bool hasFfaItem = std::ranges::any_of(*ffaItems, [&](NotNormalLootItem const& ffaItem)
- {
- return !ffaItem.is_looted;
- });
- if (hasFfaItem)
+ if (std::ranges::any_of(*ffaItems, std::identity(), &NotNormalLootItem::is_looted))
return true;
- }
return false;
}
@@ -1000,11 +1074,33 @@ void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player co
if (!uiType)
continue;
- WorldPackets::Loot::LootItemData& lootItem = packet.Items.emplace_back();
- lootItem.LootListID = item.LootListId;
- lootItem.UIType = *uiType;
- lootItem.Quantity = item.count;
- lootItem.Loot.Initialize(item);
+ switch (item.type)
+ {
+ case LootItemType::Item:
+ {
+ WorldPackets::Loot::LootItemData& lootItem = packet.Items.emplace_back();
+ lootItem.LootListID = item.LootListId;
+ lootItem.UIType = *uiType;
+ lootItem.Quantity = item.count;
+ lootItem.Loot.Initialize(item);
+ break;
+ }
+ case LootItemType::Currency:
+ {
+ WorldPackets::Loot::LootCurrency& lootCurrency = packet.Currencies.emplace_back();
+ lootCurrency.CurrencyID = item.itemid;
+ lootCurrency.Quantity = item.count;
+ lootCurrency.LootListID = item.LootListId;
+ lootCurrency.UIType = *uiType;
+
+ // fake visible quantity for SPELL_AURA_MOD_CURRENCY_CATEGORY_GAIN_PCT - handled in Player::ModifyCurrency
+ lootCurrency.Quantity = float(lootCurrency.Quantity) * viewer->GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_CURRENCY_CATEGORY_GAIN_PCT, sCurrencyTypesStore.AssertEntry(item.itemid)->CategoryID);
+ break;
+ }
+ default:
+ break;
+ }
+
}
}