diff --git a/Source/Framework/Util/CollectionExtensions.cs b/Source/Framework/Util/CollectionExtensions.cs index a8be08bd0..4f36c29b9 100644 --- a/Source/Framework/Util/CollectionExtensions.cs +++ b/Source/Framework/Util/CollectionExtensions.cs @@ -210,8 +210,5 @@ namespace System.Collections.Generic bool Invoke(T obj); } - public interface IDoWork - { - void Invoke(T obj); - } + public delegate void IDoWork(T obj); } diff --git a/Source/Game/AI/CoreAI/TotemAI.cs b/Source/Game/AI/CoreAI/TotemAI.cs index 69778e48c..49fdedb7a 100644 --- a/Source/Game/AI/CoreAI/TotemAI.cs +++ b/Source/Game/AI/CoreAI/TotemAI.cs @@ -49,7 +49,7 @@ namespace Game.AI var u_check = new NearestAttackableUnitInObjectRangeCheck(me, me.GetCharmerOrOwnerOrSelf(), max_range); var checker = new UnitLastSearcher(me, u_check); Cell.VisitAllObjects(me, checker, max_range + extraSearchRadius); - victim = checker.GetTarget(); + victim = checker.GetResult(); } // If have target diff --git a/Source/Game/AI/ScriptedAI/ScriptedAI.cs b/Source/Game/AI/ScriptedAI/ScriptedAI.cs index f82d54362..d7366abab 100644 --- a/Source/Game/AI/ScriptedAI/ScriptedAI.cs +++ b/Source/Game/AI/ScriptedAI/ScriptedAI.cs @@ -372,7 +372,7 @@ namespace Game.AI var searcher = new UnitLastSearcher(me, u_check); Cell.VisitAllObjects(me, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } //Returns a list of friendly CC'd units within range @@ -404,7 +404,7 @@ namespace Game.AI var searcher = new PlayerSearcher(me, check); Cell.VisitWorldObjects(me, searcher, minimumRange); - return searcher.GetTarget(); + return searcher.GetResult(); } public void SetEquipmentSlots(bool loadDefault, int mainHand = -1, int offHand = -1, int ranged = -1) diff --git a/Source/Game/AI/SmartScripts/SmartScript.cs b/Source/Game/AI/SmartScripts/SmartScript.cs index d11bd2bdd..6b8af5286 100644 --- a/Source/Game/AI/SmartScripts/SmartScript.cs +++ b/Source/Game/AI/SmartScripts/SmartScript.cs @@ -4257,7 +4257,7 @@ namespace Game.AI var u_check = new MostHPMissingInRange(_me, range, MinHPDiff); var searcher = new UnitLastSearcher(_me, u_check); Cell.VisitGridObjects(_me, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public Unit DoSelectBelowHpPctFriendlyWithEntry(uint entry, float range, byte minHPDiff = 1, bool excludeSelf = true) @@ -4266,7 +4266,7 @@ namespace Game.AI UnitLastSearcher searcher = new(_me, u_check); Cell.VisitAllObjects(_me, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } Unit DoSelectLowestHpPercentFriendly(float range, uint minHpPct, uint maxHpPct) @@ -4277,7 +4277,7 @@ namespace Game.AI MostHPPercentMissingInRange u_check = new(_me, range, minHpPct, maxHpPct); UnitLastSearcher searcher = new(_me, u_check); Cell.VisitGridObjects(_me, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } void DoFindFriendlyCC(List creatures, float range) @@ -4308,7 +4308,7 @@ namespace Game.AI var u_check = new AnyFriendlyUnitInObjectRangeCheck(_me, _me, range); var searcher = new UnitLastSearcher(_me, u_check); Cell.VisitAllObjects(_me, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public void SetTimedActionList(SmartScriptHolder e, uint entry, Unit invoker, uint startFromEventId = 0) diff --git a/Source/Game/Calendar/CalendarManager.cs b/Source/Game/Calendar/CalendarManager.cs index c56afec3b..a844b3ecd 100644 --- a/Source/Game/Calendar/CalendarManager.cs +++ b/Source/Game/Calendar/CalendarManager.cs @@ -558,7 +558,7 @@ namespace Game void SendCalendarEventInviteAlert(CalendarEvent calendarEvent, CalendarInvite invite) { - var packetBuilder = (Player receiver) => + IDoWork packetBuilder = (Player receiver) => { CalendarInviteAlert packet = new(); packet.Date.SetUtcTimeFromUnixTime(calendarEvent.Date); diff --git a/Source/Game/Chat/CommandHandler.cs b/Source/Game/Chat/CommandHandler.cs index 7d315b23e..8a5d8ce42 100644 --- a/Source/Game/Chat/CommandHandler.cs +++ b/Source/Game/Chat/CommandHandler.cs @@ -400,7 +400,7 @@ namespace Game.Chat NearestGameObjectCheck check = new(pl); GameObjectLastSearcher searcher = new(pl, check); Cell.VisitGridObjects(pl, searcher, MapConst.SizeofGrids); - return searcher.GetTarget(); + return searcher.GetResult(); } public string PlayerLink(string name) diff --git a/Source/Game/Chat/Commands/DebugCommands.cs b/Source/Game/Chat/Commands/DebugCommands.cs index 80c84ca1d..ac7b8eac2 100644 --- a/Source/Game/Chat/Commands/DebugCommands.cs +++ b/Source/Game/Chat/Commands/DebugCommands.cs @@ -142,7 +142,7 @@ namespace Game.Chat var check = new AllCreaturesOfEntryInRange(handler.GetPlayer(), entry, 20.0f); var searcher = new CreatureSearcher(handler.GetPlayer(), check); Cell.VisitAllObjects(handler.GetPlayer(), searcher, 30.0f); - var passenger = searcher.GetTarget(); + var passenger = searcher.GetResult(); if (passenger == null || passenger == target) return false; passenger.EnterVehicle(target, seatId); diff --git a/Source/Game/Chat/Commands/MiscCommands.cs b/Source/Game/Chat/Commands/MiscCommands.cs index 76152c267..82f65c097 100644 --- a/Source/Game/Chat/Commands/MiscCommands.cs +++ b/Source/Game/Chat/Commands/MiscCommands.cs @@ -1571,7 +1571,8 @@ namespace Game.Chat } // First handle any creatures that still have a corpse around - var worker = new WorldObjectWorker(player, new RespawnDo()); + RespawnDo u_do = new(); + WorldObjectWorker worker = new(player, u_do); Cell.VisitGridObjects(player, worker, player.GetGridActivationRange()); // Now handle any that had despawned, but had respawn time logged. diff --git a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs index 17a4593e5..a5e7fd851 100644 --- a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs +++ b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs @@ -1589,7 +1589,7 @@ namespace Game.Entities AreaTriggerAI _ai; - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { AreaTrigger Owner; ObjectFieldData ObjectMask = new(); @@ -1609,6 +1609,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject updateObject); player.SendPacket(updateObject); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } } diff --git a/Source/Game/Entities/Conversation.cs b/Source/Game/Entities/Conversation.cs index 118469a32..3a5f7c599 100644 --- a/Source/Game/Entities/Conversation.cs +++ b/Source/Game/Entities/Conversation.cs @@ -386,7 +386,7 @@ namespace Game.Entities ConversationAI _ai; - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { Conversation Owner; ObjectFieldData ObjectMask = new(); @@ -406,6 +406,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } diff --git a/Source/Game/Entities/Corpse.cs b/Source/Game/Entities/Corpse.cs index d5238d690..fbb18114c 100644 --- a/Source/Game/Entities/Corpse.cs +++ b/Source/Game/Entities/Corpse.cs @@ -320,7 +320,7 @@ namespace Game.Entities long m_time; CellCoord _cellCoord; // gride for corpse position for fast search - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { Corpse Owner; ObjectFieldData ObjectMask = new(); @@ -340,6 +340,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } } diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 505d18ddf..55a7726cf 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -747,7 +747,7 @@ namespace Game.Entities var searcher = new CreatureLastSearcher(this, u_check); Cell.VisitGridObjects(this, searcher, radius); - var creature = searcher.GetTarget(); + var creature = searcher.GetResult(); SetNoSearchAssistance(true); @@ -2323,7 +2323,7 @@ namespace Game.Entities var searcher = new UnitLastSearcher(this, u_check); Cell.VisitAllObjects(this, searcher, dist); - return searcher.GetTarget(); + return searcher.GetResult(); } // select nearest hostile unit within the given attack distance (i.e. distance is ignored if > than ATTACK_DISTANCE), regardless of threat list. @@ -2340,7 +2340,7 @@ namespace Game.Entities Cell.VisitAllObjects(this, searcher, Math.Max(dist, SharedConst.AttackDistance)); - return searcher.GetTarget(); + return searcher.GetResult(); } public void SendAIReaction(AiReaction reactionType) @@ -3327,7 +3327,7 @@ namespace Game.Entities var u_check = new NearestHostileUnitInAggroRangeCheck(this, useLOS, ignoreCivilians); var searcher = new UnitSearcher(this, u_check); Cell.VisitGridObjects(this, searcher, SharedConst.MaxAggroRadius); - return searcher.GetTarget(); + return searcher.GetResult(); } public override float GetNativeObjectScale() @@ -3880,7 +3880,7 @@ namespace Game.Entities base.ClearUpdateMask(remove); } - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { Creature Owner; ObjectFieldData ObjectMask = new(); @@ -3900,6 +3900,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } diff --git a/Source/Game/Entities/DynamicObject.cs b/Source/Game/Entities/DynamicObject.cs index faaa71a9d..ab281cf09 100644 --- a/Source/Game/Entities/DynamicObject.cs +++ b/Source/Game/Entities/DynamicObject.cs @@ -307,7 +307,7 @@ namespace Game.Entities int _duration; // for non-aura dynobjects bool _isViewpoint; - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { DynamicObject Owner; ObjectFieldData ObjectMask = new(); @@ -327,6 +327,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index 02a94c2cb..6c02c9345 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -633,7 +633,7 @@ namespace Game.Entities var checker = new NearestAttackableNoTotemUnitInObjectRangeCheck(this, radius); var searcher = new UnitLastSearcher(this, checker); Cell.VisitAllObjects(this, searcher, radius); - target = searcher.GetTarget(); + target = searcher.GetResult(); } else { @@ -641,7 +641,7 @@ namespace Game.Entities var check = new AnyUnitInObjectRangeCheck(this, radius); var searcher = new PlayerSearcher(this, check); Cell.VisitWorldObjects(this, searcher, radius); - target = searcher.GetTarget(); + target = searcher.GetResult(); } if (target != null) @@ -1465,7 +1465,7 @@ namespace Game.Entities var checker = new GameObjectSearcher(this, u_check); Cell.VisitGridObjects(this, checker, range); - return checker.GetTarget(); + return checker.GetResult(); } public void ResetDoorOrButton() @@ -3975,7 +3975,7 @@ namespace Game.Entities ObjectGuid m_linkedTrap; #endregion - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { public GameObject Owner; public ObjectFieldData ObjectMask = new(); @@ -3995,6 +3995,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } diff --git a/Source/Game/Entities/Item/AzeriteEmpoweredItem.cs b/Source/Game/Entities/Item/AzeriteEmpoweredItem.cs index 13860a719..f9a31fbba 100644 --- a/Source/Game/Entities/Item/AzeriteEmpoweredItem.cs +++ b/Source/Game/Entities/Item/AzeriteEmpoweredItem.cs @@ -224,7 +224,7 @@ namespace Game.Entities return (uint)m_azeriteEmpoweredItemData.Selections[tier]; } - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { AzeriteEmpoweredItem Owner; ObjectFieldData ObjectMask = new(); @@ -245,6 +245,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } } diff --git a/Source/Game/Entities/Item/AzeriteItem.cs b/Source/Game/Entities/Item/AzeriteItem.cs index c1db6e0e6..7c51c699d 100644 --- a/Source/Game/Entities/Item/AzeriteItem.cs +++ b/Source/Game/Entities/Item/AzeriteItem.cs @@ -510,7 +510,7 @@ namespace Game.Entities } } - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { AzeriteItem Owner; ObjectFieldData ObjectMask = new(); @@ -531,6 +531,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } diff --git a/Source/Game/Entities/Item/Bag.cs b/Source/Game/Entities/Item/Bag.cs index 66c4f7e81..23d4c88c7 100644 --- a/Source/Game/Entities/Item/Bag.cs +++ b/Source/Game/Entities/Item/Bag.cs @@ -259,7 +259,7 @@ namespace Game.Entities ContainerData m_containerData; Item[] m_bagslot = new Item[98]; - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { Bag Owner; ObjectFieldData ObjectMask = new(); @@ -280,6 +280,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } } diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index 651b5d226..533aabeb9 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -2838,7 +2838,7 @@ namespace Game.Entities Array m_gemScalingLevels = new(ItemConst.MaxGemSockets); #endregion - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { Item Owner; ObjectFieldData ObjectMask = new(); @@ -2858,6 +2858,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index af139280f..ee1ae55e5 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1642,7 +1642,7 @@ namespace Game.Entities var searcher = new CreatureLastSearcher(this, checker); Cell.VisitAllObjects(this, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public Creature FindNearestCreatureWithOptions(float range, FindCreatureOptions options) @@ -1654,7 +1654,7 @@ namespace Game.Entities searcher.i_phaseShift = PhasingHandler.GetAlwaysVisiblePhaseShift(); Cell.VisitAllObjects(this, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public GameObject FindNearestGameObject(uint entry, float range, bool spawnedOnly = true) @@ -1663,7 +1663,7 @@ namespace Game.Entities var searcher = new GameObjectLastSearcher(this, checker); Cell.VisitGridObjects(this, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public GameObject FindNearestGameObjectWithOptions(float range, FindGameObjectOptions options) @@ -1675,7 +1675,7 @@ namespace Game.Entities searcher.i_phaseShift = PhasingHandler.GetAlwaysVisiblePhaseShift(); Cell.VisitGridObjects(this, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public GameObject FindNearestUnspawnedGameObject(uint entry, float range) @@ -1684,7 +1684,7 @@ namespace Game.Entities GameObjectLastSearcher searcher = new(this, checker); Cell.VisitGridObjects(this, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public GameObject FindNearestGameObjectOfType(GameObjectTypes type, float range) @@ -1693,7 +1693,7 @@ namespace Game.Entities var searcher = new GameObjectLastSearcher(this, checker); Cell.VisitGridObjects(this, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public Player SelectNearestPlayer(float range) @@ -1701,7 +1701,7 @@ namespace Game.Entities var checker = new NearestPlayerInObjectRangeCheck(this, range); var searcher = new PlayerLastSearcher(this, checker); Cell.VisitWorldObjects(this, searcher, range); - return searcher.GetTarget(); + return searcher.GetResult(); } public ObjectGuid GetCharmerOrOwnerOrOwnGUID() @@ -4059,7 +4059,7 @@ namespace Game.Entities } } - class CombatLogSender : IDoWork + class CombatLogSender { CombatLogServerPacket i_message; @@ -4075,6 +4075,8 @@ namespace Game.Entities player.SendPacket(i_message); } + + public static implicit operator IDoWork(CombatLogSender obj) => obj.Invoke; } public struct FindCreatureOptions @@ -4257,7 +4259,7 @@ namespace Game.Entities } } - struct WorldObjectClientDestroyWork : IDoWork + struct WorldObjectClientDestroyWork { public WorldObject obj; @@ -4276,5 +4278,7 @@ namespace Game.Entities obj.DestroyForPlayer(player); player.m_clientGUIDs.Remove(obj.GetGUID()); } + + public static implicit operator IDoWork(WorldObjectClientDestroyWork obj) => obj.Invoke; } } \ No newline at end of file diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index 6eae8910d..486ae0bdb 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -255,7 +255,7 @@ namespace Game.Entities List _playerDataElementsNeedSave = new(); List _playerDataFlagsNeedSave = new(); - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { Player Owner; ObjectFieldData ObjectMask = new(); @@ -277,6 +277,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } diff --git a/Source/Game/Entities/SceneObject.cs b/Source/Game/Entities/SceneObject.cs index 47b7e8ff2..a99ca8de1 100644 --- a/Source/Game/Entities/SceneObject.cs +++ b/Source/Game/Entities/SceneObject.cs @@ -183,7 +183,7 @@ namespace Game.Entities public void SetCreatedBySpellCast(ObjectGuid castId) { _createdBySpellCast = castId; } - class ValuesUpdateForPlayerWithMaskSender : IDoWork + class ValuesUpdateForPlayerWithMaskSender { SceneObject Owner; ObjectFieldData ObjectMask = new(); @@ -203,6 +203,8 @@ namespace Game.Entities udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } + + public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } } diff --git a/Source/Game/Guilds/Guild.cs b/Source/Game/Guilds/Guild.cs index 70c4034e4..56bf3a774 100644 --- a/Source/Game/Guilds/Guild.cs +++ b/Source/Game/Guilds/Guild.cs @@ -2473,17 +2473,6 @@ namespace Game.Guilds } } - public void BroadcastWorker(Action _do, Player except = null) - { - foreach (var member in m_members.Values) - { - Player player = member.FindPlayer(); - if (player != null) - if (player != except) - _do.Invoke(player); - } - } - public int GetMembersCount() { return m_members.Count; } public GuildAchievementMgr GetAchievementMgr() { return m_achievementSys; } diff --git a/Source/Game/Maps/GridNotifiers.cs b/Source/Game/Maps/GridNotifiers.cs index 7215dac14..9fb46aca6 100644 --- a/Source/Game/Maps/GridNotifiers.cs +++ b/Source/Game/Maps/GridNotifiers.cs @@ -71,7 +71,7 @@ namespace Game.Maps { i_player = pl; i_data = new UpdateData(pl.GetMapId()); - vis_guids = new List(pl.m_clientGUIDs); + vis_guids = [.. pl.m_clientGUIDs]; i_visibleNow = new List(); } @@ -385,22 +385,17 @@ namespace Game.Maps } } - public class PacketSenderRef : IDoWork + public class PacketSenderRef(ServerPacket message) { - ServerPacket Data; - - public PacketSenderRef(ServerPacket message) - { - Data = message; - } - public virtual void Invoke(Player player) { - player.SendPacket(Data); + player.SendPacket(message); } + + public static implicit operator IDoWork(PacketSenderRef obj) => obj.Invoke; } - public class PacketSenderOwning : IDoWork where T : ServerPacket, new() + public class PacketSenderOwning where T : ServerPacket, new() { public T Data = new(); @@ -408,6 +403,8 @@ namespace Game.Maps { player.SendPacket(Data); } + + public static implicit operator IDoWork(PacketSenderOwning obj) => obj.Invoke; } public class MessageDistDeliverer : Notifier @@ -526,14 +523,14 @@ namespace Game.Maps } } - public class MessageDistDelivererToHostile : Notifier where T : IDoWork + public class MessageDistDelivererToHostile : Notifier { Unit i_source; - T i_packetSender; + IDoWork i_packetSender; PhaseShift i_phaseShift; float i_distSq; - public MessageDistDelivererToHostile(Unit src, T packetSender, float dist) + public MessageDistDelivererToHostile(Unit src, IDoWork packetSender, float dist) { i_source = src; i_packetSender = packetSender; @@ -618,13 +615,8 @@ namespace Game.Maps } } - public class UpdaterNotifier : Notifier + public class ObjectUpdater(uint diff) : Notifier { - public UpdaterNotifier(uint diff) - { - i_timeDiff = diff; - } - public override void Visit(IList objs) { for (var i = 0; i < objs.Count; ++i) @@ -635,193 +627,7 @@ namespace Game.Maps continue; if (obj.IsInWorld) - obj.Update(i_timeDiff); - } - } - - uint i_timeDiff; - } - - public class PlayerWorker : Notifier - { - PhaseShift i_phaseShift; - Action action; - - public PlayerWorker(WorldObject searcher, Action _action) - { - i_phaseShift = searcher.GetPhaseShift(); - action = _action; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (player.InSamePhase(i_phaseShift)) - action.Invoke(player); - } - } - } - - public class CreatureWorker : Notifier - { - PhaseShift i_phaseShift; - IDoWork Do; - - public CreatureWorker(WorldObject searcher, IDoWork _Do) - { - i_phaseShift = searcher.GetPhaseShift(); - Do = _Do; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (creature.InSamePhase(i_phaseShift)) - Do.Invoke(creature); - } - } - } - - public class GameObjectWorker : Notifier - { - PhaseShift i_phaseShift; - IDoWork _do; - - public GameObjectWorker(WorldObject searcher, IDoWork @do) - { - i_phaseShift = searcher.GetPhaseShift(); - _do = @do; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - GameObject gameObject = objs[i]; - if (gameObject.InSamePhase(i_phaseShift)) - _do.Invoke(gameObject); - } - } - } - - public class WorldObjectWorker : Notifier - { - GridMapTypeMask i_mapTypeMask; - PhaseShift i_phaseShift; - IDoWork i_do; - - public WorldObjectWorker(WorldObject searcher, IDoWork _do, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) - { - i_mapTypeMask = mapTypeMask; - i_phaseShift = searcher.GetPhaseShift(); - i_do = _do; - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.GameObject)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - GameObject gameObject = objs[i]; - if (gameObject.InSamePhase(i_phaseShift)) - i_do.Invoke(gameObject); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Player)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (player.InSamePhase(i_phaseShift)) - i_do.Invoke(player); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Creature)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (creature.InSamePhase(i_phaseShift)) - i_do.Invoke(creature); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Corpse)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Corpse corpse = objs[i]; - if (corpse.InSamePhase(i_phaseShift)) - i_do.Invoke(corpse); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.DynamicObject)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - DynamicObject dynamicObject = objs[i]; - if (dynamicObject.InSamePhase(i_phaseShift)) - i_do.Invoke(dynamicObject); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.AreaTrigger)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - AreaTrigger areaTrigger = objs[i]; - if (areaTrigger.InSamePhase(i_phaseShift)) - i_do.Invoke(areaTrigger); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.SceneObject)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - SceneObject sceneObject = objs[i]; - if (sceneObject.InSamePhase(i_phaseShift)) - i_do.Invoke(sceneObject); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Conversation)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Conversation conversation = objs[i]; - if (conversation.InSamePhase(i_phaseShift)) - i_do.Invoke(conversation); + obj.Update(diff); } } } @@ -847,7 +653,7 @@ namespace Game.Maps } } - public class WorldObjectChangeAccumulator : IDoWork + public class WorldObjectChangeAccumulator { Dictionary updateData; WorldObject worldObject; @@ -865,26 +671,465 @@ namespace Game.Maps if (player.HaveAtClient(worldObject) && plr_list.Add(player.GetGUID())) worldObject.BuildFieldsUpdate(player, updateData); } + + public static implicit operator IDoWork(WorldObjectChangeAccumulator obj) => obj.Invoke; + } + + //Searchers + public enum WorldObjectSearcherContinuation + { + Continue, + Return + } + + public interface IResultInserter + { + WorldObjectSearcherContinuation ShouldContinue(); + void Insert(T obj); + T GetResult(); + } + + class SearcherFirstObjectResult() : IResultInserter + { + T result; + + public WorldObjectSearcherContinuation ShouldContinue() + { + return result != null ? WorldObjectSearcherContinuation.Return : WorldObjectSearcherContinuation.Continue; + } + + public void Insert(T obj) + { + result = obj; + } + + public T GetResult() + { + return result; + } + } + + class SearcherLastObjectResult() : IResultInserter + { + T result; + + public WorldObjectSearcherContinuation ShouldContinue() + { + return WorldObjectSearcherContinuation.Continue; + } + + public void Insert(T obj) + { + result = obj; + } + + public T GetResult() + { + return result; + } + } + + class SearcherContainerResult(List container_) : IResultInserter + { + ICollection container = container_; + + public WorldObjectSearcherContinuation ShouldContinue() + { + return WorldObjectSearcherContinuation.Continue; + } + + public void Insert(T obj) + { + container.Add(obj); + } + + public T GetResult() + { + return default; + } + } + + struct DynamicGridMapTypeMaskCheck(GridMapTypeMask mask) + { + static Dictionary GridMapTypeMaskForType = new() + { + { typeof(Corpse), GridMapTypeMask.Corpse }, + { typeof(Creature), GridMapTypeMask.Creature }, + { typeof(DynamicObject), GridMapTypeMask.DynamicObject }, + { typeof(GameObject), GridMapTypeMask.GameObject }, + { typeof(Player), GridMapTypeMask.Player }, + { typeof(AreaTrigger), GridMapTypeMask.AreaTrigger }, + { typeof(SceneObject), GridMapTypeMask.SceneObject }, + { typeof(Conversation), GridMapTypeMask.Conversation } + }; + GridMapTypeMask MaskValue = mask; + + public bool Includes(GridMapTypeMask mapTypeMask) + { + return (MaskValue & mapTypeMask) != 0; + } + + public static GridMapTypeMask GetTypeMaskByType() + { + return GridMapTypeMaskForType.LookupByKey(typeof(T)); + } + } + + // WorldObject searchers & workers + + public class WorldObjectSearcherBase : Notifier where T : WorldObject + { + GridMapTypeMask i_mapTypeMask; + public PhaseShift i_phaseShift; + ICheck i_check; + IResultInserter resultInserter; + + public WorldObjectSearcherBase(PhaseShift phaseShift, IResultInserter result, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + { + i_mapTypeMask = mapTypeMask; + i_phaseShift = phaseShift; + i_check = check; + resultInserter = result; + } + + public override void Visit(IList objs) + { + if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.GameObject)) + return; + + VisitImpl(objs); + } + + public override void Visit(IList objs) + { + if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Player)) + return; + + VisitImpl(objs); + } + + public override void Visit(IList objs) + { + if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Creature)) + return; + + VisitImpl(objs); + } + + public override void Visit(IList objs) + { + if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Corpse)) + return; + + VisitImpl(objs); + } + + public override void Visit(IList objs) + { + if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.DynamicObject)) + return; + + VisitImpl(objs); + } + + public override void Visit(IList objs) + { + if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.AreaTrigger)) + return; + + VisitImpl(objs); + } + + public override void Visit(IList objs) + { + if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.SceneObject)) + return; + + VisitImpl(objs); + } + + public override void Visit(IList objs) + { + if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Conversation)) + return; + + VisitImpl(objs); + } + + void VisitImpl(IList objs) where TT : WorldObject + { + if (resultInserter.ShouldContinue() == WorldObjectSearcherContinuation.Return) + return; + + foreach (dynamic obj in objs) + { + if (!obj.InSamePhase(i_phaseShift)) + continue; + + if (i_check.Invoke(obj)) + { + resultInserter.Insert(obj); + + if (resultInserter.ShouldContinue() == WorldObjectSearcherContinuation.Return) + return; + } + } + } + + public T GetResult() + { + return resultInserter.GetResult(); + } + } + + public class WorldObjectWorkerBase(PhaseShift phaseShift, IDoWork work, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) : Notifier where T : WorldObject + { + DynamicGridMapTypeMaskCheck i_mapTypeMask = new(mapTypeMask); + PhaseShift i_phaseShift = phaseShift; + IDoWork i_work = work; + + public override void Visit(IList objs) + { + if (i_mapTypeMask.Includes(DynamicGridMapTypeMaskCheck.GetTypeMaskByType())) + VisitImpl(objs); + } + + void VisitImpl(IList objs) + { + foreach (var obj in objs) + if (obj.InSamePhase(i_phaseShift)) + i_work.Invoke(obj as T); + } + } + + public class WorldObjectSearcher : WorldObjectSearcherBase + { + public WorldObjectSearcher(PhaseShift phaseShift, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + : base(phaseShift, new SearcherFirstObjectResult(), check, mapTypeMask) { } + + public WorldObjectSearcher(WorldObject searcher, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + : this(searcher.GetPhaseShift(), check, mapTypeMask) { } + } + + public class WorldObjectLastSearcher : WorldObjectSearcherBase + { + public WorldObjectLastSearcher(PhaseShift phaseShift, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + : base(phaseShift, new SearcherLastObjectResult(), check, mapTypeMask) { } + + public WorldObjectLastSearcher(WorldObject searcher, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + : this(searcher.GetPhaseShift(), check, mapTypeMask) { } + } + + public class WorldObjectListSearcher : WorldObjectSearcherBase + { + public WorldObjectListSearcher(PhaseShift phaseShift, List container, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + : base(phaseShift, new SearcherContainerResult(container), check, mapTypeMask) { } + + public WorldObjectListSearcher(WorldObject searcher, List container, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + : this(searcher.GetPhaseShift(), container, check, mapTypeMask) { } + } + + public class WorldObjectWorker : WorldObjectWorkerBase where T : WorldObject + { + public WorldObjectWorker(PhaseShift phaseShift, IDoWork work, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + : base(phaseShift, work, mapTypeMask) { } + + public WorldObjectWorker(WorldObject searcher, IDoWork work, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) + : this(searcher.GetPhaseShift(), work, mapTypeMask) { } + } + + // Gameobject searchers + + public class GameObjectSearcherBase : WorldObjectSearcherBase + { + public GameObjectSearcherBase(PhaseShift phaseShift, IResultInserter result, ICheck check) + : base(phaseShift, result, check, GridMapTypeMask.GameObject) { } + } + + public class GameObjectSearcher : GameObjectSearcherBase + { + public GameObjectSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherFirstObjectResult(), check) { } + + public GameObjectSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class GameObjectLastSearcher : GameObjectSearcherBase + { + public GameObjectLastSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherLastObjectResult(), check) { } + + public GameObjectLastSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class GameObjectListSearcher : GameObjectSearcherBase + { + public GameObjectListSearcher(PhaseShift phaseShift, List container, ICheck check) + : base(phaseShift, new SearcherContainerResult(container), check) { } + + public GameObjectListSearcher(WorldObject searcher, List container, ICheck check) + : this(searcher.GetPhaseShift(), container, check) { } + } + + public class GameObjectWorker : WorldObjectWorkerBase + { + public GameObjectWorker(PhaseShift phaseShift, IDoWork work) + : base(phaseShift, work, GridMapTypeMask.GameObject) { } + + public GameObjectWorker(WorldObject searcher, IDoWork work) + : this(searcher.GetPhaseShift(), work) { } + } + + // Unit searchers + + public class UnitSearcherBase : WorldObjectSearcherBase + { + public UnitSearcherBase(PhaseShift phaseShift, IResultInserter result, ICheck check) + : base(phaseShift, result, check, GridMapTypeMask.Creature | GridMapTypeMask.Player) { } + } + + // First accepted by Check Unit if any + public class UnitSearcher : UnitSearcherBase + { + public UnitSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherFirstObjectResult(), check) { } + + public UnitSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + // Last accepted by Check Unit if any (Check can change requirements at each call) + public class UnitLastSearcher : UnitSearcherBase + { + public UnitLastSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherLastObjectResult(), check) { } + + public UnitLastSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + // All accepted by Check units if any + public class UnitListSearcher : UnitSearcherBase + { + public UnitListSearcher(PhaseShift phaseShift, List container, ICheck check) + : base(phaseShift, new SearcherContainerResult(container), check) { } + + public UnitListSearcher(WorldObject searcher, List container, ICheck check) + : this(searcher.GetPhaseShift(), container, check) { } + } + + public class UnitWorker : WorldObjectWorkerBase + { + public UnitWorker(PhaseShift phaseShift, IDoWork work) + : base(phaseShift, work, GridMapTypeMask.Creature | GridMapTypeMask.Player) { } + + public UnitWorker(WorldObject searcher, IDoWork work) + : this(searcher.GetPhaseShift(), work) { } + } + + // Creature searchers + + public class CreatureSearcherBase : WorldObjectSearcherBase + { + public CreatureSearcherBase(PhaseShift phaseShift, IResultInserter result, ICheck check) + : base(phaseShift, result, check, GridMapTypeMask.Creature) { } + } + + public class CreatureSearcher : CreatureSearcherBase + { + public CreatureSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherFirstObjectResult(), check) { } + + public CreatureSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + // Last accepted by Check Creature if any (Check can change requirements at each call) + public class CreatureLastSearcher : CreatureSearcherBase + { + public CreatureLastSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherLastObjectResult(), check) { } + + public CreatureLastSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class CreatureListSearcher : CreatureSearcherBase + { + public CreatureListSearcher(PhaseShift phaseShift, List container, ICheck check) + : base(phaseShift, new SearcherContainerResult(container), check) { } + + public CreatureListSearcher(WorldObject searcher, List container, ICheck check) + : this(searcher.GetPhaseShift(), container, check) { } + } + + public class CreatureWorker : WorldObjectWorkerBase + { + public CreatureWorker(PhaseShift phaseShift, IDoWork work) + : base(phaseShift, work) { } + + public CreatureWorker(WorldObject searcher, IDoWork work) + : this(searcher.GetPhaseShift(), work) { } + } + + // Player searchers + + public class PlayerSearcherBase : WorldObjectSearcherBase + { + public PlayerSearcherBase(PhaseShift phaseShift, IResultInserter result, ICheck check) + : base(phaseShift, result, check, GridMapTypeMask.Player) { } + } + + public class PlayerSearcher : PlayerSearcherBase + { + public PlayerSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherFirstObjectResult(), check) { } + + public PlayerSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class PlayerLastSearcher : PlayerSearcherBase + { + public PlayerLastSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherLastObjectResult(), check) { } + + public PlayerLastSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class PlayerListSearcher : PlayerSearcherBase + { + public PlayerListSearcher(PhaseShift phaseShift, List container, ICheck check) + : base(phaseShift, new SearcherContainerResult(container), check) { } + + + public PlayerListSearcher(WorldObject searcher, List container, ICheck check) + : this(searcher.GetPhaseShift(), container, check) { } + } + + public class PlayerWorker : WorldObjectWorkerBase + { + public PlayerWorker(PhaseShift phaseShift, IDoWork work) + : base(phaseShift, work, GridMapTypeMask.Player) { } + + public PlayerWorker(WorldObject searcher, IDoWork work) + : this(searcher.GetPhaseShift(), work) { } } public class PlayerDistWorker : Notifier { WorldObject i_searcher; float i_dist; - Action _do; + IDoWork i_work; - public PlayerDistWorker(WorldObject searcher, float _dist, IDoWork @do) + public PlayerDistWorker(WorldObject searcher, float _dist, IDoWork work) { i_searcher = searcher; i_dist = _dist; - _do = @do.Invoke; - } - - public PlayerDistWorker(WorldObject searcher, float _dist, Action destroyer) - { - i_searcher = searcher; - i_dist = _dist; - _do = destroyer; + i_work = work.Invoke; } public override void Visit(IList objs) @@ -893,1000 +1138,352 @@ namespace Game.Maps { Player player = objs[i]; if (player.InSamePhase(i_searcher) && player.IsWithinDist(i_searcher, i_dist)) - _do.Invoke(player); + i_work(player); } } } - public class CallOfHelpCreatureInRangeDo : IDoWork + // AreaTrigger searchers + + public class AreaTriggerSearcherBase : WorldObjectSearcherBase { - public CallOfHelpCreatureInRangeDo(Unit funit, Unit enemy, float range) - { - i_funit = funit; - i_enemy = enemy; - i_range = range; - } + public AreaTriggerSearcherBase(PhaseShift phaseShift, IResultInserter result, ICheck check) + : base(phaseShift, result, check, GridMapTypeMask.AreaTrigger) { } + } - public void Invoke(Creature u) - { - if (u == i_funit) - return; + public class AreaTriggerSearcher : AreaTriggerSearcherBase + { + public AreaTriggerSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherFirstObjectResult(), check) { } - if (!u.CanAssistTo(i_funit, i_enemy, false)) - return; + public AreaTriggerSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } - // too far - // Don't use combat reach distance, range must be an absolute value, otherwise the chain aggro range will be too big - if (!u.IsWithinDist(i_funit, i_range, true, false, false)) - return; + public class AreaTriggerLastSearcher : AreaTriggerSearcherBase + { + public AreaTriggerLastSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherLastObjectResult(), check) { } - // only if see assisted creature's enemy - if (!u.IsWithinLOSInMap(i_enemy)) - return; + public AreaTriggerLastSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } - u.EngageWithTarget(i_enemy); - } + public class AreaTriggerListSearcher : AreaTriggerSearcherBase + { + public AreaTriggerListSearcher(PhaseShift phaseShift, List container, ICheck check) + : base(phaseShift, new SearcherContainerResult(container), check) { } - Unit i_funit; - Unit i_enemy; + public AreaTriggerListSearcher(WorldObject searcher, List container, ICheck check) + : this(searcher.GetPhaseShift(), container, check) { } + } + + public class AreaTriggerWorker : WorldObjectWorkerBase + { + public AreaTriggerWorker(PhaseShift phaseShift, IDoWork work) + : base(phaseShift, work, GridMapTypeMask.AreaTrigger) { } + + public AreaTriggerWorker(WorldObject searcher, IDoWork work) + : this(searcher.GetPhaseShift(), work) { } + } + + // SceneObject searchers + + public class SceneObjectSearcherBase : WorldObjectSearcherBase + { + public SceneObjectSearcherBase(PhaseShift phaseShift, IResultInserter result, ICheck check) + : base(phaseShift, result, check, GridMapTypeMask.SceneObject) { } + } + + public class SceneObjectSearcher : SceneObjectSearcherBase + { + public SceneObjectSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherFirstObjectResult(), check) { } + + public SceneObjectSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class SceneObjectLastSearcher : SceneObjectSearcherBase + { + public SceneObjectLastSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherLastObjectResult(), check) { } + + public SceneObjectLastSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class SceneObjectListSearcher : SceneObjectSearcherBase + { + public SceneObjectListSearcher(PhaseShift phaseShift, List container, ICheck check) + : base(phaseShift, new SearcherContainerResult(container), check) { } + + public SceneObjectListSearcher(WorldObject searcher, List container, ICheck check) + : this(searcher.GetPhaseShift(), container, check) { } + } + + public class SceneObjectWorker : WorldObjectWorkerBase + { + public SceneObjectWorker(PhaseShift phaseShift, IDoWork work) + : base(phaseShift, work, GridMapTypeMask.SceneObject) { } + + public SceneObjectWorker(WorldObject searcher, IDoWork work) + : this(searcher.GetPhaseShift(), work) { } + } + + // Conversation searchers + + public class ConversationSearcherBase : WorldObjectSearcherBase + { + public ConversationSearcherBase(PhaseShift phaseShift, IResultInserter result, ICheck check) + : base(phaseShift, result, check, GridMapTypeMask.Conversation) { } + } + + public class ConversationSearcher : ConversationSearcherBase + { + public ConversationSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherFirstObjectResult(), check) { } + + public ConversationSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class ConversationLastSearcher : ConversationSearcherBase + { + public ConversationLastSearcher(PhaseShift phaseShift, ICheck check) + : base(phaseShift, new SearcherLastObjectResult(), check) { } + + public ConversationLastSearcher(WorldObject searcher, ICheck check) + : this(searcher.GetPhaseShift(), check) { } + } + + public class ConversationListSearcher : ConversationSearcherBase + { + public ConversationListSearcher(PhaseShift phaseShift, List container, ICheck check) + : base(phaseShift, new SearcherContainerResult(container), check) { } + + public ConversationListSearcher(WorldObject searcher, List container, ICheck check) + : this(searcher.GetPhaseShift(), container, check) { } + } + + public class ConversationWorker : WorldObjectWorkerBase + { + public ConversationWorker(PhaseShift phaseShift, IDoWork work) + : base(phaseShift, work, GridMapTypeMask.Conversation) { } + + public ConversationWorker(WorldObject searcher, IDoWork work) + : this(searcher.GetPhaseShift(), work) { } + } + + // CHECKS && DO classes + + // CHECK modifiers + public class InRangeCheckCustomizer + { + WorldObject i_obj; float i_range; - } - public class LocalizedDo : IDoWork - { - public LocalizedDo(MessageBuilder localizer) - { - _localizer = localizer; - } - - public void Invoke(Player player) - { - Locale loc_idx = player.GetSession().GetSessionDbLocaleIndex(); - int cache_idx = (int)loc_idx + 1; - IDoWork action; - - // create if not cached yet - if (_localizedCache.Length < cache_idx + 1 || _localizedCache[cache_idx] == null) - { - if (_localizedCache.Length < cache_idx + 1) - Array.Resize(ref _localizedCache, cache_idx + 1); - - action = _localizer.Invoke(loc_idx); - _localizedCache[cache_idx] = action; - } - else - action = _localizedCache[cache_idx]; - - action.Invoke(player); - } - - MessageBuilder _localizer; - IDoWork[] _localizedCache = new IDoWork[(int)Locale.Total]; // 0 = default, i => i-1 locale index - } - - public class RespawnDo : IDoWork - { - public void Invoke(WorldObject obj) - { - switch (obj.GetTypeId()) - { - case TypeId.Unit: - obj.ToCreature().Respawn(); - break; - case TypeId.GameObject: - obj.ToGameObject().Respawn(); - break; - } - } - } - - //Searchers - public class WorldObjectSearcher : Notifier - { - GridMapTypeMask i_mapTypeMask; - PhaseShift i_phaseShift; - WorldObject i_object; - ICheck i_check; - - public WorldObjectSearcher(WorldObject searcher, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) - { - i_mapTypeMask = mapTypeMask; - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.GameObject)) - return; - - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - GameObject gameObject = objs[i]; - if (!gameObject.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(gameObject)) - { - i_object = gameObject; - return; - } - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Player)) - return; - - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (!player.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(player)) - { - i_object = player; - return; - } - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Creature)) - return; - - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (!creature.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(creature)) - { - i_object = creature; - return; - } - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Corpse)) - return; - - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Corpse corpse = objs[i]; - if (!corpse.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(corpse)) - { - i_object = corpse; - return; - } - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.DynamicObject)) - return; - - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - DynamicObject dynamicObject = objs[i]; - if (!dynamicObject.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(dynamicObject)) - { - i_object = dynamicObject; - return; - } - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.AreaTrigger)) - return; - - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - AreaTrigger areaTrigger = objs[i]; - if (!areaTrigger.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(areaTrigger)) - { - i_object = areaTrigger; - return; - } - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.SceneObject)) - return; - - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - SceneObject sceneObject = objs[i]; - if (!sceneObject.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(sceneObject)) - { - i_object = sceneObject; - return; - } - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Conversation)) - return; - - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Conversation conversation = objs[i]; - if (!conversation.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(conversation)) - { - i_object = conversation; - return; - } - } - } - - public WorldObject GetTarget() { return i_object; } - } - - public class WorldObjectLastSearcher : Notifier - { - GridMapTypeMask i_mapTypeMask; - PhaseShift i_phaseShift; - WorldObject i_object; - ICheck i_check; - - public WorldObjectLastSearcher(WorldObject searcher, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) - { - i_mapTypeMask = mapTypeMask; - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.GameObject)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - GameObject gameObject = objs[i]; - if (!gameObject.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(gameObject)) - i_object = gameObject; - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Player)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (!player.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(player)) - i_object = player; - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Creature)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (!creature.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(creature)) - i_object = creature; - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Corpse)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Corpse corpse = objs[i]; - if (!corpse.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(corpse)) - i_object = corpse; - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.DynamicObject)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - DynamicObject dynamicObject = objs[i]; - if (!dynamicObject.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(dynamicObject)) - i_object = dynamicObject; - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.AreaTrigger)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - AreaTrigger areaTrigger = objs[i]; - if (!areaTrigger.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(areaTrigger)) - i_object = areaTrigger; - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.SceneObject)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - SceneObject sceneObject = objs[i]; - if (!sceneObject.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(sceneObject)) - i_object = sceneObject; - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Conversation)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Conversation conversation = objs[i]; - if (!conversation.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(conversation)) - i_object = conversation; - } - } - - public WorldObject GetTarget() { return i_object; } - } - - public class WorldObjectListSearcher : Notifier - { - GridMapTypeMask i_mapTypeMask; - List i_objects; - public PhaseShift i_phaseShift; - ICheck i_check; - - public WorldObjectListSearcher(WorldObject searcher, List objects, ICheck check, GridMapTypeMask mapTypeMask = GridMapTypeMask.All) - { - i_mapTypeMask = mapTypeMask; - i_phaseShift = searcher.GetPhaseShift(); - i_objects = objects; - i_check = check; - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Player)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (i_check.Invoke(player)) - i_objects.Add(player); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Creature)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (i_check.Invoke(creature)) - i_objects.Add(creature); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Corpse)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Corpse corpse = objs[i]; - if (i_check.Invoke(corpse)) - i_objects.Add(corpse); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.GameObject)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - GameObject gameObject = objs[i]; - if (i_check.Invoke(gameObject)) - i_objects.Add(gameObject); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.DynamicObject)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - DynamicObject dynamicObject = objs[i]; - if (i_check.Invoke(dynamicObject)) - i_objects.Add(dynamicObject); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.AreaTrigger)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - AreaTrigger areaTrigger = objs[i]; - if (i_check.Invoke(areaTrigger)) - i_objects.Add(areaTrigger); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Conversation)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - SceneObject sceneObject = objs[i]; - if (i_check.Invoke(sceneObject)) - i_objects.Add(sceneObject); - } - } - - public override void Visit(IList objs) - { - if (!i_mapTypeMask.HasAnyFlag(GridMapTypeMask.Conversation)) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Conversation conversation = objs[i]; - if (i_check.Invoke(conversation)) - i_objects.Add(conversation); - } - } - } - - public class GameObjectSearcher : Notifier - { - PhaseShift i_phaseShift; - GameObject i_object; - ICheck i_check; - - public GameObjectSearcher(WorldObject searcher, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - GameObject gameObject = objs[i]; - if (!gameObject.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(gameObject)) - { - i_object = gameObject; - return; - } - } - } - - public GameObject GetTarget() { return i_object; } - } - - public class GameObjectLastSearcher : Notifier - { - public PhaseShift i_phaseShift; - GameObject i_object; - ICheck i_check; - - public GameObjectLastSearcher(WorldObject searcher, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - GameObject gameObject = objs[i]; - if (!gameObject.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(gameObject)) - i_object = gameObject; - } - } - - public GameObject GetTarget() { return i_object; } - } - - public class GameObjectListSearcher : Notifier - { - public PhaseShift i_phaseShift; - List i_objects; - ICheck i_check; - - public GameObjectListSearcher(WorldObject searcher, List objects, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_objects = objects; - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - GameObject gameObject = objs[i]; - if (gameObject.InSamePhase(i_phaseShift)) - if (i_check.Invoke(gameObject)) - i_objects.Add(gameObject); - } - } - } - - public class UnitSearcher : Notifier - { - PhaseShift i_phaseShift; - Unit i_object; - ICheck i_check; - - public UnitSearcher(WorldObject searcher, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (!player.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(player)) - { - i_object = player; - return; - } - } - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (!creature.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(creature)) - { - i_object = creature; - return; - } - } - } - - public Unit GetTarget() { return i_object; } - } - - public class UnitLastSearcher : Notifier - { - PhaseShift i_phaseShift; - Unit i_object; - ICheck i_check; - - public UnitLastSearcher(WorldObject searcher, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (!player.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(player)) - i_object = player; - } - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (!creature.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(creature)) - i_object = creature; - } - } - - public Unit GetTarget() { return i_object; } - } - - public class UnitListSearcher : Notifier - { - public PhaseShift i_phaseShift; - List i_objects; - ICheck i_check; - - public UnitListSearcher(WorldObject searcher, List objects, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_objects = objects; - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (player.InSamePhase(i_phaseShift)) - if (i_check.Invoke(player)) - i_objects.Add(player); - } - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (creature.InSamePhase(i_phaseShift)) - if (i_check.Invoke(creature)) - i_objects.Add(creature); - } - } - } - - public class CreatureSearcher : Notifier - { - PhaseShift i_phaseShift; - Creature i_object; - ICheck i_check; - - public CreatureSearcher(WorldObject searcher, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (!creature.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(creature)) - { - i_object = creature; - return; - } - } - } - - public Creature GetTarget() { return i_object; } - } - - public class CreatureLastSearcher : Notifier - { - internal PhaseShift i_phaseShift; - Creature i_object; - ICheck i_check; - - public CreatureLastSearcher(WorldObject searcher, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (!creature.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(creature)) - i_object = creature; - } - } - - public Creature GetTarget() { return i_object; } - } - - public class CreatureListSearcher : Notifier - { - internal PhaseShift i_phaseShift; - List i_objects; - ICheck i_check; - - public CreatureListSearcher(WorldObject searcher, List objects, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_objects = objects; - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Creature creature = objs[i]; - if (creature.InSamePhase(i_phaseShift)) - if (i_check.Invoke(creature)) - i_objects.Add(creature); - } - } - } - - public class PlayerSearcher : Notifier - { - PhaseShift i_phaseShift; - Player i_object; - ICheck i_check; - - public PlayerSearcher(WorldObject searcher, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - // already found - if (i_object != null) - return; - - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (!player.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(player)) - { - i_object = player; - return; - } - } - } - - public Player GetTarget() { return i_object; } - } - - public class PlayerLastSearcher : Notifier - { - PhaseShift i_phaseShift; - Player i_object; - ICheck i_check; - - public PlayerLastSearcher(WorldObject searcher, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (!player.InSamePhase(i_phaseShift)) - continue; - - if (i_check.Invoke(player)) - i_object = player; - } - } - - public Player GetTarget() { return i_object; } - } - - public class PlayerListSearcher : Notifier - { - PhaseShift i_phaseShift; - List i_objects; - ICheck i_check; - - public PlayerListSearcher(WorldObject searcher, List objects, ICheck check) - { - i_phaseShift = searcher.GetPhaseShift(); - i_objects = objects; - i_check = check; - } - public PlayerListSearcher(PhaseShift phaseShift, List objects, ICheck check) - { - i_phaseShift = phaseShift; - i_objects = objects; - i_check = check; - } - - public override void Visit(IList objs) - { - for (var i = 0; i < objs.Count; ++i) - { - Player player = objs[i]; - if (player.InSamePhase(i_phaseShift)) - if (i_check.Invoke(player)) - i_objects.Add(player); - } - } - } - - //Checks - #region Checks - public class MostHPMissingInRange : ICheck where T : Unit - { - public MostHPMissingInRange(Unit obj, float range, uint hp) + public InRangeCheckCustomizer(WorldObject obj, float range) { i_obj = obj; i_range = range; - i_hp = hp; } - public bool Invoke(T u) + public virtual bool Test(WorldObject obj) { - if (u.IsAlive() && u.IsInCombat() && !i_obj.IsHostileTo(u) && i_obj.IsWithinDist(u, i_range) && u.GetMaxHealth() - u.GetHealth() > i_hp) + return i_obj.IsWithinDist(obj, i_range); + } + + public virtual void Update(WorldObject obj) { } + } + + public class NearestCheckCustomizer : InRangeCheckCustomizer + { + WorldObject i_obj; + float i_range; + + public NearestCheckCustomizer(WorldObject obj, float range) : base(obj, range) + { + i_obj = obj; + i_range = range; + } + + public override bool Test(WorldObject obj) + { + return i_obj.IsWithinDist(obj, i_range); + } + + public override void Update(WorldObject obj) + { + i_range = i_obj.GetDistance(obj); + } + } + + // WorldObject check classes + + public class AnyDeadUnitObjectInRangeCheck(WorldObject searchObj, float range) : ICheck where T : WorldObject + { + public virtual bool Invoke(T obj) + { + Player player = obj.ToPlayer(); + if (player != null) + return !player.IsAlive() && !player.HasAuraType(AuraType.Ghost) && searchObj.IsWithinDistInMap(player, range); + + Creature creature = obj.ToCreature(); + if (creature != null) + return !creature.IsAlive() && searchObj.IsWithinDistInMap(creature, range); + + Corpse corpse = obj.ToCorpse(); + if (corpse != null) + return corpse.GetCorpseType() != CorpseType.Bones && searchObj.IsWithinDistInMap(corpse, range); + + return false; + } + } + + public class AnyDeadUnitSpellTargetInRangeCheck : AnyDeadUnitObjectInRangeCheck where T : WorldObject + { + WorldObjectSpellTargetCheck i_check; + + public AnyDeadUnitSpellTargetInRangeCheck(WorldObject searchObj, float range, SpellInfo spellInfo, SpellTargetCheckTypes check, SpellTargetObjectTypes objectType) : base(searchObj, range) + { + i_check = new WorldObjectSpellTargetCheck(searchObj, searchObj, spellInfo, check, null, objectType); + } + + public override bool Invoke(T obj) + { + return base.Invoke(obj) && i_check.Invoke(obj); + } + } + + // WorldObject do classes + + public class RespawnDo + { + public void Invoke(Creature obj) + { + obj.Respawn(); + } + + public void Invoke(GameObject obj) + { + obj.Respawn(); + } + + public static implicit operator IDoWork(RespawnDo obj) => obj.Invoke; + public static implicit operator IDoWork(RespawnDo obj) => obj.Invoke; + } + + // GameObject checks + + class GameObjectFocusCheck(WorldObject caster, uint focusId) : ICheck + { + public bool Invoke(GameObject go) + { + if (go.GetGoInfo().GetSpellFocusType() != focusId) + return false; + + if (!go.IsSpawned()) + return false; + + float dist = go.GetGoInfo().GetSpellFocusRadius(); + return go.IsWithinDist(caster, dist); + } + } + + // Find the nearest Fishing hole and return true only if source object is in range of hole + class NearestGameObjectFishingHole(WorldObject obj, float range) : ICheck + { + public bool Invoke(GameObject go) + { + if (go.GetGoInfo().type == GameObjectTypes.FishingHole && go.IsSpawned() && obj.IsWithinDist(go, range) && obj.IsWithinDist(go, go.GetGoInfo().FishingHole.radius)) { - i_hp = (uint)(u.GetMaxHealth() - u.GetHealth()); + range = obj.GetDistance(go); return true; } return false; } - - Unit i_obj; - float i_range; - ulong i_hp; } - class MostHPPercentMissingInRange : ICheck + class NearestGameObjectCheck(WorldObject obj) : ICheck { - Unit _obj; - float _range; - float _minHpPct; - float _maxHpPct; - float _hpPct; + float i_range = 999f; - public MostHPPercentMissingInRange(Unit obj, float range, uint minHpPct, uint maxHpPct) + public bool Invoke(GameObject go) { - _obj = obj; - _range = range; - _minHpPct = minHpPct; - _maxHpPct = maxHpPct; - _hpPct = 101.0f; + if (obj.IsWithinDist(go, i_range)) + { + i_range = obj.GetDistance(go); // use found GO range as new range limit for next check + return true; + } + return false; } + } + + // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO) + class NearestGameObjectEntryInObjectRangeCheck(WorldObject obj, uint entry, float range, bool spawnedOnly = true) : ICheck + { + public bool Invoke(GameObject go) + { + if ((!spawnedOnly || go.IsSpawned()) && go.GetEntry() == entry && go.GetGUID() != obj.GetGUID() && obj.IsWithinDist(go, range)) + { + range = obj.GetDistance(go); // use found GO range as new range limit for next check + return true; + } + return false; + } + } + + // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest unspawned GO) + class NearestUnspawnedGameObjectEntryInObjectRangeCheck(WorldObject obj, uint entry, float range) : ICheck + { + public bool Invoke(GameObject go) + { + if (!go.IsSpawned() && go.GetEntry() == entry && go.GetGUID() != obj.GetGUID() && obj.IsWithinDist(go, range)) + { + range = obj.GetDistance(go); // use found GO range as new range limit for next check + return true; + } + return false; + } + } + + // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO with a certain type) + class NearestGameObjectTypeInObjectRangeCheck(WorldObject obj, GameObjectTypes type, float range) : ICheck + { + public bool Invoke(GameObject go) + { + if (go.GetGoType() == type && obj.IsWithinDist(go, range)) + { + range = obj.GetDistance(go); // use found GO range as new range limit for next check + return true; + } + return false; + } + } + + // Unit checks + + public class MostHPMissingInRange(Unit obj, float range, uint hp) : ICheck where T : Unit + { + public bool Invoke(T u) + { + if (u.IsAlive() && u.IsInCombat() && !obj.IsHostileTo(u) && obj.IsWithinDist(u, range) && u.GetMaxHealth() - u.GetHealth() > hp) + { + hp = (uint)(u.GetMaxHealth() - u.GetHealth()); + return true; + } + return false; + } + } + + class MostHPPercentMissingInRange(Unit obj, float range, uint minHpPct, uint maxHpPct) : ICheck + { + float _hpPct = 101.0f; public bool Invoke(Unit u) { - if (u.IsAlive() && u.IsInCombat() && !_obj.IsHostileTo(u) && _obj.IsWithinDist(u, _range) && _minHpPct <= u.GetHealthPct() && u.GetHealthPct() <= _maxHpPct && u.GetHealthPct() < _hpPct) + if (u.IsAlive() && u.IsInCombat() && !obj.IsHostileTo(u) && obj.IsWithinDist(u, range) && minHpPct <= u.GetHealthPct() && u.GetHealthPct() <= maxHpPct && u.GetHealthPct() < _hpPct) { _hpPct = u.GetHealthPct(); return true; @@ -1895,107 +1492,55 @@ namespace Game.Maps } } - public class FriendlyBelowHpPctEntryInRange : ICheck + public class FriendlyBelowHpPctEntryInRange(Unit obj, uint entry, float range, byte pct, bool excludeSelf) : ICheck { - public FriendlyBelowHpPctEntryInRange(Unit obj, uint entry, float range, byte pct, bool excludeSelf) - { - i_obj = obj; - i_entry = entry; - i_range = range; - i_pct = pct; - i_excludeSelf = excludeSelf; - } - public bool Invoke(Unit u) { - if (i_excludeSelf && i_obj.GetGUID() == u.GetGUID()) + if (excludeSelf && obj.GetGUID() == u.GetGUID()) return false; - if (u.GetEntry() == i_entry && u.IsAlive() && u.IsInCombat() && !i_obj.IsHostileTo(u) && i_obj.IsWithinDist(u, i_range) && u.HealthBelowPct(i_pct)) + + if (u.GetEntry() == entry && u.IsAlive() && u.IsInCombat() && !obj.IsHostileTo(u) && obj.IsWithinDist(u, range) && u.HealthBelowPct(pct)) return true; + return false; } - - Unit i_obj; - uint i_entry; - float i_range; - byte i_pct; - bool i_excludeSelf; } - public class FriendlyCCedInRange : ICheck + public class FriendlyCCedInRange(Unit obj, float range) : ICheck { - public FriendlyCCedInRange(Unit obj, float range) - { - i_obj = obj; - i_range = range; - } - public bool Invoke(Creature u) { - if (u.IsAlive() && u.IsInCombat() && !i_obj.IsHostileTo(u) && i_obj.IsWithinDist(u, i_range) && + if (u.IsAlive() && u.IsInCombat() && !obj.IsHostileTo(u) && obj.IsWithinDist(u, range) && (u.IsFeared() || u.IsCharmed() || u.HasRootAura() || u.HasUnitState(UnitState.Stunned) || u.HasUnitState(UnitState.Confused))) return true; return false; } - - Unit i_obj; - float i_range; } - public class FriendlyMissingBuffInRange : ICheck + public class FriendlyMissingBuffInRange(Unit obj, float range, uint spellid) : ICheck { - public FriendlyMissingBuffInRange(Unit obj, float range, uint spellid) - { - i_obj = obj; - i_range = range; - i_spell = spellid; - } - public bool Invoke(Creature u) { - if (u.IsAlive() && u.IsInCombat() && !i_obj.IsHostileTo(u) && i_obj.IsWithinDist(u, i_range) && - !(u.HasAura(i_spell))) - { + if (u.IsAlive() && u.IsInCombat() && !obj.IsHostileTo(u) && obj.IsWithinDist(u, range) && !u.HasAura(spellid)) return true; - } + return false; } - - Unit i_obj; - float i_range; - uint i_spell; } - public class AnyUnfriendlyUnitInObjectRangeCheck : ICheck + public class AnyUnfriendlyUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range) : ICheck { - public AnyUnfriendlyUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range) - { - i_obj = obj; - i_funit = funit; - i_range = range; - } - public bool Invoke(Unit u) { - if (u.IsAlive() && i_obj.IsWithinDist(u, i_range) && !i_funit.IsFriendlyTo(u)) + if (u.IsAlive() && obj.IsWithinDist(u, range) && !funit.IsFriendlyTo(u)) return true; - else - return false; - } - WorldObject i_obj; - Unit i_funit; - float i_range; + return false; + } } - public class NearestAttackableNoTotemUnitInObjectRangeCheck : ICheck + public class NearestAttackableNoTotemUnitInObjectRangeCheck(WorldObject obj, float range) : ICheck { - public NearestAttackableNoTotemUnitInObjectRangeCheck(WorldObject obj, float range) - { - i_obj = obj; - i_range = range; - } - public bool Invoke(Unit u) { if (!u.IsAlive()) @@ -2010,19 +1555,23 @@ namespace Game.Maps if (!u.IsTargetableForAttack(false)) return false; - if (!i_obj.IsWithinDist(u, i_range) || i_obj.IsValidAttackTarget(u)) + if (!obj.IsWithinDist(u, range) || obj.IsValidAttackTarget(u)) return false; - i_range = i_obj.GetDistance(u); + range = obj.GetDistance(u); return true; } - - WorldObject i_obj; - float i_range; } public class AnyFriendlyUnitInObjectRangeCheck : ICheck { + WorldObject i_obj; + Unit i_funit; + float i_range; + bool i_playerOnly; + bool i_incOwnRadius; + bool i_incTargetRadius; + public AnyFriendlyUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range, bool playerOnly = false, bool incOwnRadius = true, bool incTargetRadius = true) { i_obj = obj; @@ -2050,19 +1599,20 @@ namespace Game.Maps if (!i_funit.IsFriendlyTo(u)) return false; - return !i_playerOnly || u.GetTypeId() == TypeId.Player; + return !i_playerOnly || u.IsPlayer(); } - - WorldObject i_obj; - Unit i_funit; - float i_range; - bool i_playerOnly; - bool i_incOwnRadius; - bool i_incTargetRadius; } public class AnyGroupedUnitInObjectRangeCheck : ICheck { + WorldObject _source; + Unit _refUnit; + float _range; + bool _raid; + bool _playerOnly; + bool i_incOwnRadius; + bool i_incTargetRadius; + public AnyGroupedUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range, bool raid, bool playerOnly = false, bool incOwnRadius = true, bool incTargetRadius = true) { _source = obj; @@ -2101,18 +1651,15 @@ namespace Game.Maps return u.IsInMap(_source) && u.InSamePhase(_source) && u.IsWithinVerticalCylinder(_source, searchRadius, searchRadius, true); } - - WorldObject _source; - Unit _refUnit; - float _range; - bool _raid; - bool _playerOnly; - bool i_incOwnRadius; - bool i_incTargetRadius; } public class AnyUnitInObjectRangeCheck : ICheck { + WorldObject i_obj; + float i_range; + bool i_check3D; + bool i_reqAlive; + public AnyUnitInObjectRangeCheck(WorldObject obj, float range, bool check3D = true, bool reqAlive = true) { i_obj = obj; @@ -2131,42 +1678,33 @@ namespace Game.Maps return false; } - - WorldObject i_obj; - float i_range; - bool i_check3D; - bool i_reqAlive; } // Success at unit in range, range update for next check (this can be use with UnitLastSearcher to find nearest unit) - public class NearestAttackableUnitInObjectRangeCheck : ICheck + public class NearestAttackableUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range) : ICheck { - public NearestAttackableUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range) - { - i_obj = obj; - i_funit = funit; - i_range = range; - } - public bool Invoke(Unit u) { - if (u.IsTargetableForAttack() && i_obj.IsWithinDist(u, i_range) && - (i_funit.IsInCombatWith(u) || i_funit.IsHostileTo(u)) && i_obj.CanSeeOrDetect(u)) + if (u.IsTargetableForAttack() && obj.IsWithinDist(u, range) && + (funit.IsInCombatWith(u) || funit.IsHostileTo(u)) && obj.CanSeeOrDetect(u)) { - i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check + range = obj.GetDistance(u); // use found unit range as new range limit for next check return true; } return false; } - - WorldObject i_obj; - Unit i_funit; - float i_range; } public class AnyAoETargetUnitInObjectRangeCheck : ICheck { + WorldObject i_obj; + Unit i_funit; + SpellInfo _spellInfo; + float i_range; + bool i_incOwnRadius; + bool i_incTargetRadius; + public AnyAoETargetUnitInObjectRangeCheck(WorldObject obj, Unit funit, float range, SpellInfo spellInfo = null, bool incOwnRadius = true, bool incTargetRadius = true) { i_obj = obj; @@ -2208,13 +1746,31 @@ namespace Game.Maps return u.IsInMap(i_obj) && u.InSamePhase(i_obj) && u.IsWithinVerticalCylinder(i_obj, searchRadius, searchRadius, true); } + } - WorldObject i_obj; - Unit i_funit; - SpellInfo _spellInfo; - float i_range; - bool i_incOwnRadius; - bool i_incTargetRadius; + public class CallOfHelpCreatureInRangeDo(Unit funit, Unit enemy, float range) + { + public void Invoke(Creature u) + { + if (u == funit) + return; + + if (!u.CanAssistTo(funit, enemy, false)) + return; + + // too far + // Don't use combat reach distance, range must be an absolute value, otherwise the chain aggro range will be too big + if (!u.IsWithinDist(funit, range, true, false, false)) + return; + + // only if see assisted creature's enemy + if (!u.IsWithinLOSInMap(enemy)) + return; + + u.EngageWithTarget(enemy); + } + + public static implicit operator IDoWork(CallOfHelpCreatureInRangeDo obj) => obj.Invoke; } public class AnyDeadUnitCheck : ICheck @@ -2222,8 +1778,14 @@ namespace Game.Maps public bool Invoke(Unit u) { return !u.IsAlive(); } } + // Creature checks + public class NearestHostileUnitCheck : ICheck { + Creature me; + float m_range; + bool i_playerOnly; + public NearestHostileUnitCheck(Creature creature, float dist = 0, bool playerOnly = false) { me = creature; @@ -2240,20 +1802,20 @@ namespace Game.Maps if (!me.IsValidAttackTarget(u)) return false; - if (i_playerOnly && !u.IsTypeId(TypeId.Player)) + if (i_playerOnly && !u.IsPlayer()) return false; m_range = me.GetDistance(u); // use found unit range as new range limit for next check return true; } - - Creature me; - float m_range; - bool i_playerOnly; } class NearestHostileUnitInAttackDistanceCheck : ICheck { + Creature me; + float m_range; + bool m_force; + public NearestHostileUnitInAttackDistanceCheck(Creature creature, float dist = 0) { me = creature; @@ -2280,14 +1842,14 @@ namespace Game.Maps m_range = me.GetDistance(u); // use found unit range as new range limit for next check return true; } - - Creature me; - float m_range; - bool m_force; } class NearestHostileUnitInAggroRangeCheck : ICheck { + Creature _me; + bool _useLOS; + bool _ignoreCivilians; + public NearestHostileUnitInAggroRangeCheck(Creature creature, bool useLOS = false, bool ignoreCivilians = false) { _me = creature; @@ -2312,91 +1874,68 @@ namespace Game.Maps // pets in aggressive do not attack civilians if (_ignoreCivilians) { - Creature c = u.ToCreature(); - if (c != null) - if (c.IsCivilian()) - return false; + Creature creature = u.ToCreature(); + if (creature != null && creature.IsCivilian()) + return false; } return true; } - - Creature _me; - bool _useLOS; - bool _ignoreCivilians; } - class AnyAssistCreatureInRangeCheck : ICheck + class AnyAssistCreatureInRangeCheck(Unit funit, Unit enemy, float range) : ICheck { - public AnyAssistCreatureInRangeCheck(Unit funit, Unit enemy, float range) - { - i_funit = funit; - i_enemy = enemy; - i_range = range; - - } - public bool Invoke(Creature u) { - if (u == i_funit) + if (u == funit) return false; - if (!u.CanAssistTo(i_funit, i_enemy)) + if (!u.CanAssistTo(funit, enemy)) return false; // too far // Don't use combat reach distance, range must be an absolute value, otherwise the chain aggro range will be too big - if (!i_funit.IsWithinDist(u, i_range, true, false, false)) + if (!funit.IsWithinDist(u, range, true, false, false)) return false; // only if see assisted creature - if (!i_funit.IsWithinLOSInMap(u)) + if (!funit.IsWithinLOSInMap(u)) return false; return true; } - - Unit i_funit; - Unit i_enemy; - float i_range; } - class NearestAssistCreatureInCreatureRangeCheck : ICheck + class NearestAssistCreatureInCreatureRangeCheck(Creature obj, Unit enemy, float range) : ICheck { - public NearestAssistCreatureInCreatureRangeCheck(Creature obj, Unit enemy, float range) - { - i_obj = obj; - i_enemy = enemy; - i_range = range; - } - public bool Invoke(Creature u) { - if (u == i_obj) + if (u == obj) return false; - if (!u.CanAssistTo(i_obj, i_enemy)) + if (!u.CanAssistTo(obj, enemy)) return false; // Don't use combat reach distance, range must be an absolute value, otherwise the chain aggro range will be too big - if (!i_obj.IsWithinDist(u, i_range, true, false, false)) + if (!obj.IsWithinDist(u, range, true, false, false)) return false; - if (!i_obj.IsWithinLOSInMap(u)) + if (!obj.IsWithinLOSInMap(u)) return false; - i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check + range = obj.GetDistance(u); // use found unit range as new range limit for next check return true; } - - Creature i_obj; - Unit i_enemy; - float i_range; } // Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature) class NearestCreatureEntryWithLiveStateInObjectRangeCheck : ICheck { + WorldObject i_obj; + uint i_entry; + bool i_alive; + float i_range; + public NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject obj, uint entry, bool alive, float range) { i_obj = obj; @@ -2414,11 +1953,6 @@ namespace Game.Maps } return false; } - - WorldObject i_obj; - uint i_entry; - bool i_alive; - float i_range; } public class CreatureWithOptionsInObjectRangeCheck : ICheck where T : InRangeCheckCustomizer @@ -2562,150 +2096,94 @@ namespace Game.Maps } } - class AnyPlayerInPositionRangeCheck : ICheck + class AnyPlayerInPositionRangeCheck(Position pos, float range, bool reqAlive = true) : ICheck { - public AnyPlayerInPositionRangeCheck(Position pos, float range, bool reqAlive = true) - { - _pos = pos; - _range = range; - _reqAlive = reqAlive; - } - public bool Invoke(Player u) { - if (_reqAlive && !u.IsAlive()) + if (reqAlive && !u.IsAlive()) return false; - if (!u.IsWithinDist3d(_pos, _range)) + if (!u.IsWithinDist3d(pos, range)) return false; return true; } - - Position _pos; - float _range; - bool _reqAlive; } - class NearestPlayerInObjectRangeCheck : ICheck + class NearestPlayerInObjectRangeCheck(WorldObject obj, float range) : ICheck { - public NearestPlayerInObjectRangeCheck(WorldObject obj, float range) - { - i_obj = obj; - i_range = range; - - } - public bool Invoke(Player pl) { - if (pl.IsAlive() && i_obj.IsWithinDist(pl, i_range)) + if (pl.IsAlive() && obj.IsWithinDist(pl, range)) { - i_range = i_obj.GetDistance(pl); + range = obj.GetDistance(pl); return true; } return false; } - - WorldObject i_obj; - float i_range; } - class AllFriendlyCreaturesInGrid : ICheck + class AllFriendlyCreaturesInGrid(Unit obj) : ICheck { - public AllFriendlyCreaturesInGrid(Unit obj) - { - unit = obj; - } - public bool Invoke(Unit u) { - if (u.IsAlive() && u.IsVisible() && u.IsFriendlyTo(unit)) + if (u.IsAlive() && u.IsVisible() && u.IsFriendlyTo(obj)) return true; return false; } - - Unit unit; } - class AllGameObjectsWithEntryInRange : ICheck + class AllGameObjectsWithEntryInRange(WorldObject obj, uint entry, float maxRange) : ICheck { - public AllGameObjectsWithEntryInRange(WorldObject obj, uint entry, float maxRange) - { - m_pObject = obj; - m_uiEntry = entry; - m_fRange = maxRange; - } - public bool Invoke(GameObject go) { - if (m_uiEntry == 0 || go.GetEntry() == m_uiEntry && m_pObject.IsWithinDist(go, m_fRange, false)) + if (entry == 0 || go.GetEntry() == entry && obj.IsWithinDist(go, maxRange, false)) return true; return false; } - - WorldObject m_pObject; - uint m_uiEntry; - float m_fRange; } - public class AllCreaturesOfEntryInRange : ICheck + public class AllCreaturesOfEntryInRange(WorldObject obj, uint entry, float maxRange = 0f) : ICheck { - public AllCreaturesOfEntryInRange(WorldObject obj, uint entry, float maxRange = 0f) - { - m_pObject = obj; - m_uiEntry = entry; - m_fRange = maxRange; - } - public bool Invoke(Creature creature) { - if (m_uiEntry != 0) + if (entry != 0) { - if (creature.GetEntry() != m_uiEntry) + if (creature.GetEntry() != entry) return false; } - if (m_fRange != 0f) + if (maxRange != 0f) { - if (m_fRange > 0.0f && !m_pObject.IsWithinDist(creature, m_fRange, false)) + if (maxRange > 0.0f && !obj.IsWithinDist(creature, maxRange, false)) return false; - if (m_fRange < 0.0f && m_pObject.IsWithinDist(creature, m_fRange, false)) + if (maxRange < 0.0f && obj.IsWithinDist(creature, maxRange, false)) return false; } return true; } - - WorldObject m_pObject; - uint m_uiEntry; - float m_fRange; } - class PlayerAtMinimumRangeAway : ICheck + class PlayerAtMinimumRangeAway(Unit unit, float fMinRange) : ICheck { - public PlayerAtMinimumRangeAway(Unit _unit, float fMinRange) - { - unit = _unit; - fRange = fMinRange; - } - public bool Invoke(Player player) { //No threat list check, must be done explicit if expected to be in combat with creature - if (!player.IsGameMaster() && player.IsAlive() && !unit.IsWithinDist(player, fRange, false)) + if (!player.IsGameMaster() && player.IsAlive() && !unit.IsWithinDist(player, fMinRange, false)) return true; return false; } - - Unit unit; - float fRange; } class GameObjectInRangeCheck : ICheck { + float x, y, z, range; + uint entry; + public GameObjectInRangeCheck(float _x, float _y, float _z, float _range, uint _entry = 0) { x = _x; @@ -2719,373 +2197,114 @@ namespace Game.Maps { if (entry == 0 || (go.GetGoInfo() != null && go.GetGoInfo().entry == entry)) return go.IsInRange(x, y, z, range); - else return false; - } - float x, y, z, range; - uint entry; + return false; + } } - public class AllWorldObjectsInRange : ICheck + public class AllWorldObjectsInRange(WorldObject obj, float maxRange) : ICheck { - public AllWorldObjectsInRange(WorldObject obj, float maxRange) - { - m_pObject = obj; - m_fRange = maxRange; - } - public bool Invoke(WorldObject go) { - return m_pObject.IsWithinDist(go, m_fRange, false) && m_pObject.InSamePhase(go); + return obj.IsWithinDist(go, maxRange, false) && obj.InSamePhase(go); } - - WorldObject m_pObject; - float m_fRange; } - public class ObjectTypeIdCheck : ICheck + public class ObjectTypeIdCheck(TypeId typeId, bool equals) : ICheck { - public ObjectTypeIdCheck(TypeId typeId, bool equals) - { - _typeId = typeId; - _equals = equals; - } - public bool Invoke(WorldObject obj) { - return (obj.GetTypeId() == _typeId) == _equals; + return (obj.GetTypeId() == typeId) == equals; } - - TypeId _typeId; - bool _equals; } - public class ObjectGUIDCheck : ICheck + public class ObjectGUIDCheck(ObjectGuid Guid) : ICheck { - public ObjectGUIDCheck(ObjectGuid GUID) - { - _GUID = GUID; - } - public bool Invoke(WorldObject obj) { - return obj.GetGUID() == _GUID; + return obj.GetGUID() == Guid; } - public static implicit operator Predicate(ObjectGUIDCheck check) - { - return check.Invoke; - } - - ObjectGuid _GUID; + //public static implicit operator Predicate(ObjectGUIDCheck check) => check.Invoke; } - public class HeightDifferenceCheck : ICheck + public class HeightDifferenceCheck(WorldObject go, float diff, bool reverse) : ICheck { - public HeightDifferenceCheck(WorldObject go, float diff, bool reverse) - { - _baseObject = go; - _difference = diff; - _reverse = reverse; - - } - public bool Invoke(WorldObject unit) { - return (unit.GetPositionZ() - _baseObject.GetPositionZ() > _difference) != _reverse; + return (unit.GetPositionZ() - go.GetPositionZ() > diff) != reverse; } - - WorldObject _baseObject; - float _difference; - bool _reverse; } - public class UnitAuraCheck : ICheck + public class UnitAuraCheck(bool present, uint spellId, ObjectGuid casterGUID = default) : ICheck { - public UnitAuraCheck(bool present, uint spellId, ObjectGuid casterGUID = default) - { - _present = present; - _spellId = spellId; - _casterGUID = casterGUID; - } - public bool Invoke(WorldObject obj) { - return obj.ToUnit() != null && obj.ToUnit().HasAura(_spellId, _casterGUID) == _present; + return obj.ToUnit() != null && obj.ToUnit().HasAura(spellId, casterGUID) == present; } - public static implicit operator Predicate(UnitAuraCheck unit) - { - return unit.Invoke; - } - - bool _present; - uint _spellId; - ObjectGuid _casterGUID; + //public static implicit operator Predicate(UnitAuraCheck unit) => unit.Invoke; } - class ObjectEntryAndPrivateOwnerIfExistsCheck : ICheck + class ObjectEntryAndPrivateOwnerIfExistsCheck(ObjectGuid ownerGUID, uint entry) : ICheck { - ObjectGuid _ownerGUID; - uint _entry; - - public ObjectEntryAndPrivateOwnerIfExistsCheck(ObjectGuid ownerGUID, uint entry) - { - _ownerGUID = ownerGUID; - _entry = entry; - } - public bool Invoke(WorldObject obj) { - return obj.GetEntry() == _entry && (!obj.IsPrivateObject() || obj.GetPrivateObjectOwner() == _ownerGUID); + return obj.GetEntry() == entry && (!obj.IsPrivateObject() || obj.GetPrivateObjectOwner() == ownerGUID); } } - class GameObjectFocusCheck : ICheck - { - public GameObjectFocusCheck(WorldObject caster, uint focusId) - { - _caster = caster; - _focusId = focusId; - } - - public bool Invoke(GameObject go) - { - if (go.GetGoInfo().GetSpellFocusType() != _focusId) - return false; - - if (!go.IsSpawned()) - return false; - - float dist = go.GetGoInfo().GetSpellFocusRadius(); - return go.IsWithinDist(_caster, dist); - } - - WorldObject _caster; - uint _focusId; - } - - // Find the nearest Fishing hole and return true only if source object is in range of hole - class NearestGameObjectFishingHole : ICheck - { - public NearestGameObjectFishingHole(WorldObject obj, float range) - { - i_obj = obj; - i_range = range; - } - - public bool Invoke(GameObject go) - { - if (go.GetGoInfo().type == GameObjectTypes.FishingHole && go.IsSpawned() && i_obj.IsWithinDist(go, i_range) && i_obj.IsWithinDist(go, go.GetGoInfo().FishingHole.radius)) - { - i_range = i_obj.GetDistance(go); - return true; - } - return false; - } - - WorldObject i_obj; - float i_range; - } - - class NearestGameObjectCheck : ICheck - { - public NearestGameObjectCheck(WorldObject obj) - { - i_obj = obj; - i_range = 999; - } - - public bool Invoke(GameObject go) - { - if (i_obj.IsWithinDist(go, i_range)) - { - i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check - return true; - } - return false; - } - - WorldObject i_obj; - float i_range; - } - - // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO) - class NearestGameObjectEntryInObjectRangeCheck : ICheck - { - public NearestGameObjectEntryInObjectRangeCheck(WorldObject obj, uint entry, float range, bool spawnedOnly = true) - { - _obj = obj; - _entry = entry; - _range = range; - _spawnedOnly = spawnedOnly; - } - - public bool Invoke(GameObject go) - { - if ((!_spawnedOnly || go.IsSpawned()) && go.GetEntry() == _entry && go.GetGUID() != _obj.GetGUID() && _obj.IsWithinDist(go, _range)) - { - _range = _obj.GetDistance(go); // use found GO range as new range limit for next check - return true; - } - return false; - } - - WorldObject _obj; - uint _entry; - float _range; - bool _spawnedOnly; - } - - // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest unspawned GO) - class NearestUnspawnedGameObjectEntryInObjectRangeCheck : ICheck + class NearestAreaTriggerEntryInObjectRangeCheck : ICheck { WorldObject i_obj; uint i_entry; float i_range; + bool i_spawnedOnly; - public NearestUnspawnedGameObjectEntryInObjectRangeCheck(WorldObject obj, uint entry, float range) + public NearestAreaTriggerEntryInObjectRangeCheck(WorldObject obj, uint entry, float range, bool spawnedOnly = false) { i_obj = obj; i_entry = entry; i_range = range; + i_spawnedOnly = spawnedOnly; } - public bool Invoke(GameObject go) + public bool Invoke(AreaTrigger at) { - if (!go.IsSpawned() && go.GetEntry() == i_entry && go.GetGUID() != i_obj.GetGUID() && i_obj.IsWithinDist(go, i_range)) + if ((!i_spawnedOnly || at.IsStaticSpawn()) && at.GetEntry() == i_entry && at.GetGUID() != i_obj.GetGUID() && i_obj.IsWithinDist(at, i_range)) { - i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check + i_range = i_obj.GetDistance(at); return true; } return false; } } - // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO with a certain type) - class NearestGameObjectTypeInObjectRangeCheck : ICheck + public class LocalizedDo(MessageBuilder localizer) { - public NearestGameObjectTypeInObjectRangeCheck(WorldObject obj, GameObjectTypes type, float range) - { - i_obj = obj; - i_type = type; - i_range = range; - } + IDoWork[] _localizedCache = new IDoWork[(int)Locale.Total]; // 0 = default, i => i-1 locale index - public bool Invoke(GameObject go) + public void Invoke(Player player) { - if (go.GetGoType() == i_type && i_obj.IsWithinDist(go, i_range)) + Locale loc_idx = player.GetSession().GetSessionDbLocaleIndex(); + int cache_idx = (int)loc_idx + 1; + IDoWork action; + + // create if not cached yet + if (_localizedCache.Length < cache_idx + 1 || _localizedCache[cache_idx] == null) { - i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check - return true; + if (_localizedCache.Length < cache_idx + 1) + Array.Resize(ref _localizedCache, cache_idx + 1); + + action = localizer.Invoke(loc_idx); + _localizedCache[cache_idx] = action; } - return false; + else + action = _localizedCache[cache_idx]; + + action.Invoke(player); } - WorldObject i_obj; - GameObjectTypes i_type; - float i_range; + public static implicit operator IDoWork(LocalizedDo obj) => obj.Invoke; } - - // CHECK modifiers - public class InRangeCheckCustomizer - { - WorldObject _obj; - float _range; - - public InRangeCheckCustomizer(WorldObject obj, float range) - { - _obj = obj; - _range = range; - } - - public virtual bool Test(WorldObject obj) - { - return _obj.IsWithinDist(obj, _range); - } - - public virtual void Update(WorldObject o) { } - } - - class NearestCheckCustomizer : InRangeCheckCustomizer - { - WorldObject i_obj; - float i_range; - - public NearestCheckCustomizer(WorldObject obj, float range) : base(obj, range) - { - i_obj = obj; - i_range = range; - } - - public override bool Test(WorldObject obj) - { - return i_obj.IsWithinDist(obj, i_range); - } - - public override void Update(WorldObject obj) - { - i_range = i_obj.GetDistance(obj); - } - } - - public class AnyDeadUnitObjectInRangeCheck : ICheck where T : WorldObject - { - public AnyDeadUnitObjectInRangeCheck(WorldObject searchObj, float range) - { - i_searchObj = searchObj; - i_range = range; - } - - public virtual bool Invoke(T obj) - { - Player player = obj.ToPlayer(); - if (player != null) - return !player.IsAlive() && !player.HasAuraType(AuraType.Ghost) && i_searchObj.IsWithinDistInMap(player, i_range); - - Creature creature = obj.ToCreature(); - if (creature != null) - return !creature.IsAlive() && i_searchObj.IsWithinDistInMap(creature, i_range); - - Corpse corpse = obj.ToCorpse(); - if (corpse != null) - return corpse.GetCorpseType() != CorpseType.Bones && i_searchObj.IsWithinDistInMap(corpse, i_range); - - return false; - } - - WorldObject i_searchObj; - float i_range; - } - - public class AnyDeadUnitSpellTargetInRangeCheck : AnyDeadUnitObjectInRangeCheck where T : WorldObject - { - public AnyDeadUnitSpellTargetInRangeCheck(WorldObject searchObj, float range, SpellInfo spellInfo, SpellTargetCheckTypes check, SpellTargetObjectTypes objectType) : base(searchObj, range) - { - i_check = new WorldObjectSpellTargetCheck(searchObj, searchObj, spellInfo, check, null, objectType); - } - - public override bool Invoke(T obj) - { - return base.Invoke(obj) && i_check.Invoke(obj); - } - - WorldObjectSpellTargetCheck i_check; - } - - public class PlayerOrPetCheck : ICheck - { - public bool Invoke(WorldObject obj) - { - if (obj.IsTypeId(TypeId.Player)) - return false; - - Creature creature = obj.ToCreature(); - if (creature != null) - return !creature.IsPet(); - - return true; - } - } - #endregion } \ No newline at end of file diff --git a/Source/Game/Maps/Map.cs b/Source/Game/Maps/Map.cs index 80b6288b0..e5843f7da 100644 --- a/Source/Game/Maps/Map.cs +++ b/Source/Game/Maps/Map.cs @@ -601,7 +601,7 @@ namespace Game.Maps // update active cells around players and active objects ResetMarkedCells(); - var update = new UpdaterNotifier(diff); + var update = new ObjectUpdater(diff); var grid_object_update = new Visitor(update, GridMapTypeMask.AllGrid); var world_object_update = new Visitor(update, GridMapTypeMask.AllWorld); diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index a8bbd0b41..023d6983d 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -2860,8 +2860,7 @@ namespace Game.Spells if (containerTypeMask != 0) { WorldObjectSpellAreaTargetCheck check = new(radius, unitOwner, refe, unitOwner, GetSpellInfo(), selectionType, condList, SpellTargetObjectTypes.Unit); - UnitListSearcher searcher = new(unitOwner, units, check); - searcher.i_phaseShift = PhasingHandler.GetAlwaysVisiblePhaseShift(); + UnitListSearcher searcher = new(PhasingHandler.GetAlwaysVisiblePhaseShift(), units, check); Spell.SearchTargets(searcher, containerTypeMask, unitOwner, unitOwner, radius + extraSearchRadius); // by design WorldObjectSpellAreaTargetCheck allows not-in-world units (for spells) but for auras it is not acceptable diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 0b4a8fde7..cd628cd40 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -1747,9 +1747,9 @@ namespace Game.Spells return null; var check = new WorldObjectSpellNearbyTargetCheck(range, m_caster, m_spellInfo, selectionType, condList, objectType); - var searcher = new WorldObjectLastSearcher(m_caster, check, containerTypeMask); + var searcher = new WorldObjectLastSearcher(PhasingHandler.GetAlwaysVisiblePhaseShift(), check, containerTypeMask); SearchTargets(searcher, containerTypeMask, m_caster, m_caster.GetPosition(), range); - return searcher.GetTarget(); + return searcher.GetResult(); } void SearchAreaTargets(List targets, SpellEffectInfo spellEffectInfo, float range, Position position, WorldObject referer, @@ -1761,7 +1761,7 @@ namespace Game.Spells float extraSearchRadius = range > 0.0f ? SharedConst.ExtraCellSearchRadius : 0.0f; var check = new WorldObjectSpellAreaTargetCheck(range, position, m_caster, referer, m_spellInfo, selectionType, condList, objectType, searchReason); - var searcher = new WorldObjectListSearcher(m_caster, targets, check, containerTypeMask); + var searcher = new WorldObjectListSearcher(PhasingHandler.GetAlwaysVisiblePhaseShift(), targets, check, containerTypeMask); SearchTargets(searcher, containerTypeMask, m_caster, position, range + extraSearchRadius); } @@ -1870,7 +1870,7 @@ namespace Game.Spells var check = new GameObjectFocusCheck(m_caster, m_spellInfo.RequiresSpellFocus); var searcher = new GameObjectSearcher(m_caster, check); SearchTargets(searcher, GridMapTypeMask.GameObject, m_caster, m_caster, m_caster.GetVisibilityRange()); - return searcher.GetTarget(); + return searcher.GetResult(); } void PrepareDataForTriggerSystem() diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 3e607be63..b0db3968b 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -5239,17 +5239,15 @@ namespace Game.Spells if (unitTarget == null) return; - List objs = new(); - ObjectEntryAndPrivateOwnerIfExistsCheck check = new(unitTarget.GetGUID(), (uint)effectInfo.MiscValue); - WorldObjectListSearcher checker = new(unitTarget, objs, check, GridMapTypeMask.Conversation); - Cell.VisitGridObjects(unitTarget, checker, 100.0f); - - foreach (WorldObject obj in objs) + var check = new ObjectEntryAndPrivateOwnerIfExistsCheck(unitTarget.GetGUID(), (uint)effectInfo.MiscValue); + IDoWork work = conversation => { - Conversation convo = obj.ToConversation(); - if (convo != null) - convo.Remove(); - } + if (check.Invoke(conversation)) + conversation.Remove(); + }; + + ConversationWorker worker = new(unitTarget, work); + Cell.VisitGridObjects(unitTarget, worker, 100.0f); } [SpellEffectHandler(SpellEffectName.AddGarrisonFollower)] diff --git a/Source/Game/Text/ChatTextBuilder.cs b/Source/Game/Text/ChatTextBuilder.cs index 3849ff870..a8f71953a 100644 --- a/Source/Game/Text/ChatTextBuilder.cs +++ b/Source/Game/Text/ChatTextBuilder.cs @@ -7,6 +7,7 @@ using Game.DataStorage; using Game.Entities; using Game.Networking; using Game.Networking.Packets; +using System; using System.Collections.Generic; namespace Game.Chat @@ -16,7 +17,7 @@ namespace Game.Chat public virtual dynamic Invoke(Locale locale = Locale.enUS) { return default; } } - public class ChatPacketSender : IDoWork + public class ChatPacketSender { ChatMsg Type; Language Language; @@ -72,6 +73,8 @@ namespace Game.Chat } } + public static implicit operator IDoWork(ChatPacketSender obj) => obj.Invoke; + public void Invoke(Player player) { if (!player.MeetPlayerCondition(PlayerConditionID)) diff --git a/Source/Game/Text/CreatureTextManager.cs b/Source/Game/Text/CreatureTextManager.cs index db7953a45..e5b4805e2 100644 --- a/Source/Game/Text/CreatureTextManager.cs +++ b/Source/Game/Text/CreatureTextManager.cs @@ -447,8 +447,12 @@ namespace Game Max = 2, } - public class CreatureTextLocalizer : IDoWork + public class CreatureTextLocalizer { + Dictionary _packetCache = new(); + MessageBuilder _builder; + ChatMsg _msgType; + public CreatureTextLocalizer(MessageBuilder builder, ChatMsg msgType) { _builder = builder; @@ -484,9 +488,7 @@ namespace Game sender.Invoke(player); } - Dictionary _packetCache = new(); - MessageBuilder _builder; - ChatMsg _msgType; + public static implicit operator IDoWork(CreatureTextLocalizer obj) => obj.Invoke; } public class CreatureTextBuilder : MessageBuilder diff --git a/Source/Game/World/WorldManager.cs b/Source/Game/World/WorldManager.cs index d846cb3cb..8ea37b58f 100644 --- a/Source/Game/World/WorldManager.cs +++ b/Source/Game/World/WorldManager.cs @@ -2728,15 +2728,17 @@ namespace Game uint i_textId; object[] i_args; - public class MultiplePacketSender : IDoWork + public class MultiplePacketSender { + public List Packets = new(); + public void Invoke(Player receiver) { foreach (var packet in Packets) receiver.SendPacket(packet); } - public List Packets = new(); + public static implicit operator IDoWork(MultiplePacketSender obj) => obj.Invoke; } } diff --git a/Source/Scripts/Spells/Generic.cs b/Source/Scripts/Spells/Generic.cs index 32e693bf6..241066140 100644 --- a/Source/Scripts/Spells/Generic.cs +++ b/Source/Scripts/Spells/Generic.cs @@ -678,9 +678,9 @@ namespace Scripts.Spells.Generic AnyDeadUnitSpellTargetInRangeCheck check = new(caster, max_range, GetSpellInfo(), SpellTargetCheckTypes.Enemy, SpellTargetObjectTypes.CorpseEnemy); WorldObjectSearcher searcher = new(caster, check); Cell.VisitWorldObjects(caster, searcher, max_range); - if (searcher.GetTarget() == null) + if (searcher.GetResult() == null) Cell.VisitGridObjects(caster, searcher, max_range); - if (searcher.GetTarget() == null) + if (searcher.GetResult() == null) return SpellCastResult.NoEdibleCorpses; return SpellCastResult.SpellCastOk; }