添加特效触发优先级;将行动偏好的概率值引入战棋模式;添加询问可取消机制

This commit is contained in:
milimoe 2026-01-24 04:21:11 +08:00
parent 97a5c0ac41
commit f75699d5ff
Signed by: milimoe
GPG Key ID: 9554D37E4B8991D0
11 changed files with 388 additions and 333 deletions

View File

@ -24,11 +24,29 @@ namespace Milimoe.FunGame.Core.Controller
/// <param name="allTeammatesInGame">场上所有队友</param>
/// <param name="selectableEnemys">场上能够选取的敌人</param>
/// <param name="selectableTeammates">场上能够选取的队友</param>
/// <param name="pUseItem">使用物品的概率</param>
/// <param name="pCastSkill">释放技能的概率</param>
/// <param name="pNormalAttack">普通攻击的概率</param>
/// <returns>包含最佳行动的AIDecision对象</returns>
public AIDecision DecideAIAction(Character character, DecisionPoints dp, Grid startGrid, List<Grid> allPossibleMoveGrids,
List<Skill> availableSkills, List<Item> availableItems, List<Character> allEnemysInGame, List<Character> allTeammatesInGame,
List<Character> selectableEnemys, List<Character> selectableTeammates)
List<Character> selectableEnemys, List<Character> 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<AIDecision> candidateDecisions = [];
// 遍历所有可能的移动目标格子 (包括起始格子本身)
foreach (Grid potentialMoveGrid in allPossibleMoveGrids)
{
@ -45,6 +66,8 @@ namespace Milimoe.FunGame.Core.Controller
int moveDistance = GameMap.CalculateManhattanDistance(startGrid, potentialMoveGrid);
double movePenalty = moveDistance * 0.5; // 每移动一步扣0.5分
if (pNormalAttack > 0)
{
if (CanCharacterNormalAttack(character, dp))
{
// 计算普通攻击的可达格子
@ -60,21 +83,23 @@ namespace Milimoe.FunGame.Core.Controller
if (targets.Count > 0)
{
double currentScore = EvaluateNormalAttack(character, targets) - movePenalty;
if (currentScore > bestDecision.Score)
{
bestDecision = new AIDecision
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
});
}
}
}
}
if (pCastSkill > 0)
{
foreach (Skill skill in availableSkills)
{
if (CanCharacterUseSkill(character, skill, dp) && _queue.CheckCanCast(character, skill, out double cost))
@ -104,16 +129,16 @@ namespace Milimoe.FunGame.Core.Controller
if (targets.Count > 0)
{
double currentScore = EvaluateSkill(character, skill, targets, cost) - movePenalty;
if (currentScore > bestDecision.Score)
{
bestDecision = new AIDecision
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,6 +146,8 @@ namespace Milimoe.FunGame.Core.Controller
}
}
if (pUseItem > 0)
{
foreach (Item item in availableItems)
{
if (item.Skills.Active != null && CanCharacterUseItem(character, item, dp) && _queue.CheckCanCast(character, item.Skills.Active, out double cost))
@ -152,17 +179,17 @@ namespace Milimoe.FunGame.Core.Controller
if (targetsForItem.Count > 0)
{
double currentScore = EvaluateItem(character, item, targetsForItem, cost) - movePenalty;
if (currentScore > bestDecision.Score)
{
bestDecision = new AIDecision
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,26 +236,110 @@ namespace Milimoe.FunGame.Core.Controller
}
}
// 如果纯粹移动比当前最佳(什么都不做)更好
if (pureMoveScore > bestDecision.Score)
{
bestDecision = new AIDecision
candidateDecisions.Add(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)
{
decision.Score *= 1.2;
}
}
}
// 最终决策
bestDecision = candidateDecisions.OrderByDescending(d => d.Score * d.ProbabilityWeight).FirstOrDefault() ?? bestDecision;
}
return bestDecision;
}
// --- AI 决策辅助方法 ---
// 获取偏好行动类型
private static CharacterActionType? GetPreferredActionType(double pItem, double pSkill, double pAttack)
{
// 找出最高概率的行动类型
Dictionary<CharacterActionType, double> 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<Character> allEnemysInGame, List<Character> 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)
{

View File

@ -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
/// </summary>
public void OnAttributeChanged()
{
List<Effect> effects = [.. Effects.Where(e => e.IsInEffect)];
List<Effect> 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<string> 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<string> 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
/// 获取战斗状态的信息
/// </summary>
/// <param name="hardnessTimes"></param>
/// <param name="simpleStatusBar"></param>
/// <returns></returns>
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<string> 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("== 状态栏 ==");
if (simpleStatusBar)
{
builder.Append(string.Join("", effects.Select(e => e.Name)));
}
else
{
foreach (Effect effect in effects)
{
builder.AppendLine(effect.ToString());
}
}
}
return builder.ToString().Trim();
}
/// <summary>
/// 获取战斗状态的信息(简略版)
/// </summary>
/// <param name="hardnessTimes"></param>
/// <returns></returns>
public string GetSimpleInBattleInfo(double hardnessTimes)
{
StringBuilder builder = new();
builder.AppendLine((HP == 0 ? "[ 死亡 ] " : "") + ToStringWithLevel());
double exHP = ExHP + ExHP2 + ExHP3;
List<string> 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();
}
/// <summary>
/// 获取角色的技能信息
/// </summary>
@ -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();
}
/// <summary>
/// 获取角色属性和能力值信息
/// </summary>
/// <returns></returns>
public string GetAttributeInfo(bool showGrowth = true)
{
StringBuilder builder = new();
double exHP = ExHP + ExHP2 + ExHP3;
List<string> 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)
/// <summary>
/// 获取角色属性和能力值的简略版信息
/// </summary>
/// <returns></returns>
public string GetSimpleAttributeInfo(bool showGrowth = true, bool showBasicOnly = false)
{
StringBuilder builder = new();
double exHP = ExHP + ExHP2 + ExHP3;
List<string> 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();
}
/// <summary>
/// 获取角色状态信息
/// </summary>
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();
}
/// <summary>
@ -2134,7 +2095,7 @@ namespace Milimoe.FunGame.Core.Entity
List<Skill> skills = [.. Skills];
List<Item> items = [.. Items];
Character c = original.Copy();
List<Effect> effects = [.. Effects];
List<Effect> effects = [.. Effects.OrderByDescending(e => e.Priority)];
foreach (Effect e in effects)
{
e.OnEffectLost(this);

View File

@ -292,8 +292,9 @@ namespace Milimoe.FunGame.Core.Entity
/// 获取战斗状态的信息
/// </summary>
/// <param name="hardnessTimes"></param>
/// <param name="simpleStatusBar"></param>
/// <returns></returns>
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();
}
/// <summary>
/// 获取战斗状态的信息(简略版)
/// </summary>
/// <param name="hardnessTimes"></param>
/// <returns></returns>
public new string GetSimpleInBattleInfo(double hardnessTimes)
{
StringBuilder builder = new();
builder.AppendLine(ToStringWithLevel());
double exHP = ExHP + ExHP2 + ExHP3;
List<string> 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();
}
/// <summary>
/// 获取单位的技能信息
/// </summary>

