diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 67 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 3 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 37 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 10 | ||||
-rw-r--r-- | src/server/game/Handlers/MiscHandler.cpp | 23 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 4 |
6 files changed, 121 insertions, 23 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8a3f4720a2b..40f6b748d59 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -6608,6 +6608,8 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo if (count > 0) UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CURRENCY, id, count); + CurrencyChanged(id, count); + if (currency->CategoryID == CURRENCY_CATEGORY_META_CONQUEST) { // count was changed to week limit, now we can modify original points. @@ -13860,6 +13862,9 @@ bool Player::CanCompleteQuest(uint32 quest_id) case QUEST_OBJECTIVE_GAMEOBJECT: case QUEST_OBJECTIVE_PLAYERKILLS: case QUEST_OBJECTIVE_TALKTO: + case QUEST_OBJECTIVE_WINPVPPETBATTLES: + case QUEST_OBJECTIVE_HAVE_CURRENCY: + case QUEST_OBJECTIVE_OBTAIN_CURRENCY: if (GetQuestObjectiveData(qInfo, obj.StorageIndex) < obj.Amount) return false; break; @@ -13883,6 +13888,10 @@ bool Player::CanCompleteQuest(uint32 quest_id) if (!HasSpell(obj.ObjectID)) return false; break; + case QUEST_OBJECTIVE_CURRENCY: + if (!HasCurrency(obj.ObjectID, obj.Amount)) + return false; + break; default: TC_LOG_ERROR("entities.player.quest", "Player::CanCompleteQuest: Player '%s' (%s) tried to complete a quest (ID: %u) with an unknown objective type %u", GetName().c_str(), GetGUID().ToString().c_str(), quest_id, obj.Type); @@ -15685,7 +15694,7 @@ void Player::TalkedToCreature(uint32 entry, ObjectGuid guid) } } -void Player::MoneyChanged(uint32 count) +void Player::MoneyChanged(uint64 value) { for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) { @@ -15706,7 +15715,7 @@ void Player::MoneyChanged(uint32 count) if (q_status.Status == QUEST_STATUS_INCOMPLETE) { - if (int32(count) >= obj.Amount) + if (int64(value) >= obj.Amount) { if (CanCompleteQuest(questid)) CompleteQuest(questid); @@ -15714,7 +15723,7 @@ void Player::MoneyChanged(uint32 count) } else if (q_status.Status == QUEST_STATUS_COMPLETE) { - if (int32(count) < obj.Amount) + if (int64(value) < obj.Amount) IncompleteQuest(questid); } } @@ -15770,6 +15779,58 @@ void Player::ReputationChanged(FactionEntry const* factionEntry) } } +void Player::CurrencyChanged(uint32 currencyId, int32 change) +{ + for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) + { + uint32 questid = GetQuestSlotQuestId(i); + if (!questid) + continue; + + Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid); + if (!qInfo) + continue; + + for (QuestObjective const& obj : qInfo->GetObjectives()) + { + if (uint32(obj.ObjectID) != currencyId) + continue; + + if (obj.Type != QUEST_OBJECTIVE_HAVE_CURRENCY) + continue; + + QuestStatusData& q_status = m_QuestStatus[questid]; + int64 value = GetCurrency(currencyId); + if (obj.Type == QUEST_OBJECTIVE_CURRENCY || obj.Type == QUEST_OBJECTIVE_HAVE_CURRENCY) + { + if (obj.Type == QUEST_OBJECTIVE_HAVE_CURRENCY) + SetQuestObjectiveData(qInfo, obj.StorageIndex, int32(std::min<int64>(value, obj.Amount))); + + if (q_status.Status == QUEST_STATUS_INCOMPLETE) + { + if (value >= obj.Amount) + { + if (CanCompleteQuest(questid)) + CompleteQuest(questid); + } + } + else if (q_status.Status == QUEST_STATUS_COMPLETE) + { + if (value < obj.Amount) + IncompleteQuest(questid); + } + } + else if (obj.Type == QUEST_OBJECTIVE_OBTAIN_CURRENCY && value > 0) // currency losses are not accounted for in this objective type + { + int64 currentProgress = GetQuestObjectiveData(qInfo, obj.StorageIndex); + SetQuestObjectiveData(qInfo, obj.StorageIndex, int32(std::max(std::min<int64>(currentProgress + value, obj.Amount), SI64LIT(0)))); + if (CanCompleteQuest(questid)) + CompleteQuest(questid); + } + } + } +} + bool Player::HasQuestForItem(uint32 itemid) const { for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 20d0bd57fca..c4f9ad3e05f 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1556,8 +1556,9 @@ class Player : public Unit, public GridObject<Player> void KilledPlayerCredit(); void KillCreditGO(uint32 entry, ObjectGuid guid = ObjectGuid::Empty); void TalkedToCreature(uint32 entry, ObjectGuid guid); - void MoneyChanged(uint32 value); + void MoneyChanged(uint64 value); void ReputationChanged(FactionEntry const* factionEntry); + void CurrencyChanged(uint32 currencyId, int32 change); bool HasQuestForItem(uint32 itemId) const; bool HasQuestForGO(int32 goId) const; void UpdateForQuestWorldObjects(); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 2ac112f5400..d07ed98d2b3 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -4098,6 +4098,8 @@ void ObjectMgr::LoadQuests() case QUEST_OBJECTIVE_TALKTO: case QUEST_OBJECTIVE_PLAYERKILLS: case QUEST_OBJECTIVE_AREATRIGGER: + case QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC: + case QUEST_OBJECTIVE_OBTAIN_CURRENCY: TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid StorageIndex = %d for objective type %u", qinfo->GetQuestId(), obj.ID, obj.StorageIndex, obj.Type); break; default: @@ -4132,7 +4134,7 @@ void ObjectMgr::LoadQuests() case QUEST_OBJECTIVE_MIN_REPUTATION: case QUEST_OBJECTIVE_MAX_REPUTATION: if (!sFactionStore.LookupEntry(obj.ObjectID)) - TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing faction id %u", qinfo->GetQuestId(), obj.ID, obj.ObjectID); + TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing faction id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID); break; case QUEST_OBJECTIVE_PLAYERKILLS: qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL); @@ -4140,13 +4142,42 @@ void ObjectMgr::LoadQuests() TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid player kills count %d", qinfo->GetQuestId(), obj.ID, obj.Amount); break; case QUEST_OBJECTIVE_CURRENCY: + case QUEST_OBJECTIVE_HAVE_CURRENCY: + case QUEST_OBJECTIVE_OBTAIN_CURRENCY: if (!sCurrencyTypesStore.LookupEntry(obj.ObjectID)) - TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing currency %u", qinfo->GetQuestId(), obj.ID, obj.ObjectID); + TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing currency %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID); if (obj.Amount <= 0) TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid currency amount %d", qinfo->GetQuestId(), obj.ID, obj.Amount); break; + case QUEST_OBJECTIVE_LEARNSPELL: + if (!sSpellMgr->GetSpellInfo(obj.ObjectID)) + TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing spell id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID); + break; + case QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC: + if (obj.ObjectID && !sObjectMgr->GetCreatureTemplate(obj.ObjectID)) + TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing creature entry %u, quest can't be done.", + qinfo->GetQuestId(), obj.ID, uint32(obj.ObjectID)); + break; + case QUEST_OBJECTIVE_DEFEATBATTLEPET: + if (!sBattlePetSpeciesStore.LookupEntry(obj.ObjectID)) + TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing battlepet species id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID); + break; + case QUEST_OBJECTIVE_CRITERIA_TREE: + if (!sCriteriaTreeStore.LookupEntry(obj.ObjectID)) + TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing criteria tree id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID); + break; + case QUEST_OBJECTIVE_AREATRIGGER: + if (sAreaTriggerStore.LookupEntry(uint32(obj.ObjectID))) + _questAreaTriggerStore[obj.ObjectID].insert(qinfo->ID); + else if (obj.ObjectID != -1) + TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing areatrigger id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID); + break; + case QUEST_OBJECTIVE_MONEY: + case QUEST_OBJECTIVE_WINPVPPETBATTLES: + break; default: TC_LOG_ERROR("sql.sql", "Quest %u objective %u has unhandled type %u", qinfo->GetQuestId(), obj.ID, obj.Type); + break; } } @@ -5543,7 +5574,7 @@ void ObjectMgr::LoadQuestAreaTriggers() // continue; - quest modified to required objective and trigger can be allowed. } - _questAreaTriggerStore[trigger_ID] = quest_ID; + _questAreaTriggerStore[trigger_ID].insert(quest_ID); } while (result->NextRow()); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 37ac4996931..364690dfd2e 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -812,12 +812,12 @@ class ObjectMgr QuestMap const& GetQuestTemplates() const { return _questTemplates; } - uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const + std::unordered_set<uint32> const* GetQuestsForAreaTrigger(uint32 Trigger_ID) const { - QuestAreaTriggerContainer::const_iterator itr = _questAreaTriggerStore.find(Trigger_ID); + auto itr = _questAreaTriggerStore.find(Trigger_ID); if (itr != _questAreaTriggerStore.end()) - return itr->second; - return 0; + return &itr->second; + return nullptr; } bool IsTavernAreaTrigger(uint32 Trigger_ID) const @@ -1419,7 +1419,7 @@ class ObjectMgr QuestMap _questTemplates; typedef std::unordered_map<uint32, NpcText> NpcTextContainer; - typedef std::unordered_map<uint32, uint32> QuestAreaTriggerContainer; + typedef std::unordered_map<uint32, std::unordered_set<uint32>> QuestAreaTriggerContainer; typedef std::set<uint32> TavernAreaTriggerContainer; typedef std::set<uint32> GameObjectForQuestContainer; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index e43a7e2af0c..a51b61050ee 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -485,22 +485,25 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::Misc::AreaTrigger& pack if (player->IsAlive()) { - if (uint32 questId = sObjectMgr->GetQuestForAreaTrigger(packet.AreaTriggerID)) + if (std::unordered_set<uint32> const* quests = sObjectMgr->GetQuestsForAreaTrigger(packet.AreaTriggerID)) { - Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId); - if (qInfo && player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE) + for (uint32 questId : *quests) { - for (uint8 j = 0; j < qInfo->Objectives.size(); ++j) + Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId); + if (qInfo && player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE) { - if (qInfo->Objectives[j].Type == QUEST_OBJECTIVE_AREATRIGGER) + for (uint8 j = 0; j < qInfo->Objectives.size(); ++j) { - player->SetQuestObjectiveData(qInfo, j, int32(true)); - break; + if (qInfo->Objectives[j].Type == QUEST_OBJECTIVE_AREATRIGGER) + { + player->SetQuestObjectiveData(qInfo, j, int32(true)); + break; + } } - } - if (player->CanCompleteQuest(questId)) - player->CompleteQuest(questId); + if (player->CanCompleteQuest(questId)) + player->CompleteQuest(questId); + } } } } diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 7bd1f4bd647..8b27be40c20 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -231,7 +231,9 @@ enum QuestObjectiveType QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC = 11, QUEST_OBJECTIVE_DEFEATBATTLEPET = 12, QUEST_OBJECTIVE_WINPVPPETBATTLES = 13, - QUEST_OBJECTIVE_CRITERIA_TREE = 14 + QUEST_OBJECTIVE_CRITERIA_TREE = 14, + QUEST_OBJECTIVE_HAVE_CURRENCY = 16, // requires the player to have X currency when turning in but does not consume it + QUEST_OBJECTIVE_OBTAIN_CURRENCY = 17 // requires the player to gain X currency after starting the quest but not required to keep it until the end (does not consume) }; struct QuestTemplateLocale |