diff --git a/Source/Game/Chat/Commands/QuestCommands.cs b/Source/Game/Chat/Commands/QuestCommands.cs index 24dd586fc..887adf5e9 100644 --- a/Source/Game/Chat/Commands/QuestCommands.cs +++ b/Source/Game/Chat/Commands/QuestCommands.cs @@ -112,6 +112,8 @@ namespace Game.Chat Global.ScriptMgr.OnQuestStatusChange(player, quest.Id); Global.ScriptMgr.OnQuestStatusChange(player, quest, oldStatus, QuestStatus.None); + player.UpdateNearbyCreatureNpcFlags(); + handler.SendSysMessage(CypherStrings.CommandQuestRemoved); return true; } diff --git a/Source/Game/Entities/Object/Update/UpdateFields.cs b/Source/Game/Entities/Object/Update/UpdateFields.cs index 18be3bf75..e0516f35f 100644 --- a/Source/Game/Entities/Object/Update/UpdateFields.cs +++ b/Source/Game/Entities/Object/Update/UpdateFields.cs @@ -2332,8 +2332,18 @@ namespace Game.Entities uint GetViewerDependentNpcFlags(UnitData unitData, int i, Unit unit, Player receiver) { uint npcFlag = unitData.NpcFlags[i]; - if (i == 0 && unit.IsCreature() && !receiver.CanSeeSpellClickOn(unit.ToCreature())) - npcFlag &= ~(uint)NPCFlags.SpellClick; + if (i == 0) + { + Creature creature = unit.ToCreature(); + if (creature != null) + { + if (!receiver.CanSeeGossipOn(creature)) + npcFlag &= ~(uint)(NPCFlags.Gossip | NPCFlags.QuestGiver); + + if (!receiver.CanSeeSpellClickOn(creature)) + npcFlag &= ~(uint)NPCFlags.SpellClick; + } + } return npcFlag; } diff --git a/Source/Game/Entities/Player/Player.Quest.cs b/Source/Game/Entities/Player/Player.Quest.cs index d11a096d6..0aefc1f4b 100644 --- a/Source/Game/Entities/Player/Player.Quest.cs +++ b/Source/Game/Entities/Player/Player.Quest.cs @@ -841,6 +841,8 @@ namespace Game.Entities Global.ScriptMgr.OnQuestStatusChange(this, questId); Global.ScriptMgr.OnQuestStatusChange(this, quest, oldStatus, questStatusData.Status); + + UpdateNearbyCreatureNpcFlags(); } public void CompleteQuest(uint quest_id) @@ -1228,6 +1230,8 @@ namespace Game.Entities if (quest.HasFlag(QuestFlags.UpdatePhaseshift)) updateVisibility = PhasingHandler.OnConditionChange(this, false); + UpdateNearbyCreatureNpcFlags(); + //lets remove flag for delayed teleports SetCanDelayTeleport(false); @@ -1258,6 +1262,8 @@ namespace Game.Entities if (updateVisibility) UpdateObjectVisibility(); + + UpdateNearbyCreatureNpcFlags(); } public void SetRewardedQuest(uint questId) @@ -1910,6 +1916,8 @@ namespace Game.Entities Global.ScriptMgr.OnQuestStatusChange(this, quest, oldStatus, status); } + UpdateNearbyCreatureNpcFlags(); + if (update) SendQuestUpdate(questId); } @@ -2184,6 +2192,8 @@ namespace Game.Entities if (updateVisibility) UpdateObjectVisibility(); + + UpdateNearbyCreatureNpcFlags(); } public void DespawnPersonalSummonsForQuest(uint questId) @@ -2705,6 +2715,8 @@ namespace Game.Entities if (updatePhaseShift) PhasingHandler.OnConditionChange(this); + UpdateNearbyCreatureNpcFlags(); + if (updateZoneAuras) { UpdateZoneDependentAuras(GetZoneId()); @@ -2753,6 +2765,39 @@ namespace Game.Entities return false; } + public bool CanSeeGossipOn(Creature creature) + { + if (creature.HasNpcFlag(NPCFlags.Gossip)) + { + if (GetGossipMenuForSource(creature) != 0) + return true; + } + + // for cases with questgiver/ender without gossip menus + if (creature.HasNpcFlag(NPCFlags.QuestGiver)) + { + QuestRelationResult objectQIR = Global.ObjectMgr.GetCreatureQuestInvolvedRelations(creature.GetEntry()); + foreach (uint quest_id in objectQIR) + { + QuestStatus status = GetQuestStatus(quest_id); + if (status == QuestStatus.Complete || status == QuestStatus.Incomplete) + return true; + } + + QuestRelationResult objectQR = Global.ObjectMgr.GetCreatureQuestRelations(creature.GetEntry()); + foreach (uint quest_id in objectQR) + { + Quest quest = Global.ObjectMgr.GetQuestTemplate(quest_id); + if (quest == null) + continue; + + if (CanTakeQuest(quest, false)) + return true; + } + } + return false; + } + QuestObjective GetQuestObjectiveForItem(uint itemId, bool onlyIncomplete) { QuestObjective findObjectiveForItem(int tempItemId) diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 9fb90e8ef..ec91dd358 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -5490,6 +5490,35 @@ namespace Game.Entities return go; } + public void UpdateNearbyCreatureNpcFlags() + { + List creatures = GetCreatureListWithOptionsInGrid(GetVisibilityRange(), new() { IgnorePhases = false }); + + UpdateData udata = new(GetMapId()); + ObjectFieldData objMask = new(); + UnitData unitMask = new(); + for (int i = 0; i < m_unitData.NpcFlags.GetSize(); ++i) + unitMask.MarkChanged(m_unitData.NpcFlags, i); + + foreach (Creature creature in creatures) + { + if (!HaveAtClient(creature)) + continue; + + // skip creatures which dont have any npcflags set + if (creature.GetNpcFlags() == 0 && creature.GetNpcFlags2() == 0) + continue; + + creature.BuildValuesUpdateForPlayerWithMask(udata, objMask.GetUpdateMask(), unitMask.GetUpdateMask(), this); + } + + if (!udata.HasData()) + return; + + udata.BuildPacket(out UpdateObject packet); + SendPacket(packet); + } + public void SendInitialPacketsBeforeAddToMap() { if (!m_teleport_options.HasAnyFlag(TeleportToOptions.Seamless)) diff --git a/Source/Game/Handlers/QuestHandler.cs b/Source/Game/Handlers/QuestHandler.cs index 0de78b89e..d40e0aed4 100644 --- a/Source/Game/Handlers/QuestHandler.cs +++ b/Source/Game/Handlers/QuestHandler.cs @@ -445,6 +445,8 @@ namespace Game if (quest != null) Global.ScriptMgr.OnQuestStatusChange(_player, quest, oldStatus, QuestStatus.None); + + _player.UpdateNearbyCreatureNpcFlags(); } GetPlayer().UpdateCriteria(CriteriaType.AbandonAnyQuest, 1); diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 2eb70b219..af439babe 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -3752,6 +3752,8 @@ namespace Game.Spells Global.ScriptMgr.OnQuestStatusChange(player, quest_id); Global.ScriptMgr.OnQuestStatusChange(player, quest, oldStatus, QuestStatus.None); + + player.UpdateNearbyCreatureNpcFlags(); } [SpellEffectHandler(SpellEffectName.SendTaxi)]