diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-06-10 20:31:33 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-06-10 20:31:33 +0200 |
commit | 4d4c7e68935df9ca40bd5539d602ac4e779f53d5 (patch) | |
tree | cba70a6e20bb52a33815204d40d929220ac4ab0c /src/server/game | |
parent | 39bebe6a653bdd65160aa7f9fef6501d43884079 (diff) |
Core/Quests: Quest flag fixups
* Update flag names
* Implemented QUEST_FLAGS_COMPLETION_NO_DEATH and QUEST_FLAGS_FAIL_ON_LOGOUT
* Started using QUEST_FLAGS_COMPLETION_EVENT and QUEST_FLAGS_COMPLETION_AREA_TRIGGER instead of a custom SpeclalFlag
* Renamed Quest::IsAutoComplete to Quest::IsTurnIn to better describe what it means (a quest that can be turned in without accepting it to quest log)
* Implemented QUEST_FLAGS_UPDATE_PHASESHIFT and removed forced phaseshift updates on every quest status change
* Implemented QUEST_FLAGS_LAUNCH_GOSSIP_ACCEPT - reopens gossip menu with questgiver
Diffstat (limited to 'src/server/game')
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/GossipDef.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 141 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 3 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 54 | ||||
-rw-r--r-- | src/server/game/Handlers/MiscHandler.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Handlers/QuestHandler.cpp | 72 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 10 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.cpp | 12 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 47 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 |
12 files changed, 182 insertions, 172 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 7ac71ca5625..9ae7999e86f 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -1661,9 +1661,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_CALL_GROUPEVENTHAPPENS: if (Quest const* qid = sObjectMgr->GetQuestTemplate(e.action.quest.quest)) { - if (!qid->HasSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT)) + if (!qid->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) && !qid->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER)) { - TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} SpecialFlags for Quest entry {} does not include FLAGS_EXPLORATION_OR_EVENT(2), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest); + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Flags for Quest entry {} does not include QUEST_FLAGS_COMPLETION_EVENT or QUEST_FLAGS_COMPLETION_AREA_TRIGGER, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest); return false; } } diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 574d016eb06..632fb3f366a 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -283,7 +283,7 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, ObjectGuid objectGUID) text.QuestType = item.QuestIcon; text.QuestFlags[0] = quest->GetFlags(); text.QuestFlags[1] = quest->GetFlagsEx(); - text.Repeatable = quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly(); + text.Repeatable = quest->IsTurnIn() && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly(); text.QuestTitle = quest->GetLogTitle(); LocaleConstant localeConstant = _session->GetSessionDbLocaleIndex(); @@ -410,7 +410,7 @@ void PlayerMenu::SendQuestGiverQuestListMessage(Object* questgiver) text.QuestType = questMenuItem.QuestIcon; text.QuestFlags[0] = quest->GetFlags(); text.QuestFlags[1] = quest->GetFlagsEx(); - text.Repeatable = quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly(); + text.Repeatable = quest->IsTurnIn() && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly(); text.QuestTitle = quest->GetLogTitle(); LocaleConstant localeConstant = _session->GetSessionDbLocaleIndex(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 67fcd09e365..d24aae288ed 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1264,6 +1264,8 @@ void Player::setDeathState(DeathState s) InitializeSelfResurrectionSpells(); + FailQuestsWithFlag(QUEST_FLAGS_COMPLETION_NO_DEATH); + UpdateCriteria(CriteriaType::DieOnMap, 1); UpdateCriteria(CriteriaType::DieAnywhere, 1); UpdateCriteria(CriteriaType::DieInInstance, 1); @@ -14419,9 +14421,9 @@ void Player::PrepareQuestMenu(ObjectGuid guid) if (!CanTakeQuest(quest, false)) continue; - if (quest->IsAutoComplete() && (!quest->IsRepeatable() || quest->IsDaily() || quest->IsWeekly() || quest->IsMonthly())) + if (quest->IsTurnIn() && (!quest->IsRepeatable() || quest->IsDaily() || quest->IsWeekly() || quest->IsMonthly())) qm.AddMenuItem(quest_id, 0); - else if (quest->IsAutoComplete()) + else if (quest->IsTurnIn()) qm.AddMenuItem(quest_id, 4); else if (GetQuestStatus(quest_id) == QUEST_STATUS_NONE) qm.AddMenuItem(quest_id, 2); @@ -14454,9 +14456,9 @@ void Player::SendPreparedQuest(WorldObject* source) if (quest->IsAutoAccept() && CanAddQuest(quest, true) && CanTakeQuest(quest, true)) AddQuestAndCheckCompletion(quest, source); - if (quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly()) + if (quest->IsTurnIn() && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly()) PlayerTalkClass->SendQuestGiverRequestItems(quest, source->GetGUID(), CanCompleteRepeatableQuest(quest), true); - else if (quest->IsAutoComplete() && !quest->IsDailyOrWeekly() && !quest->IsMonthly()) + else if (quest->IsTurnIn() && !quest->IsDailyOrWeekly() && !quest->IsMonthly()) PlayerTalkClass->SendQuestGiverRequestItems(quest, source->GetGUID(), CanRewardQuest(quest, false), true); else PlayerTalkClass->SendQuestGiverQuestDetails(quest, source->GetGUID(), true, false); @@ -14482,7 +14484,9 @@ Quest const* Player::GetNextQuest(Object const* questGiver, Quest const* quest) if (questGiver == this) { - ASSERT(quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)); + if (!quest->HasFlag(QUEST_FLAGS_AUTO_COMPLETE)) + return nullptr; + return sObjectMgr->GetQuestTemplate(nextQuestID); } @@ -14560,7 +14564,7 @@ bool Player::CanCompleteQuest(uint32 quest_id, uint32 ignoredQuestObjectiveId /* return false; // not allow re-complete quest // auto complete quest - if (qInfo->IsAutoComplete() && CanTakeQuest(qInfo, false)) + if (qInfo->IsTurnIn() && CanTakeQuest(qInfo, false)) return true; QuestStatusMap::iterator itr = m_QuestStatus.find(quest_id); @@ -14583,7 +14587,7 @@ bool Player::CanCompleteQuest(uint32 quest_id, uint32 ignoredQuestObjectiveId /* } } - if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT) && !q_status.Explored) + if ((qInfo->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) || qInfo->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER)) && !q_status.Explored) return false; if (qInfo->GetLimitTime() && q_status.Timer == 0) @@ -14621,7 +14625,7 @@ bool Player::CanRewardQuest(Quest const* quest, bool msg) const return false; // not auto complete quest and not completed quest (only cheating case, then ignore without message) - if (!quest->IsDFQuest() && !quest->IsAutoComplete() && GetQuestStatus(quest->GetQuestId()) != QUEST_STATUS_COMPLETE) + if (!quest->IsDFQuest() && !quest->IsTurnIn() && GetQuestStatus(quest->GetQuestId()) != QUEST_STATUS_COMPLETE) return false; // daily quest can't be rewarded (25 daily quest already completed) @@ -14893,7 +14897,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetSrcSpell(), GetMap()->GetDifficultyID()); Unit* caster = this; - if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_ON_ACCEPT) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER) && !spellInfo->HasTargetType(TARGET_DEST_CASTER_SUMMON)) + if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_ACCEPT) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER) && !spellInfo->HasTargetType(TARGET_DEST_CASTER_SUMMON)) if (Unit* unit = questGiver->ToUnit()) caster = unit; @@ -14936,7 +14940,7 @@ void Player::CompleteQuest(uint32 quest_id) SetQuestSlotState(questStatus->Slot, QUEST_STATE_COMPLETE); if (Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id)) - if (qInfo->HasFlag(QUEST_FLAGS_TRACKING)) + if (qInfo->HasFlag(QUEST_FLAGS_TRACKING_EVENT)) RewardQuest(qInfo, LootItemType::Item, 0, this, false); } @@ -15069,23 +15073,29 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew switch (obj.Type) { case QUEST_OBJECTIVE_ITEM: - if (!(quest->GetFlagsEx() & QUEST_FLAGS_EX_KEEP_ADDITIONAL_ITEMS)) - DestroyItemCount(obj.ObjectID, obj.Amount, true); + { + int32 amountToDestroy = obj.Amount; + if (quest->HasFlag(QUEST_FLAGS_REMOVE_SURPLUS_ITEMS)) + amountToDestroy = std::numeric_limits<uint32>::max(); + DestroyItemCount(obj.ObjectID, amountToDestroy, true); break; + } case QUEST_OBJECTIVE_CURRENCY: RemoveCurrency(obj.ObjectID, obj.Amount, CurrencyDestroyReason::QuestTurnin); break; } } - if (!(quest->GetFlagsEx() & QUEST_FLAGS_EX_KEEP_ADDITIONAL_ITEMS)) + if (!quest->HasFlagEx(QUEST_FLAGS_EX_KEEP_ADDITIONAL_ITEMS)) { for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i) { if (quest->ItemDrop[i]) { uint32 count = quest->ItemDropQuantity[i]; - DestroyItemCount(quest->ItemDrop[i], count ? count : 9999, true); + if (!count) + count = std::numeric_limits<uint32>::max(); + DestroyItemCount(quest->ItemDrop[i], count, true); } } } @@ -15246,7 +15256,7 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew { SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(quest->GetRewSpell(), GetMap()->GetDifficultyID()); Unit* caster = this; - if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_ON_COMPLETE) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER)) + if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_COMPLETE) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER)) if (Unit* unit = questGiver->ToUnit()) caster = unit; @@ -15262,7 +15272,7 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(displaySpell.SpellId, GetMap()->GetDifficultyID()); Unit* caster = this; - if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_ON_COMPLETE) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER)) + if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_COMPLETE) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER)) if (Unit* unit = questGiver->ToUnit()) caster = unit; @@ -15290,66 +15300,66 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew SendQuestGiverStatusMultiple(); - bool conditionChanged = SendQuestUpdate(quest_id, false); + SendQuestUpdate(quest_id); + + bool updateVisibility = false; + if (quest->HasFlag(QUEST_FLAGS_UPDATE_PHASESHIFT)) + updateVisibility = PhasingHandler::OnConditionChange(this, false); //lets remove flag for delayed teleports SetCanDelayTeleport(false); - bool canHaveNextQuest = !quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE) ? questGiver && !questGiver->IsPlayer() : true; - if (canHaveNextQuest) + switch (questGiver->GetTypeId()) { - switch (questGiver->GetTypeId()) + case TYPEID_UNIT: + case TYPEID_PLAYER: { - case TYPEID_UNIT: - case TYPEID_PLAYER: + //For AutoSubmition was added plr case there as it almost same exclute AI script cases. + // Send next quest + if (Quest const* nextQuest = GetNextQuest(questGiver, quest)) { - //For AutoSubmition was added plr case there as it almost same exclute AI script cases. - // Send next quest - if (Quest const* nextQuest = GetNextQuest(questGiver, quest)) + // Only send the quest to the player if the conditions are met + if (CanTakeQuest(nextQuest, false)) { - // Only send the quest to the player if the conditions are met - if (CanTakeQuest(nextQuest, false)) - { - if (nextQuest->IsAutoAccept() && CanAddQuest(nextQuest, true)) - AddQuestAndCheckCompletion(nextQuest, questGiver); + if (nextQuest->IsAutoAccept() && CanAddQuest(nextQuest, true)) + AddQuestAndCheckCompletion(nextQuest, questGiver); - PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, questGiver->GetGUID(), true, false); - } + PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, questGiver->GetGUID(), true, false); } - - PlayerTalkClass->ClearMenus(); - if (Creature* creatureQGiver = questGiver->ToCreature()) - creatureQGiver->AI()->OnQuestReward(this, quest, rewardType, rewardId); - break; } - case TYPEID_GAMEOBJECT: + + PlayerTalkClass->ClearMenus(); + if (Creature* creatureQGiver = questGiver->ToCreature()) + creatureQGiver->AI()->OnQuestReward(this, quest, rewardType, rewardId); + break; + } + case TYPEID_GAMEOBJECT: + { + // Send next quest + if (Quest const* nextQuest = GetNextQuest(questGiver, quest)) { - // Send next quest - if (Quest const* nextQuest = GetNextQuest(questGiver, quest)) + // Only send the quest to the player if the conditions are met + if (CanTakeQuest(nextQuest, false)) { - // Only send the quest to the player if the conditions are met - if (CanTakeQuest(nextQuest, false)) - { - if (nextQuest->IsAutoAccept() && CanAddQuest(nextQuest, true)) - AddQuestAndCheckCompletion(nextQuest, questGiver); + if (nextQuest->IsAutoAccept() && CanAddQuest(nextQuest, true)) + AddQuestAndCheckCompletion(nextQuest, questGiver); - PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, questGiver->GetGUID(), true, false); - } + PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, questGiver->GetGUID(), true, false); } - - PlayerTalkClass->ClearMenus(); - questGiver->ToGameObject()->AI()->OnQuestReward(this, quest, rewardType, rewardId); - break; } - default: - break; + + PlayerTalkClass->ClearMenus(); + questGiver->ToGameObject()->AI()->OnQuestReward(this, quest, rewardType, rewardId); + break; } + default: + break; } sScriptMgr->OnQuestStatusChange(this, quest_id); sScriptMgr->OnQuestStatusChange(this, quest, oldStatus, QUEST_STATUS_REWARDED); - if (conditionChanged) + if (updateVisibility) UpdateObjectVisibility(); } @@ -15407,6 +15417,20 @@ void Player::FailQuest(uint32 questId) } } +void Player::FailQuestsWithFlag(QuestFlags flag) +{ + for (uint16 slot = 0; MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = GetQuestSlotQuestId(slot); + if (!questId) + continue; + + if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) + if (quest->HasFlag(flag)) + FailQuest(questId); + } +} + void Player::AbandonQuest(uint32 questId) { if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) @@ -15981,7 +16005,7 @@ void Player::SetQuestStatus(uint32 questId, QuestStatus status, bool update /*= QuestStatus oldStatus = m_QuestStatus[questId].Status; m_QuestStatus[questId].Status = status; - if (!quest->IsAutoComplete()) + if (!quest->IsTurnIn()) m_QuestStatusSave[questId] = QUEST_DEFAULT_SAVE_TYPE; sScriptMgr->OnQuestStatusChange(this, questId); @@ -16041,7 +16065,7 @@ void Player::RemoveRewardedQuest(uint32 questId, bool update /*= true*/) SendQuestUpdate(questId); } -bool Player::SendQuestUpdate(uint32 questId, bool updateVisiblity /*= true*/) +void Player::SendQuestUpdate(uint32 questId) { SpellAreaForQuestMapBounds saBounds = sSpellMgr->GetSpellAreaForQuestMapBounds(questId); @@ -16090,7 +16114,6 @@ bool Player::SendQuestUpdate(uint32 questId, bool updateVisiblity /*= true*/) } UpdateVisibleGameobjectsOrSpellClicks(); - return PhasingHandler::OnConditionChange(this, updateVisiblity); } QuestGiverStatus Player::GetQuestDialogStatus(Object const* questgiver) const @@ -16152,7 +16175,7 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object const* questgiver) const break; } - if (quest->IsAutoComplete() && CanTakeQuest(quest, false) && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly()) + if (quest->IsTurnIn() && CanTakeQuest(quest, false) && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly()) { if (GetLevel() <= (GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF))) result |= QuestGiverStatus::RepeatableTurnin; @@ -16951,7 +16974,7 @@ void Player::SendQuestReward(Quest const* quest, Creature const* questGiver, uin if (questGiver->IsQuestGiver()) packet.LaunchQuest = (GetQuestDialogStatus(questGiver) & ~QuestGiverStatus::Future) != QuestGiverStatus::None; - if (!quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) + if (!quest->HasFlag(QUEST_FLAGS_AUTO_COMPLETE)) if (Quest const* rewardQuest = GetNextQuest(questGiver, quest)) packet.UseQuestReward = CanTakeQuest(rewardQuest, false); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e52f4d4bd29..71b00fe46d9 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1589,6 +1589,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rewardId, Object* questGiver, bool announce = true); void SetRewardedQuest(uint32 quest_id); void FailQuest(uint32 quest_id); + void FailQuestsWithFlag(QuestFlags flag); bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const; bool SatisfyQuestLevel(Quest const* qInfo, bool msg) const; bool SatisfyQuestMinLevel(Quest const* qInfo, bool msg) const; @@ -1618,7 +1619,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SetQuestStatus(uint32 questId, QuestStatus status, bool update = true); void RemoveActiveQuest(uint32 questId, bool update = true); void RemoveRewardedQuest(uint32 questId, bool update = true); - bool SendQuestUpdate(uint32 questId, bool updateVisiblity = true); + void SendQuestUpdate(uint32 questId); QuestGiverStatus GetQuestDialogStatus(Object const* questGiver) const; void SetDailyQuestStatus(uint32 quest_id); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 94f0b5cd966..fb004f8b6eb 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -4645,7 +4645,7 @@ void ObjectMgr::LoadQuests() // additional quest integrity checks (GO, creature_template and items must be loaded already) - if (qinfo->GetQuestType() >= MAX_QUEST_TYPES) + if (qinfo->GetQuestType() >= MAX_DB_ALLOWED_QUEST_TYPES) TC_LOG_ERROR("sql.sql", "Quest {} has `Method` = {}, expected values are 0, 1 or 2.", qinfo->GetQuestId(), qinfo->GetQuestType()); if (qinfo->_specialFlags & ~QUEST_SPECIAL_FLAGS_DB_ALLOWED) @@ -4688,7 +4688,7 @@ void ObjectMgr::LoadQuests() } } - if (qinfo->_flags & QUEST_FLAGS_TRACKING) + if (qinfo->_flags & QUEST_FLAGS_TRACKING_EVENT) { // at auto-reward can be rewarded only RewardChoiceItemId[0] for (uint32 j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j ) @@ -5283,35 +5283,7 @@ void ObjectMgr::LoadQuests() } } - // check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE - for (SpellNameEntry const* spellNameEntry : sSpellNameStore) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellNameEntry->ID, DIFFICULTY_NONE); - if (!spellInfo) - continue; - - for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects()) - { - if (spellEffectInfo.Effect != SPELL_EFFECT_QUEST_COMPLETE) - continue; - - uint32 quest_id = spellEffectInfo.MiscValue; - - Quest const* quest = GetQuestTemplate(quest_id); - - // some quest referenced in spells not exist (outdated spells) - if (!quest) - continue; - - if (!quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT)) - { - TC_LOG_ERROR("sql.sql", "Spell (id: {}) have SPELL_EFFECT_QUEST_COMPLETE for quest {}, but quest not have flag QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.", spellInfo->Id, quest_id); - - // this will prevent quest completing without objective - const_cast<Quest*>(quest)->SetSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT); - } - } - } + // don't check spells with SPELL_EFFECT_QUEST_COMPLETE, a lot of invalid db2 data // Make all paragon reward quests repeatable for (ParagonReputationEntry const* paragonReputation : sParagonReputationStore) @@ -5620,15 +5592,11 @@ void ObjectMgr::LoadScripts(ScriptsType type) continue; } - if (!quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT)) + if (!quest->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) && !quest->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER)) { - TC_LOG_ERROR("sql.sql", "Table `{}` has quest (ID: {}) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id {}, but quest not have flag QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.", + TC_LOG_ERROR("sql.sql", "Table `{}` has quest (ID: {}) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id {}, but quest not have QUEST_FLAGS_COMPLETION_EVENT or QUEST_FLAGS_COMPLETION_AREA_TRIGGER in quest flags. Script command will do nothing.", tableName, tmp.QuestExplored.QuestID, tmp.id); - - // this will prevent quest completing without objective - const_cast<Quest*>(quest)->SetSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT); - - // continue; - quest objective requirement set and command can be allowed + continue; } if (float(tmp.QuestExplored.Distance) > DEFAULT_VISIBILITY_DISTANCE) @@ -6543,14 +6511,10 @@ void ObjectMgr::LoadQuestAreaTriggers() continue; } - if (!quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT)) + if (!quest->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER) && !quest->HasQuestObjectiveType(QUEST_OBJECTIVE_AREATRIGGER)) { - TC_LOG_ERROR("sql.sql", "Table `areatrigger_involvedrelation` has record (id: {}) for not quest {}, but quest not have flag QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.", trigger_ID, quest_ID); - - // this will prevent quest completing without objective - const_cast<Quest*>(quest)->SetSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT); - - // continue; - quest modified to required objective and trigger can be allowed. + TC_LOG_ERROR("sql.sql", "Table `areatrigger_involvedrelation` has record (id: {}) for not quest {}, but quest not have flag QUEST_FLAGS_COMPLETION_AREA_TRIGGER and no objective with type QUEST_OBJECTIVE_AREATRIGGER. Trigger is obsolete, skipped.", trigger_ID, quest_ID); + continue; } _questAreaTriggerStore[trigger_ID].insert(quest_ID); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index b0eca9c6b93..7e870b0a291 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -541,6 +541,9 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::AreaTrigger::AreaTrigge break; } + if (qInfo->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER)) + player->AreaExploredOrEventHappens(questId); + if (player->CanCompleteQuest(questId)) player->CompleteQuest(questId); } diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index aa80e11e1cd..9010a3d629e 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -177,7 +177,7 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPackets::Quest::QuestG { _player->AddQuestAndCheckCompletion(quest, object); - if (quest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) + if (quest->IsPushedToPartyOnAccept()) { if (Group* group = _player->GetGroup()) { @@ -203,6 +203,21 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPackets::Quest::QuestG _player->PlayerTalkClass->SendCloseGossip(); + if (quest->HasFlag(QUEST_FLAGS_LAUNCH_GOSSIP_ACCEPT)) + { + auto launchGossip = [&](WorldObject* worldObject) + { + _player->PlayerTalkClass->ClearMenus(); + _player->PrepareGossipMenu(worldObject, _player->GetGossipMenuForSource(worldObject), true); + _player->SendPreparedGossip(worldObject); + }; + + if (Creature* creature = object->ToCreature()) + launchGossip(creature); + else if (GameObject* go = object->ToGameObject()) + launchGossip(go); + } + return; } } @@ -230,7 +245,7 @@ void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPackets::Quest::QuestGi if (quest->IsAutoAccept() && _player->CanAddQuest(quest, true)) _player->AddQuestAndCheckCompletion(quest, object); - if (quest->IsAutoComplete()) + if (quest->IsTurnIn()) _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, object->GetGUID(), _player->CanCompleteQuest(quest->GetQuestId()), true); else _player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, object->GetGUID(), true, false); @@ -359,7 +374,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest Object* object = _player; - if (!quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) + if (!quest->HasFlag(QUEST_FLAGS_AUTO_COMPLETE)) { object = ObjectAccessor::GetObjectByTypeMask(*_player, packet.QuestGiverGUID, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); if (!object || !object->hasInvolvedQuest(packet.QuestID)) @@ -371,7 +386,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest } if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(packet.QuestID) == QUEST_STATUS_NONE) || - (_player->GetQuestStatus(packet.QuestID) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete())) + (_player->GetQuestStatus(packet.QuestID) != QUEST_STATUS_COMPLETE && !quest->IsTurnIn())) { TC_LOG_ERROR("network", "Error in QUEST_STATUS_COMPLETE: player {} {} tried to complete quest {}, but is not allowed to do so (possible packet-hacking or high latency)", _player->GetName(), _player->GetGUID().ToString(), packet.QuestID); @@ -474,34 +489,34 @@ void WorldSession::HandleQuestConfirmAccept(WorldPackets::Quest::QuestConfirmAcc { TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT questId = {}", packet.QuestID); - if (Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID)) - { - if (!quest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) - return; + if (_player->GetSharedQuestID() != uint32(packet.QuestID)) + return; - Player* originalPlayer = ObjectAccessor::FindPlayer(_player->GetPlayerSharingQuest()); - if (!originalPlayer) - return; + _player->ClearQuestSharingInfo(); + Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID); + if (!quest) + return; - if (!_player->IsInSameRaidWith(originalPlayer)) - return; + Player* originalPlayer = ObjectAccessor::FindPlayer(_player->GetPlayerSharingQuest()); + if (!originalPlayer) + return; - if (!originalPlayer->IsActiveQuest(packet.QuestID)) - return; + if (!_player->IsInSameRaidWith(originalPlayer)) + return; - if (!_player->CanTakeQuest(quest, true)) - return; + if (!originalPlayer->IsActiveQuest(packet.QuestID)) + return; - if (_player->CanAddQuest(quest, true)) - { - _player->AddQuestAndCheckCompletion(quest, nullptr); // NULL, this prevent DB script from duplicate running + if (!_player->CanTakeQuest(quest, true)) + return; - if (quest->GetSrcSpell() > 0) - _player->CastSpell(_player, quest->GetSrcSpell(), true); - } - } + if (!_player->CanAddQuest(quest, true)) + return; - _player->ClearQuestSharingInfo(); + _player->AddQuestAndCheckCompletion(quest, nullptr); // NULL, this prevent DB script from duplicate running + + if (quest->GetSrcSpell() > 0) + _player->CastSpell(_player, quest->GetSrcSpell(), true); } void WorldSession::HandleQuestgiverCompleteQuest(WorldPackets::Quest::QuestGiverCompleteQuest& packet) @@ -514,9 +529,6 @@ void WorldSession::HandleQuestgiverCompleteQuest(WorldPackets::Quest::QuestGiver if (!quest) return; - if (autoCompleteMode && !quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) - return; - Object* object = nullptr; if (autoCompleteMode) object = _player; @@ -526,7 +538,7 @@ void WorldSession::HandleQuestgiverCompleteQuest(WorldPackets::Quest::QuestGiver if (!object) return; - if (!autoCompleteMode) + if (!quest->HasFlag(QUEST_FLAGS_AUTO_COMPLETE)) { if (!object->hasInvolvedQuest(packet.QuestID)) return; @@ -716,7 +728,7 @@ void WorldSession::HandlePushQuestToParty(WorldPackets::Quest::PushQuestToParty& sender->SendPushToPartyResponse(receiver, QuestPushReason::Success); - if (quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) + if (quest->IsTurnIn() && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) receiver->PlayerTalkClass->SendQuestGiverRequestItems(quest, sender->GetGUID(), receiver->CanCompleteRepeatableQuest(quest), true); else { diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 250628f3d05..f39a9937d85 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -5060,11 +5060,15 @@ enum HolidayIds enum QuestType { - QUEST_TYPE_AUTOCOMPLETE = 0, - QUEST_TYPE_DISABLED = 1, + QUEST_TYPE_TURNIN = 0, + QUEST_TYPE_WITH_MAX_LEVEL = 1, QUEST_TYPE_NORMAL = 2, QUEST_TYPE_TASK = 3, - MAX_QUEST_TYPES = 4 + MAX_DB_ALLOWED_QUEST_TYPES = 4, + + // values used in quest menu packets + QUEST_TYPE_IN_PROGRESS = 4, + QUEST_TYPE_TASK_IN_PROGRESS = 5 }; // QuestInfo.dbc (9.0.2.37176) diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index e3d39cef7a9..2feff84a03d 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -521,7 +521,7 @@ void Quest::BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player uint32 Quest::GetRewMoneyMaxLevel() const { // If Quest has flag to not give money on max level, it's 0 - if (HasFlag(QUEST_FLAGS_NO_MONEY_FROM_XP)) + if (HasFlag(QUEST_FLAGS_NO_MONEY_FOR_XP)) return 0; // Else, return the rewarded copper sum modified by the rate @@ -533,9 +533,9 @@ bool Quest::IsAutoAccept() const return !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT) && HasFlag(QUEST_FLAGS_AUTO_ACCEPT); } -bool Quest::IsAutoComplete() const +bool Quest::IsTurnIn() const { - return !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) && _type == QUEST_TYPE_AUTOCOMPLETE; + return !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) && _type == QUEST_TYPE_TURNIN; } bool Quest::IsRaidQuest(Difficulty difficulty) const @@ -552,7 +552,7 @@ bool Quest::IsRaidQuest(Difficulty difficulty) const break; } - if ((_flags & QUEST_FLAGS_RAID) != 0) + if ((_flags & QUEST_FLAGS_RAID_GROUP_OK) != 0) return true; return false; @@ -654,7 +654,7 @@ WorldPacket Quest::BuildQueryData(LocaleConstant loc, Player* player) const response.Info.RewardXPDifficulty = GetXPDifficulty(); response.Info.RewardXPMultiplier = GetXPMultiplier(); - if (!HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) + if (!HasFlag(QUEST_FLAGS_HIDE_REWARD)) response.Info.RewardMoney = player ? player->GetQuestMoneyReward(this) : GetMaxMoneyReward(); response.Info.RewardMoneyDifficulty = GetRewMoneyDifficulty(); @@ -697,7 +697,7 @@ WorldPacket Quest::BuildQueryData(LocaleConstant loc, Player* player) const response.Info.ItemDropQuantity[i] = ItemDropQuantity[i]; } - if (!HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) + if (!HasFlag(QUEST_FLAGS_HIDE_REWARD)) { for (uint8 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i) { diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 016ec2dc958..d16e8b1ad09 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -179,37 +179,37 @@ DEFINE_ENUM_FLAG(QuestGiverStatus); enum QuestFlags : uint32 { QUEST_FLAGS_NONE = 0x00000000, - QUEST_FLAGS_STAY_ALIVE = 0x00000001, // Not used currently - QUEST_FLAGS_PARTY_ACCEPT = 0x00000002, // Not used currently. If player in party, all players that can accept this quest will receive confirmation box to accept quest CMSG_QUEST_CONFIRM_ACCEPT/SMSG_QUEST_CONFIRM_ACCEPT - QUEST_FLAGS_EXPLORATION = 0x00000004, // Not used currently + QUEST_FLAGS_COMPLETION_NO_DEATH = 0x00000001, + QUEST_FLAGS_COMPLETION_EVENT = 0x00000002, + QUEST_FLAGS_COMPLETION_AREA_TRIGGER = 0x00000004, QUEST_FLAGS_SHARABLE = 0x00000008, // Can be shared: Player::CanShareQuest() QUEST_FLAGS_HAS_CONDITION = 0x00000010, // Not used currently - QUEST_FLAGS_HIDE_REWARD_POI = 0x00000020, // Not used currently: Unsure of content - QUEST_FLAGS_RAID = 0x00000040, // Can be completed while in raid + QUEST_FLAGS_HIDE_REWARD_POI = 0x00000020, // Hides questgiver turn-in minimap icon + QUEST_FLAGS_RAID_GROUP_OK = 0x00000040, // Can be completed while in raid QUEST_FLAGS_WAR_MODE_REWARDS_OPT_IN = 0x00000080, // Not used currently - QUEST_FLAGS_NO_MONEY_FROM_XP = 0x00000100, // Not used currently: Experience is not converted to gold at max level - QUEST_FLAGS_HIDDEN_REWARDS = 0x00000200, // Items and money rewarded only sent in SMSG_QUESTGIVER_OFFER_REWARD (not in SMSG_QUEST_GIVER_QUEST_DETAILS or in client quest log(SMSG_QUEST_QUERY_RESPONSE)) - QUEST_FLAGS_TRACKING = 0x00000400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side. + QUEST_FLAGS_NO_MONEY_FOR_XP = 0x00000100, // Experience is not converted to gold at max level + QUEST_FLAGS_HIDE_REWARD = 0x00000200, // Items and money rewarded only sent in SMSG_QUESTGIVER_OFFER_REWARD (not in SMSG_QUEST_GIVER_QUEST_DETAILS or in client quest log(SMSG_QUEST_QUERY_RESPONSE)) + QUEST_FLAGS_TRACKING_EVENT = 0x00000400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side. QUEST_FLAGS_DEPRECATE_REPUTATION = 0x00000800, // Not used currently QUEST_FLAGS_DAILY = 0x00001000, // Used to know quest is Daily one QUEST_FLAGS_FLAGS_PVP = 0x00002000, // Having this quest in log forces PvP flag - QUEST_FLAGS_UNAVAILABLE = 0x00004000, // Used on quests that are not generically available + QUEST_FLAGS_DEPRECATED = 0x00004000, // Used on quests that are not generally available QUEST_FLAGS_WEEKLY = 0x00008000, - QUEST_FLAGS_AUTOCOMPLETE = 0x00010000, // Quests with this flag player submit automatically by special button in player gui + QUEST_FLAGS_AUTO_COMPLETE = 0x00010000, // Quests with this flag player submit automatically by special button in player gui QUEST_FLAGS_DISPLAY_ITEM_IN_TRACKER = 0x00020000, // Displays usable item in quest tracker - QUEST_FLAGS_OBJ_TEXT = 0x00040000, // use Objective text as Complete text + QUEST_FLAGS_DISABLE_COMPLETION_TEXT = 0x00040000, // use Objective text as Complete text QUEST_FLAGS_AUTO_ACCEPT = 0x00080000, // The client recognizes this flag as auto-accept. - QUEST_FLAGS_PLAYER_CAST_ON_ACCEPT = 0x00100000, - QUEST_FLAGS_PLAYER_CAST_ON_COMPLETE = 0x00200000, - QUEST_FLAGS_UPDATE_PHASE_SHIFT = 0x00400000, + QUEST_FLAGS_PLAYER_CAST_ACCEPT = 0x00100000, + QUEST_FLAGS_PLAYER_CAST_COMPLETE = 0x00200000, + QUEST_FLAGS_UPDATE_PHASESHIFT = 0x00400000, QUEST_FLAGS_SOR_WHITELIST = 0x00800000, QUEST_FLAGS_LAUNCH_GOSSIP_COMPLETE = 0x01000000, - QUEST_FLAGS_REMOVE_EXTRA_GET_ITEMS = 0x02000000, - QUEST_FLAGS_HIDE_UNTIL_DISCOVERED = 0x04000000, + QUEST_FLAGS_REMOVE_SURPLUS_ITEMS = 0x02000000, // Remove all items from inventory that have the same id as the objective, not just the amount required by quest + QUEST_FLAGS_WELL_KNOWN = 0x04000000, QUEST_FLAGS_PORTRAIT_IN_QUEST_LOG = 0x08000000, QUEST_FLAGS_SHOW_ITEM_WHEN_COMPLETED = 0x10000000, QUEST_FLAGS_LAUNCH_GOSSIP_ACCEPT = 0x20000000, - QUEST_FLAGS_ITEMS_GLOW_WHEN_DONE = 0x40000000, + QUEST_FLAGS_ITEMS_GLOW_WHEN_COMPLETE = 0x40000000, QUEST_FLAGS_FAIL_ON_LOGOUT = 0x80000000 }; @@ -276,13 +276,13 @@ enum QuestSpecialFlags QUEST_SPECIAL_FLAGS_NONE = 0x000, // Trinity flags for set SpecialFlags in DB if required but used only at server QUEST_SPECIAL_FLAGS_REPEATABLE = 0x001, // Set by 1 in SpecialFlags from DB - QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT = 0x002, // Set by 2 in SpecialFlags from DB (if required area explore, spell SPELL_EFFECT_QUEST_COMPLETE casting, table `FECT_QUEST_COMPLETE casting, table `*_script` command SCRIPT_COMMAND_QUEST_EXPLORED use, set from script) + QUEST_SPECIAL_FLAGS_AUTO_PUSH_TO_PARTY = 0x002, // Set by 2 in SpecialFlags from DB will make quest be pushed to entire party when one member accepts it QUEST_SPECIAL_FLAGS_AUTO_ACCEPT = 0x004, // Set by 4 in SpecialFlags in DB if the quest is to be auto-accepted. QUEST_SPECIAL_FLAGS_DF_QUEST = 0x008, // Set by 8 in SpecialFlags in DB if the quest is used by Dungeon Finder. QUEST_SPECIAL_FLAGS_MONTHLY = 0x010, // Set by 16 in SpecialFlags in DB if the quest is reset at the begining of the month // room for more custom flags - QUEST_SPECIAL_FLAGS_DB_ALLOWED = QUEST_SPECIAL_FLAGS_REPEATABLE | QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT | QUEST_SPECIAL_FLAGS_AUTO_ACCEPT | QUEST_SPECIAL_FLAGS_DF_QUEST | QUEST_SPECIAL_FLAGS_MONTHLY, + QUEST_SPECIAL_FLAGS_DB_ALLOWED = QUEST_SPECIAL_FLAGS_REPEATABLE | QUEST_SPECIAL_FLAGS_AUTO_ACCEPT | QUEST_SPECIAL_FLAGS_DF_QUEST | QUEST_SPECIAL_FLAGS_MONTHLY, QUEST_SPECIAL_FLAGS_SEQUENCED_OBJECTIVES = 0x020, // Internal flag computed only }; @@ -540,15 +540,15 @@ class TC_GAME_API Quest bool HasFlagEx(QuestFlagsEx flag) const { return (_flagsEx & uint32(flag)) != 0; } bool HasFlagEx2(QuestFlagsEx2 flag) const { return (_flagsEx2 & uint32(flag)) != 0; } - bool HasSpecialFlag(uint32 flag) const { return (_specialFlags & flag) != 0; } - void SetSpecialFlag(uint32 flag) { _specialFlags |= flag; } + bool HasSpecialFlag(QuestSpecialFlags flag) const { return (_specialFlags & flag) != 0; } + void SetSpecialFlag(QuestSpecialFlags flag) { _specialFlags |= flag; } bool HasQuestObjectiveType(QuestObjectiveType type) const { return _usedQuestObjectiveTypes[type]; } bool IsAutoPush() const { return HasFlagEx(QUEST_FLAGS_EX_AUTO_PUSH); } bool IsWorldQuest() const { return HasFlagEx(QUEST_FLAGS_EX_IS_WORLD_QUEST); } // Possibly deprecated flag - bool IsUnavailable() const { return HasFlag(QUEST_FLAGS_UNAVAILABLE); } + bool IsUnavailable() const { return HasFlag(QUEST_FLAGS_DEPRECATED); } // whether the quest is globally enabled (spawned by pool, game event active etc.) static bool IsTakingQuestEnabled(uint32 questId); @@ -623,7 +623,7 @@ class TC_GAME_API Quest uint32 GetCompleteEmoteDelay() const { return _emoteOnCompleteDelay; } bool IsRepeatable() const { return _specialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE; } bool IsAutoAccept() const; - bool IsAutoComplete() const; + bool IsTurnIn() const; uint32 GetFlags() const { return _flags; } uint32 GetFlagsEx() const { return _flagsEx; } uint32 GetFlagsEx2() const { return _flagsEx2; } @@ -649,6 +649,7 @@ class TC_GAME_API Quest bool IsRaidQuest(Difficulty difficulty) const; bool IsAllowedInRaid(Difficulty difficulty) const; bool IsDFQuest() const { return (_specialFlags & QUEST_SPECIAL_FLAGS_DF_QUEST) != 0; } + bool IsPushedToPartyOnAccept() const { return HasSpecialFlag(QUEST_SPECIAL_FLAGS_AUTO_PUSH_TO_PARTY); } uint32 CalculateHonorGain(uint8 level) const; bool CanIncreaseRewardedQuestCounters() const; diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 021f22abc10..c4c46c044d9 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -615,6 +615,8 @@ void WorldSession::LogoutPlayer(bool save) ///- Clear whisper whitelist _player->ClearWhisperWhiteList(); + _player->FailQuestsWithFlag(QUEST_FLAGS_FAIL_ON_LOGOUT); + ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (save) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 09f80cfd2c7..c39de7d0c1c 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3652,7 +3652,7 @@ void Spell::EffectQuestComplete() uint16 logSlot = player->FindQuestSlot(questId); if (logSlot < MAX_QUEST_LOG_SIZE) player->AreaExploredOrEventHappens(questId); - else if (quest->HasFlag(QUEST_FLAGS_TRACKING)) // Check if the quest is used as a serverside flag. + else if (quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT)) // Check if the quest is used as a serverside flag. player->SetRewardedQuest(questId); // If so, set status to rewarded without broadcasting it to client. } } |