diff options
author | Roger Stebler <roger.stebler@students.unibe.ch> | 2017-08-20 17:24:41 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2017-08-20 17:24:41 +0200 |
commit | 4bc9ed0fdeee0822fb2142c94c8360c1af777f6b (patch) | |
tree | 741d5dcb24ed8adbb2631ae8ff61890357f54eed /src | |
parent | 1de03622c5ee61298a7e3da42b22626b8f89f2d4 (diff) |
Core/Quests: Implemented criteria tree quest objective type
Closes #20161
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 8 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.h | 8 | ||||
-rw-r--r-- | src/server/game/Achievements/AchievementMgr.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Achievements/CriteriaHandler.cpp | 28 | ||||
-rw-r--r-- | src/server/game/Achievements/CriteriaHandler.h | 17 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 48 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 5 | ||||
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 6 | ||||
-rw-r--r-- | src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp | 320 | ||||
-rw-r--r-- | src/server/game/Quests/QuestObjectiveCriteriaMgr.h | 64 |
11 files changed, 503 insertions, 13 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 34bef1ea62a..ad4998b9543 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -94,6 +94,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, timer FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES, "SELECT quest, objective, data FROM character_queststatus_objectives WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA, "SELECT questObjectiveId FROM character_queststatus_objectives_criteria WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "SELECT criteriaId, counter, date FROM character_queststatus_objectives_criteria_progress WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); @@ -549,6 +551,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_CHAR_TAXIMASK, "UPDATE characters SET taximask = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS, "DELETE FROM character_queststatus WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES, "DELETE FROM character_queststatus_objectives WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA, "DELETE FROM character_queststatus_objectives_criteria WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "DELETE FROM character_queststatus_objectives_criteria_progress WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS_BY_CRITERIA, "DELETE FROM character_queststatus_objectives_criteria_progress WHERE guid = ? AND criteriaId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID, "DELETE FROM character_social WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND, "DELETE FROM character_social WHERE friend = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT, "DELETE FROM character_achievement WHERE achievement = ? AND guid = ?", CONNECTION_ASYNC); @@ -596,11 +601,14 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, "DELETE FROM character_queststatus WHERE guid = ? AND quest = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES, "REPLACE INTO character_queststatus_objectives (guid, quest, objective, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_BY_QUEST, "DELETE FROM character_queststatus_objectives WHERE guid = ? AND quest = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA, "INSERT INTO character_queststatus_objectives_criteria (guid, questObjectiveId) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, "INSERT INTO character_queststatus_objectives_criteria_progress (guid, criteriaId, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_REWARDED, "INSERT IGNORE INTO character_queststatus_rewarded (guid, quest, active) VALUES (?, ?, 1)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, "DELETE FROM character_queststatus_rewarded WHERE guid = ? AND quest = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE, "UPDATE character_queststatus_rewarded SET quest = ? WHERE quest = ? AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE, "UPDATE character_queststatus_rewarded SET active = 1 WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, "UPDATE character_queststatus_rewarded SET active = 0 WHERE quest = ? AND guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_INVALID_QUEST_PROGRESS_CRITERIA, "DELETE FROM character_queststatus_objectives_criteria WHERE questObjectiveId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_SKILLS, "INSERT INTO character_skills (guid, skill, value, max) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_SKILLS, "UPDATE character_skills SET value = ?, max = ? WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index c2ea5136261..b2acafc2308 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -71,6 +71,8 @@ enum CharacterDatabaseStatements : uint32 CHAR_SEL_CHARACTER_QUESTSTATUS, CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES, + CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA, + CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY, @@ -450,6 +452,9 @@ enum CharacterDatabaseStatements : uint32 CHAR_UPD_CHAR_TAXIMASK, CHAR_DEL_CHAR_QUESTSTATUS, CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES, + CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA, + CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, + CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS_BY_CRITERIA, CHAR_DEL_CHAR_SOCIAL_BY_GUID, CHAR_DEL_CHAR_SOCIAL_BY_FRIEND, CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT, @@ -497,11 +502,14 @@ enum CharacterDatabaseStatements : uint32 CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES, CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_BY_QUEST, + CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA, + CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS, CHAR_INS_CHAR_QUESTSTATUS_REWARDED, CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE, CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE, CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, + CHAR_DEL_INVALID_QUEST_PROGRESS_CRITERIA, CHAR_DEL_CHAR_SKILL_BY_SKILL, CHAR_INS_CHAR_SKILLS, CHAR_UPD_CHAR_SKILLS, diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index b4d7ad07eb6..6ab15152d75 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -272,7 +272,7 @@ void PlayerAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Pre TC_LOG_ERROR("criteria.achievement", "Non-existing achievement criteria %u data has been removed from the table `character_achievement_progress`.", id); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA); - stmt->setUInt32(0, uint16(id)); + stmt->setUInt32(0, id); CharacterDatabase.Execute(stmt); continue; @@ -716,7 +716,7 @@ void GuildAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Prep TC_LOG_ERROR("criteria.achievement", "Non-existing achievement criteria %u data removed from table `guild_achievement_progress`.", id); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA_GUILD); - stmt->setUInt32(0, uint16(id)); + stmt->setUInt32(0, id); CharacterDatabase.Execute(stmt); continue; } diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index cbf296ddb7e..f3bb97ecf4b 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -2227,19 +2227,34 @@ void CriteriaMgr::LoadCriteriaList() if (scenarioStep->CriteriaTreeID) scenarioCriteriaTreeIds[scenarioStep->CriteriaTreeID] = scenarioStep; + std::unordered_map<uint32 /*criteriaTreeID*/, QuestObjective const*> questObjectiveCriteriaTreeIds; + for (std::pair<uint32 /*questID*/, Quest const*> itr : sObjectMgr->GetQuestTemplates()) + { + for (QuestObjective const& objective : itr.second->Objectives) + { + if (objective.Type != QUEST_OBJECTIVE_CRITERIA_TREE) + continue; + + if (objective.ObjectID) + questObjectiveCriteriaTreeIds[objective.ObjectID] = &objective; + } + } + // Load criteria tree nodes for (CriteriaTreeEntry const* tree : sCriteriaTreeStore) { // Find linked achievement AchievementEntry const* achievement = GetEntry(achievementCriteriaTreeIds, tree); ScenarioStepEntry const* scenarioStep = GetEntry(scenarioCriteriaTreeIds, tree); - if (!achievement && !scenarioStep) + QuestObjective const* questObjective = GetEntry(questObjectiveCriteriaTreeIds, tree); + if (!achievement && !scenarioStep && !questObjective) continue; CriteriaTree* criteriaTree = new CriteriaTree(); criteriaTree->ID = tree->ID; criteriaTree->Achievement = achievement; criteriaTree->ScenarioStep = scenarioStep; + criteriaTree->QuestObjective = questObjective; criteriaTree->Entry = tree; _criteriaTrees[criteriaTree->Entry->ID] = criteriaTree; @@ -2274,6 +2289,7 @@ void CriteriaMgr::LoadCriteriaList() uint32 criterias = 0; uint32 guildCriterias = 0; uint32 scenarioCriterias = 0; + uint32 questObjectiveCriterias = 0; for (CriteriaEntry const* criteriaEntry : sCriteriaStore) { ASSERT(criteriaEntry->Type < CRITERIA_TYPE_TOTAL, "CRITERIA_TYPE_TOTAL must be greater than or equal to %u but is currently equal to %u", @@ -2305,6 +2321,8 @@ void CriteriaMgr::LoadCriteriaList() } else if (tree->ScenarioStep) criteria->FlagsCu |= CRITERIA_FLAG_CU_SCENARIO; + else if (tree->QuestObjective) + criteria->FlagsCu |= CRITERIA_FLAG_CU_QUEST_OBJECTIVE; } if (criteria->FlagsCu & (CRITERIA_FLAG_CU_PLAYER | CRITERIA_FLAG_CU_ACCOUNT)) @@ -2325,6 +2343,12 @@ void CriteriaMgr::LoadCriteriaList() _scenarioCriteriasByType[criteriaEntry->Type].push_back(criteria); } + if (criteria->FlagsCu & CRITERIA_FLAG_CU_QUEST_OBJECTIVE) + { + ++questObjectiveCriterias; + _questObjectiveCriteriasByType[criteriaEntry->Type].push_back(criteria); + } + if (criteriaEntry->StartTimer) _criteriasByTimedType[criteriaEntry->StartEvent].push_back(criteria); } @@ -2332,7 +2356,7 @@ void CriteriaMgr::LoadCriteriaList() for (auto& p : _criteriaTrees) const_cast<CriteriaTree*>(p.second)->Criteria = GetCriteria(p.second->Entry->CriteriaID); - TC_LOG_INFO("server.loading", ">> Loaded %u criteria, %u guild criteria and %u scenario criteria in %u ms.", criterias, guildCriterias, scenarioCriterias, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u criteria, %u guild criteria, %u scenario criteria and %u quest objective criteria in %u ms.", criterias, guildCriterias, scenarioCriterias, questObjectiveCriterias, GetMSTimeDiffToNow(oldMSTime)); } void CriteriaMgr::LoadCriteriaData() diff --git a/src/server/game/Achievements/CriteriaHandler.h b/src/server/game/Achievements/CriteriaHandler.h index c8b96b144cd..7d14df68be1 100644 --- a/src/server/game/Achievements/CriteriaHandler.h +++ b/src/server/game/Achievements/CriteriaHandler.h @@ -34,6 +34,7 @@ struct AchievementEntry; struct CriteriaEntry; struct CriteriaTreeEntry; struct ModifierTreeEntry; +struct QuestObjective; struct ScenarioStepEntry; struct ModifierTreeNode @@ -44,10 +45,11 @@ struct ModifierTreeNode enum CriteriaFlagsCu { - CRITERIA_FLAG_CU_PLAYER = 0x1, - CRITERIA_FLAG_CU_ACCOUNT = 0x2, - CRITERIA_FLAG_CU_GUILD = 0x4, - CRITERIA_FLAG_CU_SCENARIO = 0x8 + CRITERIA_FLAG_CU_PLAYER = 0x1, + CRITERIA_FLAG_CU_ACCOUNT = 0x2, + CRITERIA_FLAG_CU_GUILD = 0x4, + CRITERIA_FLAG_CU_SCENARIO = 0x8, + CRITERIA_FLAG_CU_QUEST_OBJECTIVE = 0x10 }; struct Criteria @@ -66,6 +68,7 @@ struct CriteriaTree CriteriaTreeEntry const* Entry = nullptr; AchievementEntry const* Achievement = nullptr; ScenarioStepEntry const* ScenarioStep = nullptr; + QuestObjective const* QuestObjective = nullptr; struct Criteria const* Criteria = nullptr; std::vector<CriteriaTree const*> Children; }; @@ -331,6 +334,11 @@ public: return _scenarioCriteriasByType[type]; } + CriteriaList const& GetQuestObjectiveCriteriaByType(CriteriaTypes type) const + { + return _questObjectiveCriteriasByType[type]; + } + CriteriaTreeList const* GetCriteriaTreesByCriteria(uint32 criteriaId) const { auto itr = _criteriaTreeByCriteria.find(criteriaId); @@ -395,6 +403,7 @@ private: CriteriaList _criteriasByType[CRITERIA_TYPE_TOTAL]; CriteriaList _guildCriteriasByType[CRITERIA_TYPE_TOTAL]; CriteriaList _scenarioCriteriasByType[CRITERIA_TYPE_TOTAL]; + CriteriaList _questObjectiveCriteriasByType[CRITERIA_TYPE_TOTAL]; CriteriaList _criteriasByTimedType[CRITERIA_TIMED_TYPE_MAX]; }; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9f5a82f96ea..e2611e9c9ac 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -89,6 +89,7 @@ #include "PetPackets.h" #include "QueryHolder.h" #include "QuestDef.h" +#include "QuestObjectiveCriteriaMgr.h" #include "QuestPackets.h" #include "Realm.h" #include "ReputationMgr.h" @@ -346,6 +347,7 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this) m_achievementMgr = new PlayerAchievementMgr(this); m_reputationMgr = new ReputationMgr(this); + m_questObjectiveCriteriaMgr = Trinity::make_unique<QuestObjectiveCriteriaMgr>(this); for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) _CUFProfiles[i] = nullptr; @@ -14745,6 +14747,11 @@ void Player::AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver) { AddQuest(quest, questGiver); + for (QuestObjective const& obj : quest->GetObjectives()) + if (obj.Type == QUEST_OBJECTIVE_CRITERIA_TREE) + if (m_questObjectiveCriteriaMgr->HasCompletedObjective(&obj)) + KillCreditCriteriaTreeObjective(obj); + if (CanCompleteQuest(quest->GetQuestId())) CompleteQuest(quest->GetQuestId()); @@ -14900,9 +14907,22 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) AdjustQuestReqItemCount(quest); for (QuestObjective const& obj : quest->GetObjectives()) - if (obj.Type == QUEST_OBJECTIVE_MIN_REPUTATION || obj.Type == QUEST_OBJECTIVE_MAX_REPUTATION) - if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(obj.ObjectID)) - GetReputationMgr().SetVisible(factionEntry); + { + switch (obj.Type) + { + case QUEST_OBJECTIVE_MIN_REPUTATION: + case QUEST_OBJECTIVE_MAX_REPUTATION: + if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(obj.ObjectID)) + GetReputationMgr().SetVisible(factionEntry); + break; + case QUEST_OBJECTIVE_CRITERIA_TREE: + if (quest->HasFlagEx(QUEST_FLAGS_EX_CLEAR_PROGRESS_OF_CRITERIA_TREE_OBJECTIVES_ON_ACCEPT)) + m_questObjectiveCriteriaMgr->ResetCriteriaTree(obj.ObjectID); + break; + default: + break; + } + } uint32 qtime = 0; if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED)) @@ -16563,6 +16583,21 @@ void Player::TalkedToCreature(uint32 entry, ObjectGuid guid) } } +void Player::KillCreditCriteriaTreeObjective(QuestObjective const& questObjective) +{ + if (questObjective.Type != QUEST_OBJECTIVE_CRITERIA_TREE) + return; + + if (GetQuestStatus(questObjective.QuestID) == QUEST_STATUS_INCOMPLETE) + { + SetQuestObjectiveData(questObjective, 1); + SendQuestUpdateAddCreditSimple(questObjective); + + if (CanCompleteQuest(questObjective.QuestID)) + CompleteQuest(questObjective.QuestID); + } +} + void Player::MoneyChanged(uint64 value) { for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) @@ -16813,6 +16848,7 @@ bool Player::IsQuestObjectiveComplete(QuestObjective const& objective) const return false; break; case QUEST_OBJECTIVE_AREATRIGGER: + case QUEST_OBJECTIVE_CRITERIA_TREE: if (!GetQuestObjectiveData(quest, objective.StorageIndex)) return false; break; @@ -17389,6 +17425,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateCriteria) m_achievementMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS)); + m_questObjectiveCriteriaMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS)); uint64 money = fields[8].GetUInt64(); if (money > MAX_MONEY_AMOUNT) @@ -18056,6 +18093,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) } m_achievementMgr->CheckAllAchievementCriteria(this); + m_questObjectiveCriteriaMgr->CheckAllQuestObjectiveCriteria(this); return true; } @@ -19966,6 +20004,7 @@ void Player::SaveToDB(bool create /*=false*/) _SaveSkills(trans); m_achievementMgr->SaveToDB(trans); m_reputationMgr->SaveToDB(trans); + m_questObjectiveCriteriaMgr->SaveToDB(trans); _SaveEquipmentSets(trans); GetSession()->SaveTutorialsData(trans); // changed only while character in game _SaveInstanceTimeRestrictions(trans); @@ -23448,6 +23487,7 @@ void Player::SendInitialPacketsBeforeAddToMap() SendEquipmentSetList(); m_achievementMgr->SendAllData(this); + m_questObjectiveCriteriaMgr->SendAllData(this); /// SMSG_LOGIN_SETTIMESPEED static float const TimeSpeed = 0.01666667f; @@ -25876,11 +25916,13 @@ void Player::RemoveCriteriaTimer(CriteriaTimedTypes type, uint32 entry) void Player::ResetCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, bool evenIfCriteriaComplete /* = false*/) { m_achievementMgr->ResetCriteria(type, miscValue1, miscValue2, evenIfCriteriaComplete); + m_questObjectiveCriteriaMgr->ResetCriteria(type, miscValue1, miscValue2, evenIfCriteriaComplete); } void Player::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit* unit /*= NULL*/) { m_achievementMgr->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); + m_questObjectiveCriteriaMgr->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); // Update only individual achievement criteria here, otherwise we may get multiple updates // from a single boss kill diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 414515b5e36..4f3f270fdc6 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -77,6 +77,7 @@ class PlayerAI; class PlayerAchievementMgr; class PlayerMenu; class PlayerSocial; +class QuestObjectiveCriteriaMgr; class ReputationMgr; class RestMgr; class SpellCastTargets; @@ -785,6 +786,8 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_SPELLS, PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS, PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES, + PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA, + PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS, PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS, PLAYER_LOGIN_QUERY_LOAD_REPUTATION, PLAYER_LOGIN_QUERY_LOAD_INVENTORY, @@ -1415,6 +1418,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void KilledPlayerCredit(); void KillCreditGO(uint32 entry, ObjectGuid guid = ObjectGuid::Empty); void TalkedToCreature(uint32 entry, ObjectGuid guid); + void KillCreditCriteriaTreeObjective(QuestObjective const& questObjective); void MoneyChanged(uint64 value); void ReputationChanged(FactionEntry const* factionEntry); void CurrencyChanged(uint32 currencyId, int32 change); @@ -2659,6 +2663,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> PlayerAchievementMgr* m_achievementMgr; ReputationMgr* m_reputationMgr; + std::unique_ptr<QuestObjectiveCriteriaMgr> m_questObjectiveCriteriaMgr; uint32 m_ChampioningFaction; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 17ddf3ed8a6..1ee32b74991 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -113,6 +113,14 @@ bool LoginQueryHolder::Initialize() stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY); stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS, stmt); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 49bce2fe583..700216ef7e8 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -132,7 +132,7 @@ enum QuestGiverStatus DIALOG_STATUS_SCRIPTED_NO_STATUS = 0x1000 }; -enum QuestFlags +enum QuestFlags : uint32 { QUEST_FLAGS_NONE = 0x00000000, QUEST_FLAGS_STAY_ALIVE = 0x00000001, // Not used currently @@ -164,7 +164,7 @@ enum QuestFlags }; // last checked in 19802 -enum QuestFlagsEx +enum QuestFlagsEx : uint32 { QUEST_FLAGS_EX_NONE = 0x0000000, QUEST_FLAGS_EX_KEEP_ADDITIONAL_ITEMS = 0x0000001, @@ -335,6 +335,8 @@ class TC_GAME_API Quest bool HasSpecialFlag(uint32 flag) const { return (SpecialFlags & flag) != 0; } void SetSpecialFlag(uint32 flag) { SpecialFlags |= flag; } + bool HasFlagEx(QuestFlagsEx flag) const { return (FlagsEx & uint32(flag)) != 0; } + // table data accessors: uint32 GetQuestId() const { return ID; } uint32 GetQuestType() const { return Type; } diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp new file mode 100644 index 00000000000..965cbd804d1 --- /dev/null +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "QuestObjectiveCriteriaMgr.h" +#include "AchievementPackets.h" +#include "DatabaseEnv.h" +#include "DB2Structure.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "Player.h" + +QuestObjectiveCriteriaMgr::QuestObjectiveCriteriaMgr(Player* owner) : _owner(owner) +{ +} + +QuestObjectiveCriteriaMgr::~QuestObjectiveCriteriaMgr() +{ +} + +void QuestObjectiveCriteriaMgr::CheckAllQuestObjectiveCriteria(Player* referencePlayer) +{ + // suppress sending packets + for (uint32 i = 0; i < CRITERIA_TYPE_TOTAL; ++i) + UpdateCriteria(CriteriaTypes(i), 0, 0, 0, nullptr, referencePlayer); +} + +void QuestObjectiveCriteriaMgr::Reset() +{ + for (auto& criteriaProgres : _criteriaProgress) + SendCriteriaProgressRemoved(criteriaProgres.first); + + _criteriaProgress.clear(); + + DeleteFromDB(_owner->GetGUID()); + + // re-fill data + CheckAllQuestObjectiveCriteria(_owner); +} + +void QuestObjectiveCriteriaMgr::DeleteFromDB(ObjectGuid const& guid) +{ + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA); + stmt->setUInt64(0, guid.GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS); + stmt->setUInt64(0, guid.GetCounter()); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); +} + +void QuestObjectiveCriteriaMgr::LoadFromDB(PreparedQueryResult objectiveResult, PreparedQueryResult criteriaResult) +{ + if (objectiveResult) + { + do + { + uint32 objectiveId = (*objectiveResult)[0].GetUInt32(); + + QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveId); + if (!objective) + continue; + + _completedObjectives.insert(objectiveId); + + } while (objectiveResult->NextRow()); + } + + if (criteriaResult) + { + time_t now = time(nullptr); + do + { + Field* fields = criteriaResult->Fetch(); + uint32 criteriaId = fields[0].GetUInt32(); + uint64 counter = fields[1].GetUInt64(); + time_t date = time_t(fields[2].GetUInt32()); + + Criteria const* criteria = sCriteriaMgr->GetCriteria(criteriaId); + if (!criteria) + { + // Removing non-existing criteria data for all characters + TC_LOG_ERROR("criteria.quest", "Non-existing quest objective criteria %u data has been removed from the table `character_queststatus_objectives_criteria_progress`.", criteriaId); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_QUEST_PROGRESS_CRITERIA); + stmt->setUInt32(0, criteriaId); + CharacterDatabase.Execute(stmt); + + continue; + } + + if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now) + continue; + + CriteriaProgress& progress = _criteriaProgress[criteriaId]; + progress.Counter = counter; + progress.Date = date; + progress.Changed = false; + } while (criteriaResult->NextRow()); + } +} + +void QuestObjectiveCriteriaMgr::SaveToDB(SQLTransaction& trans) +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + + if (!_completedObjectives.empty()) + { + for (uint32 completedObjectiveId : _completedObjectives) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, completedObjectiveId); + trans->Append(stmt); + } + } + + if (!_criteriaProgress.empty()) + { + for (auto& criteriaProgres : _criteriaProgress) + { + if (!criteriaProgres.second.Changed) + continue; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS_BY_CRITERIA); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, criteriaProgres.first); + trans->Append(stmt); + + if (criteriaProgres.second.Counter) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, criteriaProgres.first); + stmt->setUInt64(2, criteriaProgres.second.Counter); + stmt->setUInt32(3, uint32(criteriaProgres.second.Date)); + trans->Append(stmt); + } + + criteriaProgres.second.Changed = false; + } + } +} + +void QuestObjectiveCriteriaMgr::ResetCriteria(CriteriaTypes type, uint64 miscValue1, uint64 miscValue2, bool evenIfCriteriaComplete) +{ + TC_LOG_DEBUG("criteria.quest", "QuestObjectiveCriteriaMgr::ResetCriteria(%u, " UI64FMTD ", " UI64FMTD ")", type, miscValue1, miscValue2); + + // disable for gamemasters with GM-mode enabled + if (_owner->IsGameMaster()) + return; + + CriteriaList const& playerCriteriaList = GetCriteriaByType(type); + for (Criteria const* playerCriteria : playerCriteriaList) + { + if (playerCriteria->Entry->FailEvent != miscValue1 || (playerCriteria->Entry->FailAsset && playerCriteria->Entry->FailAsset != miscValue2)) + continue; + + std::vector<CriteriaTree const*> const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(playerCriteria->ID); + bool allComplete = true; + for (CriteriaTree const* tree : *trees) + { + // don't update already completed criteria if not forced + if (!(IsCompletedCriteriaTree(tree) && !evenIfCriteriaComplete)) + { + allComplete = false; + break; + } + } + + if (allComplete) + continue; + + RemoveCriteriaProgress(playerCriteria); + } +} + +void QuestObjectiveCriteriaMgr::ResetCriteriaTree(uint32 criteriaTreeId) +{ + CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(criteriaTreeId); + if (!tree) + return; + + CriteriaMgr::WalkCriteriaTree(tree, [this](CriteriaTree const* criteriaTree) + { + RemoveCriteriaProgress(criteriaTree->Criteria); + }); +} + +void QuestObjectiveCriteriaMgr::SendAllData(Player const* /*receiver*/) const +{ + for (const auto& criteriaProgres : _criteriaProgress) + { + WorldPackets::Achievement::CriteriaUpdate criteriaUpdate; + + criteriaUpdate.CriteriaID = criteriaProgres.first; + criteriaUpdate.Quantity = criteriaProgres.second.Counter; + criteriaUpdate.PlayerGUID = _owner->GetGUID(); + criteriaUpdate.Flags = 0; + + criteriaUpdate.CurrentTime = criteriaProgres.second.Date; + criteriaUpdate.CreationTime = 0; + + SendPacket(criteriaUpdate.Write()); + } +} + +void QuestObjectiveCriteriaMgr::CompletedObjective(QuestObjective const* questObjective, Player* referencePlayer) +{ + // disable for gamemasters with GM-mode enabled + if (_owner->IsGameMaster()) + return; + + if (HasCompletedObjective(questObjective)) + return; + + referencePlayer->KillCreditCriteriaTreeObjective(*questObjective); + + TC_LOG_INFO("criteria.quest", "QuestObjectiveCriteriaMgr::CompletedObjective(%u). %s", questObjective->ID, GetOwnerInfo().c_str()); + + _completedObjectives.insert(questObjective->ID); +} + +bool QuestObjectiveCriteriaMgr::HasCompletedObjective(QuestObjective const* questObjective) const +{ + return _completedObjectives.find(questObjective->ID) != _completedObjectives.end(); +} + +void QuestObjectiveCriteriaMgr::SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const +{ + WorldPackets::Achievement::CriteriaUpdate criteriaUpdate; + + criteriaUpdate.CriteriaID = criteria->ID; + criteriaUpdate.Quantity = progress->Counter; + criteriaUpdate.PlayerGUID = _owner->GetGUID(); + criteriaUpdate.Flags = 0; + if (criteria->Entry->StartTimer) + criteriaUpdate.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client + + criteriaUpdate.CurrentTime = progress->Date; + criteriaUpdate.ElapsedTime = timeElapsed; + criteriaUpdate.CreationTime = 0; + + SendPacket(criteriaUpdate.Write()); +} + +void QuestObjectiveCriteriaMgr::SendCriteriaProgressRemoved(uint32 criteriaId) +{ + WorldPackets::Achievement::CriteriaDeleted criteriaDeleted; + criteriaDeleted.CriteriaID = criteriaId; + SendPacket(criteriaDeleted.Write()); +} + +bool QuestObjectiveCriteriaMgr::CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const +{ + QuestObjective const* objective = tree->QuestObjective; + if (!objective) + return false; + + if (HasCompletedObjective(objective)) + { + TC_LOG_TRACE("criteria.quest", "QuestObjectiveCriteriaMgr::CanUpdateCriteriaTree: (Id: %u Type %s Quest Objective %u) Objective already completed", + criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type), objective->ID); + return false; + } + + return CriteriaHandler::CanUpdateCriteriaTree(criteria, tree, referencePlayer); +} + +bool QuestObjectiveCriteriaMgr::CanCompleteCriteriaTree(CriteriaTree const* tree) +{ + QuestObjective const* objective = tree->QuestObjective; + if (!objective) + return false; + + return CriteriaHandler::CanCompleteCriteriaTree(tree); +} + +void QuestObjectiveCriteriaMgr::CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) +{ + QuestObjective const* objective = tree->QuestObjective; + if (!objective) + return; + + CompletedObjective(objective, referencePlayer); +} + +void QuestObjectiveCriteriaMgr::SendPacket(WorldPacket const* data) const +{ + _owner->SendDirectMessage(data); +} + +std::string QuestObjectiveCriteriaMgr::GetOwnerInfo() const +{ + return Trinity::StringFormat("%s %s", _owner->GetGUID().ToString().c_str(), _owner->GetName().c_str()); +} + +CriteriaList const& QuestObjectiveCriteriaMgr::GetCriteriaByType(CriteriaTypes type) const +{ + return sCriteriaMgr->GetQuestObjectiveCriteriaByType(type); +} diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.h b/src/server/game/Quests/QuestObjectiveCriteriaMgr.h new file mode 100644 index 00000000000..76c6bbb8d1d --- /dev/null +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QuestObjectiveCriteriaMgr_h__ +#define QuestObjectiveCriteriaMgr_h__ + +#include "CriteriaHandler.h" + +class TC_GAME_API QuestObjectiveCriteriaMgr : public CriteriaHandler +{ +public: + explicit QuestObjectiveCriteriaMgr(Player* owner); + ~QuestObjectiveCriteriaMgr(); + + void CheckAllQuestObjectiveCriteria(Player* referencePlayer); + + void Reset() override; + + static void DeleteFromDB(ObjectGuid const& guid); + void LoadFromDB(PreparedQueryResult objectiveResult, PreparedQueryResult criteriaResult); + void SaveToDB(SQLTransaction& trans); + + void ResetCriteria(CriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); + void ResetCriteriaTree(uint32 criteriaTreeId); + + void SendAllData(Player const* receiver) const override; + + void CompletedObjective(QuestObjective const* questObjective, Player* referencePlayer); + bool HasCompletedObjective(QuestObjective const* questObjective) const; + +protected: + void SendCriteriaUpdate(Criteria const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const override; + + void SendCriteriaProgressRemoved(uint32 criteriaId) override; + + bool CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const override; + bool CanCompleteCriteriaTree(CriteriaTree const* tree) override; + void CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) override; + + void SendPacket(WorldPacket const* data) const override; + + std::string GetOwnerInfo() const override; + CriteriaList const& GetCriteriaByType(CriteriaTypes type) const override; + +private: + Player* _owner; + std::unordered_set<uint32> _completedObjectives; +}; + +#endif |