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
Port From (https://github.com/TrinityCore/TrinityCore/commit/4d4c7e68935df9ca40bd5539d602ac4e779f53d5)
This commit is contained in:
hondacrx
2023-06-13 08:52:22 -04:00
parent 7d6b5fbe76
commit e6432f8c97
12 changed files with 205 additions and 192 deletions
+29 -25
View File
@@ -74,11 +74,15 @@ namespace Framework.Constants
public enum QuestType public enum QuestType
{ {
AutoComplete= 0, TurnIn= 0,
Disabled = 1, WithMaxLevel = 1,
Normal = 2, Normal = 2,
Task = 3, Task = 3,
Max = 4 MaxDBAllowedQuestTypes = 4,
// values used in quest menu packets
InProgress = 4,
TaskInProgress = 5
} }
public enum QuestInfos public enum QuestInfos
@@ -428,37 +432,37 @@ namespace Framework.Constants
public enum QuestFlags : uint public enum QuestFlags : uint
{ {
None = 0x00, None = 0x00,
StayAlive = 0x01, // Not Used Currently CompletionNoDeath = 0x01,
PartyAccept = 0x02, // 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 CompletionEvent = 0x02,
Exploration = 0x04, // Not Used Currently CompletionAreaTrigger = 0x04,
Sharable = 0x08, // Can Be Shared: Player.Cansharequest() Sharable = 0x08, // Can Be Shared: Player.Cansharequest()
HasCondition = 0x10, // Not Used Currently HasCondition = 0x10, // Not Used Currently
HideRewardPoi = 0x20, // Not Used Currently: Unsure Of Content HideRewardPoi = 0x20, // Hides questgiver turn-in minimap icon
Raid = 0x40, // Can be completed while in raid RaidGroupOk = 0x40, // Can be completed while in raid
WarModeRewardsOptIn = 0x80, // Not Used Currently WarModeRewardsOptIn = 0x80, // Not Used Currently
NoMoneyFromXp = 0x100, // Not Used Currently: Experience Is Not Converted To Gold At Max Level NoMoneyForXp = 0x100, // Experience is not converted to gold at max level
HiddenRewards = 0x200, // Items And Money Rewarded Only Sent In Smsg_Questgiver_Offer_Reward (Not In Smsg_Questgiver_Quest_Details Or In Client Quest Log(Smsg_Quest_Query_Response)) HideReward = 0x200, // 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))
Tracking = 0x400, // These Quests Are Automatically Rewarded On Quest Complete And They Will Never Appear In Quest Log Client Side. TrackingEvent = 0x400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side.
DeprecateReputation = 0x800, // Not Used Currently DeprecateReputation = 0x800, // Not Used Currently
Daily = 0x1000, // Used To Know Quest Is Daily One Daily = 0x1000, // Used To Know Quest Is Daily One
Pvp = 0x2000, // Having This Quest In Log Forces Pvp Flag Pvp = 0x2000, // Having This Quest In Log Forces Pvp Flag
Unavailable = 0x4000, // Used On Quests That Are Not Generically Available Deprecated = 0x4000, // Used on quests that are not generally available
Weekly = 0x8000, Weekly = 0x8000,
AutoComplete = 0x10000, // Quests with this flag player submit automatically by special button in player gui AutoComplete = 0x10000, // Quests with this flag player submit automatically by special button in player gui
DisplayItemInTracker = 0x20000, // Displays Usable Item In Quest Tracker DisplayItemInTracker = 0x20000, // Displays Usable Item In Quest Tracker
ObjText = 0x40000, // Use Objective Text As Complete Text DisableCompletionText = 0x40000, // Use Objective Text As Complete Text
AutoAccept = 0x80000, // The client recognizes this flag as auto-accept. AutoAccept = 0x80000, // The client recognizes this flag as auto-accept.
PlayerCastOnAccept = 0x100000, PlayerCastAccept = 0x100000,
PlayerCastOnComplete = 0x200000, PlayerCastComplete = 0x200000,
UpdatePhaseShift = 0x400000, UpdatePhaseshift = 0x400000,
SorWhitelist = 0x800000, SorWhitelist = 0x800000,
LaunchGossipComplete = 0x1000000, LaunchGossipComplete = 0x1000000,
RemoveExtraGetItems = 0x2000000, RemoveSurplusItems = 0x2000000, // Remove all items from inventory that have the same id as the objective, not just the amount required by quest
HideUntilDiscovered = 0x4000000, WellKnown = 0x04000000,
PortraitInQuestLog = 0x8000000, PortraitInQuestLog = 0x8000000,
ShowItemWhenCompleted = 0x10000000, ShowItemWhenCompleted = 0x10000000,
LaunchGossipAccept = 0x20000000, LaunchGossipAccept = 0x20000000,
ItemsGlowWhenDone = 0x40000000, ItemsGlowWhenComplete = 0x40000000,
FailOnLogout = 0x80000000 FailOnLogout = 0x80000000
} }
@@ -524,14 +528,14 @@ namespace Framework.Constants
{ {
None = 0x00, None = 0x00,
// Flags For Set Specialflags In Db If Required But Used Only At Server // Flags For Set Specialflags In Db If Required But Used Only At Server
Repeatable = 0x001, Repeatable = 0x001, // Set by 1 in SpecialFlags from DB
ExplorationOrEvent = 0x002, // If Required Area Explore, Spell Spell_Effect_Quest_Complete Casting, Table `*_Script` Command Script_Command_Quest_Explored Use, Set From Script) AutoPushToParty = 0x002, // Set by 2 in SpecialFlags from DB will make quest be pushed to entire party when one member accepts it
AutoAccept = 0x004, // Quest Is To Be Auto-Accepted. AutoAccept = 0x004, // Set by 4 in SpecialFlags in DB if the quest is to be auto-accepted.
DfQuest = 0x008, // Quest Is Used By Dungeon Finder. DfQuest = 0x008, // Set by 8 in SpecialFlags in DB if the quest is used by Dungeon Finder.
Monthly = 0x010, // Quest Is Reset At The Begining Of The Month 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 // Room For More Custom Flags
DbAllowed = Repeatable | ExplorationOrEvent | AutoAccept | DfQuest | Monthly, DbAllowed = Repeatable | AutoAccept | DfQuest | Monthly,
SequencedObjectives = 0x20 // Internal flag computed only SequencedObjectives = 0x20 // Internal flag computed only
} }
@@ -1461,9 +1461,9 @@ namespace Game.AI
Quest qid = Global.ObjectMgr.GetQuestTemplate(e.Action.quest.questId); Quest qid = Global.ObjectMgr.GetQuestTemplate(e.Action.quest.questId);
if (qid != null) if (qid != null)
{ {
if (!qid.HasSpecialFlag(QuestSpecialFlags.ExplorationOrEvent)) if (!qid.HasFlag(QuestFlags.CompletionEvent) && !qid.HasFlag(QuestFlags.CompletionAreaTrigger))
{ {
Log.outError(LogFilter.ScriptsAi, $"SmartAIMgr: {e} SpecialFlags for Quest entry {e.Action.quest.questId} does not include FLAGS_EXPLORATION_OR_EVENT(2), skipped."); Log.outError(LogFilter.ScriptsAi, $"SmartAIMgr: {e} Flags for Quest entry {e.Action.quest.questId} does not include QUEST_FLAGS_COMPLETION_EVENT or QUEST_FLAGS_COMPLETION_AREA_TRIGGER, skipped.");
return false; return false;
} }
} }
+2 -2
View File
@@ -282,7 +282,7 @@ namespace Game.Misc
gossipText.QuestType = item.QuestIcon; gossipText.QuestType = item.QuestIcon;
gossipText.QuestFlags = (uint)quest.Flags; gossipText.QuestFlags = (uint)quest.Flags;
gossipText.QuestFlagsEx = (uint)quest.FlagsEx; gossipText.QuestFlagsEx = (uint)quest.FlagsEx;
gossipText.Repeatable = quest.IsAutoComplete() && quest.IsRepeatable() && !quest.IsDailyOrWeekly() && !quest.IsMonthly(); gossipText.Repeatable = quest.IsTurnIn() && quest.IsRepeatable() && !quest.IsDailyOrWeekly() && !quest.IsMonthly();
gossipText.QuestTitle = quest.LogTitle; gossipText.QuestTitle = quest.LogTitle;
Locale locale = _session.GetSessionDbLocaleIndex(); Locale locale = _session.GetSessionDbLocaleIndex();
@@ -374,7 +374,7 @@ namespace Game.Misc
text.QuestType = questMenuItem.QuestIcon; text.QuestType = questMenuItem.QuestIcon;
text.QuestFlags = (uint)quest.Flags; text.QuestFlags = (uint)quest.Flags;
text.QuestFlagsEx = (uint)quest.FlagsEx; text.QuestFlagsEx = (uint)quest.FlagsEx;
text.Repeatable = quest.IsAutoComplete() && quest.IsRepeatable() && !quest.IsDailyOrWeekly() && !quest.IsMonthly(); text.Repeatable = quest.IsTurnIn() && quest.IsRepeatable() && !quest.IsDailyOrWeekly() && !quest.IsMonthly();
text.QuestTitle = quest.LogTitle; text.QuestTitle = quest.LogTitle;
if (localeConstant != Locale.enUS) if (localeConstant != Locale.enUS)
+86 -63
View File
@@ -310,9 +310,9 @@ namespace Game.Entities
if (!CanTakeQuest(quest, false)) if (!CanTakeQuest(quest, false))
continue; 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(questId, 0); qm.AddMenuItem(questId, 0);
else if (quest.IsAutoComplete()) else if (quest.IsTurnIn())
qm.AddMenuItem(questId, 4); qm.AddMenuItem(questId, 4);
else if (GetQuestStatus(questId) == QuestStatus.None) else if (GetQuestStatus(questId) == QuestStatus.None)
qm.AddMenuItem(questId, 2); qm.AddMenuItem(questId, 2);
@@ -347,9 +347,9 @@ namespace Game.Entities
if (quest.IsAutoAccept() && CanAddQuest(quest, true) && CanTakeQuest(quest, true)) if (quest.IsAutoAccept() && CanAddQuest(quest, true) && CanTakeQuest(quest, true))
AddQuestAndCheckCompletion(quest, source); 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); 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); PlayerTalkClass.SendQuestGiverRequestItems(quest, source.GetGUID(), CanRewardQuest(quest, false), true);
else else
PlayerTalkClass.SendQuestGiverQuestDetails(quest, source.GetGUID(), true, false); PlayerTalkClass.SendQuestGiverQuestDetails(quest, source.GetGUID(), true, false);
@@ -376,7 +376,9 @@ namespace Game.Entities
if (questGiver == this) if (questGiver == this)
{ {
Cypher.Assert(quest.HasFlag(QuestFlags.AutoComplete)); if (!quest.HasFlag(QuestFlags.AutoComplete))
return null;
return Global.ObjectMgr.GetQuestTemplate(nextQuestID); return Global.ObjectMgr.GetQuestTemplate(nextQuestID);
} }
@@ -453,7 +455,7 @@ namespace Game.Entities
return false; // not allow re-complete quest return false; // not allow re-complete quest
// auto complete quest // auto complete quest
if (qInfo.IsAutoComplete() && CanTakeQuest(qInfo, false)) if (qInfo.IsTurnIn() && CanTakeQuest(qInfo, false))
return true; return true;
var q_status = m_QuestStatus.LookupByKey(questId); var q_status = m_QuestStatus.LookupByKey(questId);
@@ -474,7 +476,7 @@ namespace Game.Entities
} }
} }
if (qInfo.HasSpecialFlag(QuestSpecialFlags.ExplorationOrEvent) && !q_status.Explored) if ((qInfo.HasFlag(QuestFlags.CompletionEvent) || qInfo.HasFlag(QuestFlags.CompletionAreaTrigger)) && !q_status.Explored)
return false; return false;
if (qInfo.LimitTime != 0 && q_status.Timer == 0) if (qInfo.LimitTime != 0 && q_status.Timer == 0)
@@ -512,7 +514,7 @@ namespace Game.Entities
return false; return false;
// not auto complete quest and not completed quest (only cheating case, then ignore without message) // not auto complete quest and not completed quest (only cheating case, then ignore without message)
if (!quest.IsDFQuest() && !quest.IsAutoComplete() && GetQuestStatus(quest.Id) != QuestStatus.Complete) if (!quest.IsDFQuest() && !quest.IsTurnIn() && GetQuestStatus(quest.Id) != QuestStatus.Complete)
return false; return false;
// daily quest can't be rewarded (25 daily quest already completed) // daily quest can't be rewarded (25 daily quest already completed)
@@ -784,7 +786,7 @@ namespace Game.Entities
{ {
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.SourceSpellID, GetMap().GetDifficultyID()); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.SourceSpellID, GetMap().GetDifficultyID());
Unit caster = this; Unit caster = this;
if (questGiver != null && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastOnAccept) && !spellInfo.HasTargetType(Targets.UnitCaster) && !spellInfo.HasTargetType(Targets.DestCasterSummon)) if (questGiver != null && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastAccept) && !spellInfo.HasTargetType(Targets.UnitCaster) && !spellInfo.HasTargetType(Targets.DestCasterSummon))
{ {
Unit unit = questGiver.ToUnit(); Unit unit = questGiver.ToUnit();
if (unit != null) if (unit != null)
@@ -819,7 +821,7 @@ namespace Game.Entities
Quest qInfo = Global.ObjectMgr.GetQuestTemplate(quest_id); Quest qInfo = Global.ObjectMgr.GetQuestTemplate(quest_id);
if (qInfo != null) if (qInfo != null)
if (qInfo.HasFlag(QuestFlags.Tracking)) if (qInfo.HasFlag(QuestFlags.TrackingEvent))
RewardQuest(qInfo, LootItemType.Item, 0, this, false); RewardQuest(qInfo, LootItemType.Item, 0, this, false);
} }
} }
@@ -943,8 +945,13 @@ namespace Game.Entities
switch (obj.Type) switch (obj.Type)
{ {
case QuestObjectiveType.Item: case QuestObjectiveType.Item:
DestroyItemCount((uint)obj.ObjectID, (uint)obj.Amount, true); {
int amountToDestroy = obj.Amount;
if (quest.HasFlag(QuestFlags.RemoveSurplusItems))
amountToDestroy = int.MaxValue;
DestroyItemCount((uint)obj.ObjectID, (uint)amountToDestroy, true);
break; break;
}
case QuestObjectiveType.Currency: case QuestObjectiveType.Currency:
RemoveCurrency((uint)obj.ObjectID, obj.Amount, CurrencyDestroyReason.QuestTurnin); RemoveCurrency((uint)obj.ObjectID, obj.Amount, CurrencyDestroyReason.QuestTurnin);
break; break;
@@ -958,7 +965,9 @@ namespace Game.Entities
if (quest.ItemDrop[i] != 0) if (quest.ItemDrop[i] != 0)
{ {
uint count = quest.ItemDropQuantity[i]; uint count = quest.ItemDropQuantity[i];
DestroyItemCount(quest.ItemDrop[i], count != 0 ? count : 9999, true); if (count == 0)
count = uint.MaxValue;
DestroyItemCount(quest.ItemDrop[i], count, true);
} }
} }
} }
@@ -1117,7 +1126,7 @@ namespace Game.Entities
{ {
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardSpell, GetMap().GetDifficultyID()); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardSpell, GetMap().GetDifficultyID());
Unit caster = this; Unit caster = this;
if (questGiver != null && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastOnComplete) && !spellInfo.HasTargetType(Targets.UnitCaster)) if (questGiver != null && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastComplete) && !spellInfo.HasTargetType(Targets.UnitCaster))
{ {
Unit unit = questGiver.ToUnit(); Unit unit = questGiver.ToUnit();
if (unit != null) if (unit != null)
@@ -1137,7 +1146,7 @@ namespace Game.Entities
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(displaySpell.SpellId, GetMap().GetDifficultyID()); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(displaySpell.SpellId, GetMap().GetDifficultyID());
Unit caster = this; Unit caster = this;
if (questGiver && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastOnComplete) && !spellInfo.HasTargetType(Targets.UnitCaster)) if (questGiver && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastComplete) && !spellInfo.HasTargetType(Targets.UnitCaster))
{ {
Unit unit = questGiver.ToUnit(); Unit unit = questGiver.ToUnit();
if (unit) if (unit)
@@ -1170,69 +1179,69 @@ namespace Game.Entities
SendQuestGiverStatusMultiple(); SendQuestGiverStatusMultiple();
bool conditionChanged = SendQuestUpdate(questId, false); SendQuestUpdate(questId);
bool updateVisibility = false;
if (quest.HasFlag(QuestFlags.UpdatePhaseshift))
updateVisibility = PhasingHandler.OnConditionChange(this, false);
//lets remove flag for delayed teleports //lets remove flag for delayed teleports
SetCanDelayTeleport(false); SetCanDelayTeleport(false);
bool canHaveNextQuest = !quest.HasFlag(QuestFlags.AutoComplete) ? questGiver != null && !questGiver.IsPlayer() : true; switch (questGiver.GetTypeId())
if (canHaveNextQuest)
{ {
switch (questGiver.GetTypeId()) case TypeId.Unit:
case TypeId.Player:
{ {
case TypeId.Unit: //For AutoSubmition was added plr case there as it almost same exclute AI script cases.
case TypeId.Player: // Send next quest
Quest nextQuest = GetNextQuest(questGiver, quest);
if (nextQuest != null)
{ {
//For AutoSubmition was added plr case there as it almost same exclute AI script cases. // Only send the quest to the player if the conditions are met
// Send next quest if (CanTakeQuest(nextQuest, false))
Quest nextQuest = GetNextQuest(questGiver, quest);
if (nextQuest != null)
{ {
// Only send the quest to the player if the conditions are met if (nextQuest.IsAutoAccept() && CanAddQuest(nextQuest, true))
if (CanTakeQuest(nextQuest, false)) 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();
Creature creatureQGiver = questGiver.ToCreature();
if (creatureQGiver != null)
creatureQGiver.GetAI().OnQuestReward(this, quest, rewardType, rewardId);
break;
} }
case TypeId.GameObject:
{
// Send next quest
Quest nextQuest = GetNextQuest(questGiver, quest);
if (nextQuest != null)
{
// 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);
PlayerTalkClass.SendQuestGiverQuestDetails(nextQuest, questGiver.GetGUID(), true, false); PlayerTalkClass.ClearMenus();
} Creature creatureQGiver = questGiver.ToCreature();
} if (creatureQGiver != null)
creatureQGiver.GetAI().OnQuestReward(this, quest, rewardType, rewardId);
PlayerTalkClass.ClearMenus(); break;
questGiver.ToGameObject()?.GetAI()?.OnQuestReward(this, quest, rewardType, rewardId);
break;
}
default:
break;
} }
case TypeId.GameObject:
{
// Send next quest
Quest nextQuest = GetNextQuest(questGiver, quest);
if (nextQuest != null)
{
// 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);
PlayerTalkClass.SendQuestGiverQuestDetails(nextQuest, questGiver.GetGUID(), true, false);
}
}
PlayerTalkClass.ClearMenus();
questGiver.ToGameObject()?.GetAI()?.OnQuestReward(this, quest, rewardType, rewardId);
break;
}
default:
break;
} }
Global.ScriptMgr.OnQuestStatusChange(this, questId); Global.ScriptMgr.OnQuestStatusChange(this, questId);
Global.ScriptMgr.OnQuestStatusChange(this, quest, oldStatus, QuestStatus.Rewarded); Global.ScriptMgr.OnQuestStatusChange(this, quest, oldStatus, QuestStatus.Rewarded);
if (conditionChanged) if (updateVisibility)
UpdateObjectVisibility(); UpdateObjectVisibility();
} }
@@ -1299,6 +1308,21 @@ namespace Game.Entities
} }
} }
public void FailQuestsWithFlag(QuestFlags flag)
{
for (ushort slot = 0; slot < SharedConst.MaxQuestLogSize; ++slot)
{
uint questId = GetQuestSlotQuestId(slot);
if (questId == 0)
continue;
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
if (quest != null)
if (quest.HasFlag(flag))
FailQuest(questId);
}
}
public void AbandonQuest(uint questId) public void AbandonQuest(uint questId)
{ {
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId); Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
@@ -1865,7 +1889,7 @@ namespace Game.Entities
QuestStatus oldStatus = m_QuestStatus[questId].Status; QuestStatus oldStatus = m_QuestStatus[questId].Status;
m_QuestStatus[questId].Status = status; m_QuestStatus[questId].Status = status;
if (!quest.IsAutoComplete()) if (!quest.IsTurnIn())
m_QuestStatusSave[questId] = QuestSaveType.Default; m_QuestStatusSave[questId] = QuestSaveType.Default;
Global.ScriptMgr.OnQuestStatusChange(this, questId); Global.ScriptMgr.OnQuestStatusChange(this, questId);
@@ -1922,7 +1946,7 @@ namespace Game.Entities
SendQuestUpdate(questId); SendQuestUpdate(questId);
} }
bool SendQuestUpdate(uint questId, bool updateVisiblity = true) void SendQuestUpdate(uint questId)
{ {
var saBounds = Global.SpellMgr.GetSpellAreaForQuestMapBounds(questId); var saBounds = Global.SpellMgr.GetSpellAreaForQuestMapBounds(questId);
if (!saBounds.Empty()) if (!saBounds.Empty())
@@ -1970,7 +1994,6 @@ namespace Game.Entities
} }
UpdateVisibleGameobjectsOrSpellClicks(); UpdateVisibleGameobjectsOrSpellClicks();
return PhasingHandler.OnConditionChange(this, updateVisiblity);
} }
public QuestGiverStatus GetQuestDialogStatus(WorldObject questgiver) public QuestGiverStatus GetQuestDialogStatus(WorldObject questgiver)
@@ -2042,7 +2065,7 @@ namespace Game.Entities
break; 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) + WorldConfig.GetIntValue(WorldCfg.QuestLowLevelHideDiff))) if (GetLevel() <= (GetQuestLevel(quest) + WorldConfig.GetIntValue(WorldCfg.QuestLowLevelHideDiff)))
result |= QuestGiverStatus.RepeatableTurnin; result |= QuestGiverStatus.RepeatableTurnin;
+2
View File
@@ -650,6 +650,8 @@ namespace Game.Entities
InitializeSelfResurrectionSpells(); InitializeSelfResurrectionSpells();
FailQuestsWithFlag(QuestFlags.CompletionNoDeath);
UpdateCriteria(CriteriaType.DieOnMap, 1); UpdateCriteria(CriteriaType.DieOnMap, 1);
UpdateCriteria(CriteriaType.DieAnywhere, 1); UpdateCriteria(CriteriaType.DieAnywhere, 1);
UpdateCriteria(CriteriaType.DieInInstance, 1); UpdateCriteria(CriteriaType.DieInInstance, 1);
+16 -52
View File
@@ -1214,15 +1214,12 @@ namespace Game
continue; continue;
} }
if (!quest.HasSpecialFlag(QuestSpecialFlags.ExplorationOrEvent)) if (!quest.HasFlag(QuestFlags.CompletionEvent) && !quest.HasFlag(QuestFlags.CompletionAreaTrigger))
{ {
Log.outError(LogFilter.Sql, "Table `{0}` has quest (ID: {1}) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id {2}, 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.", Log.outError(LogFilter.Sql, "Table `{0}` has quest (ID: {1}) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id {2}, 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); tableName, tmp.QuestExplored.QuestID, tmp.id);
// this will prevent quest completing without objective continue;
quest.SetSpecialFlag(QuestSpecialFlags.ExplorationOrEvent);
// continue; - quest objective requirement set and command can be allowed
} }
if (tmp.QuestExplored.Distance > SharedConst.DefaultVisibilityDistance) if (tmp.QuestExplored.Distance > SharedConst.DefaultVisibilityDistance)
@@ -7249,7 +7246,7 @@ namespace Game
// additional quest integrity checks (GO, creaturetemplate and itemtemplate must be loaded already) // additional quest integrity checks (GO, creaturetemplate and itemtemplate must be loaded already)
if (qinfo.Type >= QuestType.Max) if (qinfo.Type >= QuestType.MaxDBAllowedQuestTypes)
Log.outError(LogFilter.Sql, "Quest {0} has `Method` = {1}, expected values are 0, 1 or 2.", qinfo.Id, qinfo.Type); Log.outError(LogFilter.Sql, "Quest {0} has `Method` = {1}, expected values are 0, 1 or 2.", qinfo.Id, qinfo.Type);
if (Convert.ToBoolean(qinfo.SpecialFlags & ~QuestSpecialFlags.DbAllowed)) if (Convert.ToBoolean(qinfo.SpecialFlags & ~QuestSpecialFlags.DbAllowed))
@@ -7292,7 +7289,7 @@ namespace Game
} }
} }
if (Convert.ToBoolean(qinfo.Flags & QuestFlags.Tracking)) if (Convert.ToBoolean(qinfo.Flags & QuestFlags.TrackingEvent))
{ {
// at auto-reward can be rewarded only RewardChoiceItemId[0] // at auto-reward can be rewarded only RewardChoiceItemId[0]
for (int j = 1; j < qinfo.RewardChoiceItemId.Length; ++j) for (int j = 1; j < qinfo.RewardChoiceItemId.Length; ++j)
@@ -7878,35 +7875,7 @@ namespace Game
} }
} }
// check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE // don't check spells with SPELL_EFFECT_QUEST_COMPLETE, a lot of invalid db2 data
foreach (SpellNameRecord spellNameEntry in CliDB.SpellNameStorage.Values)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellNameEntry.Id, Difficulty.None);
if (spellInfo == null)
continue;
foreach (var spellEffectInfo in spellInfo.GetEffects())
{
if (spellEffectInfo.Effect != SpellEffectName.QuestComplete)
continue;
uint questId = (uint)spellEffectInfo.MiscValue;
Quest quest = GetQuestTemplate(questId);
// some quest referenced in spells not exist (outdated spells)
if (quest == null)
continue;
if (!quest.HasSpecialFlag(QuestSpecialFlags.ExplorationOrEvent))
{
Log.outError(LogFilter.Sql, "Spell (id: {0}) have SPELL_EFFECT_QUEST_COMPLETE for quest {1}, but quest not have flag QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT. " +
"Quest flags must be fixed, quest modified to enable objective.", spellInfo.Id, questId);
// this will prevent quest completing without objective
quest.SetSpecialFlag(QuestSpecialFlags.ExplorationOrEvent);
}
}
}
// Make all paragon reward quests repeatable // Make all paragon reward quests repeatable
foreach (ParagonReputationRecord paragonReputation in CliDB.ParagonReputationStorage.Values) foreach (ParagonReputationRecord paragonReputation in CliDB.ParagonReputationStorage.Values)
@@ -8122,35 +8091,30 @@ namespace Game
{ {
++count; ++count;
uint trigger_ID = result.Read<uint>(0); uint triggerId = result.Read<uint>(0);
uint quest_ID = result.Read<uint>(1); uint questId = result.Read<uint>(1);
AreaTriggerRecord atEntry = CliDB.AreaTriggerStorage.LookupByKey(trigger_ID); AreaTriggerRecord atEntry = CliDB.AreaTriggerStorage.LookupByKey(triggerId);
if (atEntry == null) if (atEntry == null)
{ {
Log.outError(LogFilter.Sql, "Area trigger (ID:{0}) does not exist in `AreaTrigger.dbc`.", trigger_ID); Log.outError(LogFilter.Sql, "Area trigger (ID:{0}) does not exist in `AreaTrigger.dbc`.", triggerId);
continue; continue;
} }
Quest quest = GetQuestTemplate(quest_ID); Quest quest = GetQuestTemplate(questId);
if (quest == null) if (quest == null)
{ {
Log.outError(LogFilter.Sql, "Table `areatrigger_involvedrelation` has record (id: {0}) for not existing quest {1}", trigger_ID, quest_ID); Log.outError(LogFilter.Sql, "Table `areatrigger_involvedrelation` has record (id: {0}) for not existing quest {1}", triggerId, questId);
continue; continue;
} }
if (!quest.HasSpecialFlag(QuestSpecialFlags.ExplorationOrEvent)) if (!quest.HasFlag(QuestFlags.CompletionAreaTrigger) && !quest.HasQuestObjectiveType(QuestObjectiveType.AreaTrigger))
{ {
Log.outError(LogFilter.Sql, "Table `areatrigger_involvedrelation` has record (id: {0}) for not quest {1}, 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); Log.outError(LogFilter.Sql, $"Table `areatrigger_involvedrelation` has record (id: {triggerId}) for not quest {questId}, but quest not have flag QUEST_FLAGS_COMPLETION_AREA_TRIGGER and no objective with type QUEST_OBJECTIVE_AREATRIGGER. Trigger is obsolete, skipped.");
continue;
// this will prevent quest completing without objective
quest.SetSpecialFlag(QuestSpecialFlags.ExplorationOrEvent);
// continue; - quest modified to required objective and trigger can be allowed.
} }
_questAreaTriggerStorage.Add(trigger_ID, quest_ID); _questAreaTriggerStorage.Add(triggerId, questId);
} while (result.NextRow()); } while (result.NextRow());
+2 -1
View File
@@ -220,7 +220,8 @@ namespace Game
break; break;
} }
player.AreaExploredOrEventHappens(questId); if (qInfo.HasFlag(QuestFlags.CompletionAreaTrigger))
player.AreaExploredOrEventHappens(questId);
if (player.CanCompleteQuest(questId)) if (player.CanCompleteQuest(questId))
player.CompleteQuest(questId); player.CompleteQuest(questId);
+45 -29
View File
@@ -148,7 +148,7 @@ namespace Game
{ {
_player.AddQuestAndCheckCompletion(quest, obj); _player.AddQuestAndCheckCompletion(quest, obj);
if (quest.HasFlag(QuestFlags.PartyAccept)) if (quest.IsPushedToPartyOnAccept())
{ {
var group = _player.GetGroup(); var group = _player.GetGroup();
if (group) if (group)
@@ -175,6 +175,26 @@ namespace Game
_player.PlayerTalkClass.SendCloseGossip(); _player.PlayerTalkClass.SendCloseGossip();
if (quest.HasFlag(QuestFlags.LaunchGossipAccept))
{
void launchGossip(WorldObject worldObject)
{
_player.PlayerTalkClass.ClearMenus();
_player.PrepareGossipMenu(worldObject, _player.GetGossipMenuForSource(worldObject), true);
_player.SendPreparedGossip(worldObject);
}
Creature creature = obj.ToCreature();
if (creature != null)
launchGossip(creature);
else
{
GameObject go = obj.ToGameObject();
if (go != null)
launchGossip(go);
}
}
return; return;
} }
} }
@@ -202,7 +222,7 @@ namespace Game
if (quest.IsAutoAccept() && GetPlayer().CanAddQuest(quest, true)) if (quest.IsAutoAccept() && GetPlayer().CanAddQuest(quest, true))
GetPlayer().AddQuestAndCheckCompletion(quest, obj); GetPlayer().AddQuestAndCheckCompletion(quest, obj);
if (quest.IsAutoComplete()) if (quest.IsTurnIn())
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, obj.GetGUID(), GetPlayer().CanCompleteQuest(quest.Id), true); GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, obj.GetGUID(), GetPlayer().CanCompleteQuest(quest.Id), true);
else else
GetPlayer().PlayerTalkClass.SendQuestGiverQuestDetails(quest, obj.GetGUID(), true, false); GetPlayer().PlayerTalkClass.SendQuestGiverQuestDetails(quest, obj.GetGUID(), true, false);
@@ -331,7 +351,7 @@ namespace Game
} }
if ((!GetPlayer().CanSeeStartQuest(quest) && GetPlayer().GetQuestStatus(packet.QuestID) == QuestStatus.None) || if ((!GetPlayer().CanSeeStartQuest(quest) && GetPlayer().GetQuestStatus(packet.QuestID) == QuestStatus.None) ||
(GetPlayer().GetQuestStatus(packet.QuestID) != QuestStatus.Complete && !quest.IsAutoComplete())) (GetPlayer().GetQuestStatus(packet.QuestID) != QuestStatus.Complete && !quest.IsTurnIn()))
{ {
Log.outError(LogFilter.Network, "Error in QuestStatus.Complete: player {0} ({1}) tried to complete quest {2}, but is not allowed to do so (possible packet-hacking or high latency)", Log.outError(LogFilter.Network, "Error in QuestStatus.Complete: player {0} ({1}) tried to complete quest {2}, but is not allowed to do so (possible packet-hacking or high latency)",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.QuestID); GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.QuestID);
@@ -422,35 +442,34 @@ namespace Game
[WorldPacketHandler(ClientOpcodes.QuestConfirmAccept)] [WorldPacketHandler(ClientOpcodes.QuestConfirmAccept)]
void HandleQuestConfirmAccept(QuestConfirmAccept packet) void HandleQuestConfirmAccept(QuestConfirmAccept packet)
{ {
if (_player.GetSharedQuestID() != packet.QuestID)
return;
_player.ClearQuestSharingInfo();
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID); Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest != null) if (quest == null)
{ return;
if (!quest.HasFlag(QuestFlags.PartyAccept))
return;
Player originalPlayer = Global.ObjAccessor.FindPlayer(GetPlayer().GetPlayerSharingQuest()); Player originalPlayer = Global.ObjAccessor.FindPlayer(GetPlayer().GetPlayerSharingQuest());
if (originalPlayer == null) if (originalPlayer == null)
return; return;
if (!GetPlayer().IsInSameRaidWith(originalPlayer)) if (!_player.IsInSameRaidWith(originalPlayer))
return; return;
if (!originalPlayer.IsActiveQuest(packet.QuestID)) if (!originalPlayer.IsActiveQuest(packet.QuestID))
return; return;
if (!GetPlayer().CanTakeQuest(quest, true)) if (!_player.CanTakeQuest(quest, true))
return; return;
if (GetPlayer().CanAddQuest(quest, true)) if (!_player.CanAddQuest(quest, true))
{ return;
GetPlayer().AddQuestAndCheckCompletion(quest, null); // NULL, this prevent DB script from duplicate running
if (quest.SourceSpellID > 0) _player.AddQuestAndCheckCompletion(quest, null); // NULL, this prevent DB script from duplicate running
_player.CastSpell(_player, quest.SourceSpellID, true);
}
}
GetPlayer().ClearQuestSharingInfo(); if (quest.SourceSpellID > 0)
_player.CastSpell(_player, quest.SourceSpellID, true);
} }
[WorldPacketHandler(ClientOpcodes.QuestGiverCompleteQuest, Processing = PacketProcessing.Inplace)] [WorldPacketHandler(ClientOpcodes.QuestGiverCompleteQuest, Processing = PacketProcessing.Inplace)]
@@ -462,9 +481,6 @@ namespace Game
if (quest == null) if (quest == null)
return; return;
if (autoCompleteMode && !quest.HasFlag(QuestFlags.AutoComplete))
return;
WorldObject obj; WorldObject obj;
if (autoCompleteMode) if (autoCompleteMode)
obj = GetPlayer(); obj = GetPlayer();
@@ -474,7 +490,7 @@ namespace Game
if (!obj) if (!obj)
return; return;
if (!autoCompleteMode) if (!quest.HasFlag(QuestFlags.AutoComplete))
{ {
if (!obj.HasInvolvedQuest(packet.QuestID)) if (!obj.HasInvolvedQuest(packet.QuestID))
return; return;
@@ -666,7 +682,7 @@ namespace Game
sender.SendPushToPartyResponse(receiver, QuestPushReason.Success); sender.SendPushToPartyResponse(receiver, QuestPushReason.Success);
if ((quest.IsAutoComplete() && quest.IsRepeatable() && !quest.IsDailyOrWeekly()) || quest.HasFlag(QuestFlags.AutoComplete)) if (quest.IsTurnIn() && quest.IsRepeatable() && !quest.IsDailyOrWeekly())
receiver.PlayerTalkClass.SendQuestGiverRequestItems(quest, sender.GetGUID(), receiver.CanCompleteRepeatableQuest(quest), true); receiver.PlayerTalkClass.SendQuestGiverRequestItems(quest, sender.GetGUID(), receiver.CanCompleteRepeatableQuest(quest), true);
else else
{ {
+10 -9
View File
@@ -532,7 +532,7 @@ namespace Game
public uint GetRewMoneyMaxLevel() public uint GetRewMoneyMaxLevel()
{ {
// If Quest has flag to not give money on max level, it's 0 // If Quest has flag to not give money on max level, it's 0
if (HasFlag(QuestFlags.NoMoneyFromXp)) if (HasFlag(QuestFlags.NoMoneyForXp))
return 0; return 0;
// Else, return the rewarded copper sum modified by the rate // Else, return the rewarded copper sum modified by the rate
@@ -544,9 +544,9 @@ namespace Game
return !WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreAutoAccept) && HasFlag(QuestFlags.AutoAccept); return !WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreAutoAccept) && HasFlag(QuestFlags.AutoAccept);
} }
public bool IsAutoComplete() public bool IsTurnIn()
{ {
return !WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreAutoComplete) && Type == QuestType.AutoComplete; return !WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreAutoComplete) && Type == QuestType.TurnIn;
} }
public bool IsRaidQuest(Difficulty difficulty) public bool IsRaidQuest(Difficulty difficulty)
@@ -563,7 +563,7 @@ namespace Game
break; break;
} }
if (Flags.HasAnyFlag(QuestFlags.Raid)) if (Flags.HasAnyFlag(QuestFlags.RaidGroupOk))
return true; return true;
return false; return false;
@@ -655,7 +655,7 @@ namespace Game
response.Info.RewardXPDifficulty = RewardXPDifficulty; response.Info.RewardXPDifficulty = RewardXPDifficulty;
response.Info.RewardXPMultiplier = RewardXPMultiplier; response.Info.RewardXPMultiplier = RewardXPMultiplier;
if (!HasFlag(QuestFlags.HiddenRewards)) if (!HasFlag(QuestFlags.HideReward))
response.Info.RewardMoney = (int)(player != null ? player.GetQuestMoneyReward(this) : GetMaxMoneyReward()); response.Info.RewardMoney = (int)(player != null ? player.GetQuestMoneyReward(this) : GetMaxMoneyReward());
response.Info.RewardMoneyDifficulty = RewardMoneyDifficulty; response.Info.RewardMoneyDifficulty = RewardMoneyDifficulty;
@@ -699,7 +699,7 @@ namespace Game
response.Info.ItemDropQuantity[i] = (int)ItemDropQuantity[i]; response.Info.ItemDropQuantity[i] = (int)ItemDropQuantity[i];
} }
if (!HasFlag(QuestFlags.HiddenRewards)) if (!HasFlag(QuestFlags.HideReward))
{ {
for (byte i = 0; i < SharedConst.QuestRewardItemCount; ++i) for (byte i = 0; i < SharedConst.QuestRewardItemCount; ++i)
{ {
@@ -781,11 +781,11 @@ namespace Game
public bool HasQuestObjectiveType(QuestObjectiveType type) { return _usedQuestObjectiveTypes[(int)type]; } public bool HasQuestObjectiveType(QuestObjectiveType type) { return _usedQuestObjectiveTypes[(int)type]; }
public bool IsAutoPush() { return HasFlagEx(QuestFlagsEx.AutoPush); } public bool IsAutoPush() { return HasFlagEx(QuestFlagsEx.AutoPush); }
public bool IsWorldQuest() { return HasFlagEx(QuestFlagsEx.IsWorldQuest);} public bool IsWorldQuest() { return HasFlagEx(QuestFlagsEx.IsWorldQuest); }
// Possibly deprecated flag // Possibly deprecated flag
public bool IsUnavailable() { return HasFlag(QuestFlags.Unavailable); } public bool IsUnavailable() { return HasFlag(QuestFlags.Deprecated); }
// table data accessors: // table data accessors:
public bool IsRepeatable() { return SpecialFlags.HasAnyFlag(QuestSpecialFlags.Repeatable); } public bool IsRepeatable() { return SpecialFlags.HasAnyFlag(QuestSpecialFlags.Repeatable); }
@@ -800,6 +800,7 @@ namespace Game
} }
public bool IsDailyOrWeekly() { return Flags.HasAnyFlag(QuestFlags.Daily | QuestFlags.Weekly); } public bool IsDailyOrWeekly() { return Flags.HasAnyFlag(QuestFlags.Daily | QuestFlags.Weekly); }
public bool IsDFQuest() { return SpecialFlags.HasAnyFlag(QuestSpecialFlags.DfQuest); } public bool IsDFQuest() { return SpecialFlags.HasAnyFlag(QuestSpecialFlags.DfQuest); }
public bool IsPushedToPartyOnAccept() { return HasSpecialFlag(QuestSpecialFlags.AutoPushToParty); }
public uint GetRewChoiceItemsCount() { return _rewChoiceItemsCount; } public uint GetRewChoiceItemsCount() { return _rewChoiceItemsCount; }
public uint GetRewItemsCount() { return _rewItemsCount; } public uint GetRewItemsCount() { return _rewItemsCount; }
+2
View File
@@ -153,6 +153,8 @@ namespace Game
// Clear whisper whitelist // Clear whisper whitelist
_player.ClearWhisperWhiteList(); _player.ClearWhisperWhiteList();
_player.FailQuestsWithFlag(QuestFlags.FailOnLogout);
// empty buyback items and save the player in the database // 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) // some save parts only correctly work in case player present in map/player_lists (pets, etc)
if (save) if (save)
+2 -2
View File
@@ -71,10 +71,10 @@ namespace Game.Spells
_triggeredCastFlags = triggerFlags; _triggeredCastFlags = triggerFlags;
if (info.HasAttribute(SpellAttr2.DoNotReportSpellFailure)) if (info.HasAttribute(SpellAttr2.DoNotReportSpellFailure))
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.DontReportCastError; _triggeredCastFlags |= TriggerCastFlags.DontReportCastError;
if (m_spellInfo.HasAttribute(SpellAttr4.AllowCastWhileCasting)) if (m_spellInfo.HasAttribute(SpellAttr4.AllowCastWhileCasting))
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.IgnoreCastInProgress; _triggeredCastFlags |= TriggerCastFlags.IgnoreCastInProgress;
m_castItemLevel = -1; m_castItemLevel = -1;
+1 -1
View File
@@ -3362,7 +3362,7 @@ namespace Game.Spells
ushort logSlot = player.FindQuestSlot(questId); ushort logSlot = player.FindQuestSlot(questId);
if (logSlot < SharedConst.MaxQuestLogSize) if (logSlot < SharedConst.MaxQuestLogSize)
player.AreaExploredOrEventHappens(questId); player.AreaExploredOrEventHappens(questId);
else if (quest.HasFlag(QuestFlags.Tracking)) // Check if the quest is used as a serverside flag. else if (quest.HasFlag(QuestFlags.TrackingEvent)) // Check if the quest is used as a serverside flag.
player.SetRewardedQuest(questId); // If so, set status to rewarded without broadcasting it to client. player.SetRewardedQuest(questId); // If so, set status to rewarded without broadcasting it to client.
} }
} }