diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-12-29 01:02:52 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2024-12-29 01:02:52 +0100 |
commit | d913e38cbab9521c80d826417093d22b2c4a1c1a (patch) | |
tree | 70d2ecd420f068cc46a116e7f6bd8de5c9e92abd /src/server/game/Loot | |
parent | 0b16756172b2c3cc78b0861af86b93daae60edda (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.cpp | 79 | ||||
-rw-r--r-- | src/server/game/Loot/Loot.h | 6 | ||||
-rw-r--r-- | src/server/game/Loot/LootItemType.h | 5 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 48 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.h | 7 |
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 |