diff options
-rw-r--r-- | sql/updates/world/master/2021_11_26_26_world_2019_04_10_00_world.sql | 327 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 58 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 10 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 58 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.cpp | 23 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 3 |
6 files changed, 453 insertions, 26 deletions
diff --git a/sql/updates/world/master/2021_11_26_26_world_2019_04_10_00_world.sql b/sql/updates/world/master/2021_11_26_26_world_2019_04_10_00_world.sql new file mode 100644 index 00000000000..a7a57218d56 --- /dev/null +++ b/sql/updates/world/master/2021_11_26_26_world_2019_04_10_00_world.sql @@ -0,0 +1,327 @@ +ALTER TABLE `quest_template_addon` +ADD COLUMN `BreadcrumbForQuestId` int(11) NOT NULL DEFAULT '0' AFTER `ExclusiveGroup`; + +-- Assisting Arch Druid Runetotem +UPDATE `quest_template_addon` SET `NextQuestID` = 0,`ExclusiveGroup`=0,`BreadcrumbForQuestId` = 3761 WHERE `ID` IN (936, 3762, 3784); + +-- Assisting Arch Druid Staghelm +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0, `BreadcrumbForQuestId` = 3764 WHERE `ID` IN (3763, 3789, 3790, 10520); + +-- Lost Deathstalkers +DELETE FROM `quest_template_addon` WHERE `ID` IN (428,429); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (428, 429); + +-- On Guard in Stonetalon +DELETE FROM `quest_template_addon` WHERE `ID` IN (1070); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (1070, 1085); + +-- The Crown of Will +DELETE FROM `quest_template_addon` WHERE `ID` IN (495,518); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (495,518); + +-- Camp Mojache +DELETE FROM `quest_template_addon` WHERE `ID` IN (7489,7492); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (7492,7489); + +-- Feathermoon Stronghold +DELETE FROM `quest_template_addon` WHERE `ID` IN (7488,7494); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (7494,7488); + +-- Journey to Stonetalon Peak +DELETE FROM `quest_template_addon` WHERE `ID` IN (1056); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (1056,1057); + +-- Castpipe's Task +DELETE FROM `quest_template_addon` WHERE `ID` IN (2931); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (2931,2930); + +-- Kayneth Stillwind +DELETE FROM `quest_template_addon` WHERE `ID` IN (1011); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1011 WHERE `ID`=4581; + +-- Carendin Summons +-- UPDATE `quest_template` SET `AllowableRaces` = 512 WHERE `Id` = 10605; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1472 WHERE `ID`=10605; + + +-- Seeking Strahad (Horde) +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0,`BreadcrumbForQuestId` = 1801 WHERE `ID` IN (2996,3001); + +-- Seeking Strahad (Alliance) +DELETE FROM `quest_template_addon` WHERE `ID` IN (1758); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=1758 WHERE `ID`=1798; + +-- A Helping Hand +DELETE FROM `quest_template_addon` WHERE `ID` IN (9533); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (9533,9517); + +-- Trouble In Darkshore? +-- UPDATE `quest_template` SET `AllowableRaces` = 1101 WHERE `Id` IN (729,730,731,741,942,943); +DELETE FROM `quest_template_addon` WHERE `ID` IN (730); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (730,729); + +-- Yorus Barleybrew +UPDATE `quest_template_addon` SET `NextQuestID`=0, `ExclusiveGroup`=0, `BreadcrumbForQuestId` = 1699 WHERE `ID` IN (1698,10371); + +-- Speak with Ruga +UPDATE `quest_template_addon` SET `PrevQuestId`=0 WHERE `ID`=1824; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=1824 WHERE `ID`=1823; + +-- A Strange One +DELETE FROM `quest_template_addon` WHERE `ID` IN (6605); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (6605,4505); + +-- A Call to Arms: The Plaguelands! (horde) +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0,`BreadcrumbForQuestId`=5096 WHERE `ID` IN (5093, 5094, 5095, 10374); + +-- A Call to Arms: The Plaguelands! (alliance) +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0,`BreadcrumbForQuestId`=5092 WHERE `ID` IN (5066, 5090, 5091, 10373); + +-- Trouble in Winterspring! +DELETE FROM `quest_template_addon` WHERE `ID` IN (5082, 6603); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (6603,5082); + +-- Neeka Bloodscar +DELETE FROM `quest_template_addon` WHERE `ID` IN (1418); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (1418,1420); + +-- Taking Back Silithus +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0,`BreadcrumbForQuestId`=8280 WHERE `ID` IN (8275,8276); + +-- To Winterspring! & Starfall +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0,`BreadcrumbForQuestId` = 5244 WHERE `ID` IN (5249,5250); + +-- Tinkee Steamboil +UPDATE `quest_template_addon` SET `PrevQuestID`=4810 WHERE `ID`=4734; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=4734 WHERE `ID`=4907; + +-- Westbrook Garrison Needs Help! +DELETE FROM `quest_template_addon` WHERE `ID` IN (11); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=11 WHERE `ID`=239; + +-- Elmore's Task +UPDATE `quest_template_addon` SET `PrevQuestID`=0 WHERE `ID`=353; +DELETE FROM `quest_template_addon` WHERE `ID` IN (1097); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (1097,353); + +-- Brother Anton +DELETE FROM `quest_template_addon` WHERE `ID` IN (6141); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (6141,261); + +-- Chillwind Camp +UPDATE `quest_template_addon` SET `PrevQuestID`=0 WHERE `ID`=8414; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=8414 WHERE `ID`=8415; + +-- Report to Jennea +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=1920 WHERE `ID`=1919; + +-- High Sorcerer Andromath +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=1938 WHERE `ID`=1939; + +-- Vital Supplies +UPDATE `quest_template_addon` SET `PrevQuestID`=0 WHERE `ID`=1395; +DELETE FROM `quest_template_addon` WHERE `ID` IN (1477); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (1477,1395); + +-- Tabetha's Task +DELETE FROM `quest_template_addon` WHERE `ID` IN (2861); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (2861,2846); + +-- James Hyal +UPDATE `quest_template_addon` SET `PrevQuestID`=0 WHERE `ID`=1302; +DELETE FROM `quest_template_addon` WHERE `ID` IN (1301); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (1301,1302); + +-- Morgan Stern +DELETE FROM `quest_template_addon` WHERE `ID` IN (1204, 1260); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (1260,1204); + +-- Mayara Brightwing +DELETE FROM `quest_template_addon` WHERE `ID` IN (4764,4766); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (4766,4764); + +-- Tinkmaster Overspark +DELETE FROM `quest_template_addon` WHERE `ID` IN (2922,2923); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (2923,2922); + +-- Knowledge of the Orb of Orahil +-- UPDATE `quest_template` SET `AllowableRaces` = 690 WHERE `Id` IN (4967); +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0,`BreadcrumbForQuestId`=1799 WHERE `ID` IN (4965,4967,4968,4969); + +-- In Search of Menara Voidrender +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0,`BreadcrumbForQuestId`=1796 WHERE `ID` IN (4736,4737,4738,4739); + +-- Gakin's Summons / The Slaughtered Lamb +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0,`BreadcrumbForQuestId`=1688 WHERE `ID` IN (1685, 1715); + +-- Gakin's Summons +UPDATE `quest_template_addon` SET `PrevQuestID`=0 WHERE `ID`=1716; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=1716 WHERE `ID` = 1717; + +-- Jonespyre's Request +-- UPDATE `quest_template` SET `AllowableRaces` = 1101 WHERE `Id` = 3787; +UPDATE `quest_template_addon` SET `PrevQuestID`=3785 WHERE `ID` = 3791; +UPDATE `quest_template_addon` SET `ExclusiveGroup`=0, `BreadcrumbForQuestId`=3791 WHERE `ID` IN (3787,3788); + +-- Malin's Request +DELETE FROM `quest_template_addon` WHERE `ID` IN (690,691); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (690,691); + +-- Report to Anastasia +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=1960 WHERE `ID` = 1959; + +-- Speak with Deino +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=1944 WHERE `ID` = 1943; + +-- Torwa Pathfinder +UPDATE `quest_template_addon` SET `PrevQuestID`=0 WHERE `ID`=9052; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=9052 WHERE `ID` = 9063; + +-- The Hermit +DELETE FROM `quest_template_addon` WHERE `ID` IN (165,148); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (165,148); + +-- Deliveries to Sven +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=95 WHERE `ID` = 164; + +-- Raven Hill +DELETE FROM `quest_template_addon` WHERE `ID` IN (5, 163); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (163,5); + +-- Enraged Wildkin +DELETE FROM `quest_template_addon` WHERE `ID` IN (6604); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (6604,4861); + +-- Ironband's Excavation +DELETE FROM `quest_template_addon` WHERE `ID` IN (436); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (436,297); + +-- Stonegear's Search +DELETE FROM `quest_template_addon` WHERE `ID` IN (466,467); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (467,466); + +-- Mountaineer Stormpike's Task +DELETE FROM `quest_template_addon` WHERE `ID` IN (1339); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (1339,1338); + +-- Report to Mountaineer Rockgar +UPDATE `quest_template_addon` SET `PrevQuestID`=0 WHERE `ID`=455; +DELETE FROM `quest_template_addon` WHERE `ID` IN (468); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (468,455); + +-- Find Bingles +DELETE FROM `quest_template_addon` WHERE `ID` IN (2039); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (2039,2038); + +-- The Greenwarden +DELETE FROM `quest_template_addon` WHERE `ID` IN (463); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (463,276); + +-- Rejold's New Brew +UPDATE `quest_template_addon` SET `PrevQuestID` = 315 WHERE `ID` = 413; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 413 WHERE `Id` = 415; + +-- Klockmort's Essentials +DELETE FROM `quest_template_addon` WHERE `ID` IN (2925); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (2925,2924); + +-- Speak with Shoni +DELETE FROM `quest_template_addon` WHERE `ID` IN (2041); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (2041,2040); + +-- Imperial Plate Armor +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 7652 WHERE `Id` IN (10891,10892); + +-- I Know A Guy... / To Gadgetzan You Go! +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 6610 WHERE `Id` IN (6611,6612); + +-- Alliance Trauma +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 6624 WHERE `Id` IN (6625); + +-- I Got Nothin' Left! +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 6607 WHERE `Id` IN (6609); + +-- Trollbane +DELETE FROM `quest_template_addon` WHERE `ID` IN (638, 639); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (638, 639); + +-- Horde Trauma +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 6622 WHERE `Id` IN (6623); + +-- The Hermit of Witch Hill / The Hermit of Swamplight Manor +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1218 WHERE `Id` IN (11177); +DELETE FROM `quest_template_addon` WHERE `ID` IN (11225); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (11225, 1218); + +-- Vivian Lagrave +DELETE FROM `quest_template_addon` WHERE `ID` IN (4133, 4134); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (4133, 4134); + +-- Vivian Lagrave and the Darkstone Tablet +DELETE FROM `quest_template_addon` WHERE `ID` IN (4768, 4769); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (4769, 4768); + +-- Yuka Screwspigot +DELETE FROM `quest_template_addon` WHERE `ID` IN (4136, 4324); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (4324, 4136); + +-- Help Watcher Biggs +DELETE FROM `quest_template_addon` WHERE `ID` IN (9609); +INSERT INTO `quest_template_addon` (`ID`,`BreadcrumbForQuestId`) VALUES (9609, 1396); + +-- Taking a Stand +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 12503 WHERE `Id` IN (12795); +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` IN (12503, 12596); + +-- The Exiles of Ulduar +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 12930 WHERE `Id` IN (12885); + +-- Assist Exarch Orelis +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 10241; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 10241 WHERE `ID` = 11038; + +-- Off To Area 52 / Out of This World Produce! / A Strange Vision / Parts for the Rocket-Chief / A Mystifying Vision +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0,`BreadcrumbForQuestId` = 10186 WHERE `ID` IN (10183, 11036, 11037, 11040, 11042); + +-- Horde Warlock Voidwalker questlines +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0 WHERE `ID` IN (10789,1478,1473,1471,10790,1506,1501,1504,10788,9529,9619); +UPDATE `quest_template_addon` SET `PrevQuestId` = 1473 WHERE `ID` = 1471; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1473 WHERE `ID` IN (10789, 1478); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1501 WHERE `ID` IN (10790, 1506); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 9529 WHERE `ID` IN (10788); + +-- Horde Mage level 10 quests +-- Speak with Anastasia (1881) b-> The Balnir Farmstead (1882) +-- Speak with Un'thuwa (1883) b-> Ju-Ju Heaps (1884) +-- Fetch! (9402) -> The Purest Water (9403) -> Recently Living (9404) +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0 WHERE `ID` IN (1881,1883,9402); +UPDATE `quest_template_addon` SET `PrevQuestId` = 0 WHERE `ID` IN (1884); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1882 WHERE `ID` IN (1881); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1884 WHERE `ID` IN (1883); +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 1882 WHERE `ID` IN (1882,1884,9402); + +-- Alliance Mage level 10 quests +-- Speak with Jennea (1860) b-> Mirror Lake (1861) +-- Speak with Bink (1879) b-> Mage-tastic Gizmonitor (1880) +-- Control (9595) +-- UPDATE `quest_template` SET `AllowableRaces` = 1101 WHERE `Id` = 1861; +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0 WHERE `ID` IN (1860,1879); +UPDATE `quest_template_addon` SET `PrevQuestId` = 0 WHERE `ID` IN (1880); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1861 WHERE `ID` IN (1860); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1880 WHERE `ID` IN (1879); +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 1861 WHERE `ID` IN (1861,1880,9595); + +-- SI:7 / Erion's Behest / Kingly Shakedown +UPDATE `quest_template_addon` SET `NextQuestId` = 0,`ExclusiveGroup`=0,`BreadcrumbForQuestId` = 2260 WHERE `ID` IN (2259); +UPDATE `quest_template_addon` SET `NextQuestId` = 0,`ExclusiveGroup`=0,`BreadcrumbForQuestId` = 2298 WHERE `ID` IN (2299); +UPDATE `quest_template_addon` SET `NextQuestId` = 0,`ExclusiveGroup`=0,`BreadcrumbForQuestId` = 2281 WHERE `ID` IN (2260,2298,2300); + +-- Alliance Rogue level 10 quests +-- Road to Salvation (2218) b-> Simple Subterfugin' (2238) -> Onin's Report (2239) +-- Seek out SI:7 (2205) b-> Snatch and Grab (2206) +-- The Apple Falls (2241) b-> Destiny Calls (2242) +UPDATE `quest_template_addon` SET `PrevQuestId` = 0,`ExclusiveGroup`= 2206 WHERE `ID` IN (2206,2238,2242); +UPDATE `quest_template_addon` SET `NextQuestId` = 0,`ExclusiveGroup`= 0 WHERE `ID` IN (2218,2205,2241); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2238 WHERE `ID` IN (2218); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2206 WHERE `ID` IN (2205); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2242 WHERE `ID` IN (2241); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 30638cb502c..9751b596fe2 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15037,7 +15037,7 @@ Quest const* Player::GetNextQuest(ObjectGuid guid, Quest const* quest) const return nullptr; } -bool Player::CanSeeStartQuest(Quest const* quest) +bool Player::CanSeeStartQuest(Quest const* quest) const { if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) && SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) && @@ -15051,7 +15051,7 @@ bool Player::CanSeeStartQuest(Quest const* quest) return false; } -bool Player::CanTakeQuest(Quest const* quest, bool msg) +bool Player::CanTakeQuest(Quest const* quest, bool msg) const { return !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestStatus(quest, msg) && SatisfyQuestExclusiveGroup(quest, msg) @@ -15960,7 +15960,8 @@ bool Player::SatisfyQuestLog(bool msg) const bool Player::SatisfyQuestDependentQuests(Quest const* qInfo, bool msg) const { - return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg); + return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg) && + SatisfyQuestBreadcrumbQuest(qInfo, msg) && SatisfyQuestDependentBreadcrumbQuests(qInfo, msg); } bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const @@ -16048,6 +16049,51 @@ bool Player::SatisfyQuestDependentPreviousQuests(Quest const* qInfo, bool msg) c return false; } +bool Player::SatisfyQuestBreadcrumbQuest(Quest const* qInfo, bool msg) const +{ + uint32 breadcrumbTargetQuestId = std::abs(qInfo->GetBreadcrumbForQuestId()); + + //If this is not a breadcrumb quest. + if (!breadcrumbTargetQuestId) + return true; + + // If the target quest is not available + if (!CanTakeQuest(sObjectMgr->GetQuestTemplate(breadcrumbTargetQuestId), false)) + { + if (msg) + { + SendCanTakeQuestResponse(QUEST_ERR_NONE); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestBreadcrumbQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because target quest (QuestID: %u) is not available to player '%s' (%s).", + qInfo->GetQuestId(), breadcrumbTargetQuestId, GetName().c_str(), GetGUID().ToString().c_str()); + } + + return false; + } + + return true; +} + +bool Player::SatisfyQuestDependentBreadcrumbQuests(Quest const* qInfo, bool msg) const +{ + for (uint32 breadcrumbQuestId : qInfo->DependentBreadcrumbQuests) + { + QuestStatus status = GetQuestStatus(breadcrumbQuestId); + // If any of the breadcrumb quests are in the quest log, return false. + if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_FAILED) + { + if (msg) + { + SendCanTakeQuestResponse(QUEST_ERR_NONE); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentBreadcrumbQuests: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) has a breadcrumb quest towards this quest in the quest log.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); + } + + return false; + } + } + return true; +} + bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const { uint32 reqClass = qInfo->GetAllowableClasses(); @@ -16086,7 +16132,7 @@ bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg) const return true; } -bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) const { uint32 fIdMin = qInfo->GetRequiredMinRepFaction(); //Min required rep if (fIdMin && GetReputationMgr().GetReputation(fIdMin) < qInfo->GetRequiredMinRepValue()) @@ -16141,9 +16187,9 @@ bool Player::SatisfyQuestStatus(Quest const* qInfo, bool msg) const return true; } -bool Player::SatisfyQuestConditions(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestConditions(Quest const* qInfo, bool msg) const { - if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_AVAILABLE, qInfo->GetQuestId(), this)) + if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_AVAILABLE, qInfo->GetQuestId(), const_cast<Player*>(this))) { if (msg) { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 7cd807e6e53..9774f6a9b69 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1499,8 +1499,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SendPreparedQuest(WorldObject* source); bool IsActiveQuest(uint32 quest_id) const; Quest const* GetNextQuest(ObjectGuid guid, Quest const* quest) const; - bool CanSeeStartQuest(Quest const* quest); - bool CanTakeQuest(Quest const* quest, bool msg); + bool CanSeeStartQuest(Quest const* quest) const; + bool CanTakeQuest(Quest const* quest, bool msg) const; bool CanAddQuest(Quest const* quest, bool msg) const; bool CanCompleteQuest(uint32 quest_id, uint32 ignoredQuestObjectiveId = 0); bool CanCompleteRepeatableQuest(Quest const* quest); @@ -1526,11 +1526,13 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool SatisfyQuestDependentQuests(Quest const* qInfo, bool msg) const; bool SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const; bool SatisfyQuestDependentPreviousQuests(Quest const* qInfo, bool msg) const; + bool SatisfyQuestBreadcrumbQuest(Quest const* qInfo, bool msg) const; + bool SatisfyQuestDependentBreadcrumbQuests(Quest const* qInfo, bool msg) const; bool SatisfyQuestClass(Quest const* qInfo, bool msg) const; bool SatisfyQuestRace(Quest const* qInfo, bool msg) const; - bool SatisfyQuestReputation(Quest const* qInfo, bool msg); + bool SatisfyQuestReputation(Quest const* qInfo, bool msg) const; bool SatisfyQuestStatus(Quest const* qInfo, bool msg) const; - bool SatisfyQuestConditions(Quest const* qInfo, bool msg); + bool SatisfyQuestConditions(Quest const* qInfo, bool msg) const; bool SatisfyQuestTimed(Quest const* qInfo, bool msg) const; bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const; bool SatisfyQuestDay(Quest const* qInfo, bool msg) const; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index ce3d12c8ef4..4cbe4830866 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -4326,11 +4326,11 @@ void ObjectMgr::LoadQuests() // 0 1 2 3 4 5 6 7 8 9 { "ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4, RewardText", "quest_offer_reward", "", "reward emotes", &Quest::LoadQuestOfferReward }, - // 0 1 2 3 4 5 6 7 8 - { "ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, RewardMailTemplateID, RewardMailDelay," - // 9 10 11 12 13 14 15 16 + // 0 1 2 3 4 5 6 7 8 9 + { "ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, BreadcrumbForQuestId, RewardMailTemplateID, RewardMailDelay," + // 10 11 12 13 14 15 16 17 " RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, SpecialFlags," - // 17 + // 18 " ScriptName", "quest_template_addon", "", "template addons", &Quest::LoadQuestTemplateAddon }, // 0 1 @@ -4986,8 +4986,11 @@ void ObjectMgr::LoadQuests() // fill additional data stores if (uint32 prevQuestId = std::abs(qinfo->_prevQuestID)) { - if (!_questTemplates.count(prevQuestId)) + auto prevQuestItr = _questTemplates.find(prevQuestId); + if (prevQuestItr == _questTemplates.end()) TC_LOG_ERROR("sql.sql", "Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId()); + else if (prevQuestItr->second._breadcrumbForQuestId) + TC_LOG_ERROR("sql.sql", "Quest %u should not be unlocked by breadcrumb quest %u", qinfo->_id, prevQuestId); } if (uint32 nextQuestId = qinfo->_nextQuestID) @@ -4999,10 +5002,55 @@ void ObjectMgr::LoadQuests() nextQuestItr->second.DependentPreviousQuests.push_back(qinfo->GetQuestId()); } + if (uint32 breadcrumbForQuestId = std::abs(qinfo->_breadcrumbForQuestId)) + { + if (_questTemplates.find(breadcrumbForQuestId) == _questTemplates.end()) + { + TC_LOG_ERROR("sql.sql", "Quest %u is a breadcrumb for quest %u, but no such quest exists", qinfo->_id, breadcrumbForQuestId); + qinfo->_breadcrumbForQuestId = 0; + } + if (qinfo->_nextQuestID) + TC_LOG_ERROR("sql.sql", "Quest %u is a breadcrumb, should not unlock quest %u", qinfo->_id, qinfo->_nextQuestID); + if (qinfo->_exclusiveGroup) + TC_LOG_ERROR("sql.sql", "Quest %u is a breadcrumb in exclusive group %i", qinfo->_id, qinfo->_exclusiveGroup); + } + if (qinfo->_exclusiveGroup) _exclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->_exclusiveGroup, qinfo->GetQuestId())); } + // Disallow any breadcrumb loops and inform quests of their breadcrumbs + for (auto& questPair : _questTemplates) + { + // skip post-loading checks for disabled quests + if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, questPair.first, nullptr)) + continue; + + Quest* qinfo = &questPair.second; + uint32 qid = qinfo->GetQuestId(); + uint32 breadcrumbForQuestId = std::abs(qinfo->_breadcrumbForQuestId); + std::set<uint32> questSet; + + while(breadcrumbForQuestId) + { + //a previously visited quest was found as a breadcrumb quest + //breadcrumb loop found! + if (!questSet.insert(qinfo->_id).second) + { + TC_LOG_ERROR("sql.sql", "Breadcrumb quests %u and %u are in a loop", qid, breadcrumbForQuestId); + qinfo->_breadcrumbForQuestId = 0; + break; + } + + qinfo = const_cast<Quest*>(sObjectMgr->GetQuestTemplate(breadcrumbForQuestId)); + + //every quest has a list of every breadcrumb towards it + qinfo->DependentBreadcrumbQuests.push_back(qid); + + breadcrumbForQuestId = qinfo->GetBreadcrumbForQuestId(); + } + } + // check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE for (SpellNameEntry const* spellNameEntry : sSpellNameStore) { diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 5cdf17c01ca..ad918fe67d6 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -217,17 +217,18 @@ void Quest::LoadQuestTemplateAddon(Field* fields) _prevQuestID = fields[4].GetInt32(); _nextQuestID = fields[5].GetUInt32(); _exclusiveGroup = fields[6].GetInt32(); - _rewardMailTemplateId = fields[7].GetUInt32(); - _rewardMailDelay = fields[8].GetUInt32(); - _requiredSkillId = fields[9].GetUInt16(); - _requiredSkillPoints = fields[10].GetUInt16(); - _requiredMinRepFaction = fields[11].GetUInt16(); - _requiredMaxRepFaction = fields[12].GetUInt16(); - _requiredMinRepValue = fields[13].GetInt32(); - _requiredMaxRepValue = fields[14].GetInt32(); - _sourceItemIdCount = fields[15].GetUInt8(); - _specialFlags = fields[16].GetUInt8(); - _scriptId = sObjectMgr->GetScriptId(fields[17].GetString()); + _breadcrumbForQuestId = fields[7].GetInt32(); + _rewardMailTemplateId = fields[8].GetUInt32(); + _rewardMailDelay = fields[9].GetUInt32(); + _requiredSkillId = fields[10].GetUInt16(); + _requiredSkillPoints = fields[11].GetUInt16(); + _requiredMinRepFaction = fields[12].GetUInt16(); + _requiredMaxRepFaction = fields[13].GetUInt16(); + _requiredMinRepValue = fields[14].GetInt32(); + _requiredMaxRepValue = fields[15].GetInt32(); + _sourceItemIdCount = fields[16].GetUInt8(); + _specialFlags = fields[17].GetUInt8(); + _scriptId = sObjectMgr->GetScriptId(fields[18].GetString()); if (_specialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) _flags |= QUEST_FLAGS_AUTO_ACCEPT; diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 3b0c541b3a8..7468cd26926 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -529,6 +529,7 @@ class TC_GAME_API Quest int32 GetPrevQuestId() const { return _prevQuestID; } uint32 GetNextQuestId() const { return _nextQuestID; } int32 GetExclusiveGroup() const { return _exclusiveGroup; } + int32 GetBreadcrumbForQuestId() const { return _breadcrumbForQuestId; } uint32 GetNextQuestInChain() const { return _nextQuestInChain; } int32 GetRewArenaPoints() const {return _rewardArenaPoints; } uint32 GetXPDifficulty() const { return _rewardXPDifficulty; } @@ -638,6 +639,7 @@ class TC_GAME_API Quest void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const; std::vector<uint32> DependentPreviousQuests; + std::vector<uint32> DependentBreadcrumbQuests; std::array<WorldPacket, TOTAL_LOCALES> QueryData; private: @@ -720,6 +722,7 @@ class TC_GAME_API Quest int32 _prevQuestID = 0; uint32 _nextQuestID = 0; int32 _exclusiveGroup = 0; + int32 _breadcrumbForQuestId = 0; uint32 _rewardMailTemplateId = 0; uint32 _rewardMailDelay = 0; uint32 _requiredSkillId = 0; |