aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Loot/LootMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Loot/LootMgr.cpp')
-rw-r--r--src/server/game/Loot/LootMgr.cpp119
1 files changed, 98 insertions, 21 deletions
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index de99abab57e..2104cc0c5ab 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -66,9 +66,7 @@ struct LootGroupInvalidSelector
if (!(item->lootmode & _lootMode))
return true;
- if (_personalLooter && !LootItem::AllowedForPlayer(_personalLooter, nullptr, item->itemid, item->needs_quest,
- !item->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(item->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
- true, item->conditions))
+ if (_personalLooter && !LootItem::AllowedForPlayer(_personalLooter, *item, true))
return true;
return false;
@@ -265,6 +263,14 @@ bool LootStoreItem::Roll(bool rate) const
}
case Type::Reference:
return roll_chance_f(chance * (rate ? sWorld->getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
+ case Type::Currency:
+ {
+ CurrencyTypesEntry const* currency = sCurrencyTypesStore.AssertEntry(itemid);
+
+ float qualityModifier = currency && rate && QualityToRate[currency->Quality] != MAX_RATES ? sWorld->getRate(QualityToRate[currency->Quality]) : 1.0f;
+
+ return roll_chance_f(chance * qualityModifier);
+ }
default:
break;
}
@@ -327,6 +333,38 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
return false;
}
break;
+ case Type::Currency:
+ {
+ if (!sCurrencyTypesStore.HasRecord(itemid))
+ {
+ TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: currency does not exist - skipped",
+ store.GetName(), entry, type, itemid);
+ return false;
+ }
+
+ if (chance == 0 && groupid == 0) // Zero chance is allowed for grouped entries only
+ {
+ TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: equal-chanced grouped entry, but group not defined - skipped",
+ store.GetName(), entry, type, itemid);
+ return false;
+ }
+
+ if (chance != 0 && chance < 0.0001f) // loot with low chance
+ {
+ TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: low chance ({}) - skipped",
+ store.GetName(), entry, type, itemid, chance);
+ return false;
+ }
+
+ if (maxcount < mincount) // wrong max count
+ {
+ TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: MaxCount ({}) less that MinCount ({}) - skipped",
+ store.GetName(), entry, type, itemid, int32(maxcount), mincount);
+ return false;
+ }
+ break;
+ }
+
default:
TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: invalid ItemType {}, skipped",
store.GetName(), entry, itemid, type);
@@ -387,15 +425,11 @@ LootStoreItem const* LootTemplate::LootGroup::Roll(uint16 lootMode, Player const
bool LootTemplate::LootGroup::HasDropForPlayer(Player const* player, bool strictUsabilityCheck) const
{
for (std::unique_ptr<LootStoreItem> const& lootStoreItem : ExplicitlyChanced)
- if (LootItem::AllowedForPlayer(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))
+ if (LootItem::AllowedForPlayer(player, *lootStoreItem, strictUsabilityCheck))
return true;
for (std::unique_ptr<LootStoreItem> const& lootStoreItem : EqualChanced)
- if (LootItem::AllowedForPlayer(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))
+ if (LootItem::AllowedForPlayer(player, *lootStoreItem, strictUsabilityCheck))
return true;
return false;
@@ -416,10 +450,24 @@ bool LootTemplate::LootGroup::HasQuestDrop() const
// True if group includes at least 1 quest drop entry for active quests of the player
bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const* player) const
{
- if (std::ranges::any_of(ExplicitlyChanced, [player](uint32 itemId) { return player->HasQuestForItem(itemId); }, &LootStoreItem::itemid))
+ auto hasQuestForLootItem = [player](std::unique_ptr<LootStoreItem> const& item)
+ {
+ switch (item->type)
+ {
+ case LootStoreItem::Type::Item:
+ return player->HasQuestForItem(item->itemid);
+ case LootStoreItem::Type::Currency:
+ return player->HasQuestForCurrency(item->itemid);
+ default:
+ break;
+ }
+ return false;
+ };
+
+ if (std::ranges::any_of(ExplicitlyChanced, hasQuestForLootItem))
return true;
- if (std::ranges::any_of(EqualChanced, [player](uint32 itemId) { return player->HasQuestForItem(itemId); }, &LootStoreItem::itemid))
+ if (std::ranges::any_of(EqualChanced, hasQuestForLootItem))
return true;
return false;
@@ -519,6 +567,22 @@ void LootTemplate::CopyConditions(LootItem* li) const
// Copies the conditions list from a template item to a LootItemData
for (std::unique_ptr<LootStoreItem> const& item : Entries)
{
+ switch (item->type)
+ {
+ case LootStoreItem::Type::Item:
+ if (li->type != LootItemType::Item)
+ continue;
+ break;
+ case LootStoreItem::Type::Reference:
+ continue;
+ case LootStoreItem::Type::Currency:
+ if (li->type != LootItemType::Currency)
+ continue;
+ break;
+ default:
+ break;
+ }
+
if (item->itemid != li->itemid)
continue;
@@ -554,12 +618,10 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId
switch (item->type)
{
case LootStoreItem::Type::Item:
+ case LootStoreItem::Type::Currency:
// Plain entries (not a reference, not grouped)
// Chance is already checked, just add
- if (!personalLooter
- || LootItem::AllowedForPlayer(personalLooter, nullptr, item->itemid, item->needs_quest,
- !item->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(item->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
- true, item->conditions))
+ if (!personalLooter || LootItem::AllowedForPlayer(personalLooter, *item, true))
loot.AddItem(*item);
break;
@@ -616,9 +678,7 @@ void LootTemplate::ProcessPersonalLoot(std::unordered_map<Player*, std::unique_p
// Chance is already checked, just add
std::vector<Player*> lootersForItem = getLootersForItem([&](Player const* looter)
{
- return LootItem::AllowedForPlayer(looter, nullptr, item->itemid, item->needs_quest,
- !item->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(item->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
- true, item->conditions);
+ return LootItem::AllowedForPlayer(looter, *item, true);
});
if (!lootersForItem.empty())
@@ -668,6 +728,19 @@ void LootTemplate::ProcessPersonalLoot(std::unordered_map<Player*, std::unique_p
break;
}
+ case LootStoreItem::Type::Currency:
+ {
+ // Plain entries (not a reference, not grouped)
+ // Chance is already checked, just add
+ std::vector<Player*> lootersForItem = getLootersForItem([&](Player const* looter)
+ {
+ return LootItem::AllowedForPlayer(looter, *item, true);
+ });
+
+ for (Player* looter : lootersForItem)
+ personalLoot[looter]->AddItem(*item);
+ break;
+ }
default:
break;
}
@@ -712,9 +785,8 @@ bool LootTemplate::HasDropForPlayer(Player const* player, uint8 groupId, bool st
switch (lootStoreItem->type)
{
case LootStoreItem::Type::Item:
- if (LootItem::AllowedForPlayer(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:
+ if (LootItem::AllowedForPlayer(player, *lootStoreItem, strictUsabilityCheck))
return true; // active quest drop found
break;
case LootStoreItem::Type::Reference:
@@ -758,6 +830,7 @@ bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) con
switch (item->type)
{
case LootStoreItem::Type::Item:
+ case LootStoreItem::Type::Currency:
if (item->needs_quest)
return true; // quest drop found
break;
@@ -815,6 +888,10 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co
return true;
break;
}
+ case LootStoreItem::Type::Currency:
+ if (player->HasQuestForCurrency(item->itemid))
+ return true; // active quest drop found
+ break;
default:
break;
}