aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Loot
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2024-12-29 01:02:52 +0100
committerShauren <shauren.trinity@gmail.com>2024-12-29 01:02:52 +0100
commitd913e38cbab9521c80d826417093d22b2c4a1c1a (patch)
tree70d2ecd420f068cc46a116e7f6bd8de5c9e92abd /src/server/game/Loot
parent0b16756172b2c3cc78b0861af86b93daae60edda (diff)
Core/Loot: Implemented automatic flagging of tracking quests from loot
Diffstat (limited to 'src/server/game/Loot')
-rw-r--r--src/server/game/Loot/Loot.cpp79
-rw-r--r--src/server/game/Loot/Loot.h6
-rw-r--r--src/server/game/Loot/LootItemType.h5
-rw-r--r--src/server/game/Loot/LootMgr.cpp48
-rw-r--r--src/server/game/Loot/LootMgr.h7
5 files changed, 126 insertions, 19 deletions
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp
index 35fe799915f..a992e33414c 100644
--- a/src/server/game/Loot/Loot.cpp
+++ b/src/server/game/Loot/Loot.cpp
@@ -57,6 +57,10 @@ LootItem::LootItem(LootStoreItem const& li) : itemid(li.itemid), conditions(li.c
type = LootItemType::Currency;
freeforall = true;
break;
+ case LootStoreItem::Type::TrackingQuest:
+ type = LootItemType::TrackingQuest;
+ freeforall = true;
+ break;
default:
break;
}
@@ -77,6 +81,8 @@ bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot) const
return ItemAllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules, false, conditions);
case LootItemType::Currency:
return CurrencyAllowedForPlayer(player, itemid, needs_quest, conditions);
+ case LootItemType::TrackingQuest:
+ return TrackingQuestAllowedForPlayer(player, itemid, conditions);
default:
break;
}
@@ -93,6 +99,8 @@ bool LootItem::AllowedForPlayer(Player const* player, LootStoreItem const& lootS
strictUsabilityCheck, lootStoreItem.conditions);
case LootStoreItem::Type::Currency:
return CurrencyAllowedForPlayer(player, lootStoreItem.itemid, lootStoreItem.needs_quest, lootStoreItem.conditions);
+ case LootStoreItem::Type::TrackingQuest:
+ return TrackingQuestAllowedForPlayer(player, lootStoreItem.itemid, lootStoreItem.conditions);
default:
break;
}
@@ -177,6 +185,18 @@ bool LootItem::CurrencyAllowedForPlayer(Player const* player, uint32 currencyId,
return true;
}
+bool LootItem::TrackingQuestAllowedForPlayer(Player const* player, uint32 questId, ConditionsReference const& conditions)
+{
+ // DB conditions check
+ if (!conditions.Meets(player))
+ return false;
+
+ if (player->IsQuestCompletedBitSet(questId))
+ return false;
+
+ return true;
+}
+
void LootItem::AddAllowedLooter(Player const* player)
{
allowedGUIDs.insert(player->GetGUID());
@@ -774,9 +794,9 @@ void Loot::NotifyMoneyRemoved(Map const* map)
}
}
-void Loot::OnLootOpened(Map* map, ObjectGuid looter)
+void Loot::OnLootOpened(Map* map, Player* looter)
{
- AddLooter(looter);
+ AddLooter(looter->GetGUID());
if (!_wasOpened)
{
_wasOpened = true;
@@ -804,18 +824,20 @@ void Loot::OnLootOpened(Map* map, ObjectGuid looter)
}
else if (_lootMethod == MASTER_LOOT)
{
- if (looter == _lootMaster)
+ if (looter->GetGUID() == _lootMaster)
{
- if (Player* lootMaster = ObjectAccessor::GetPlayer(map, looter))
- {
- WorldPackets::Loot::MasterLootCandidateList masterLootCandidateList;
- masterLootCandidateList.LootObj = GetGUID();
- masterLootCandidateList.Players = _allowedLooters;
- lootMaster->SendDirectMessage(masterLootCandidateList.Write());
- }
+ WorldPackets::Loot::MasterLootCandidateList masterLootCandidateList;
+ masterLootCandidateList.LootObj = GetGUID();
+ masterLootCandidateList.Players = _allowedLooters;
+ looter->SendDirectMessage(masterLootCandidateList.Write());
}
}
}
+
+ // Flag tracking quests as completed after all items were scanned for this player (some might depend on this quest not being completed)
+ //if (!_mailUnlootedItems)
+ if (std::vector<NotNormalLootItem>* ffaItems = Trinity::Containers::MapGetValuePtr(PlayerFFAItems, looter->GetGUID()))
+ AutoStoreTrackingQuests(looter, *ffaItems);
}
bool Loot::HasAllowedLooter(ObjectGuid const& looter) const
@@ -866,7 +888,7 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
roundRobinPlayer = lootOwner->GetGUID();
for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
- if (Player const* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
+ if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
if (player->IsAtGroupRewardDistance(lootOwner))
FillNotNormalLootFor(player);
@@ -939,6 +961,14 @@ void Loot::AddItem(LootStoreItem const& item)
items.push_back(generatedLoot);
break;
}
+ case LootStoreItem::Type::TrackingQuest:
+ {
+ LootItem generatedLoot(item);
+ generatedLoot.count = 1;
+ generatedLoot.LootListId = items.size();
+ items.push_back(generatedLoot);
+ break;
+ }
default:
break;
}
@@ -995,6 +1025,11 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool
case LootItemType::Currency:
player->ModifyCurrency(lootItem->itemid, lootItem->count, CurrencyGainSource::Loot);
break;
+ case LootItemType::TrackingQuest:
+
+ if (Quest const* quest = sObjectMgr->GetQuestTemplate(lootItem->itemid))
+ player->RewardQuest(quest, LootItemType::Item, 0, player, false);
+ break;
}
if (ffaitem)
@@ -1009,6 +1044,20 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool
return allLooted;
}
+void Loot::AutoStoreTrackingQuests(Player* player, NotNormalLootItemList& ffaItems)
+{
+ for (NotNormalLootItem& ffaItem : ffaItems)
+ {
+ if (items[ffaItem.LootListId].type != LootItemType::TrackingQuest)
+ continue;
+
+ --unlootedCount;
+ ffaItem.is_looted = true;
+ if (Quest const* quest = sObjectMgr->GetQuestTemplate(items[ffaItem.LootListId].itemid))
+ player->RewardQuest(quest, LootItemType::Item, 0, player, false);
+ }
+}
+
void Loot::LootMoney()
{
gold = 0;
@@ -1149,7 +1198,7 @@ void Loot::Update()
}
}
-void Loot::FillNotNormalLootFor(Player const* player)
+void Loot::FillNotNormalLootFor(Player* player)
{
ObjectGuid plguid = player->GetGUID();
_allowedLooters.insert(plguid);
@@ -1176,7 +1225,13 @@ void Loot::FillNotNormalLootFor(Player const* player)
}
if (!ffaItems->empty())
+ {
+ // TODO: flag immediately for loot that is supposed to be mailed if unlooted, otherwise flag when sending SMSG_LOOT_RESPONSE
+ //if (_mailUnlootedItems)
+ // AutoStoreTrackingQuests(player, *ffaItems);
+
PlayerFFAItems[player->GetGUID()] = std::move(ffaItems);
+ }
}
//
diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h
index f29975ebeee..14b9509a678 100644
--- a/src/server/game/Loot/Loot.h
+++ b/src/server/game/Loot/Loot.h
@@ -212,6 +212,7 @@ struct TC_GAME_API LootItem
static bool ItemAllowedForPlayer(Player const* player, Loot const* loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck,
ConditionsReference const& conditions);
static bool CurrencyAllowedForPlayer(Player const* player, uint32 currencyId, bool needs_quest, ConditionsReference const& conditions);
+ static bool TrackingQuestAllowedForPlayer(Player const* player, uint32 questId, ConditionsReference const& conditions);
void AddAllowedLooter(Player const* player);
GuidSet const& GetAllowedLooters() const { return allowedGUIDs; }
bool HasAllowedLooter(ObjectGuid const& looter) const;
@@ -314,7 +315,7 @@ struct TC_GAME_API Loot
void NotifyLootList(Map const* map) const;
void NotifyItemRemoved(uint8 lootListId, Map const* map);
void NotifyMoneyRemoved(Map const* map);
- void OnLootOpened(Map* map, ObjectGuid looter);
+ void OnLootOpened(Map* map, Player* looter);
void AddLooter(ObjectGuid GUID) { PlayersLooting.insert(GUID); }
void RemoveLooter(ObjectGuid GUID) { PlayersLooting.erase(GUID); }
@@ -322,12 +323,13 @@ struct TC_GAME_API Loot
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount);
bool FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError = false, uint16 lootMode = LOOT_MODE_DEFAULT, ItemContext context = ItemContext::NONE);
- void FillNotNormalLootFor(Player const* player); // count unlooted items
+ void FillNotNormalLootFor(Player* player); // count unlooted items
// Inserts the item into the loot (called by LootTemplate processors)
void AddItem(LootStoreItem const& item);
bool AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast = false, bool createdByPlayer = false);
+ void AutoStoreTrackingQuests(Player* player, NotNormalLootItemList& ffaItems);
void LootMoney();
LootItem const* GetItemInSlot(uint32 lootListId) const;
diff --git a/src/server/game/Loot/LootItemType.h b/src/server/game/Loot/LootItemType.h
index 31f0da51787..aa1d420295e 100644
--- a/src/server/game/Loot/LootItemType.h
+++ b/src/server/game/Loot/LootItemType.h
@@ -22,8 +22,9 @@
enum class LootItemType : uint8
{
- Item = 0,
- Currency = 1
+ Item = 0,
+ Currency = 1,
+ TrackingQuest = 2
};
#endif // LootItemType_h__
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index b974c7dd8d9..e1134b479a9 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -271,6 +271,8 @@ bool LootStoreItem::Roll(bool rate) const
return roll_chance_f(chance * qualityModifier);
}
+ case Type::TrackingQuest:
+ return roll_chance_f(chance);
default:
break;
}
@@ -364,6 +366,45 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
}
break;
}
+ case Type::TrackingQuest:
+ {
+ Quest const* quest = sObjectMgr->GetQuestTemplate(itemid);
+ if (!quest)
+ {
+ TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: quest does not exist - skipped",
+ store.GetName(), entry, type, itemid);
+ return false;
+ }
+
+ if (!quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT))
+ {
+ TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: quest is not a tracking flag - 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 (mincount != 1 || maxcount) // wrong count
+ {
+ TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: tracking quest has count other than 1 (MinCount {} MaxCount {}) - skipped",
+ store.GetName(), entry, type, itemid, int32(maxcount), mincount);
+ return false;
+ }
+ break;
+ }
default:
TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: invalid ItemType {}, skipped",
@@ -579,6 +620,10 @@ void LootTemplate::CopyConditions(LootItem* li) const
if (li->type != LootItemType::Currency)
continue;
break;
+ case LootStoreItem::Type::TrackingQuest:
+ if (li->type != LootItemType::TrackingQuest)
+ continue;
+ break;
default:
break;
}
@@ -619,6 +664,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId
{
case LootStoreItem::Type::Item:
case LootStoreItem::Type::Currency:
+ case LootStoreItem::Type::TrackingQuest:
// Plain entries (not a reference, not grouped)
// Chance is already checked, just add
if (!personalLooter || LootItem::AllowedForPlayer(personalLooter, *item, true))
@@ -729,6 +775,7 @@ void LootTemplate::ProcessPersonalLoot(std::unordered_map<Player*, std::unique_p
break;
}
case LootStoreItem::Type::Currency:
+ case LootStoreItem::Type::TrackingQuest:
{
// Plain entries (not a reference, not grouped)
// Chance is already checked, just add
@@ -786,6 +833,7 @@ bool LootTemplate::HasDropForPlayer(Player const* player, uint8 groupId, bool st
{
case LootStoreItem::Type::Item:
case LootStoreItem::Type::Currency:
+ case LootStoreItem::Type::TrackingQuest:
if (LootItem::AllowedForPlayer(player, *lootStoreItem, strictUsabilityCheck))
return true; // active quest drop found
break;
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index 92501e53ef5..fea1155ac63 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -39,9 +39,10 @@ struct TC_GAME_API LootStoreItem
{
enum class Type : int8
{
- Item = 0,
- Reference = 1,
- Currency = 2,
+ Item = 0,
+ Reference = 1,
+ Currency = 2,
+ TrackingQuest = 3,
};
uint32 itemid; // id of the item