diff --git a/Controller/AIController.cs b/Controller/AIController.cs index 6f3236b..266b659 100644 --- a/Controller/AIController.cs +++ b/Controller/AIController.cs @@ -24,11 +24,29 @@ namespace Milimoe.FunGame.Core.Controller /// 场上所有队友 /// 场上能够选取的敌人 /// 场上能够选取的队友 + /// 使用物品的概率 + /// 释放技能的概率 + /// 普通攻击的概率 /// 包含最佳行动的AIDecision对象 public AIDecision DecideAIAction(Character character, DecisionPoints dp, Grid startGrid, List allPossibleMoveGrids, List availableSkills, List availableItems, List allEnemysInGame, List allTeammatesInGame, - List selectableEnemys, List selectableTeammates) + List selectableEnemys, List selectableTeammates, double pUseItem, double pCastSkill, double pNormalAttack) { + // 动态调整概率 + double dynamicPUseItem = pUseItem; + double dynamicPCastSkill = pCastSkill; + double dynamicPNormalAttack = pNormalAttack; + AdjustProbabilitiesBasedOnContext(ref dynamicPUseItem, ref dynamicPCastSkill, ref dynamicPNormalAttack, character, allEnemysInGame, allTeammatesInGame); + + // 归一化概率 + double[] normalizedProbs = NormalizeProbabilities(dynamicPUseItem, dynamicPCastSkill, dynamicPNormalAttack); + double normalizedPUseItem = normalizedProbs[0]; + double normalizedPCastSkill = normalizedProbs[1]; + double normalizedPNormalAttack = normalizedProbs[2]; + + // 获取偏好行动类型 + CharacterActionType? preferredAction = GetPreferredActionType(pUseItem, pCastSkill, pNormalAttack); + // 初始化一个默认的“结束回合”决策作为基准 AIDecision bestDecision = new() { @@ -38,6 +56,9 @@ namespace Milimoe.FunGame.Core.Controller Score = -1000.0 }; + // 候选决策 + List candidateDecisions = []; + // 遍历所有可能的移动目标格子 (包括起始格子本身) foreach (Grid potentialMoveGrid in allPossibleMoveGrids) { @@ -45,75 +66,79 @@ namespace Milimoe.FunGame.Core.Controller int moveDistance = GameMap.CalculateManhattanDistance(startGrid, potentialMoveGrid); double movePenalty = moveDistance * 0.5; // 每移动一步扣0.5分 - if (CanCharacterNormalAttack(character, dp)) + if (pNormalAttack > 0) { - // 计算普通攻击的可达格子 - List normalAttackReachableGrids = _map.GetGridsByRange(potentialMoveGrid, character.ATR, true); - - List normalAttackReachableEnemys = [.. allEnemysInGame.Where(c => normalAttackReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c)).Distinct()]; - List normalAttackReachableTeammates = [.. allTeammatesInGame.Where(c => normalAttackReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c)).Distinct()]; - - if (normalAttackReachableEnemys.Count > 0) + if (CanCharacterNormalAttack(character, dp)) { - // 将筛选后的目标列表传递给 SelectTargets - List targets = SelectTargets(character, character.NormalAttack, normalAttackReachableEnemys, normalAttackReachableTeammates); - if (targets.Count > 0) + // 计算普通攻击的可达格子 + List normalAttackReachableGrids = _map.GetGridsByRange(potentialMoveGrid, character.ATR, true); + + List normalAttackReachableEnemys = [.. allEnemysInGame.Where(c => normalAttackReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c)).Distinct()]; + List normalAttackReachableTeammates = [.. allTeammatesInGame.Where(c => normalAttackReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c)).Distinct()]; + + if (normalAttackReachableEnemys.Count > 0) { - double currentScore = EvaluateNormalAttack(character, targets) - movePenalty; - if (currentScore > bestDecision.Score) + // 将筛选后的目标列表传递给 SelectTargets + List targets = SelectTargets(character, character.NormalAttack, normalAttackReachableEnemys, normalAttackReachableTeammates); + if (targets.Count > 0) { - bestDecision = new AIDecision + double currentScore = EvaluateNormalAttack(character, targets) - movePenalty; + double probabilityWeight = 1.0 + (normalizedPNormalAttack * 0.3); + candidateDecisions.Add(new AIDecision { ActionType = CharacterActionType.NormalAttack, TargetMoveGrid = potentialMoveGrid, SkillToUse = character.NormalAttack, Targets = targets, - Score = currentScore - }; + Score = currentScore, + ProbabilityWeight = probabilityWeight + }); } } } } - foreach (Skill skill in availableSkills) + if (pCastSkill > 0) { - if (CanCharacterUseSkill(character, skill, dp) && _queue.CheckCanCast(character, skill, out double cost)) + foreach (Skill skill in availableSkills) { - // 计算当前技能的可达格子 - List skillReachableGrids = _map.GetGridsByRange(potentialMoveGrid, skill.CastRange, true); - - if (skill.IsNonDirectional) + if (CanCharacterUseSkill(character, skill, dp) && _queue.CheckCanCast(character, skill, out double cost)) { - AIDecision? nonDirDecision = EvaluateNonDirectionalSkill(character, skill, potentialMoveGrid, skillReachableGrids, allEnemysInGame, allTeammatesInGame, cost); + // 计算当前技能的可达格子 + List skillReachableGrids = _map.GetGridsByRange(potentialMoveGrid, skill.CastRange, true); - if (nonDirDecision != null && nonDirDecision.Score > bestDecision.Score) + if (skill.IsNonDirectional) { - bestDecision = nonDirDecision; - } - } - else - { - List skillReachableEnemys = [.. allEnemysInGame.Where(c => skillReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c)).Distinct()]; - List skillReachableTeammates = [.. allTeammatesInGame.Where(c => skillReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c)).Distinct()]; + AIDecision? nonDirDecision = EvaluateNonDirectionalSkill(character, skill, potentialMoveGrid, skillReachableGrids, allEnemysInGame, allTeammatesInGame, cost); - // 检查是否有可用的目标(敌人或队友,取决于技能类型) - if (skillReachableEnemys.Count > 0 || skillReachableTeammates.Count > 0) - { - // 将筛选后的目标列表传递给 SelectTargets - List targets = SelectTargets(character, skill, skillReachableEnemys, skillReachableTeammates); - if (targets.Count > 0) + if (nonDirDecision != null && nonDirDecision.Score > bestDecision.Score) { - double currentScore = EvaluateSkill(character, skill, targets, cost) - movePenalty; - if (currentScore > bestDecision.Score) + bestDecision = nonDirDecision; + } + } + else + { + List skillReachableEnemys = [.. allEnemysInGame.Where(c => skillReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c)).Distinct()]; + List skillReachableTeammates = [.. allTeammatesInGame.Where(c => skillReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c)).Distinct()]; + + // 检查是否有可用的目标(敌人或队友,取决于技能类型) + if (skillReachableEnemys.Count > 0 || skillReachableTeammates.Count > 0) + { + // 将筛选后的目标列表传递给 SelectTargets + List targets = SelectTargets(character, skill, skillReachableEnemys, skillReachableTeammates); + if (targets.Count > 0) { - bestDecision = new AIDecision + double currentScore = EvaluateSkill(character, skill, targets, cost) - movePenalty; + double probabilityWeight = 1.0 + (normalizedPCastSkill * 0.3); + candidateDecisions.Add(new AIDecision { ActionType = CharacterActionType.PreCastSkill, TargetMoveGrid = potentialMoveGrid, SkillToUse = skill, Targets = targets, - Score = currentScore - }; + Score = currentScore, + ProbabilityWeight = probabilityWeight + }); } } } @@ -121,48 +146,50 @@ namespace Milimoe.FunGame.Core.Controller } } - foreach (Item item in availableItems) + if (pUseItem > 0) { - if (item.Skills.Active != null && CanCharacterUseItem(character, item, dp) && _queue.CheckCanCast(character, item.Skills.Active, out double cost)) + foreach (Item item in availableItems) { - Skill itemSkill = item.Skills.Active; - - // 计算当前物品技能的可达格子 - List itemSkillReachableGrids = _map.GetGridsByRange(potentialMoveGrid, itemSkill.CastRange, true); - - if (itemSkill.IsNonDirectional) + if (item.Skills.Active != null && CanCharacterUseItem(character, item, dp) && _queue.CheckCanCast(character, item.Skills.Active, out double cost)) { - AIDecision? nonDirDecision = EvaluateNonDirectionalSkill(character, itemSkill, potentialMoveGrid, itemSkillReachableGrids, allEnemysInGame, allTeammatesInGame, cost); + Skill itemSkill = item.Skills.Active; - if (nonDirDecision != null && nonDirDecision.Score > bestDecision.Score) - { - bestDecision = nonDirDecision; - } - } - else - { - List itemSkillReachableEnemys = [.. allEnemysInGame.Where(c => itemSkillReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c)).Distinct()]; - List itemSkillReachableTeammates = [.. allTeammatesInGame.Where(c => itemSkillReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c)).Distinct()]; + // 计算当前物品技能的可达格子 + List itemSkillReachableGrids = _map.GetGridsByRange(potentialMoveGrid, itemSkill.CastRange, true); - // 检查是否有可用的目标 - if (itemSkillReachableEnemys.Count > 0 || itemSkillReachableTeammates.Count > 0) + if (itemSkill.IsNonDirectional) { - // 将筛选后的目标列表传递给 SelectTargets - List targetsForItem = SelectTargets(character, itemSkill, itemSkillReachableEnemys, itemSkillReachableTeammates); - if (targetsForItem.Count > 0) + AIDecision? nonDirDecision = EvaluateNonDirectionalSkill(character, itemSkill, potentialMoveGrid, itemSkillReachableGrids, allEnemysInGame, allTeammatesInGame, cost); + + if (nonDirDecision != null && nonDirDecision.Score > bestDecision.Score) { - double currentScore = EvaluateItem(character, item, targetsForItem, cost) - movePenalty; - if (currentScore > bestDecision.Score) + bestDecision = nonDirDecision; + } + } + else + { + List itemSkillReachableEnemys = [.. allEnemysInGame.Where(c => itemSkillReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c)).Distinct()]; + List itemSkillReachableTeammates = [.. allTeammatesInGame.Where(c => itemSkillReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c)).Distinct()]; + + // 检查是否有可用的目标 + if (itemSkillReachableEnemys.Count > 0 || itemSkillReachableTeammates.Count > 0) + { + // 将筛选后的目标列表传递给 SelectTargets + List targetsForItem = SelectTargets(character, itemSkill, itemSkillReachableEnemys, itemSkillReachableTeammates); + if (targetsForItem.Count > 0) { - bestDecision = new AIDecision + double currentScore = EvaluateItem(character, item, targetsForItem, cost) - movePenalty; + double probabilityWeight = 1.0 + (normalizedPUseItem * 0.3); + candidateDecisions.Add(new AIDecision { ActionType = CharacterActionType.UseItem, TargetMoveGrid = potentialMoveGrid, ItemToUse = item, SkillToUse = itemSkill, Targets = targetsForItem, - Score = currentScore - }; + Score = currentScore, + ProbabilityWeight = probabilityWeight + }); } } } @@ -209,19 +236,30 @@ namespace Milimoe.FunGame.Core.Controller } } - // 如果纯粹移动比当前最佳(什么都不做)更好 - if (pureMoveScore > bestDecision.Score) + candidateDecisions.Add(new AIDecision { - bestDecision = new AIDecision + ActionType = CharacterActionType.Move, + TargetMoveGrid = potentialMoveGrid, + Targets = [], + Score = pureMoveScore, + IsPureMove = true + }); + } + + // 偏好类型额外加分 + if (preferredAction.HasValue) + { + foreach (var decision in candidateDecisions) + { + if (decision.ActionType == preferredAction.Value) { - ActionType = CharacterActionType.Move, - TargetMoveGrid = potentialMoveGrid, - Targets = [], - Score = pureMoveScore, - IsPureMove = true - }; + decision.Score *= 1.2; + } } } + + // 最终决策 + bestDecision = candidateDecisions.OrderByDescending(d => d.Score * d.ProbabilityWeight).FirstOrDefault() ?? bestDecision; } return bestDecision; @@ -229,6 +267,79 @@ namespace Milimoe.FunGame.Core.Controller // --- AI 决策辅助方法 --- + // 获取偏好行动类型 + private static CharacterActionType? GetPreferredActionType(double pItem, double pSkill, double pAttack) + { + // 找出最高概率的行动类型 + Dictionary probabilities = new() + { + { CharacterActionType.UseItem, pItem }, + { CharacterActionType.PreCastSkill, pSkill }, + { CharacterActionType.NormalAttack, pAttack } + }; + + double maxProb = probabilities.Values.Max(); + if (maxProb > 0) + { + CharacterActionType preferredType = probabilities.FirstOrDefault(kvp => kvp.Value == maxProb).Key; + + // 如果最高概率超过阈值,优先考虑该类型 + if (maxProb > 0.7) + { + return preferredType; + } + } + + return null; + } + + // 动态调整概率 + private static void AdjustProbabilitiesBasedOnContext(ref double pUseItem, ref double pCastSkill, ref double pNormalAttack, Character character, List allEnemysInGame, List allTeammatesInGame) + { + // 基于角色状态调整 + if (character.HP / character.MaxHP < 0.3 || allTeammatesInGame.Any(c => c.HP / c.MaxHP < 0.3)) + { + // 低生命值时增加使用物品概率 + if (pUseItem > 0) pUseItem *= 1.5; + if (pCastSkill > 0) pCastSkill *= 0.7; + } + + // 基于敌人数量调整 + int enemyCount = allEnemysInGame.Count; + if (enemyCount > 3) + { + // 敌人多时倾向于范围技能 + if (pCastSkill > 0) pCastSkill *= 1.3; + } + else if (enemyCount == 1) + { + // 单个敌人时倾向于普通攻击 + if (pNormalAttack > 0) pNormalAttack *= 1.2; + } + + if (pUseItem > 0) pUseItem = Math.Max(0, pUseItem); + if (pCastSkill > 0) pCastSkill = Math.Max(0, pCastSkill); + if (pNormalAttack > 0) pNormalAttack = Math.Max(0, pNormalAttack); + } + + // / 归一化概率分布 + private static double[] NormalizeProbabilities(double pUseItem, double pCastSkill, double pNormalAttack) + { + if (pUseItem <= 0 && pCastSkill <= 0 && pNormalAttack <= 0) + { + return [0, 0, 0]; + } + + double sum = pUseItem + pCastSkill + pNormalAttack; + if (sum <= 0) return [0.33, 0.33, 0.34]; + + return [ + pUseItem / sum, + pCastSkill / sum, + pNormalAttack / sum + ]; + } + // 检查角色是否能进行普通攻击(基于状态) private static bool CanCharacterNormalAttack(Character character, DecisionPoints dp) { diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs index 225ed4e..4f17db5 100644 --- a/Entity/Character/Character.cs +++ b/Entity/Character/Character.cs @@ -1283,7 +1283,7 @@ namespace Milimoe.FunGame.Core.Entity } if (isUp) { - Effect[] effects = [.. Effects.Where(e => e.IsInEffect)]; + Effect[] effects = [.. Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect e in effects) { e.OnOwnerLevelUp(this, Level); @@ -1312,7 +1312,7 @@ namespace Milimoe.FunGame.Core.Entity /// public void OnAttributeChanged() { - List effects = [.. Effects.Where(e => e.IsInEffect)]; + List effects = [.. Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.OnAttributeChanged(this); @@ -1447,41 +1447,8 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})"); builder.AppendLine($"经验值:{EXP:0.##}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}"); } - double exHP = ExHP + ExHP2 + ExHP3; - List shield = []; - if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical: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; - builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); - builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); - double exATK = ExATK + ExATK2 + ExATK3; - builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); - double exDEF = ExDEF + ExDEF2 + ExDEF3; - builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exDEF >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)"); - builder.AppendLine(GetMagicResistanceInfo().Trim()); - double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD; - builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)"); - builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); - double exSTR = ExSTR + ExSTR2; - builder.AppendLine($"力量:{STR:0.##}" + (exSTR != 0 ? $" [{BaseSTR:0.##} {(exSTR >= 0 ? "+" : "-")} {Math.Abs(exSTR):0.##}]" : "") + (showGrowth ? $"({(STRGrowth >= 0 ? "+" : "-")}{Math.Abs(STRGrowth)}/Lv)" : "") + $"({STRExemption * 100:0.##}%)"); - double exAGI = ExAGI + ExAGI2; - builder.AppendLine($"敏捷:{AGI:0.##}" + (exAGI != 0 ? $" [{BaseAGI:0.##} {(exAGI >= 0 ? "+" : "-")} {Math.Abs(exAGI):0.##}]" : "") + (showGrowth ? $"({(AGIGrowth >= 0 ? "+" : "-")}{Math.Abs(AGIGrowth)}/Lv)" : "") + $"({AGIExemption * 100:0.##}%)"); - double exINT = ExINT + ExINT2; - builder.AppendLine($"智力:{INT:0.##}" + (exINT != 0 ? $" [{BaseINT:0.##} {(exINT >= 0 ? "+" : "-")} {Math.Abs(exINT):0.##}]" : "") + (showGrowth ? $"({(INTGrowth >= 0 ? "+" : "-")}{Math.Abs(INTGrowth)}/Lv)" : "") + $"({INTExemption * 100:0.##}%)"); - builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : "")); - builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : "")); - builder.AppendLine($"暴击率:{CritRate * 100:0.##}%"); - builder.AppendLine($"暴击伤害:{CritDMG * 100:0.##}%"); - builder.AppendLine($"闪避率:{EvadeRate * 100:0.##}%"); - builder.AppendLine($"生命偷取:{Lifesteal * 100:0.##}%"); - builder.AppendLine($"冷却缩减:{CDR * 100:0.##}%"); - builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:0.##}%"); - builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%"); - builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%"); - builder.AppendLine($"魔法消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastMPReduce * 100:0.##}%"); - builder.AppendLine($"能量消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastEPReduce * 100:0.##}%"); + + builder.AppendLine(GetAttributeInfo(showGrowth).Trim()); if (showMapRelated) { @@ -1489,7 +1456,7 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine($"攻击距离:{ATR}"); } - GetStatusInfo(builder); + builder.AppendLine(GetStatusInfo().Trim()); builder.AppendLine("== 普通攻击 =="); builder.Append(NormalAttack.ToString()); @@ -1541,38 +1508,8 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})"); builder.AppendLine($"经验值:{EXP:0.##}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}"); } - double exHP = ExHP + ExHP2 + ExHP3; - List shield = []; - if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical: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; - builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); - builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); - double exATK = ExATK + ExATK2 + ExATK3; - builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); - double exDEF = ExDEF + ExDEF2 + ExDEF3; - builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exDEF >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)"); - builder.AppendLine(GetMagicResistanceInfo().Trim()); - if (showBasicOnly) - { - builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}({CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)})"); - } - else - { - double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD; - builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)"); - builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); - double exSTR = ExSTR + ExSTR2; - builder.AppendLine($"力量:{STR:0.##}" + (exSTR != 0 ? $" [{BaseSTR:0.##} {(exSTR >= 0 ? "+" : "-")} {Math.Abs(exSTR):0.##}]" : "") + (showGrowth ? $"({(STRGrowth >= 0 ? "+" : "-")}{Math.Abs(STRGrowth)}/Lv)" : "") + $"({STRExemption * 100:0.##}%)"); - double exAGI = ExAGI + ExAGI2; - builder.AppendLine($"敏捷:{AGI:0.##}" + (exAGI != 0 ? $" [{BaseAGI:0.##} {(exAGI >= 0 ? "+" : "-")} {Math.Abs(exAGI):0.##}]" : "") + (showGrowth ? $"({(AGIGrowth >= 0 ? "+" : "-")}{Math.Abs(AGIGrowth)}/Lv)" : "") + $"({AGIExemption * 100:0.##}%)"); - double exINT = ExINT + ExINT2; - builder.AppendLine($"智力:{INT:0.##}" + (exINT != 0 ? $" [{BaseINT:0.##} {(exINT >= 0 ? "+" : "-")} {Math.Abs(exINT):0.##}]" : "") + (showGrowth ? $"({(INTGrowth >= 0 ? "+" : "-")}{Math.Abs(INTGrowth)}/Lv)" : "") + $"({INTExemption * 100:0.##}%)"); - } - builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : "")); - builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : "")); + + builder.AppendLine(GetSimpleAttributeInfo(showGrowth, showBasicOnly).Trim()); if (showMapRelated) { @@ -1582,7 +1519,7 @@ namespace Milimoe.FunGame.Core.Entity if (!showBasicOnly) { - GetStatusInfo(builder); + builder.AppendLine(GetStatusInfo().Trim()); if (Skills.Count > 0) { @@ -1636,26 +1573,16 @@ namespace Milimoe.FunGame.Core.Entity /// 获取战斗状态的信息 /// /// + /// /// - public string GetInBattleInfo(double hardnessTimes) + public string GetInBattleInfo(double hardnessTimes, bool simpleStatusBar = false) { StringBuilder builder = new(); builder.AppendLine((HP == 0 ? "[ 死亡 ] " : "") + ToStringWithLevel()); - double exHP = ExHP + ExHP2 + ExHP3; - List shield = []; - if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical: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; - builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); - builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); - double exATK = ExATK + ExATK2 + ExATK3; - builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); - builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}" + (ExPrimaryAttributeValue != 0 ? $" [{BasePrimaryAttributeValue:0.##} {(ExPrimaryAttributeValue >= 0 ? "+" : "-")} {Math.Abs(ExPrimaryAttributeValue):0.##}]" : "")); - GetStatusInfo(builder); + builder.AppendLine(GetSimpleAttributeInfo(false, true).Trim()); + builder.AppendLine(GetStatusInfo().Trim()); builder.AppendLine($"硬直时间:{hardnessTimes:0.##}"); @@ -1663,49 +1590,22 @@ namespace Milimoe.FunGame.Core.Entity if (effects.Length > 0) { builder.AppendLine("== 状态栏 =="); - foreach (Effect effect in effects) + if (simpleStatusBar) { - builder.AppendLine(effect.ToString()); + builder.Append(string.Join(",", effects.Select(e => e.Name))); + } + else + { + foreach (Effect effect in effects) + { + builder.AppendLine(effect.ToString()); + } } } return builder.ToString().Trim(); } - /// - /// 获取战斗状态的信息(简略版) - /// - /// - /// - public string GetSimpleInBattleInfo(double hardnessTimes) - { - StringBuilder builder = new(); - - builder.AppendLine((HP == 0 ? "[ 死亡 ] " : "") + ToStringWithLevel()); - double exHP = ExHP + ExHP2 + ExHP3; - List shield = []; - if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical: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; - builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); - builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); - double exATK = ExATK + ExATK2 + ExATK3; - builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); - builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}" + (ExPrimaryAttributeValue != 0 ? $" [{BasePrimaryAttributeValue:0.##} {(ExPrimaryAttributeValue >= 0 ? "+" : "-")} {Math.Abs(ExPrimaryAttributeValue):0.##}]" : "")); - builder.AppendLine($"硬直时间:{hardnessTimes:0.##}"); - - Effect[] effects = [.. Effects.Where(e => e.ShowInStatusBar)]; - if (effects.Length > 0) - { - builder.AppendLine("== 状态栏 =="); - builder.Append(string.Join(",", effects.Select(e => e.Name))); - } - - return builder.ToString(); - } - /// /// 获取角色的技能信息 /// @@ -1716,7 +1616,7 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine((HP == 0 ? "[ 死亡 ] " : "") + (showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser())); - GetStatusInfo(builder); + builder.AppendLine(GetStatusInfo().Trim()); builder.AppendLine("== 普通攻击 =="); builder.Append(NormalAttack.ToString()); @@ -1757,6 +1657,35 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})"); builder.AppendLine($"经验值:{EXP:0.##}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}"); } + + builder.AppendLine(GetAttributeInfo(showGrowth).Trim()); + + if (showMapRelated) + { + builder.AppendLine($"移动距离:{MOV}"); + builder.AppendLine($"攻击距离:{ATR}"); + } + + if (EquipSlot.Any()) + { + builder.AppendLine(GetEquipSlotInfo().Trim()); + } + + if (Items.Count > 0) + { + builder.AppendLine(GetBackpackItemsInfo().Trim()); + } + + return builder.ToString(); + } + + /// + /// 获取角色属性和能力值信息 + /// + /// + public string GetAttributeInfo(bool showGrowth = true) + { + StringBuilder builder = new(); double exHP = ExHP + ExHP2 + ExHP3; List shield = []; if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}"); @@ -1792,28 +1721,58 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%"); builder.AppendLine($"魔法消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastMPReduce * 100:0.##}%"); builder.AppendLine($"能量消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastEPReduce * 100:0.##}%"); - - if (showMapRelated) - { - builder.AppendLine($"移动距离:{MOV}"); - builder.AppendLine($"攻击距离:{ATR}"); - } - - if (EquipSlot.Any()) - { - builder.AppendLine(GetEquipSlotInfo().Trim()); - } - - if (Items.Count > 0) - { - builder.AppendLine(GetBackpackItemsInfo().Trim()); - } - return builder.ToString(); } - private void GetStatusInfo(StringBuilder builder) + /// + /// 获取角色属性和能力值的简略版信息 + /// + /// + public string GetSimpleAttributeInfo(bool showGrowth = true, bool showBasicOnly = false) { + StringBuilder builder = new(); + double exHP = ExHP + ExHP2 + ExHP3; + List shield = []; + if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical: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; + builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); + builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); + double exATK = ExATK + ExATK2 + ExATK3; + builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); + double exDEF = ExDEF + ExDEF2 + ExDEF3; + builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exDEF >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)"); + builder.AppendLine(GetMagicResistanceInfo().Trim()); + if (showBasicOnly) + { + builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}({CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)})"); + } + else + { + double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD; + builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)"); + builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); + double exSTR = ExSTR + ExSTR2; + builder.AppendLine($"力量:{STR:0.##}" + (exSTR != 0 ? $" [{BaseSTR:0.##} {(exSTR >= 0 ? "+" : "-")} {Math.Abs(exSTR):0.##}]" : "") + (showGrowth ? $"({(STRGrowth >= 0 ? "+" : "-")}{Math.Abs(STRGrowth)}/Lv)" : "") + $"({STRExemption * 100:0.##}%)"); + double exAGI = ExAGI + ExAGI2; + builder.AppendLine($"敏捷:{AGI:0.##}" + (exAGI != 0 ? $" [{BaseAGI:0.##} {(exAGI >= 0 ? "+" : "-")} {Math.Abs(exAGI):0.##}]" : "") + (showGrowth ? $"({(AGIGrowth >= 0 ? "+" : "-")}{Math.Abs(AGIGrowth)}/Lv)" : "") + $"({AGIExemption * 100:0.##}%)"); + double exINT = ExINT + ExINT2; + builder.AppendLine($"智力:{INT:0.##}" + (exINT != 0 ? $" [{BaseINT:0.##} {(exINT >= 0 ? "+" : "-")} {Math.Abs(exINT):0.##}]" : "") + (showGrowth ? $"({(INTGrowth >= 0 ? "+" : "-")}{Math.Abs(INTGrowth)}/Lv)" : "") + $"({INTExemption * 100:0.##}%)"); + } + builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : "")); + builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : "")); + return builder.ToString(); + } + + /// + /// 获取角色状态信息 + /// + public string GetStatusInfo() + { + StringBuilder builder = new(); + if (CharacterState != CharacterState.Actionable) { builder.AppendLine(CharacterSet.GetCharacterState(CharacterState)); @@ -1848,6 +1807,8 @@ namespace Milimoe.FunGame.Core.Entity { builder.AppendLine("角色是不可选中的"); } + + return builder.ToString(); } /// @@ -2134,7 +2095,7 @@ namespace Milimoe.FunGame.Core.Entity List skills = [.. Skills]; List items = [.. Items]; Character c = original.Copy(); - List effects = [.. Effects]; + List effects = [.. Effects.OrderByDescending(e => e.Priority)]; foreach (Effect e in effects) { e.OnEffectLost(this); diff --git a/Entity/Character/Unit.cs b/Entity/Character/Unit.cs index 071c163..8456d7b 100644 --- a/Entity/Character/Unit.cs +++ b/Entity/Character/Unit.cs @@ -292,8 +292,9 @@ namespace Milimoe.FunGame.Core.Entity /// 获取战斗状态的信息 /// /// + /// /// - public new string GetInBattleInfo(double hardnessTimes) + public new string GetInBattleInfo(double hardnessTimes, bool simpleStatusBar = false) { StringBuilder builder = new(); @@ -339,38 +340,6 @@ namespace Milimoe.FunGame.Core.Entity return builder.ToString(); } - /// - /// 获取战斗状态的信息(简略版) - /// - /// - /// - public new string GetSimpleInBattleInfo(double hardnessTimes) - { - StringBuilder builder = new(); - - builder.AppendLine(ToStringWithLevel()); - double exHP = ExHP + ExHP2 + ExHP3; - List shield = []; - if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical: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; - builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); - double exATK = ExATK + ExATK2 + ExATK3; - builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); - builder.AppendLine($"硬直时间:{hardnessTimes:0.##}"); - - Effect[] effects = [.. Effects.Where(e => e.ShowInStatusBar)]; - if (effects.Length > 0) - { - builder.AppendLine("== 状态栏 =="); - builder.Append(string.Join(",", effects.Select(e => e.Name))); - } - - return builder.ToString(); - } - /// /// 获取单位的技能信息 /// diff --git a/Entity/Item/Item.cs b/Entity/Item/Item.cs index 0b59c15..5b69611 100644 --- a/Entity/Item/Item.cs +++ b/Entity/Item/Item.cs @@ -252,7 +252,7 @@ namespace Milimoe.FunGame.Core.Entity { foreach (Skill skill in Skills.Passives) { - List effects = [.. Character.Effects.Where(e => e.Skill == skill && e.IsInEffect)]; + List effects = [.. Character.Effects.Where(e => e.Skill == skill && e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect e in effects) { Character.Effects.Remove(e); diff --git a/Entity/Skill/Effect.cs b/Entity/Skill/Effect.cs index 5ecaf53..0cda70c 100644 --- a/Entity/Skill/Effect.cs +++ b/Entity/Skill/Effect.cs @@ -18,6 +18,12 @@ namespace Milimoe.FunGame.Core.Entity /// public Skill Skill { get; } + /// + /// 特效触发优先级 + /// 越大优先级越高;默认值为 0,在状态栏()中使用默认哈希排序。 + /// + public int Priority { get; set; } = 0; + /// /// 特殊效果类型 /// 注意:如果技能特效没有原生施加控制效果,请始终保持此属性为 。 @@ -1267,7 +1273,7 @@ namespace Milimoe.FunGame.Core.Entity { return; } - Effect[] effects = [.. target.Effects.Where(e => e.ShowInStatusBar)]; + Effect[] effects = [.. target.Effects.Where(e => e.ShowInStatusBar).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { if (effect.OnEffectIsBeingDispelled(dispeller, target, this, isEnemy)) diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs index c4cb1d4..5f306f4 100644 --- a/Entity/Skill/Skill.cs +++ b/Entity/Skill/Skill.cs @@ -408,7 +408,7 @@ namespace Milimoe.FunGame.Core.Entity } if (Level > 0 && Character != null) { - Effect[] effects = [.. Character.Effects.Where(e => e.IsInEffect)]; + Effect[] effects = [.. Character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect e in effects) { e.OnSkillLevelUp(Character, Level); @@ -474,7 +474,7 @@ namespace Milimoe.FunGame.Core.Entity foreach (Character character in enemys) { - IEnumerable effects = Effects.Where(e => e.IsInEffect); + 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)))) { @@ -609,7 +609,7 @@ namespace Milimoe.FunGame.Core.Entity if (allEnemys.Contains(character)) { - IEnumerable effects = Effects.Where(e => e.IsInEffect); + IEnumerable effects = Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority); if (CanSelectEnemy && ((AllowSelectDead && character.HP == 0) || (!AllowSelectDead && character.HP > 0)) && ((character.ImmuneType & checkType) == ImmuneType.None || effects.Any(e => e.IgnoreImmune == ImmuneType.All || e.IgnoreImmune == ImmuneType.Skilled || (IsMagic && e.IgnoreImmune == ImmuneType.Magical)))) { @@ -725,7 +725,7 @@ namespace Milimoe.FunGame.Core.Entity Character[] characters = [caster, .. targets]; foreach (Character target in characters) { - Effect[] effects = [.. target.Effects.Where(e => e.IsInEffect)]; + Effect[] effects = [.. target.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect e in effects) { e.GamingQueue = GamingQueue; diff --git a/Library/Common/Addon/GameMap.cs b/Library/Common/Addon/GameMap.cs index 6e95626..81bb5d2 100644 --- a/Library/Common/Addon/GameMap.cs +++ b/Library/Common/Addon/GameMap.cs @@ -979,7 +979,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon foreach (Grid grid in Grids.Values) { - List effects = [.. grid.Effects]; + List effects = [.. grid.Effects.OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { if (effect.Durative) diff --git a/Model/AIDecision.cs b/Model/AIDecision.cs index 2046e0a..884cb6e 100644 --- a/Model/AIDecision.cs +++ b/Model/AIDecision.cs @@ -14,6 +14,7 @@ namespace Milimoe.FunGame.Core.Model public List Targets { get; set; } = []; public List TargetGrids { get; set; } = []; public double Score { get; set; } = 0; + public double ProbabilityWeight { get; set; } = 0; public bool IsPureMove { get; set; } = false; } } diff --git a/Model/GamingQueue.cs b/Model/GamingQueue.cs index d444c89..1000854 100644 --- a/Model/GamingQueue.cs +++ b/Model/GamingQueue.cs @@ -712,7 +712,7 @@ namespace Milimoe.FunGame.Core.Model { // 触发游戏开始事件 OnGameStartEvent(); - Effect[] effects = [.. _queue.SelectMany(c => c.Effects).Where(e => e.IsInEffect)]; + Effect[] effects = [.. _queue.SelectMany(c => c.Effects).Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.OnGameStart(); @@ -795,7 +795,7 @@ namespace Milimoe.FunGame.Core.Model double reallyReHP = needHP >= recoveryHP ? recoveryHP : needHP; double reallyReMP = needMP >= recoveryMP ? recoveryMP : needMP; bool allowRecovery = true; - Effect[] effects = [.. character.Effects]; + Effect[] effects = [.. character.Effects.OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { if (!effect.BeforeApplyRecoveryAtTimeLapsing(character, ref reallyReHP, ref reallyReMP)) @@ -847,7 +847,7 @@ namespace Milimoe.FunGame.Core.Model _map?.OnTimeElapsed(timeToReduce); // 移除到时间的特效 - effects = [.. character.Effects]; + effects = [.. character.Effects.OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { if (!character.Shield.ShieldOfEffects.ContainsKey(effect)) @@ -919,7 +919,7 @@ namespace Milimoe.FunGame.Core.Model } // 如果特效具备临时驱散或者持续性驱散的功能 - effects = [.. character.Effects.Where(e => e.Source != null && (e.EffectType == EffectType.WeakDispelling || e.EffectType == EffectType.StrongDispelling))]; + effects = [.. character.Effects.Where(e => e.Source != null && (e.EffectType == EffectType.WeakDispelling || e.EffectType == EffectType.StrongDispelling)).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { if (effect.Source is null) continue; @@ -1025,7 +1025,7 @@ namespace Milimoe.FunGame.Core.Model skillTurnStart.OnTurnStart(character, selectableEnemys, selectableTeammates, skills, items); } - List effects = [.. character.Effects.Where(e => e.IsInEffect)]; + List effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.OnTurnStart(character, selectableEnemys, selectableTeammates, skills, items); @@ -1128,7 +1128,7 @@ namespace Milimoe.FunGame.Core.Model // 行动开始前,可以修改可选取的角色列表 Dictionary continuousKillingTemp = new(_continuousKilling); Dictionary earnedMoneyTemp = new(_earnedMoney); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterSelectListBeforeAction(character, enemys, teammates, skills, continuousKillingTemp, earnedMoneyTemp); @@ -1159,7 +1159,7 @@ namespace Milimoe.FunGame.Core.Model if (character.CharacterState != CharacterState.Casting && character.CharacterState != CharacterState.PreCastSuperSkill) { CharacterActionType actionTypeTemp = CharacterActionType.None; - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { bool force = false; @@ -1268,7 +1268,7 @@ namespace Milimoe.FunGame.Core.Model 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); + aiDecision = ai.DecideAIAction(character, dp, startGrid, canMoveGrids, skills, items, allEnemys, allTeammates, enemys, teammates, pUseItem, pCastSkill, pNormalAttack); type = aiDecision.ActionType; } else @@ -1307,7 +1307,7 @@ namespace Milimoe.FunGame.Core.Model int costDP = dp.GetActionPointCost(type); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.OnCharacterActionStart(character, dp, type); @@ -1396,14 +1396,14 @@ namespace Milimoe.FunGame.Core.Model character.NormalAttack.Attack(this, character, null, targets); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterNormalAttack(character, character.NormalAttack, targets); } baseTime += character.NormalAttack.RealHardnessTime; - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterNormalAttack(character, ref baseTime, ref isCheckProtected); @@ -1493,7 +1493,7 @@ namespace Milimoe.FunGame.Core.Model isCheckProtected = false; skill.OnSkillCasting(this, character, targets, grids); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterStartCasting(character, skill, targets); @@ -1568,7 +1568,7 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasting(this, character, targets, grids); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterStartCasting(character, skill, targets); @@ -1587,13 +1587,13 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasted(this, character, targets, grids); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterCastSkill(character, skill, targets); } - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected); @@ -1663,13 +1663,13 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasted(this, character, targets, grids); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterCastSkill(character, skill, targets); } - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected); @@ -1735,13 +1735,13 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasted(this, character, targets, grids); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterCastSkill(character, skill, targets); } - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected); @@ -1815,7 +1815,7 @@ namespace Milimoe.FunGame.Core.Model LastRound.Items[CharacterActionType.UseItem] = item; decided = true; baseTime += skill.RealHardnessTime > 0 ? skill.RealHardnessTime : 5; - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected); @@ -1864,7 +1864,7 @@ namespace Milimoe.FunGame.Core.Model OnCharacterActionTakenEvent(character, dp, type, LastRound); - effects = [.. _queue.Union([character]).SelectMany(c => c.Effects).Where(e => e.IsInEffect).Distinct()]; + effects = [.. _queue.Union([character]).SelectMany(c => c.Effects).Where(e => e.IsInEffect).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { effect.OnCharacterActionTaken(character, dp, type); @@ -1888,7 +1888,7 @@ namespace Milimoe.FunGame.Core.Model AfterCharacterDecision(character, dp); OnCharacterDecisionCompletedEvent(character, dp, LastRound); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.OnCharacterDecisionCompleted(character, dp); @@ -1928,7 +1928,7 @@ namespace Milimoe.FunGame.Core.Model LastRound.HardnessTime = newHardnessTime; OnQueueUpdatedEvent(_queue, character, dp, newHardnessTime, QueueUpdatedReason.Action, "设置角色行动后的硬直时间。"); - effects = [.. character.Effects]; + effects = [.. character.Effects.OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { if (effect.IsInEffect) @@ -1959,9 +1959,6 @@ namespace Milimoe.FunGame.Core.Model // 清空临时决策点 dp.ClearTempActionQuota(); - // 有人想要插队吗? - WillPreCastSuperSkill(); - // 回合结束事件 OnTurnEndEvent(character, dp); @@ -1969,6 +1966,10 @@ namespace Milimoe.FunGame.Core.Model WriteLine(""); _isInRound = false; + + // 有人想要插队吗? + WillPreCastSuperSkill(); + return _isGameEnd; } @@ -2126,7 +2127,7 @@ namespace Milimoe.FunGame.Core.Model // 真实伤害跳过伤害加成区间 if (damageType != DamageType.True) { - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { double damageBonus = effect.AlterActualDamageAfterCalculation(actor, enemy, damage, isNormalAttack, damageType, magicType, damageResult, ref isEvaded, totalDamageBonus); @@ -2140,7 +2141,7 @@ namespace Milimoe.FunGame.Core.Model } else { - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (effect.BeforeApplyTrueDamage(actor, enemy, damage, isNormalAttack, damageResult)) @@ -2188,7 +2189,7 @@ namespace Milimoe.FunGame.Core.Model ignore = true; } } - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (!effect.OnDamageImmuneCheck(actor, enemy, isNormalAttack, damageType, magicType, damage)) @@ -2227,7 +2228,7 @@ namespace Milimoe.FunGame.Core.Model { // 在护盾结算前,特效可以有自己的逻辑 bool change = false; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { double damageReduce = 0; @@ -2248,7 +2249,7 @@ namespace Milimoe.FunGame.Core.Model double remain = actualDamage; // 检查特效护盾 - effects = [.. enemy.Shield.ShieldOfEffects.Keys]; + effects = [.. enemy.Shield.ShieldOfEffects.Keys.OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { ShieldOfEffect soe = enemy.Shield.ShieldOfEffects[effect]; @@ -2277,7 +2278,7 @@ namespace Milimoe.FunGame.Core.Model { WriteLine($"[ {enemy} ] 发动了 [ {effect.Skill.Name} ] 的护盾效果,抵消了 {effectShield:0.##} 点{damageTypeString},护盾已破碎!"); remain -= effectShield; - Effect[] effects2 = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + Effect[] effects2 = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect2 in effects2) { if (!effect2.OnShieldBroken(enemy, actor, effect, remain)) @@ -2289,7 +2290,7 @@ namespace Milimoe.FunGame.Core.Model } if (remain <= 0) { - Effect[] effects2 = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + Effect[] effects2 = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect2 in effects2) { effect2.OnShieldNeutralizeDamage(enemy, actor, damageType, magicType, damage, ShieldType.Effect); @@ -2315,7 +2316,7 @@ namespace Milimoe.FunGame.Core.Model WriteLine($"[ {enemy} ] 的{shieldTypeString}护盾抵消了 {remain:0.##} 点{damageTypeString}!"); enemy.Shield[isMagicDamage, magicType] -= remain; remain = 0; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { effect.OnShieldNeutralizeDamage(enemy, actor, damageType, magicType, damage, shieldType); @@ -2328,7 +2329,7 @@ namespace Milimoe.FunGame.Core.Model enemy.Shield[isMagicDamage, magicType] = 0; if (isMagicDamage && enemy.Shield.TotalMagical <= 0 || !isMagicDamage && enemy.Shield.TotalPhysical <= 0) { - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (!effect.OnShieldBroken(enemy, actor, shieldType, remain)) @@ -2351,7 +2352,7 @@ namespace Milimoe.FunGame.Core.Model WriteLine($"[ {enemy} ] 的混合护盾抵消了 {remain:0.##} 点{damageTypeString}!"); enemy.Shield.Mix -= remain; remain = 0; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { effect.OnShieldNeutralizeDamage(enemy, actor, damageType, magicType, damage, ShieldType.Mix); @@ -2362,7 +2363,7 @@ namespace Milimoe.FunGame.Core.Model WriteLine($"[ {enemy} ] 的混合护盾抵消了 {enemy.Shield.TotalMix:0.##} 点{damageTypeString}并破碎!"); remain -= enemy.Shield.TotalMix; enemy.Shield.Mix = 0; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (!effect.OnShieldBroken(enemy, actor, ShieldType.Mix, remain)) @@ -2397,7 +2398,7 @@ namespace Milimoe.FunGame.Core.Model options.ActualDamage = actualDamage; enemy.HP -= actualDamage; string strDamageMessage = $"[ {enemy} ] 受到了 {actualDamage:0.##} 点{damageTypeString}!{shieldMsg}"; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { effect.OnApplyDamage(enemy, actor, damage, actualDamage, isNormalAttack, damageType, magicType, damageResult, shieldMsg, ref strDamageMessage); @@ -2425,7 +2426,7 @@ namespace Milimoe.FunGame.Core.Model // 生命偷取 double steal = actualDamage * actor.Lifesteal; bool allowSteal = true; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (!effect.BeforeLifesteal(actor, enemy, damage, steal)) @@ -2436,7 +2437,7 @@ namespace Milimoe.FunGame.Core.Model if (allowSteal) { HealToTarget(actor, actor, steal, false, true); - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { effect.AfterLifesteal(actor, enemy, damage, steal); @@ -2447,7 +2448,7 @@ namespace Milimoe.FunGame.Core.Model double ep = GetEP(actualDamage, GameplayEquilibriumConstant.DamageGetEPFactor, GameplayEquilibriumConstant.DamageGetEPMax); if (ep > 0) { - effects = [.. actor.Effects.Where(e => e.IsInEffect)]; + effects = [.. actor.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterEPAfterDamage(actor, ref ep); @@ -2457,7 +2458,7 @@ namespace Milimoe.FunGame.Core.Model ep = GetEP(actualDamage, GameplayEquilibriumConstant.TakenDamageGetEPFactor, GameplayEquilibriumConstant.TakenDamageGetEPMax); if (ep > 0) { - effects = [.. enemy.Effects.Where(e => e.IsInEffect)]; + effects = [.. enemy.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterEPAfterGetDamage(enemy, ref ep); @@ -2497,7 +2498,7 @@ namespace Milimoe.FunGame.Core.Model if (options.TriggerEffects) { - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { effect.AfterDamageCalculation(actor, enemy, damage, actualDamage, isNormalAttack, damageType, magicType, damageResult); @@ -2761,7 +2762,7 @@ namespace Milimoe.FunGame.Core.Model } bool allowHealing = true; - List effects = [.. actor.Effects.Union(target.Effects).Distinct().Where(e => e.IsInEffect)]; + List effects = [.. actor.Effects.Union(target.Effects).Distinct().Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { if (!effect.BeforeHealToTarget(actor, target, heal, canRespawn)) @@ -2782,7 +2783,7 @@ namespace Milimoe.FunGame.Core.Model if (triggerEffects) { Dictionary totalHealBonus = []; - effects = [.. actor.Effects.Union(target.Effects).Distinct().Where(e => e.IsInEffect)]; + effects = [.. actor.Effects.Union(target.Effects).Distinct().Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { bool changeCanRespawn = false; @@ -2971,7 +2972,7 @@ namespace Milimoe.FunGame.Core.Model public void DealWithCharacterDied(Character killer, Character death, Character[] assists) { // 给所有角色的特效广播角色死亡结算 - List effects = [.. _queue.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Union(killer.Effects).Distinct()]; + List effects = [.. _queue.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Union(killer.Effects).Distinct().OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterDeathCalculation(death, death.Master != null, killer, _continuousKilling, _earnedMoney, assists); @@ -3084,7 +3085,7 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasting(this, character, targets, grids); - Effect[] effects = [.. character.Effects.Where(e => e.IsInEffect)]; + Effect[] effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterStartCasting(character, skill, targets); @@ -3119,13 +3120,13 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasted(this, character, targets, grids); - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterCastSkill(character, skill, targets); } - effects = [.. character.Effects.Where(e => e.IsInEffect)]; + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterUseItem(character, item, skill, targets); @@ -3234,7 +3235,7 @@ namespace Milimoe.FunGame.Core.Model /// public Grid SelectTargetGrid(Character character, List enemys, List teammates, GameMap map, List moveRange) { - List effects = [.. character.Effects.Where(e => e.IsInEffect)]; + List effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.BeforeSelectTargetGrid(character, enemys, teammates, map, moveRange); @@ -3265,7 +3266,7 @@ namespace Milimoe.FunGame.Core.Model /// public List SelectTargets(Character caster, Skill skill, List enemys, List teammates, List castRange) { - List effects = [.. caster.Effects.Where(e => e.IsInEffect)]; + List effects = [.. caster.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterSelectListBeforeSelection(caster, skill, enemys, teammates); @@ -3308,7 +3309,7 @@ namespace Milimoe.FunGame.Core.Model /// public List SelectTargets(Character character, NormalAttack attack, List enemys, List teammates, List attackRange) { - List effects = [.. character.Effects.Where(e => e.IsInEffect)]; + List effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AlterSelectListBeforeSelection(character, attack, enemys, teammates); @@ -3416,7 +3417,7 @@ namespace Milimoe.FunGame.Core.Model List characters = [actor, enemy]; DamageType damageType = DamageType.Physical; MagicType magicType = MagicType.None; - List effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + List effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; Dictionary totalDamageBonus = []; if (options.TriggerEffects) { @@ -3433,7 +3434,7 @@ namespace Milimoe.FunGame.Core.Model } } - effects = [.. actor.Effects.Union(enemy.Effects).Distinct().Where(e => e.IsInEffect)]; + effects = [.. actor.Effects.Union(enemy.Effects).Distinct().Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, DamageType.Physical, MagicType.None, totalDamageBonus); @@ -3449,7 +3450,7 @@ namespace Milimoe.FunGame.Core.Model bool checkCritical = true; if (isNormalAttack && options.CalculateEvade) { - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (!effect.BeforeEvadeCheck(actor, enemy, ref throwingBonus)) @@ -3464,7 +3465,7 @@ namespace Milimoe.FunGame.Core.Model if (dice < (enemy.EvadeRate + throwingBonus)) { bool isAlterEvaded = false; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (effect.OnEvadedTriggered(actor, enemy, dice)) @@ -3500,7 +3501,7 @@ namespace Milimoe.FunGame.Core.Model if (options.CalculateCritical) { // 暴击检定 - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (!effect.BeforeCriticalCheck(actor, enemy, isNormalAttack, ref throwingBonus)) @@ -3517,7 +3518,7 @@ namespace Milimoe.FunGame.Core.Model options.CriticalDamage = finalDamage * (actor.CritDMG - 1); finalDamage *= actor.CritDMG; // 暴击伤害倍率加成 WriteLine("暴击生效!!"); - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { effect.OnCriticalDamageTriggered(actor, enemy, dice); @@ -3549,7 +3550,7 @@ namespace Milimoe.FunGame.Core.Model if (options.ExpectedDamage == 0) options.ExpectedDamage = expectedDamage; List characters = [actor, enemy]; DamageType damageType = DamageType.Magical; - List effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + List effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; Dictionary totalDamageBonus = []; if (options.TriggerEffects) { @@ -3566,7 +3567,7 @@ namespace Milimoe.FunGame.Core.Model } } - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, DamageType.Magical, magicType, totalDamageBonus); @@ -3582,7 +3583,7 @@ namespace Milimoe.FunGame.Core.Model bool checkCritical = true; if (isNormalAttack && options.CalculateEvade) { - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (!effect.BeforeEvadeCheck(actor, enemy, ref throwingBonus)) @@ -3597,7 +3598,7 @@ namespace Milimoe.FunGame.Core.Model if (dice < (enemy.EvadeRate + throwingBonus)) { bool isAlterEvaded = false; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (effect.OnEvadedTriggered(actor, enemy, dice)) @@ -3633,7 +3634,7 @@ namespace Milimoe.FunGame.Core.Model if (options.CalculateCritical) { // 暴击检定 - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { if (!effect.BeforeCriticalCheck(actor, enemy, isNormalAttack, ref throwingBonus)) @@ -3650,7 +3651,7 @@ namespace Milimoe.FunGame.Core.Model options.CriticalDamage = finalDamage * (actor.CritDMG - 1); finalDamage *= actor.CritDMG; // 暴击伤害倍率加成 WriteLine("暴击生效!!"); - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { effect.OnCriticalDamageTriggered(actor, enemy, dice); @@ -3959,7 +3960,7 @@ namespace Milimoe.FunGame.Core.Model if (skill != null) { bool interruption = true; - List effects = [.. caster.Effects.Union(interrupter.Effects).Distinct().Where(e => e.IsInEffect)]; + List effects = [.. caster.Effects.Union(interrupter.Effects).Distinct().Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect e in effects) { if (!e.BeforeSkillCastWillBeInterrupted(caster, skill, interrupter)) @@ -3971,7 +3972,7 @@ namespace Milimoe.FunGame.Core.Model { _castingSkills.Remove(caster); WriteLine($"[ {caster} ] 的施法被 [ {interrupter} ] 打断了!!"); - effects = [.. caster.Effects.Union(interrupter.Effects).Distinct().Where(e => e.IsInEffect)]; + effects = [.. caster.Effects.Union(interrupter.Effects).Distinct().Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect e in effects) { e.OnSkillCastInterrupted(caster, skill, interrupter); @@ -3995,7 +3996,7 @@ namespace Milimoe.FunGame.Core.Model { Skill skill = skillTarget.Skill; WriteLine($"[ {caster} ] 丢失了施法目标!!"); - List effects = [.. caster.Effects.Union(interrupter.Effects).Distinct().Where(e => e.IsInEffect)]; + List effects = [.. caster.Effects.Union(interrupter.Effects).Distinct().Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.OnSkillCastInterrupted(caster, skill, interrupter); @@ -4040,6 +4041,10 @@ namespace Milimoe.FunGame.Core.Model /// public void SetCharacterPreCastSuperSkill(Character character, Skill skill) { + if (LastRound.Actor == character && _isInRound) + { + return; + } if (_decisionPoints.TryGetValue(character, out DecisionPoints? dp) && dp != null) { if (dp.CurrentDecisionPoints < GameplayEquilibriumConstant.DecisionPointsCostSuperSkillOutOfTurn) @@ -4104,7 +4109,7 @@ namespace Milimoe.FunGame.Core.Model AddCharacter(character, newHardnessTime, false); skill.OnSkillCasting(this, character, [], []); - Effect[] effects = [.. character.Effects.Where(e => e.IsInEffect)]; + Effect[] effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.AfterCharacterStartCasting(character, skill, []); @@ -4289,7 +4294,7 @@ namespace Milimoe.FunGame.Core.Model (target.ImmuneType & ImmuneType.Skilled) == ImmuneType.Skilled || (target.ImmuneType & ImmuneType.All) == ImmuneType.All; if (isImmune) { - Effect[] effects = [.. skill.Effects.Where(e => e.IsInEffect)]; + Effect[] effects = [.. skill.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { // 自带无视免疫 @@ -4301,7 +4306,7 @@ namespace Milimoe.FunGame.Core.Model if (!ignore) { Character[] characters = [character, target]; - effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect effect in effects) { // 特效免疫检定不通过可无视免疫 @@ -4345,7 +4350,7 @@ namespace Milimoe.FunGame.Core.Model bool checkExempted = true; double throwingBonus = 0; Character[] characters = source != null ? [character, source] : [character]; - Effect[] effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; + Effect[] effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()]; foreach (Effect e in effects) { if (!e.OnExemptionCheck(character, source, effect, isEvade, ref throwingBonus)) @@ -4520,7 +4525,7 @@ namespace Milimoe.FunGame.Core.Model _decisionPoints[character] = dp; } InquiryResponse response = OnCharacterInquiryEvent(character, dp, options); - Effect[] effects = [.. character.Effects.Where(e => e.IsInEffect)]; + Effect[] effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { effect.OnCharacterInquiry(character, options, response); diff --git a/Model/InquiryOptions.cs b/Model/InquiryOptions.cs index b5784e4..2a765b5 100644 --- a/Model/InquiryOptions.cs +++ b/Model/InquiryOptions.cs @@ -12,6 +12,7 @@ namespace Milimoe.FunGame.Core.Model public double MinNumberValue { get; set; } = 0; public double MaxNumberValue { get; set; } = 0; public double DefaultNumberValue { get; set; } = 0; + public bool CanCancel { get; set; } = true; public Dictionary CustomArgs { get; set; } = []; public InquiryOptions(InquiryType type, string topic) diff --git a/Model/InquiryResponse.cs b/Model/InquiryResponse.cs index dbba58e..59aaabc 100644 --- a/Model/InquiryResponse.cs +++ b/Model/InquiryResponse.cs @@ -9,6 +9,7 @@ namespace Milimoe.FunGame.Core.Model public List Choices { get; set; } = []; public string TextResult { get; set; } = ""; public double NumberResult { get; set; } = 0; + public bool Cancel { get; set; } = false; public Dictionary CustomResponse { get; set; } = []; public InquiryResponse(InquiryType type, string topic)