diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs index ffd098d..139d405 100644 --- a/Entity/Character/Character.cs +++ b/Entity/Character/Character.cs @@ -1401,7 +1401,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; @@ -1488,7 +1488,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; @@ -1583,7 +1583,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; @@ -1623,7 +1623,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; @@ -1698,7 +1698,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; diff --git a/Entity/Character/Shield.cs b/Entity/Character/Shield.cs index 52b895e..66a8a06 100644 --- a/Entity/Character/Shield.cs +++ b/Entity/Character/Shield.cs @@ -80,7 +80,7 @@ namespace Milimoe.FunGame.Core.Entity /// /// 总计魔法护盾 /// - public double TotalMagicial => None + Starmark + PurityNatural + PurityContemporary + Bright + Shadow + Element + Aster + SpatioTemporal + ShieldOfEffects.Values.Where(soe => soe.ShieldType == ShieldType.Magical && soe.Shield > 0).Sum(soe => soe.Shield); + public double TotalMagical => None + Starmark + PurityNatural + PurityContemporary + Bright + Shadow + Element + Aster + SpatioTemporal + ShieldOfEffects.Values.Where(soe => soe.ShieldType == ShieldType.Magical && soe.Shield > 0).Sum(soe => soe.Shield); /// /// 获取或设置护盾值 diff --git a/Entity/Character/Unit.cs b/Entity/Character/Unit.cs index d553f00..bd0cb18 100644 --- a/Entity/Character/Unit.cs +++ b/Entity/Character/Unit.cs @@ -56,7 +56,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; @@ -183,7 +183,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; @@ -284,7 +284,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; @@ -335,7 +335,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; @@ -417,7 +417,7 @@ namespace Milimoe.FunGame.Core.Entity double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); - if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}"); + if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}"); if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}"); builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : "")); double exMP = ExMP + ExMP2 + ExMP3; diff --git a/Library/Common/Addon/Example/ExampleGameModule.cs b/Library/Common/Addon/Example/ExampleGameModule.cs index 0ad8370..2ad54bd 100644 --- a/Library/Common/Addon/Example/ExampleGameModule.cs +++ b/Library/Common/Addon/Example/ExampleGameModule.cs @@ -331,6 +331,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example { // 因为模组在模组管理器中都是单例的,所以每次游戏都需要返回一个新的地图对象给队列 GameMap map = new ExampleGameMap(); + map.Load(); // 做一些绑定,以便介入游戏队列 /// 但是,传入的 queue 可能不是 ,要做类型检查 diff --git a/Library/Common/Addon/GameMap.cs b/Library/Common/Addon/GameMap.cs index e9cccee..07b6bd8 100644 --- a/Library/Common/Addon/GameMap.cs +++ b/Library/Common/Addon/GameMap.cs @@ -153,6 +153,12 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon return true; } + /// + /// 初始化游戏队列,要求返回一个新的地图实例,而不是 this + /// + /// + public abstract GameMap InitGamingQueue(IGamingQueue queue); + /// /// 获取角色当前所在的格子 /// @@ -216,8 +222,8 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon if (Math.Abs(dx) + Math.Abs(dy) <= range) { //检查是否在棋盘范围内 - int x = grid.X; - int y = grid.Y; + int x = grid.X + dx; + int y = grid.Y + dy; int z = grid.Z; if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? select) && select != null) { @@ -231,6 +237,44 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon return grids; } + /// + /// 获取以某个格子为中心,一定半径内的格子(圆形范围,欧几里得距离),只考虑同一平面的格子,不包含中心格子。 + /// + /// + /// + /// + public virtual List GetGridsByCircleRange(Grid grid, int range) + { + List grids = []; + + // 预计算半径的平方 + int rangeSquared = range * range; + + // 遍历以中心格子为中心的方形区域 + // 范围从 -range 到 +range,覆盖所有可能的圆形区域内的格子 + for (int dx = -range; dx <= range; ++dx) + { + for (int dy = -range; dy <= range; ++dy) + { + // 计算当前格子与中心格子的欧几里得距离的平方 + if ((dx * dx) + (dy * dy) <= rangeSquared) + { + int x = grid.X + dx; + int y = grid.Y + dy; + int z = grid.Z; + + if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? select) && select != null) + { + grids.Add(select); + } + } + } + } + grids.RemoveAll(g => g.Id == grid.Id); + + return grids; + } + /// /// 设置角色移动 /// @@ -305,12 +349,107 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon } /// - /// 初始化游戏队列 + /// 设置角色移动。如果不能达到目标格子,则移动到离目标格子最近的一个可达格子上。 /// - /// - public virtual GameMap InitGamingQueue(IGamingQueue queue) + /// + /// + /// + /// 移动的步数,只算平面移动步数 + public virtual int CharacterMoveToClosestReachable(Character character, Grid? current, Grid target) { - return this; + if (current is null || current.Id < 0 || target.Id < 0 || !Grids.ContainsValue(target)) + { + return -1; + } + + Grid? realGrid = GetCharacterCurrentGrid(character); + + if (current.Id == target.Id) + { + SetCharacterCurrentGrid(character, current); + return 0; + } + + // 使用 BFS 算法探索所有可达格子,并记录它们到起点的步数 + Queue<(Grid grid, int steps)> queue = new(); + + // 记录已访问的格子ID + HashSet visited = []; + + // 初始化 BFS 队列,将起始格子加入,步数为0 + queue.Enqueue((current, 0)); + visited.Add(current.Id); + + Grid? bestReachableGrid = current; + int minDistanceToTarget = CalculateManhattanDistance(current, target); + int stepsToBestReachable = 0; + + // 定义平面移动的四个方向 + (int dx, int dy)[] directions = [ + (0, 1), (0, -1), (1, 0), (-1, 0) + ]; + + while (queue.Count > 0) + { + var (currentGrid, currentSteps) = queue.Dequeue(); + + // 计算当前可达格子到目标格子的曼哈顿距离 + int distToTarget = CalculateManhattanDistance(currentGrid, target); + + // 如果当前格子比之前找到的 bestReachableGrid 更接近目标 + if (distToTarget < minDistanceToTarget) + { + minDistanceToTarget = distToTarget; + bestReachableGrid = currentGrid; + stepsToBestReachable = currentSteps; + } + // 如果距离相同,优先选择到达步数更少的格子(作为一种 tie-breaking 规则) + else if (distToTarget == minDistanceToTarget && currentSteps < stepsToBestReachable) + { + bestReachableGrid = currentGrid; + stepsToBestReachable = currentSteps; + } + + // 探索相邻格子 + foreach (var (dx, dy) in directions) + { + int nextX = currentGrid.X + dx; + int nextY = currentGrid.Y + dy; + int nextZ = currentGrid.Z; + + Grid? neighborGrid = this[nextX, nextY, nextZ]; + + // 如果相邻格子存在且未被访问过 + if (neighborGrid != null && !visited.Contains(neighborGrid.Id)) + { + visited.Add(neighborGrid.Id); + queue.Enqueue((neighborGrid, currentSteps + 1)); + } + } + } + + // 理论上 bestReachableGrid 不会是 null,因为 current 至少是可达的 + if (bestReachableGrid == null) + { + return -1; + } + + // 更新角色的实际位置 + realGrid?.Characters.Remove(character); + SetCharacterCurrentGrid(character, bestReachableGrid); + + return stepsToBestReachable; + } + + /// + /// 计算两个格子之间的曼哈顿距离 + /// + /// + /// + /// 两个格子之间的曼哈顿距离 + public static int CalculateManhattanDistance(Grid g1, Grid g2) + { + return Math.Abs(g1.X - g2.X) + Math.Abs(g1.Y - g2.Y) + Math.Abs(g1.Z - g2.Z); } /// diff --git a/Model/GamingQueue.cs b/Model/GamingQueue.cs index 2d058af..55b656e 100644 --- a/Model/GamingQueue.cs +++ b/Model/GamingQueue.cs @@ -1699,7 +1699,7 @@ namespace Milimoe.FunGame.Core.Model WriteLine($"[ {enemy} ] 的{shieldTypeString}护盾抵消了 {enemy.Shield[isMagicDamage, magicType]:0.##} 点{damageTypeString}并破碎!"); remain -= enemy.Shield[isMagicDamage, magicType]; enemy.Shield[isMagicDamage, magicType] = 0; - if (isMagicDamage && enemy.Shield.TotalMagicial <= 0 || !isMagicDamage && enemy.Shield.TotalPhysical <= 0) + if (isMagicDamage && enemy.Shield.TotalMagical <= 0 || !isMagicDamage && enemy.Shield.TotalPhysical <= 0) { effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; foreach (Effect effect in effects)