81 return ItemAllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules,
false, conditions);
83 return CurrencyAllowedForPlayer(player, itemid, needs_quest, conditions);
85 return TrackingQuestAllowedForPlayer(player, itemid, conditions);
94 switch (lootStoreItem.
type)
99 strictUsabilityCheck, lootStoreItem.
conditions);
143 if (player->
HasSpell(itemEffect->SpellID))
152 if (strictUsabilityCheck)
223 if (ffaItemItr != ffaItems->end() && !ffaItemItr->is_looted)
301 startLootRoll.
ValidRolls &= ~ROLL_FLAG_TYPE_NEED;
328 lootAllPassed.
Write();
348 lootRoll.
Player = targetGuid;
349 lootRoll.
Roll = rollNumber;
362 if (playerGuid == rollWinner)
378 player->SendDirectMessage(lootRoll.
Write());
398 SendRoll(playerGuid, roll.RollNumber, roll.Vote, targetGuid);
405 lootRollWon.
Winner = targetGuid;
406 lootRollWon.
Roll = rollNumber;
419 if (playerGuid == targetGuid)
433 player->SendDirectMessage(lootRollWon.
Write());
469 if (lootListId >= loot.
items.size())
524 RollVoteMap::iterator voterItr =
m_rollVoteMap.find(playerGuid);
528 voterItr->second.Vote = vote;
531 voterItr->second.RollNumber =
urand(1, 100);
590 bool isSomeoneNeed =
false;
595 switch (itr->second.Vote)
598 if (!isSomeoneNeed || winnerItr ==
m_rollVoteMap.end() || itr->second.RollNumber > winnerItr->second.RollNumber)
600 isSomeoneNeed =
true;
608 if (winnerItr ==
m_rollVoteMap.end() || itr->second.RollNumber > winnerItr->second.RollNumber)
623 return notVoted == 0;
648 return disenchantLoot->
ID;
685 SendLootRollWon(winnerItr->first, winnerItr->second.RollNumber, winnerItr->second.Vote);
705 player->SendItemRetrievalMail(disenchantLoot->itemid, disenchantLoot->count, disenchantLoot->context);
724 _lootMaster(group ? group->GetMasterLooterGuid() :
ObjectGuid::
Empty), _wasOpened(false), _changed(false), _dungeonEncounterId(0)
733 player->GetSession()->DoLootRelease(
this);
753 allowedLooter->SendDirectMessage(lootList.
GetRawPacket());
786 player->SendNotifyLootMoneyRemoved(
GetGUID());
803 uint16 maxEnchantingSkill = 0;
806 maxEnchantingSkill = std::max(maxEnchantingSkill, allowedLooter->GetSkillValue(
SKILL_ENCHANTING));
808 for (
uint32 lootListId = 0; lootListId <
items.size(); ++lootListId)
814 auto&& [itr, inserted] =
_rolls.try_emplace(lootListId);
815 if (!itr->second.TryToStart(map, *
this, lootListId, maxEnchantingSkill))
849 if (maxAmount <= minAmount)
851 else if ((maxAmount - minAmount) < 32700)
870 TC_LOG_ERROR(
"sql.sql",
"Table '{}' loot id #{} used but it doesn't have records.", store.
GetName(), lootId);
882 if (!personal && group)
889 Player* member = itr.GetSource();
902 item.is_underthreshold =
true;
911 item.is_blocked =
true;
950 items.push_back(generatedLoot);
960 items.push_back(generatedLoot);
966 generatedLoot.
count = 1;
968 items.push_back(generatedLoot);
978 bool allLooted =
true;
997 switch (lootItem->
type)
1054 ffaItem.is_looted =
true;
1068 if (lootListId <
items.size())
1069 return &
items[lootListId];
1076 if (lootListId >=
items.size())
1089 if (notNormalLootItem.LootListId == lootListId)
1091 is_looted = notNormalLootItem.is_looted;
1093 *ffaItem = ¬NormalLootItem;
1116 if (!item.is_looted && item.follow_loot_rules && !item.freeforall && item.conditions.IsEmpty())
1126 if (!lootItem.is_looted && !lootItem.follow_loot_rules && lootItem.GetAllowedLooters().contains(player->
GetGUID()))
1141 if (!
items[i].is_looted && !
items[i].is_underthreshold && !
items[i].freeforall)
1164 lootItem.
Type = item.type;
1165 lootItem.
UIType = *uiType;
1174 lootCurrency.
Quantity = item.count;
1176 lootCurrency.
UIType = *uiType;
1193 if (itr->second.UpdateRoll())
1205 std::unique_ptr<NotNormalLootItemList> ffaItems = std::make_unique<NotNormalLootItemList>();
1209 if (!item.AllowedForPlayer(player,
this))
1212 item.AddAllowedLooter(player);
1214 if (item.freeforall)
1216 ffaItems->emplace_back(item.LootListId);
1219 else if (!item.is_counted)
1221 item.is_counted =
true;
1226 if (!ffaItems->empty())
1242 auto itr =
_byItem.find(item);
1244 _byOrder[itr->second].count += count;
1250 value.
count = count;
DB2Storage< CurrencyTypesEntry > sCurrencyTypesStore("CurrencyTypes.db2", &CurrencyTypesLoadInfo::Instance)
#define ASSERT_NOTNULL(pointer)
ItemRandomBonusListId GenerateItemRandomBonusListId(uint32 item_id)
@ ITEM_FLAG2_FACTION_HORDE
@ ITEM_FLAG2_FACTION_ALLIANCE
@ ITEM_FLAG2_CAN_ONLY_ROLL_GREED
@ ITEM_SPELLTRIGGER_ON_LEARN
@ ITEM_FLAG_HIDE_UNUSABLE_RECIPE
@ ITEM_FLAGS_CU_FOLLOW_LOOT_RULES
@ ITEM_FLAGS_CU_IGNORE_QUEST_STATUS
#define TC_LOG_ERROR(filterType__, message__,...)
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true)
@ ROLL_FLAG_TYPE_DISENCHANT
@ LOOT_SLOT_TYPE_ROLL_ONGOING
@ LOOT_SLOT_TYPE_ALLOW_LOOT
std::vector< NotNormalLootItem > NotNormalLootItemList
#define MAX_NR_LOOT_ITEMS
constexpr Minutes LOOT_ROLL_TIMEOUT
std::set< ObjectGuid > GuidSet
std::optional< T > Optional
Optional helper class to wrap optional values within.
std::vector< ItemPosCount > ItemPosCountVec
uint32 urand(uint32 min, uint32 max)
@ SPELL_AURA_MOD_CURRENCY_CATEGORY_GAIN_PCT
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
std::unordered_map< Item *, OrderedStorage::size_type > _byItem
OrderedStorage::const_iterator end() const
OrderedStorage::const_iterator begin() const
void Add(Item *item, uint8 count, LootType lootType, uint32 dungeonEncounterId)
ObjectGuid const & GetGUID() const
ItemQualities GetLootThreshold() const
GroupRefManager & GetMembers()
static ItemDisenchantLootEntry const * GetBaseDisenchantLoot(ItemTemplate const *itemTemplate, uint32 quality, uint32 itemLevel)
uint32 GetItemLevel(Player const *owner) const
bool PlayerVote(Player *player, RollVote vote)
Optional< uint16 > GetItemDisenchantSkillRequired() const
void Finish(RollVoteMap::const_iterator winnerItr)
bool AllPlayerVoted(RollVoteMap::const_iterator &winnerItr)
Check if all player have voted and return true in that case. Also return current winner.
bool TryToStart(Map *map, Loot &loot, uint32 lootListId, uint16 enchantingSkill)
Optional< uint32 > GetItemDisenchantLootId() const
bool IsLootItem(ObjectGuid const &lootObject, uint32 lootListId) const
RollVoteMap m_rollVoteMap
void SendLootRollWon(ObjectGuid const &targetGuid, int32 rollNumber, RollVote rollType)
void SendRoll(ObjectGuid const &targetGuid, int32 rollNumber, RollVote rollType, Optional< ObjectGuid > const &rollWinner)
void FillPacket(WorldPackets::Loot::LootItemData &lootItem) const
LootTemplate const * GetLootFor(uint32 loot_id) const
bool IsRatesAllowed() const
char const * GetName() const
void Process(Loot &loot, bool rate, uint16 lootMode, uint8 groupId, Player const *personalLooter=nullptr) const
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Item * StoreNewItem(ItemPosCountVec const &pos, uint32 itemId, bool update, ItemRandomBonusListId randomBonusListId=0, GuidSet const &allowedLooters=GuidSet(), ItemContext context=ItemContext::NONE, std::vector< int32 > const *bonusListIDs=nullptr, bool addToCollection=true)
void ApplyItemLootedSpell(Item *item, bool apply)
InventoryResult CanRollNeedForItem(ItemTemplate const *item, Map const *map, bool restrictOnlyLfg) const
void SendDirectMessage(WorldPacket const *data) const
bool HasQuestForItem(uint32 itemId) const
bool HasQuestForCurrency(uint32 currencyId) const
bool IsQuestCompletedBitSet(uint32 questId) const
bool IsAtGroupRewardDistance(WorldObject const *pRewardSource) const
bool HasSkill(uint32 skill) const
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
void AddLootRoll(LootRoll *roll)
QuestStatus GetQuestStatus(uint32 quest_id) const
bool GetPassOnGroupLoot() const
bool HasSpell(uint32 spell) const override
Group * GetGroup(Optional< uint8 > partyIndex)
void RemoveLootRoll(LootRoll *roll)
void ModifyCurrency(uint32 id, int32 amount, CurrencyGainSource gainSource=CurrencyGainSource::Cheat, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Modify currency amount.
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
void RewardQuest(Quest const *quest, LootItemType rewardType, uint32 rewardId, Object *questGiver, bool announce=true)
void SendNewItem(Item *item, uint32 quantity, bool received, bool created, bool broadcast=false, uint32 dungeonEncounterId=0)
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
WorldPacket const * Write() override
Optional< ObjectGuid > Master
WorldPacket const * Write() override
Optional< ObjectGuid > RoundRobinWinner
std::vector< LootItemData > Items
std::vector< LootCurrency > Currencies
WorldPacket const * Write() override
int32 Roll
Roll value can be negative, it means that it is an "offspec" roll but only during roll selection broa...
bool Autopassed
Triggers message |HlootHistory:d|h[Loot]|h: You automatically passed on: s because you cannot loot th...
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Duration< Milliseconds, uint32 > RollTime
WorldPacket const * GetRawPacket() const
TimePoint Now()
Current chrono steady_clock time point.
std::vector< int32 > GetBonusListsForItem(uint32 itemId, ItemBonusGenerationParams const ¶ms)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
uint32 dungeonEncounterId
void Initialize(ItemTemplate const *proto)
bool Meets(WorldObject const *object) const
EnumFlag< CurrencyTypesFlags > GetFlags() const
uint32 GetMaxStackSize() const
uint32 GetStartQuest() const
std::vector< ItemEffectEntry const * > Effects
bool HasFlag(ItemFlags flag) const
bool IsUsableByLootSpecialization(Player const *player, bool alwaysAllowBoundToAccount) const
uint32 GetRequiredSkill() const
bool HasAllowedLooter(ObjectGuid const &looter) const
std::vector< int32 > BonusListIDs
Optional< LootSlotType > GetUiTypeForPlayer(Player const *player, Loot const &loot) const
void AddAllowedLooter(Player const *player)
ObjectGuid rollWinnerGUID
bool AllowedForPlayer(Player const *player, Loot const *loot) const
static bool CurrencyAllowedForPlayer(Player const *player, uint32 currencyId, bool needs_quest, ConditionsReference const &conditions)
static bool ItemAllowedForPlayer(Player const *player, Loot const *loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck, ConditionsReference const &conditions)
ItemRandomBonusListId randomBonusListId
ConditionsReference conditions
GuidSet const & GetAllowedLooters() const
static bool TrackingQuestAllowedForPlayer(Player const *player, uint32 questId, ConditionsReference const &conditions)
ConditionsReference conditions
void AutoStoreTrackingQuests(Player *player, NotNormalLootItemList &ffaItems)
void OnLootOpened(Map *map, Player *looter)
void AddLooter(ObjectGuid GUID)
void FillNotNormalLootFor(Player *player)
void NotifyLootList(Map const *map) const
bool AutoStore(Player *player, uint8 bag, uint8 slot, bool broadcast=false, bool createdByPlayer=false)
GuidUnorderedSet _allowedLooters
bool hasOverThresholdItem() const
NotNormalLootItemMap PlayerFFAItems
void BuildLootResponse(WorldPackets::Loot::LootResponse &packet, Player const *viewer) const
void NotifyMoneyRemoved(Map const *map)
void NotifyItemRemoved(uint8 lootListId, Map const *map)
Loot(Map *map, ObjectGuid owner, LootType type, Group const *group)
void AddItem(LootStoreItem const &item)
LootItem const * GetItemInSlot(uint32 lootListId) const
ObjectGuid roundRobinPlayer
ObjectGuid const & GetOwnerGUID() const
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
bool hasItemFor(Player const *player) const
bool hasItemForAll() const
LootItem * LootItemInSlot(uint32 lootListId, Player const *player, NotNormalLootItem **ffaItem=nullptr)
ObjectGuid const & GetGUID() const
std::vector< LootItem > items
std::unordered_map< uint32, LootRoll > _rolls
NotNormalLootItemMap const & GetPlayerFFAItems() const
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT, ItemContext context=ItemContext::NONE)
uint32 GetDungeonEncounterId() const
ObjectGuid const & GetLootMasterGUID() const
LootMethod GetLootMethod() const
bool HasAllowedLooter(ObjectGuid const &looter) const
void Initialize(::Item const *item)
WorldPackets::Item::ItemInstance Loot