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 | |
parent | 0b16756172b2c3cc78b0861af86b93daae60edda (diff) |
Core/Loot: Implemented automatic flagging of tracking quests from loot
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 5 | ||||
-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 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/Language.h | 2 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_npc.cpp | 28 |
8 files changed, 158 insertions, 22 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 780176f64f1..6b2ca21827c 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9214,7 +9214,7 @@ void Player::SendLoot(Loot& loot, bool aeLooting) SendDirectMessage(packet.Write()); // add 'this' player as one of the players that are looting 'loot' - loot.OnLootOpened(GetMap(), GetGUID()); + loot.OnLootOpened(GetMap(), this); m_AELootView[loot.GetGUID()] = &loot; if (loot.loot_type == LOOT_CORPSE && !loot.GetOwnerGUID().IsItem()) @@ -26708,6 +26708,9 @@ void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot* case LootItemType::Currency: ModifyCurrency(item->itemid, item->count, CurrencyGainSource::Loot); break; + case LootItemType::TrackingQuest: + // nothing to do, already handled + break; } if (ffaItem) 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 diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 0693d1e9200..bc6c15d525b 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -343,7 +343,7 @@ enum TrinityStrings LANG_COMMAND_NPC_SHOWLOOT_MONEY = 292, LANG_COMMAND_NPC_SHOWLOOT_LABEL_2 = 293, LANG_COMMAND_NPC_SHOWLOOT_SUBLABEL = 294, - LANG_COMMAND_NPC_SHOWLOOT_ENTRY_2 = 295, + LANG_COMMAND_NPC_SHOWLOOT_TRACKING_QUEST = 295, LANG_COMMAND_NPC_SHOWLOOT_CURRENCY = 296, // END diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 376fd0da969..ea62d0ca55b 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1174,7 +1174,7 @@ public: name = itemTemplate->GetName(handler->GetSessionDbcLocale()); if (!name) name = "Unknown item"; - handler->PSendSysMessage(alternateString ? LANG_COMMAND_NPC_SHOWLOOT_ENTRY_2 : LANG_COMMAND_NPC_SHOWLOOT_ENTRY, + handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_ENTRY, alternateString ? 6 : 3 /*number of bytes from following string*/, "\xE2\x94\x80\xE2\x94\x80", itemCount, ItemQualityColors[itemTemplate ? static_cast<ItemQualities>(itemTemplate->GetQuality()) : ITEM_QUALITY_POOR], itemId, name, itemId); } @@ -1190,6 +1190,23 @@ public: count, ItemQualityColors[currency ? static_cast<ItemQualities>(currency->Quality) : ITEM_QUALITY_POOR], currencyId, count, name, currencyId); } + static void _ShowLootTrackingQuestCurrencyEntry(ChatHandler* handler, uint32 questId, bool alternateString = false) + { + Quest const* quest = sObjectMgr->GetQuestTemplate(questId); + std::string_view name; + if (quest) + { + name = quest->GetLogTitle(); + if (handler->GetSessionDbLocaleIndex() != LOCALE_enUS) + if (QuestTemplateLocale const* localeData = sObjectMgr->GetQuestLocale(questId)) + ObjectMgr::GetLocaleString(localeData->LogTitle, handler->GetSessionDbLocaleIndex(), name); + } + if (name.empty()) + name = "Unknown quest"; + handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_TRACKING_QUEST, alternateString ? 6 : 3 /*number of bytes from following string*/, "\xE2\x94\x80\xE2\x94\x80", + questId, STRING_VIEW_FMT_ARG(name), questId); + } + static void _IterateNotNormalLootMap(ChatHandler* handler, NotNormalLootItemMap const& map, std::vector<LootItem> const& items) { for (NotNormalLootItemMap::value_type const& pair : map) @@ -1212,6 +1229,9 @@ public: case LootItemType::Currency: _ShowLootCurrencyEntry(handler, item.itemid, item.count, true); break; + case LootItemType::TrackingQuest: + _ShowLootTrackingQuestCurrencyEntry(handler, item.itemid, true); + break; } } } @@ -1237,6 +1257,9 @@ public: case LootItemType::Currency: _ShowLootCurrencyEntry(handler, item.itemid, item.count); break; + case LootItemType::TrackingQuest: + _ShowLootTrackingQuestCurrencyEntry(handler, item.itemid); + break; } } } @@ -1256,6 +1279,9 @@ public: case LootItemType::Currency: _ShowLootCurrencyEntry(handler, item.itemid, item.count); break; + case LootItemType::TrackingQuest: + _ShowLootTrackingQuestCurrencyEntry(handler, item.itemid); + break; } } } |