From 64ab9870b3503316b6963adb58d898c40574b750 Mon Sep 17 00:00:00 2001 From: milimoe <110188673+milimoe@users.noreply.github.com> Date: Wed, 15 Apr 2026 00:12:32 +0800 Subject: [PATCH] =?UTF-8?q?SelectTargets=20=E5=B0=86=E6=89=80=E6=9C=89?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=88=97=E8=A1=A8=E4=BC=A0=E5=85=A5=20(#154)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Controller/AIController.cs | 10 ++--- Entity/Skill/Effect.cs | 4 +- Entity/Skill/NormalAttack.cs | 10 +++-- Entity/Skill/Skill.cs | 39 ++++++++++++----- Interface/Base/IGamingQueue.cs | 8 +++- Interface/Entity/Typical/ISkill.cs | 4 +- .../Common/Addon/Example/ExampleGameModule.cs | 12 +++--- Model/GamingQueue.cs | 43 +++++++++++-------- 8 files changed, 83 insertions(+), 47 deletions(-) diff --git a/Controller/AIController.cs b/Controller/AIController.cs index c58000c..03e794e 100644 --- a/Controller/AIController.cs +++ b/Controller/AIController.cs @@ -162,7 +162,7 @@ namespace Milimoe.FunGame.Core.Controller if (normalAttackReachableEnemys.Count > 0) { - List targets = SelectTargets(character, character.NormalAttack, normalAttackReachableEnemys, []); + List targets = SelectTargets(character, character.NormalAttack, allEnemysInGame, allTeammatesInGame, normalAttackReachableEnemys, []); if (targets.Count > 0) { double currentScore = EvaluateNormalAttack(character, targets) - movePenalty; @@ -223,7 +223,7 @@ namespace Milimoe.FunGame.Core.Controller if (skillReachableEnemys.Count > 0 || skillReachableTeammates.Count > 0) { - List targets = SelectTargets(character, skill, skillReachableEnemys, skillReachableTeammates); + List targets = SelectTargets(character, skill, allEnemysInGame, allTeammatesInGame, skillReachableEnemys, skillReachableTeammates); if (targets.Count > 0) { double currentScore = EvaluateSkill(character, skill, targets, cost) - movePenalty; @@ -288,7 +288,7 @@ namespace Milimoe.FunGame.Core.Controller if (itemSkillReachableEnemys.Count > 0 || itemSkillReachableTeammates.Count > 0) { - List targetsForItem = SelectTargets(character, itemSkill, itemSkillReachableEnemys, itemSkillReachableTeammates); + List targetsForItem = SelectTargets(character, itemSkill, allEnemysInGame, allTeammatesInGame, itemSkillReachableEnemys, itemSkillReachableTeammates); if (targetsForItem.Count > 0) { double currentScore = EvaluateItem(character, item, targetsForItem, cost) - movePenalty; @@ -484,9 +484,9 @@ namespace Milimoe.FunGame.Core.Controller } // 选择技能的最佳目标 - private static List SelectTargets(Character character, ISkill skill, List enemys, List teammates) + private static List SelectTargets(Character character, ISkill skill, List allEnemys, List allTeammates, List enemys, List teammates) { - List targets = skill.GetSelectableTargets(character, enemys, teammates); + List targets = skill.GetSelectableTargets(character, allEnemys, allTeammates, enemys, teammates); int count = skill.RealCanSelectTargetCount(enemys, teammates); return [.. targets.OrderBy(o => Random.Shared.Next()).Take(count)]; } diff --git a/Entity/Skill/Effect.cs b/Entity/Skill/Effect.cs index 9789a2c..776b836 100644 --- a/Entity/Skill/Effect.cs +++ b/Entity/Skill/Effect.cs @@ -714,9 +714,11 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// + /// + /// /// /// - public virtual void AlterSelectListBeforeSelection(Character character, ISkill skill, List enemys, List teammates) + public virtual void AlterSelectListBeforeSelection(Character character, ISkill skill, List allEnemys, List allTeammates, List enemys, List teammates) { } diff --git a/Entity/Skill/NormalAttack.cs b/Entity/Skill/NormalAttack.cs index fd306fa..b6d79e8 100644 --- a/Entity/Skill/NormalAttack.cs +++ b/Entity/Skill/NormalAttack.cs @@ -248,10 +248,12 @@ namespace Milimoe.FunGame.Core.Entity /// 获取可选择的目标列表 /// /// + /// + /// /// /// /// - public List GetSelectableTargets(Character attacker, List enemys, List teammates) + public List GetSelectableTargets(Character attacker, List allEnemys, List allTeammates, List enemys, List teammates) { List selectable = []; @@ -300,12 +302,14 @@ namespace Milimoe.FunGame.Core.Entity /// 选取普攻目标 /// /// + /// + /// /// /// /// - public List SelectTargets(Character attacker, List enemys, List teammates) + public List SelectTargets(Character attacker, List allEnemys, List allTeammates, List enemys, List teammates) { - List tobeSelected = GetSelectableTargets(attacker, enemys, teammates); + List tobeSelected = GetSelectableTargets(attacker, allEnemys, allTeammates, enemys, teammates); List targets = []; diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs index f914cb8..b49ea7c 100644 --- a/Entity/Skill/Skill.cs +++ b/Entity/Skill/Skill.cs @@ -180,7 +180,7 @@ namespace Milimoe.FunGame.Core.Entity public virtual bool AllowSelectNoCharacterGrid { get; set; } = false; /// - /// 是否可以选择已死亡的角色。仅 = true 时有效。 + /// 是否可以选择已死亡的角色 /// public virtual bool AllowSelectDead { get; set; } = false; @@ -485,10 +485,12 @@ namespace Milimoe.FunGame.Core.Entity /// 获取可选择的目标列表 /// /// + /// + /// /// /// /// - public virtual List GetSelectableTargets(Character caster, List enemys, List teammates) + public virtual List GetSelectableTargets(Character caster, List allEnemys, List allTeammates, List enemys, List teammates) { List selectable = []; @@ -503,22 +505,35 @@ namespace Milimoe.FunGame.Core.Entity checkType |= ImmuneType.Magical; } - foreach (Character character in enemys) + if (CanSelectEnemy) { - IEnumerable effects = Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority); - if (CanSelectEnemy && ((character.ImmuneType & checkType) == ImmuneType.None || - effects.Any(e => e.IgnoreImmune == ImmuneType.All || e.IgnoreImmune == ImmuneType.Skilled || (IsMagic && e.IgnoreImmune == ImmuneType.Magical)))) + foreach (Character character in enemys) { - selectable.Add(character); + IEnumerable effects = Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority); + if ((character.ImmuneType & checkType) == ImmuneType.None || + effects.Any(e => e.IgnoreImmune == ImmuneType.All || e.IgnoreImmune == ImmuneType.Skilled || (IsMagic && e.IgnoreImmune == ImmuneType.Magical))) + { + selectable.Add(character); + } + } + + if (AllowSelectDead) + { + selectable.AddRange(allEnemys.Where(c => c.HP == 0)); } } - foreach (Character character in teammates) + if (CanSelectTeammate) { - if (CanSelectTeammate) + foreach (Character character in teammates) { selectable.Add(character); } + + if (AllowSelectDead) + { + selectable.AddRange(allTeammates.Where(c => c.HP == 0)); + } } // 其他条件 @@ -548,12 +563,14 @@ namespace Milimoe.FunGame.Core.Entity /// 选取技能目标 /// /// + /// + /// /// /// /// - public virtual List SelectTargets(Character caster, List enemys, List teammates) + public virtual List SelectTargets(Character caster, List allEnemys, List allTeammates, List enemys, List teammates) { - List tobeSelected = GetSelectableTargets(caster, enemys, teammates); + List tobeSelected = GetSelectableTargets(caster, allEnemys, allTeammates, enemys, teammates); List targets = []; diff --git a/Interface/Base/IGamingQueue.cs b/Interface/Base/IGamingQueue.cs index d104b1c..076bfae 100644 --- a/Interface/Base/IGamingQueue.cs +++ b/Interface/Base/IGamingQueue.cs @@ -205,22 +205,26 @@ namespace Milimoe.FunGame.Core.Interface.Base /// /// /// + /// + /// /// /// /// /// - public List SelectTargets(Character caster, Skill skill, List enemys, List teammates, List castRange); + public List SelectTargets(Character caster, Skill skill, List allEnemys, List allTeammates, List enemys, List teammates, List castRange); /// /// 选取普通攻击目标 /// /// /// + /// + /// /// /// /// /// - public List SelectTargets(Character character, NormalAttack attack, List enemys, List teammates, List attackRange); + public List SelectTargets(Character character, NormalAttack attack, List allEnemys, List allTeammates, List enemys, List teammates, List attackRange); /// /// 获取某角色的敌人列表 diff --git a/Interface/Entity/Typical/ISkill.cs b/Interface/Entity/Typical/ISkill.cs index cfea5ff..353fd4b 100644 --- a/Interface/Entity/Typical/ISkill.cs +++ b/Interface/Entity/Typical/ISkill.cs @@ -112,10 +112,12 @@ namespace Milimoe.FunGame.Core.Interface.Entity /// 获取可选择的目标列表 /// /// + /// + /// /// /// /// - public List GetSelectableTargets(Character caster, List enemys, List teammates); + public List GetSelectableTargets(Character caster, List allEnemys, List allTeammates, List enemys, List teammates); /// /// 实际可选取的目标数量 diff --git a/Library/Common/Addon/Example/ExampleGameModule.cs b/Library/Common/Addon/Example/ExampleGameModule.cs index defc09f..3e9f8be 100644 --- a/Library/Common/Addon/Example/ExampleGameModule.cs +++ b/Library/Common/Addon/Example/ExampleGameModule.cs @@ -392,10 +392,10 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example //queue.TurnEndEvent += Queue_TurnEndEvent; // 我们示范两个事件,一是选择技能目标,需要和客户端交互的事件 - queue.SelectSkillTargetsEvent += (queue, caster, skill, enemys, teammates, castRange) => + queue.SelectSkillTargetsEvent += (queue, caster, skill, allEnemys, allTeammates, enemys, teammates, castRange) => { /// 如果你的逻辑都写在 里就不用这么麻烦每次都传 obj 和 worker 了。 - return Queue_SelectSkillTargetsEvent(worker, caster, skill, enemys, teammates, castRange); + return Queue_SelectSkillTargetsEvent(worker, caster, skill, allEnemys, allTeammates, enemys, teammates, castRange); }; // 二是角色行动完毕,需要通知客户端更新状态的事件 @@ -511,21 +511,23 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example }); } - private List Queue_SelectSkillTargetsEvent(ModuleServerWorker worker, Character caster, Skill skill, List enemys, List teammates, List castRange) + private List Queue_SelectSkillTargetsEvent(ModuleServerWorker worker, Character caster, Skill skill, List allEnemys, List allTeammates, List enemys, List teammates, List castRange) { // 这是一个需要与客户端交互的事件,其他的选择事件与之做法相同 // SyncAwaiter是一个允许同步方法安全等待异步任务完成的工具类 - return SyncAwaiter.WaitResult(RequestClientSelectSkillTargets(worker, caster, skill, enemys, teammates, castRange)); + return SyncAwaiter.WaitResult(RequestClientSelectSkillTargets(worker, caster, skill, allEnemys, allTeammates, enemys, teammates, castRange)); } - private async Task> RequestClientSelectSkillTargets(ModuleServerWorker worker, Character caster, Skill skill, List enemys, List teammates, List castRange) + private async Task> RequestClientSelectSkillTargets(ModuleServerWorker worker, Character caster, Skill skill, List allEnemys, List allTeammates, List enemys, List teammates, List castRange) { List selectTargets = []; Dictionary data = []; data.Add("event", "SelectSkillTargets"); data.Add("caster", caster.Id); data.Add("skill", skill.Id); + data.Add("allenemys", allEnemys.Select(c => c.Id)); data.Add("enemys", enemys.Select(c => c.Id)); + data.Add("allteammates", allTeammates.Select(c => c.Id)); data.Add("teammates", teammates.Select(c => c.Id)); data.Add("castRange", castRange.Select(g => g.Id)); await SendGamingMessage(_clientModels, GamingType.Skill, data); diff --git a/Model/GamingQueue.cs b/Model/GamingQueue.cs index 8ab4a1a..f68bd90 100644 --- a/Model/GamingQueue.cs +++ b/Model/GamingQueue.cs @@ -1270,9 +1270,6 @@ namespace Milimoe.FunGame.Core.Model // 启用战棋地图时的专属 AI 决策方法 if (isAI && ai != null && startGrid != null) { - List allEnemysInGame = [.. allEnemys.Where(canAttackGridsByStartGrid.Union(canCastGridsByStartGrid).SelectMany(g => g.Characters).Contains)]; - List allTeammatesInGame = [.. allTeammates.Where(canAttackGridsByStartGrid.Union(canCastGridsByStartGrid).SelectMany(g => g.Characters).Contains)]; - aiDecision = ai.DecideAIAction(character, dp, startGrid, canMoveGrids, skills, items, allEnemys, allTeammates, enemys, teammates, pUseItem, pCastSkill, pNormalAttack); type = aiDecision.ActionType; } @@ -1386,7 +1383,7 @@ namespace Milimoe.FunGame.Core.Model enemys = [.. enemys.Where(attackRange.SelectMany(g => g.Characters).Contains)]; teammates = [.. teammates.Where(attackRange.SelectMany(g => g.Characters).Contains)]; } - targets = SelectTargets(character, character.NormalAttack, enemys, teammates, attackRange); + targets = SelectTargets(character, character.NormalAttack, allEnemys, allTeammates, enemys, teammates, attackRange); } if (targets.Count > 0) { @@ -2972,7 +2969,7 @@ namespace Milimoe.FunGame.Core.Model if (aiDecision != null) targets = aiDecision.Targets; if (targets.Count == 0) { - targets = SelectTargets(character, skill, enemys, teammates, castRange); + targets = SelectTargets(character, skill, allEnemys, allTeammates, enemys, teammates, castRange); } if (skill.CanSelectTargetRange > 0) { @@ -3283,21 +3280,23 @@ namespace Milimoe.FunGame.Core.Model /// /// /// + /// + /// /// /// /// /// - public List SelectTargets(Character caster, Skill skill, List enemys, List teammates, List castRange) + public List SelectTargets(Character caster, Skill skill, List allEnemys, List allTeammates, List enemys, List teammates, List castRange) { List effects = [.. caster.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { - effect.AlterSelectListBeforeSelection(caster, skill, enemys, teammates); + effect.AlterSelectListBeforeSelection(caster, skill, allEnemys, allTeammates, enemys, teammates); } - List targets = OnSelectSkillTargetsEvent(caster, skill, enemys, teammates, castRange); + List targets = OnSelectSkillTargetsEvent(caster, skill, allEnemys, allTeammates, enemys, teammates, castRange); if (targets.Count == 0 && IsCharacterInAIControlling(caster)) { - targets = skill.SelectTargets(caster, enemys, teammates); + targets = skill.SelectTargets(caster, allEnemys, allTeammates, enemys, teammates); } return targets; } @@ -3326,21 +3325,23 @@ namespace Milimoe.FunGame.Core.Model /// /// /// + /// + /// /// /// /// /// - public List SelectTargets(Character character, NormalAttack attack, List enemys, List teammates, List attackRange) + public List SelectTargets(Character character, NormalAttack attack, List allEnemys, List allTeammates, List enemys, List teammates, List attackRange) { List effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { - effect.AlterSelectListBeforeSelection(character, attack, enemys, teammates); + effect.AlterSelectListBeforeSelection(character, attack, allEnemys, allTeammates, enemys, teammates); } - List targets = OnSelectNormalAttackTargetsEvent(character, attack, enemys, teammates, attackRange); + List targets = OnSelectNormalAttackTargetsEvent(character, attack, allEnemys, allTeammates, enemys, teammates, attackRange); if (targets.Count == 0 && IsCharacterInAIControlling(character)) { - targets = character.NormalAttack.SelectTargets(character, enemys, teammates); + targets = character.NormalAttack.SelectTargets(character, allEnemys, allTeammates, enemys, teammates); } return targets; } @@ -4698,7 +4699,7 @@ namespace Milimoe.FunGame.Core.Model return SelectTargetGridEvent?.Invoke(this, character, enemys, teammates, map, moveRange) ?? Grid.Empty; } - public delegate List SelectSkillTargetsEventHandler(GamingQueue queue, Character caster, Skill skill, List enemys, List teammates, List castRange); + public delegate List SelectSkillTargetsEventHandler(GamingQueue queue, Character caster, Skill skill, List allEnemys, List allTeammates, List enemys, List teammates, List castRange); /// /// 选取技能目标事件 /// @@ -4708,13 +4709,15 @@ namespace Milimoe.FunGame.Core.Model /// /// /// + /// + /// /// /// /// /// - protected List OnSelectSkillTargetsEvent(Character caster, Skill skill, List enemys, List teammates, List castRange) + protected List OnSelectSkillTargetsEvent(Character caster, Skill skill, List allEnemys, List allTeammates, List enemys, List teammates, List castRange) { - return SelectSkillTargetsEvent?.Invoke(this, caster, skill, enemys, teammates, castRange) ?? []; + return SelectSkillTargetsEvent?.Invoke(this, caster, skill, allEnemys, allTeammates, enemys, teammates, castRange) ?? []; } public delegate List SelectNonDirectionalSkillTargetsEventHandler(GamingQueue queue, Character caster, Skill skill, List enemys, List teammates, List castRange); @@ -4736,7 +4739,7 @@ namespace Milimoe.FunGame.Core.Model return SelectNonDirectionalSkillTargetsEvent?.Invoke(this, caster, skill, enemys, teammates, castRange) ?? []; } - public delegate List SelectNormalAttackTargetsEventHandler(GamingQueue queue, Character character, NormalAttack attack, List enemys, List teammates, List attackRange); + public delegate List SelectNormalAttackTargetsEventHandler(GamingQueue queue, Character character, NormalAttack attack, List allEnemys, List allTeammates, List enemys, List teammates, List attackRange); /// /// 选取普通攻击目标事件 /// @@ -4746,13 +4749,15 @@ namespace Milimoe.FunGame.Core.Model /// /// /// + /// + /// /// /// /// /// - protected List OnSelectNormalAttackTargetsEvent(Character character, NormalAttack attack, List enemys, List teammates, List attackRange) + protected List OnSelectNormalAttackTargetsEvent(Character character, NormalAttack attack, List allEnemys, List allTeammates, List enemys, List teammates, List attackRange) { - return SelectNormalAttackTargetsEvent?.Invoke(this, character, attack, enemys, teammates, attackRange) ?? []; + return SelectNormalAttackTargetsEvent?.Invoke(this, character, attack, allEnemys, allTeammates, enemys, teammates, attackRange) ?? []; } public delegate void InterruptCastingEventHandler(GamingQueue queue, Character cast, Skill? skill, Character interrupter);