public static WarriorAI Build(this WarriorAI ai, string aiType) { switch (aiType) { case "NormalNpcMonster": ai.ActLast = () => NormalNpcMonster(ai); break; case "EMPConnon": ai.ActLast = () => { NormalNpcMonster(ai); // 每次损失 40% 最大血量 AddHpRoundly(ai, (warrior) => - (warrior.MaxHP * 4 / 10).Clamp(1, warrior.HP)); }; break; case "FastEMPConnon": // 加速炮台 ai.ActLast = () => { NormalNpcMonster(ai); ai.Owner.ActionDone = false; // 额外一次攻击,每次损失 50% 最大血量 NormalNpcMonster(ai); AddHpRoundly(ai, (warrior) => - (warrior.MaxHP / 2).Clamp(1, warrior.HP)); }; break; case "Dumb": break; default: Debug.Assert(false, "no such type of ai: " + aiType); break; } return(ai); }
public EMPCannon(BattleMap map, bool fastCannon) : base(map) { ID = "EMPCannon"; AI = new WarriorAI(this).Build(fastCannon ? "FastEMPConnon" : "EMPConnon"); Battle.AddBuff(new CounterAttack(this)); // 反击 buff }
// 每回合加血 static void AddHpRoundly(WarriorAI ai, Func <Warrior, int> calcDhp) { var warrior = ai.Owner; var bt = warrior.Battle; var dhp = calcDhp(warrior); bt.AddHP(warrior, dhp); }
public Boar(BattleMap map) : base(map) { ID = "Boar"; AI = new WarriorAI(this).Build("NormalNpcMonster"); // AI Battle.AddBuff(new CounterAttack(this)); // 反击 buff }
// 走向最近的目标并攻击之 static void Forward2NearestTargetAndAttack(WarriorAI ai) { // 先寻找最近目标 var warrior = ai.Owner; var target = warrior.Map.FindNearestTarget(warrior); if (warrior.ActionDone || target == null) { return; } ForwardAndAttack(ai, target); }
// 普通怪物 npc 战斗逻辑 static void NormalNpcMonster(WarriorAI ai) { var warrior = ai.Owner; var bt = warrior.Map.Battle; var map = warrior.Map; // 检查在移动后可以攻击到的敌人 Warrior target = null; FindPriorTarget(warrior, FindTargetsReachable(warrior).Keys.ToArray(), (t) => target = t); if (target == null) { // 没有够得到的攻击目标 if (warrior.IsCloseAttack()) // 近战单位 { // 近战单位,就寻找血量最少的目标,向其移动 target = FindTheWeakestTarget(warrior); ForwardAndAttack(ai, target); } else { // 远程单位,就寻找最近的队友,向其移动 target = FindTheNearestTeammate(warrior); if (target != null) { Forward2Target(ai, target); } } } else { // 根据要攻击的目标确定站位 var tx = 0; var ty = 0; CheckoutAttackingPosition(warrior, target, (x, y) => { tx = x; ty = y; }); warrior.GetPosInMap(out int fx, out int fy); var path = map.FindPath(fx, fy, tx, ty, warrior.MoveRange, warrior.StandableTiles); if (path.Count > 0) { warrior.MovingPath.Clear(); warrior.MovingPath.AddRange(path); bt.MoveOnPath(warrior); } bt.Attack(warrior, target); } }
// 走向指定目标,并攻击之 static void ForwardAndAttack(WarriorAI ai, Warrior target) { var warrior = ai.Owner; var bt = warrior.Map.Battle; target.GetPosInMap(out int tx, out int ty); // 检查攻击范围限制 // 不在攻击范围内,则先移动过去 if (!warrior.InAttackRange(tx, ty) && warrior.MoveRange > 0) { Forward2Target(ai, target); } // 攻击目标 if (warrior.InAttackRange(tx, ty)) { bt.Attack(warrior, target); } }
// 走向指定目标 static void Forward2Target(WarriorAI ai, Warrior target) { var warrior = ai.Owner; var bt = warrior.Map.Battle; target.GetPosInMap(out int tx, out int ty); warrior.GetPosInMap(out int fx, out int fy); var path = warrior.MovingPath; path.Clear(); path.AddRange(warrior.Map.FindPath(fx, fy, tx, ty, warrior.MoveRange, warrior.StandableTiles)); // 限制移动距离 while (path.Count > warrior.MoveRange * 2) { path.RemoveRange(path.Count - 2, 2); } if (path.Count > 0) { bt.MoveOnPath(warrior); } }
// 哑 AI,不做任何事情 static IEnumerator Dumb(WarriorAI ai) { yield return(null); }