View File

@ -252,7 +252,7 @@ namespace Milimoe.FunGame.Core.Entity
{
foreach (Skill skill in Skills.Passives)
{
List<Effect> effects = [.. Character.Effects.Where(e => e.Skill == skill && e.IsInEffect)];
List<Effect> effects = [.. Character.Effects.Where(e => e.Skill == skill && e.IsInEffect).OrderByDescending(e => e.Priority)];
foreach (Effect e in effects)
{
Character.Effects.Remove(e);

View File

@ -18,6 +18,12 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary>
public Skill Skill { get; }
/// <summary>
/// 特效触发优先级
/// 越大优先级越高;默认值为 0在状态栏<see cref="Character.Effects"/>)中使用默认哈希排序。
/// </summary>
public int Priority { get; set; } = 0;
/// <summary>
/// 特殊效果类型<para/>
/// 注意:如果技能特效没有原生施加控制效果,请始终保持此属性为 <see cref="EffectType.None"/>。
@ -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))

View File

@ -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<Effect> effects = Effects.Where(e => e.IsInEffect);
IEnumerable<Effect> 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<Effect> effects = Effects.Where(e => e.IsInEffect);
IEnumerable<Effect> 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;

View File

@ -979,7 +979,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
foreach (Grid grid in Grids.Values)
{
List<Effect> effects = [.. grid.Effects];
List<Effect> effects = [.. grid.Effects.OrderByDescending(e => e.Priority)];
foreach (Effect effect in effects)
{
if (effect.Durative)

View File

@ -14,6 +14,7 @@ namespace Milimoe.FunGame.Core.Model
public List<Character> Targets { get; set; } = [];
public List<Grid> TargetGrids { get; set; } = [];
public double Score { get; set; } = 0;
public double ProbabilityWeight { get; set; } = 0;
public bool IsPureMove { get; set; } = false;
}
}

View File

@ -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<Effect> effects = [.. character.Effects.Where(e => e.IsInEffect)];
List<Effect> 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<Character, int> continuousKillingTemp = new(_continuousKilling);
Dictionary<Character, int> 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<Character> allEnemysInGame = [.. allEnemys.Where(canAttackGridsByStartGrid.Union(canCastGridsByStartGrid).SelectMany(g => g.Characters).Contains)];
List<Character> 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<Effect> effects = [.. actor.Effects.Union(target.Effects).Distinct().Where(e => e.IsInEffect)];
List<Effect> 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<Effect, double> 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<Effect> effects = [.. _queue.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Union(killer.Effects).Distinct()];
List<Effect> 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
/// <returns></returns>
public Grid SelectTargetGrid(Character character, List<Character> enemys, List<Character> teammates, GameMap map, List<Grid> moveRange)
{
List<Effect> effects = [.. character.Effects.Where(e => e.IsInEffect)];
List<Effect> 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
/// <returns></returns>
public List<Character> SelectTargets(Character caster, Skill skill, List<Character> enemys, List<Character> teammates, List<Grid> castRange)
{
List<Effect> effects = [.. caster.Effects.Where(e => e.IsInEffect)];
List<Effect> 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
/// <returns></returns>
public List<Character> SelectTargets(Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates, List<Grid> attackRange)
{
List<Effect> effects = [.. character.Effects.Where(e => e.IsInEffect)];
List<Effect> 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<Character> characters = [actor, enemy];
DamageType damageType = DamageType.Physical;
MagicType magicType = MagicType.None;
List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()];
Dictionary<Effect, double> 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<Character> characters = [actor, enemy];
DamageType damageType = DamageType.Magical;
List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).OrderByDescending(e => e.Priority).Distinct()];
Dictionary<Effect, double> 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<Effect> effects = [.. caster.Effects.Union(interrupter.Effects).Distinct().Where(e => e.IsInEffect)];
List<Effect> 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<Effect> effects = [.. caster.Effects.Union(interrupter.Effects).Distinct().Where(e => e.IsInEffect)];
List<Effect> 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
/// <param name="skill"></param>
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);

View File

@ -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<string, object> CustomArgs { get; set; } = [];
public InquiryOptions(InquiryType type, string topic)

View File

@ -9,6 +9,7 @@ namespace Milimoe.FunGame.Core.Model
public List<string> Choices { get; set; } = [];
public string TextResult { get; set; } = "";
public double NumberResult { get; set; } = 0;
public bool Cancel { get; set; } = false;
public Dictionary<string, object> CustomResponse { get; set; } = [];
public InquiryResponse(InquiryType type, string topic)