Core/Creatures: Implemented serverside checks for UNIT_FLAG2_INTERACT_WHILE_HOSTILE and UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT
* Also stop sending npc flags for hostile creatures Port From (https://github.com/TrinityCore/TrinityCore/commit/c2e36dea6c6af6139bf60454e9299447ec7d9897)
This commit is contained in:
@@ -131,26 +131,26 @@ namespace Framework.Constants
|
|||||||
public enum UnitFlags3 : uint
|
public enum UnitFlags3 : uint
|
||||||
{
|
{
|
||||||
Unk0 = 0x01,
|
Unk0 = 0x01,
|
||||||
UnconsciousOnDeath = 0x02, // Title Unconscious On Death Description Shows "Unconscious" In Unit Tooltip Instead Of "Dead"
|
UnconsciousOnDeath = 0x02, // Description Shows "Unconscious" In Unit Tooltip Instead Of "Dead"
|
||||||
AllowMountedCombat = 0x04, // Title Allow Mounted Combat
|
AllowMountedCombat = 0x04,
|
||||||
GarrisonPet = 0x08, // Title Garrison Pet Description Special Garrison Pet Creatures That Display One Of Favorite Player Battle Pets - This Flag Allows Querying Name And Turns Off Default Battle Pet Behavior
|
GarrisonPet = 0x08, // Special Garrison Pet Creatures That Display One Of Favorite Player Battle Pets - This Flag Allows Querying Name And Turns Off Default Battle Pet Behavior
|
||||||
UiCanGetPosition = 0x10, // Title Ui Can Get Position Description Allows Lua Functions Like Unitposition To Always Get The Position Even For Npcs Or Non-Grouped Players
|
UiCanGetPosition = 0x10, // Allows Lua Functions Like Unitposition To Always Get The Position Even For Npcs Or Non-Grouped Players
|
||||||
AiObstacle = 0x20,
|
AiObstacle = 0x20,
|
||||||
AlternativeDefaultLanguage = 0x40,
|
AlternativeDefaultLanguage = 0x40,
|
||||||
SuppressAllNpcFeedback = 0x80, // Title Suppress All Npc Feedback Description Skips Playing Sounds On Left Clicking Npc For All Npcs As Long As Npc With This Flag Is Visible
|
SuppressAllNpcFeedback = 0x80, // Skips Playing Sounds On Left Clicking Npc For All Npcs As Long As Npc With This Flag Is Visible
|
||||||
IgnoreCombat = 0x100, // Title Ignore Combat Description Same As SpellAuraIgnoreCombat
|
IgnoreCombat = 0x100, // Same As SpellAuraIgnoreCombat
|
||||||
SuppressNpcFeedback = 0x200, // Title Suppress Npc Feedback Description Skips Playing Sounds On Left Clicking Npc
|
SuppressNpcFeedback = 0x200, // Skips Playing Sounds On Left Clicking Npc
|
||||||
Unk10 = 0x400,
|
Unk10 = 0x400,
|
||||||
Unk11 = 0x800,
|
Unk11 = 0x800,
|
||||||
Unk12 = 0x1000,
|
Unk12 = 0x1000,
|
||||||
FakeDead = 0x2000, // Title Show As Dead
|
FakeDead = 0x2000, // Title Show As Dead
|
||||||
NoFacingOnInteractAndFastFacingChase = 0x4000, // Causes The Creature To Both Not Change Facing On Interaction And Speeds Up Smooth Facing Changes While Attacking (Clientside)
|
NoFacingOnInteractAndFastFacingChase = 0x4000, // Causes The Creature To Both Not Change Facing On Interaction And Speeds Up Smooth Facing Changes While Attacking (Clientside)
|
||||||
UntargetableFromUi = 0x8000, // Title Untargetable From Ui Description Cannot Be Targeted From Lua Functions Startattack, Targetunit, Petattack
|
UntargetableFromUi = 0x8000, // Cannot Be Targeted From Lua Functions Startattack, Targetunit, Petattack
|
||||||
NoFacingOnInteractWhileFakeDead = 0x10000, // Prevents Facing Changes While Interacting If Creature Has Flag FakeDead
|
NoFacingOnInteractWhileFakeDead = 0x10000, // Prevents Facing Changes While Interacting If Creature Has Flag FakeDead
|
||||||
AlreadySkinned = 0x20000,
|
AlreadySkinned = 0x20000,
|
||||||
SuppressAllNpcSounds = 0x40000, // Title Suppress All Npc Sounds Description Skips Playing Sounds On Beginning And End Of Npc Interaction For All Npcs As Long As Npc With This Flag Is Visible
|
SuppressAllNpcSounds = 0x40000, // Skips Playing Sounds On Beginning And End Of Npc Interaction For All Npcs As Long As Npc With This Flag Is Visible
|
||||||
SuppressNpcSounds = 0x80000, // Title Suppress Npc Sounds Description Skips Playing Sounds On Beginning And End Of Npc Interaction
|
SuppressNpcSounds = 0x80000, // Skips Playing Sounds On Beginning And End Of Npc Interaction
|
||||||
Unk20 = 0x100000,
|
AllowInteractionWhileInCombat = 0x100000, //Allows using various NPC functions while in combat (vendor, gossip, questgiver)
|
||||||
Unk21 = 0x200000,
|
Unk21 = 0x200000,
|
||||||
DontFadeOut = 0x400000,
|
DontFadeOut = 0x400000,
|
||||||
Unk23 = 0x800000,
|
Unk23 = 0x800000,
|
||||||
@@ -168,7 +168,7 @@ namespace Framework.Constants
|
|||||||
IgnoreCombat | SuppressNpcFeedback | Unk10 | Unk11 |
|
IgnoreCombat | SuppressNpcFeedback | Unk10 | Unk11 |
|
||||||
Unk12 | /* FakeDead | */ /* NoFacingOnInteractAndFastFacingChase | */ /* UntargetableFromUi | */
|
Unk12 | /* FakeDead | */ /* NoFacingOnInteractAndFastFacingChase | */ /* UntargetableFromUi | */
|
||||||
/* NoFacingOnInteractWhileFakeDead | */ AlreadySkinned | /* SuppressAllNpcSounds | */ /* SuppressNpcSounds | */
|
/* NoFacingOnInteractWhileFakeDead | */ AlreadySkinned | /* SuppressAllNpcSounds | */ /* SuppressNpcSounds | */
|
||||||
Unk20 | Unk21 | /* DontFadeOut | */ Unk23 |
|
AllowInteractionWhileInCombat | Unk21 | /* DontFadeOut | */ Unk23 |
|
||||||
ForceHideNameplate | Unk25 | Unk26 | Unk27 |
|
ForceHideNameplate | Unk25 | Unk26 | Unk27 |
|
||||||
Unk28 | Unk29 | Unk30 | Unk31), // Skip
|
Unk28 | Unk29 | Unk30 | Unk31), // Skip
|
||||||
Allowed = (0xffffffff & ~Disallowed) // Skip
|
Allowed = (0xffffffff & ~Disallowed) // Skip
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
// TODO: migrate these in DB
|
// TODO: migrate these in DB
|
||||||
_staticFlags.ApplyFlag(CreatureStaticFlags2.AllowMountedCombat, GetCreatureDifficulty().TypeFlags.HasFlag(CreatureTypeFlags.AllowMountedCombat));
|
_staticFlags.ApplyFlag(CreatureStaticFlags2.AllowMountedCombat, GetCreatureDifficulty().TypeFlags.HasFlag(CreatureTypeFlags.AllowMountedCombat));
|
||||||
|
SetInteractionAllowedInCombat(GetCreatureDifficulty().TypeFlags.HasAnyFlag(CreatureTypeFlags.AllowInteractionWhileInCombat));
|
||||||
SetTreatAsRaidUnit(GetCreatureDifficulty().TypeFlags.HasAnyFlag(CreatureTypeFlags.TreatAsRaidUnit));
|
SetTreatAsRaidUnit(GetCreatureDifficulty().TypeFlags.HasAnyFlag(CreatureTypeFlags.TreatAsRaidUnit));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -2756,6 +2757,33 @@ namespace Game.Entities
|
|||||||
m_respawnTime = Math.Max(m_corpseRemoveTime + m_respawnDelay, m_respawnTime);
|
m_respawnTime = Math.Max(m_corpseRemoveTime + m_respawnDelay, m_respawnTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetInteractionAllowedWhileHostile(bool interactionAllowed)
|
||||||
|
{
|
||||||
|
_staticFlags.ApplyFlag(CreatureStaticFlags5.InteractWhileHostile, interactionAllowed);
|
||||||
|
base.SetInteractionAllowedWhileHostile(interactionAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetInteractionAllowedInCombat(bool interactionAllowed)
|
||||||
|
{
|
||||||
|
_staticFlags.ApplyFlag(CreatureStaticFlags3.AllowInteractionWhileInCombat, interactionAllowed);
|
||||||
|
base.SetInteractionAllowedInCombat(interactionAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateNearbyPlayersInteractions()
|
||||||
|
{
|
||||||
|
base.UpdateNearbyPlayersInteractions();
|
||||||
|
|
||||||
|
// If as a result of npcflag updates we stop seeing UNIT_NPC_FLAG_QUESTGIVER then
|
||||||
|
// we must also send SMSG_QUEST_GIVER_STATUS_MULTIPLE because client will not request it automatically
|
||||||
|
if (IsQuestGiver())
|
||||||
|
{
|
||||||
|
var sender = (Player receiver) => receiver.PlayerTalkClass.SendQuestGiverStatus(receiver.GetQuestDialogStatus(this), GetGUID());
|
||||||
|
|
||||||
|
MessageDistDeliverer notifier = new(this, sender, GetVisibilityRange());
|
||||||
|
Cell.VisitWorldObjects(this, notifier, GetVisibilityRange());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool HasScalableLevels()
|
public bool HasScalableLevels()
|
||||||
{
|
{
|
||||||
return m_unitData.ContentTuningID != 0;
|
return m_unitData.ContentTuningID != 0;
|
||||||
|
|||||||
@@ -2332,16 +2332,25 @@ namespace Game.Entities
|
|||||||
uint GetViewerDependentNpcFlags(UnitData unitData, int i, Unit unit, Player receiver)
|
uint GetViewerDependentNpcFlags(UnitData unitData, int i, Unit unit, Player receiver)
|
||||||
{
|
{
|
||||||
uint npcFlag = unitData.NpcFlags[i];
|
uint npcFlag = unitData.NpcFlags[i];
|
||||||
if (i == 0)
|
if (npcFlag != 0)
|
||||||
{
|
{
|
||||||
Creature creature = unit.ToCreature();
|
if ((!unit.IsInteractionAllowedInCombat() && unit.IsInCombat())
|
||||||
if (creature != null)
|
|| (!unit.IsInteractionAllowedWhileHostile() && unit.IsHostileTo(receiver)))
|
||||||
|
npcFlag = 0;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (!receiver.CanSeeGossipOn(creature))
|
Creature creature = unit.ToCreature();
|
||||||
npcFlag &= ~(uint)(NPCFlags.Gossip | NPCFlags.QuestGiver);
|
if (creature != null)
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
if (!receiver.CanSeeGossipOn(creature))
|
||||||
|
npcFlag &= ~(uint)(NPCFlags.Gossip | NPCFlags.QuestGiver);
|
||||||
|
|
||||||
if (!receiver.CanSeeSpellClickOn(creature))
|
if (!receiver.CanSeeSpellClickOn(creature))
|
||||||
npcFlag &= ~(uint)NPCFlags.SpellClick;
|
npcFlag &= ~(uint)NPCFlags.SpellClick;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2032,6 +2032,14 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
case TypeId.Unit:
|
case TypeId.Unit:
|
||||||
{
|
{
|
||||||
|
Creature questGiverCreature = questgiver.ToCreature();
|
||||||
|
if (!questGiverCreature.IsInteractionAllowedWhileHostile() && questGiverCreature.IsHostileTo(this))
|
||||||
|
return QuestGiverStatus.None;
|
||||||
|
|
||||||
|
if (!questGiverCreature.IsInteractionAllowedInCombat() && questGiverCreature.IsInCombat())
|
||||||
|
return QuestGiverStatus.None;
|
||||||
|
|
||||||
|
|
||||||
CreatureAI ai = questgiver.ToCreature().GetAI();
|
CreatureAI ai = questgiver.ToCreature().GetAI();
|
||||||
if (ai != null)
|
if (ai != null)
|
||||||
{
|
{
|
||||||
@@ -3220,7 +3228,7 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
// need also pet quests case support
|
// need also pet quests case support
|
||||||
Creature questgiver = ObjectAccessor.GetCreatureOrPetOrVehicle(this, itr);
|
Creature questgiver = ObjectAccessor.GetCreatureOrPetOrVehicle(this, itr);
|
||||||
if (questgiver == null || questgiver.IsHostileTo(this))
|
if (questgiver == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!questgiver.HasNpcFlag(NPCFlags.QuestGiver))
|
if (!questgiver.HasNpcFlag(NPCFlags.QuestGiver))
|
||||||
|
|||||||
@@ -5472,7 +5472,10 @@ namespace Game.Entities
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
// not unfriendly/hostile
|
// not unfriendly/hostile
|
||||||
if (!creature.HasUnitFlag2(UnitFlags2.InteractWhileHostile) && creature.GetReactionTo(this) <= ReputationRank.Unfriendly)
|
if (!creature.IsInteractionAllowedWhileHostile() && creature.GetReactionTo(this) <= ReputationRank.Unfriendly)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (creature.IsInCombat() && !creature.IsInteractionAllowedInCombat())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// not too far, taken from CGGameUI::SetInteractTarget
|
// not too far, taken from CGGameUI::SetInteractTarget
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ namespace Game.Entities
|
|||||||
|
|
||||||
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnteringCombat);
|
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnteringCombat);
|
||||||
ProcSkillsAndAuras(this, null, new ProcFlagsInit(ProcFlags.EnterCombat), new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
|
ProcSkillsAndAuras(this, null, new ProcFlagsInit(ProcFlags.EnterCombat), new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
|
||||||
|
|
||||||
|
if (!IsInteractionAllowedInCombat())
|
||||||
|
UpdateNearbyPlayersInteractions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void AtExitCombat()
|
public virtual void AtExitCombat()
|
||||||
@@ -43,6 +46,9 @@ namespace Game.Entities
|
|||||||
pair.Value.GetBase().CallScriptEnterLeaveCombatHandlers(pair.Value, false);
|
pair.Value.GetBase().CallScriptEnterLeaveCombatHandlers(pair.Value, false);
|
||||||
|
|
||||||
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LeavingCombat);
|
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LeavingCombat);
|
||||||
|
|
||||||
|
if (!IsInteractionAllowedInCombat())
|
||||||
|
UpdateNearbyPlayersInteractions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void AtEngage(Unit target) { }
|
public virtual void AtEngage(Unit target) { }
|
||||||
@@ -1654,5 +1660,46 @@ namespace Game.Entities
|
|||||||
/// enables / disables combat interaction of this unit
|
/// enables / disables combat interaction of this unit
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetIsCombatDisallowed(bool apply) { _isCombatDisallowed = apply; }
|
public void SetIsCombatDisallowed(bool apply) { _isCombatDisallowed = apply; }
|
||||||
|
|
||||||
|
public bool IsInteractionAllowedWhileHostile()
|
||||||
|
{
|
||||||
|
return HasUnitFlag2(UnitFlags2.InteractWhileHostile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void SetInteractionAllowedWhileHostile(bool interactionAllowed)
|
||||||
|
{
|
||||||
|
if (interactionAllowed)
|
||||||
|
SetUnitFlag2(UnitFlags2.InteractWhileHostile);
|
||||||
|
else
|
||||||
|
RemoveUnitFlag2(UnitFlags2.InteractWhileHostile);
|
||||||
|
|
||||||
|
UpdateNearbyPlayersInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInteractionAllowedInCombat()
|
||||||
|
{
|
||||||
|
return HasUnitFlag3(UnitFlags3.AllowInteractionWhileInCombat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void SetInteractionAllowedInCombat(bool interactionAllowed)
|
||||||
|
{
|
||||||
|
if (interactionAllowed)
|
||||||
|
SetUnitFlag3(UnitFlags3.AllowInteractionWhileInCombat);
|
||||||
|
else
|
||||||
|
RemoveUnitFlag3(UnitFlags3.AllowInteractionWhileInCombat);
|
||||||
|
|
||||||
|
if (IsInCombat())
|
||||||
|
UpdateNearbyPlayersInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void UpdateNearbyPlayersInteractions()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_unitData.NpcFlags.GetSize(); ++i)
|
||||||
|
if (m_unitData.NpcFlags[i] != 0)
|
||||||
|
{
|
||||||
|
m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.NpcFlags, i);
|
||||||
|
ForceUpdateFieldChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,12 @@ namespace Game
|
|||||||
if (staticFlags.HasFlag(CreatureStaticFlags3.CannotTurn))
|
if (staticFlags.HasFlag(CreatureStaticFlags3.CannotTurn))
|
||||||
unitFlags2 |= (uint)UnitFlags2.CannotTurn;
|
unitFlags2 |= (uint)UnitFlags2.CannotTurn;
|
||||||
|
|
||||||
|
if (staticFlags.HasFlag(CreatureStaticFlags5.InteractWhileHostile))
|
||||||
|
unitFlags2 |= (uint)UnitFlags2.InteractWhileHostile;
|
||||||
|
|
||||||
unitFlags3 = data != null && data.unit_flags3.HasValue ? data.unit_flags3.Value : cInfo.UnitFlags3;
|
unitFlags3 = data != null && data.unit_flags3.HasValue ? data.unit_flags3.Value : cInfo.UnitFlags3;
|
||||||
|
if (staticFlags.HasFlag(CreatureStaticFlags3.AllowInteractionWhileInCombat))
|
||||||
|
unitFlags3 |= (uint)UnitFlags3.AllowInteractionWhileInCombat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ResponseCodes CheckPlayerName(string name, Locale locale, bool create = false)
|
public static ResponseCodes CheckPlayerName(string name, Locale locale, bool create = false)
|
||||||
|
|||||||
@@ -17,28 +17,14 @@ namespace Game
|
|||||||
[WorldPacketHandler(ClientOpcodes.QuestGiverStatusQuery, Processing = PacketProcessing.Inplace)]
|
[WorldPacketHandler(ClientOpcodes.QuestGiverStatusQuery, Processing = PacketProcessing.Inplace)]
|
||||||
void HandleQuestgiverStatusQuery(QuestGiverStatusQuery packet)
|
void HandleQuestgiverStatusQuery(QuestGiverStatusQuery packet)
|
||||||
{
|
{
|
||||||
QuestGiverStatus questStatus = QuestGiverStatus.None;
|
var questGiver = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
|
||||||
|
if (questGiver == null)
|
||||||
var questgiver = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
|
|
||||||
if (questgiver == null)
|
|
||||||
{
|
{
|
||||||
Log.outInfo(LogFilter.Network, "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver {0}", packet.QuestGiverGUID.ToString());
|
Log.outInfo(LogFilter.Network, "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver {0}", packet.QuestGiverGUID.ToString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (questgiver.GetTypeId())
|
QuestGiverStatus questStatus = _player.GetQuestDialogStatus(questGiver);
|
||||||
{
|
|
||||||
case TypeId.Unit:
|
|
||||||
if (!questgiver.ToCreature().IsHostileTo(GetPlayer()))// do not show quest status to enemies
|
|
||||||
questStatus = GetPlayer().GetQuestDialogStatus(questgiver);
|
|
||||||
break;
|
|
||||||
case TypeId.GameObject:
|
|
||||||
questStatus = GetPlayer().GetQuestDialogStatus(questgiver);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.outError(LogFilter.Network, "QuestGiver called for unexpected type {0}", questgiver.GetTypeId());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//inform client about status of quest
|
//inform client about status of quest
|
||||||
GetPlayer().PlayerTalkClass.SendQuestGiverStatus(questStatus, packet.QuestGiverGUID);
|
GetPlayer().PlayerTalkClass.SendQuestGiverStatus(questStatus, packet.QuestGiverGUID);
|
||||||
|
|||||||
Reference in New Issue
Block a user