diff options
Diffstat (limited to 'src/server/game/Loot/Loot.cpp')
-rw-r--r-- | src/server/game/Loot/Loot.cpp | 240 |
1 files changed, 167 insertions, 73 deletions
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp index d1ab49f662e..6314e9d9f01 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,36 @@ 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); + } + else + player->ApplyItemLootedSpell(sObjectMgr->GetItemTemplate(lootItem->itemid)); + + break; + } + case LootItemType::Currency: + player->ModifyCurrency(lootItem->itemid, lootItem->count, CurrencyGainSource::Loot); + break; } if (ffaitem) @@ -887,14 +973,6 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool lootItem->is_looted = true; --unlootedCount; - - 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); - } - else - player->ApplyItemLootedSpell(sObjectMgr->GetItemTemplate(lootItem->itemid)); } return allLooted; @@ -966,18 +1044,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; } @@ -1004,11 +1076,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; + } + } } |