From 3e28ee080a1cf3c7cd332a8d1e0808505b4ea9d4 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 26 Aug 2024 15:02:22 +0200 Subject: Core/Loot: Implemented currency loot --- src/server/game/Entities/Player/Player.cpp | 126 ++++++++++++++++++++--------- src/server/game/Entities/Player/Player.h | 1 + 2 files changed, 89 insertions(+), 38 deletions(-) (limited to 'src/server/game/Entities/Player') diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 0816202ba2f..2a53a6906bb 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -16960,6 +16960,44 @@ QuestObjective const* Player::GetQuestObjectiveForItem(uint32 itemId, bool onlyI return nullptr; } +bool Player::HasQuestForCurrency(uint32 currencyId) const +{ + auto isCompletableObjective = [this](QuestObjectiveStatusData const& objectiveStatus) + { + Quest const* qInfo = sObjectMgr->GetQuestTemplate(objectiveStatus.QuestStatusItr->first); + QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveStatus.ObjectiveId); + if (!qInfo || !objective || !IsQuestObjectiveCompletable(objectiveStatus.QuestStatusItr->second.Slot, qInfo, *objective)) + return false; + + // hide quest if player is in raid-group and quest is no raid quest + if (GetGroup() && GetGroup()->isRaidGroup() && !qInfo->IsAllowedInRaid(GetMap()->GetDifficultyID())) + if (!InBattleground()) //there are two ways.. we can make every bg-quest a raidquest, or add this code here.. i don't know if this can be exploited by other quests, but i think all other quests depend on a specific area.. but keep this in mind, if something strange happens later + return false; + + if (!IsQuestObjectiveComplete(objectiveStatus.QuestStatusItr->second.Slot, qInfo, *objective)) + return true; + + return false; + }; + + auto hasObjectiveTypeForCurrency = [&](QuestObjectiveType type) + { + return std::ranges::any_of(Trinity::Containers::MapEqualRange(m_questObjectiveStatus, { type, currencyId }), + isCompletableObjective, &QuestObjectiveStatusMap::value_type::second); + }; + + if (hasObjectiveTypeForCurrency(QUEST_OBJECTIVE_CURRENCY)) + return true; + + if (hasObjectiveTypeForCurrency(QUEST_OBJECTIVE_HAVE_CURRENCY)) + return true; + + if (hasObjectiveTypeForCurrency(QUEST_OBJECTIVE_OBTAIN_CURRENCY)) + return true; + + return false; +} + int32 Player::GetQuestObjectiveData(QuestObjective const& objective) const { uint16 slot = FindQuestSlot(objective.QuestID); @@ -26601,53 +26639,65 @@ void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot* return; } - ItemPosCountVec dest; - InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); - if (msg == EQUIP_ERR_OK) + switch (item->type) { - Item* newitem = StoreNewItem(dest, item->itemid, true, item->randomBonusListId, item->GetAllowedLooters(), item->context); - - if (ffaItem) + case LootItemType::Item: { - //freeforall case, notify only one player of the removal - ffaItem->is_looted = true; - SendNotifyLootItemRemoved(loot->GetGUID(), loot->GetOwnerGUID(), lootSlot); - } - else //not freeforall, notify everyone - loot->NotifyItemRemoved(lootSlot, GetMap()); + ItemPosCountVec dest; + InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); + if (msg != EQUIP_ERR_OK) + { + SendEquipError(msg, nullptr, nullptr, item->itemid); + return; + } - //if only one person is supposed to loot the item, then set it to looted - if (!item->freeforall) - item->is_looted = true; + Item* newitem = StoreNewItem(dest, item->itemid, true, item->randomBonusListId, item->GetAllowedLooters(), item->context); - --loot->unlootedCount; + if (newitem && (newitem->GetQuality() > ITEM_QUALITY_EPIC || (newitem->GetQuality() == ITEM_QUALITY_EPIC && newitem->GetItemLevel(this) >= MinNewsItemLevel))) + if (Guild* guild = GetGuild()) + guild->AddGuildNews(GUILD_NEWS_ITEM_LOOTED, GetGUID(), 0, item->itemid); - if (newitem && (newitem->GetQuality() > ITEM_QUALITY_EPIC || (newitem->GetQuality() == ITEM_QUALITY_EPIC && newitem->GetItemLevel(this) >= MinNewsItemLevel))) - if (Guild* guild = GetGuild()) - guild->AddGuildNews(GUILD_NEWS_ITEM_LOOTED, GetGUID(), 0, item->itemid); + // if aeLooting then we must delay sending out item so that it appears properly stacked in chat + if (!aeResult || !newitem) + { + SendNewItem(newitem, uint32(item->count), false, false, true, loot->GetDungeonEncounterId()); + UpdateCriteria(CriteriaType::LootItem, item->itemid, item->count); + UpdateCriteria(CriteriaType::GetLootByType, item->itemid, item->count, GetLootTypeForClient(loot->loot_type)); + UpdateCriteria(CriteriaType::LootAnyItem, item->itemid, item->count); + } + else + aeResult->Add(newitem, item->count, GetLootTypeForClient(loot->loot_type), loot->GetDungeonEncounterId()); - // if aeLooting then we must delay sending out item so that it appears properly stacked in chat - if (!aeResult || !newitem) - { - SendNewItem(newitem, uint32(item->count), false, false, true, loot->GetDungeonEncounterId()); - UpdateCriteria(CriteriaType::LootItem, item->itemid, item->count); - UpdateCriteria(CriteriaType::GetLootByType, item->itemid, item->count, GetLootTypeForClient(loot->loot_type)); - UpdateCriteria(CriteriaType::LootAnyItem, item->itemid, item->count); - } - else - aeResult->Add(newitem, item->count, GetLootTypeForClient(loot->loot_type), loot->GetDungeonEncounterId()); + if (newitem) + ApplyItemLootedSpell(newitem, true); + else + ApplyItemLootedSpell(sObjectMgr->GetItemTemplate(item->itemid)); - // LootItem is being removed (looted) from the container, delete it from the DB. - if (loot->loot_type == LOOT_ITEM) - sLootItemStorage->RemoveStoredLootItemForContainer(lootWorldObjectGuid.GetCounter(), item->itemid, item->count, item->LootListId); + break; + } + case LootItemType::Currency: + ModifyCurrency(item->itemid, item->count, CurrencyGainSource::Loot); + break; + } - if (newitem) - ApplyItemLootedSpell(newitem, true); - else - ApplyItemLootedSpell(sObjectMgr->GetItemTemplate(item->itemid)); + if (ffaItem) + { + //freeforall case, notify only one player of the removal + ffaItem->is_looted = true; + SendNotifyLootItemRemoved(loot->GetGUID(), loot->GetOwnerGUID(), lootSlot); } - else - SendEquipError(msg, nullptr, nullptr, item->itemid); + else //not freeforall, notify everyone + loot->NotifyItemRemoved(lootSlot, GetMap()); + + //if only one person is supposed to loot the item, then set it to looted + if (!item->freeforall) + item->is_looted = true; + + --loot->unlootedCount; + + // LootItem is being removed (looted) from the container, delete it from the DB. + if (loot->loot_type == LOOT_ITEM) + sLootItemStorage->RemoveStoredLootItemForContainer(lootWorldObjectGuid.GetCounter(), item->type, item->itemid, item->count, item->LootListId); } void Player::_LoadSkills(PreparedQueryResult result) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 43a42c6ab71..5dbc2e8c305 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1726,6 +1726,7 @@ class TC_GAME_API Player final : public Unit, public GridObject bool HasQuestForItem(uint32 itemId) const; QuestObjective const* GetQuestObjectiveForItem(uint32 itemId, bool onlyIncomplete) const; bool HasQuestForGO(int32 goId) const; + bool HasQuestForCurrency(uint32 currencyId) const; void UpdateVisibleObjectInteractions(bool allUnits, bool onlySpellClicks, bool gameObjectQuestGiverStatus, bool questObjectiveGameObjects); bool CanShareQuest(uint32 questId) const; -- cgit v1.2.3