From 5194fe39e93da34fc6d23d97392ca10969f511a5 Mon Sep 17 00:00:00 2001 From: milimoe <110188673+milimoe@users.noreply.github.com> Date: Mon, 2 Mar 2026 02:00:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20DamageRecord=EF=BC=9B?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BA=86=E9=A2=84=E5=88=B6=E6=8A=80=E8=83=BD?= =?UTF-8?q?=E7=81=B5=E9=AD=82=E7=BB=91=E5=AE=9A=EF=BC=9B=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=9B=B4=E5=A4=9A=E9=92=A9=E5=AD=90=20(#149)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Entity/Skill/Effect.cs | 53 +++++++--- Entity/Skill/Skill.cs | 29 ++++- Library/Common/Addon/Example/ExampleSkill.cs | 4 +- Model/DamageCalculationOptions.cs | 6 ++ Model/DamageRecord.cs | 100 ++++++++++++++++++ Model/GamingQueue.cs | 16 ++- .../CourageCommandSkill.cs | 3 +- Model/PrefabricatedEntity/MagicCardPack.cs | 6 +- .../NeuralCalibrationEffect.cs | 2 +- Model/PrefabricatedEntity/SoulboundSkill.cs | 50 ++++++++- 10 files changed, 239 insertions(+), 30 deletions(-) create mode 100644 Model/DamageRecord.cs diff --git a/Entity/Skill/Effect.cs b/Entity/Skill/Effect.cs index badd996..9789a2c 100644 --- a/Entity/Skill/Effect.cs +++ b/Entity/Skill/Effect.cs @@ -455,7 +455,20 @@ namespace Milimoe.FunGame.Core.Entity } /// - /// 在技能释放前触发 + /// 在技能释放前触发 [ 技能的特效组 ] + /// + /// + /// + /// + /// + /// + public virtual void BeforeSkillCasted(Character caster, List targets, List grids, double mpCost = 0, double epCost = 0) + { + + } + + /// + /// 在技能释放前触发 [ 状态栏特效 ] /// /// /// @@ -468,6 +481,17 @@ namespace Milimoe.FunGame.Core.Entity return true; } + /// + /// 在技能释放后触发 [ 技能的特效组 ] + /// + /// + /// + /// + public virtual void AfterSkillCasted(Character caster, List targets, List grids) + { + + } + /// /// 在时间流逝期间应用生命/魔法回复前修改 [ 允许取消回复 ] /// @@ -1051,21 +1075,24 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// - public DamageResult DamageToEnemy(Character actor, Character enemy, DamageType damageType, MagicType magicType, double expectedDamage, DamageCalculationOptions? options = null) + public DamageRecord DamageToEnemy(Character actor, Character enemy, DamageType damageType, MagicType magicType, double expectedDamage, DamageCalculationOptions? options = null) { - if (GamingQueue is null) return DamageResult.Evaded; - int changeCount = 0; - DamageResult result = DamageResult.Normal; - double damage = expectedDamage; - options ??= new(actor); - options.Skill = Skill; - if (options.ExpectedDamage == 0) options.ExpectedDamage = expectedDamage; - if (options.NeedCalculate && damageType != DamageType.True) + if (GamingQueue != null) { - result = damageType == DamageType.Physical ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out damage, ref changeCount, ref options) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage, ref changeCount, ref options); + int changeCount = 0; + DamageResult result = DamageResult.Normal; + double damage = expectedDamage; + options ??= new(actor); + options.Skill = Skill; + if (options.ExpectedDamage == 0) options.ExpectedDamage = expectedDamage; + if (options.NeedCalculate && damageType != DamageType.True) + { + result = damageType == DamageType.Physical ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out damage, ref changeCount, ref options) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage, ref changeCount, ref options); + } + GamingQueue.DamageToEnemy(actor, enemy, damage, false, damageType, magicType, result, options); + return options?.GetDamageRecord(damageType, result) ?? new(); } - GamingQueue.DamageToEnemy(actor, enemy, damage, false, damageType, magicType, result, options); - return result; + return new(); } /// diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs index 590ec86..f914cb8 100644 --- a/Entity/Skill/Skill.cs +++ b/Entity/Skill/Skill.cs @@ -385,6 +385,10 @@ namespace Milimoe.FunGame.Core.Entity SkillType = type; CastAnywhere = SkillType == SkillType.Magic; Character = character; + if (SkillType == SkillType.SuperSkill) + { + EPCost = 100; + } } /// @@ -712,7 +716,7 @@ namespace Milimoe.FunGame.Core.Entity public void OnSkillCasting(IGamingQueue queue, Character caster, List targets, List grids) { GamingQueue = queue; - foreach (Effect e in Effects) + foreach (Effect e in Effects.OrderByDescending(e => e.Priority)) { e.GamingQueue = GamingQueue; e.OnSkillCasting(caster, targets, grids); @@ -722,10 +726,15 @@ namespace Milimoe.FunGame.Core.Entity /// /// 技能效果触发前 /// - public void BeforeSkillCasted() + public void BeforeSkillCasted(Character caster, List targets, List grids) { LastCostMP = RealMPCost; LastCostEP = RealEPCost; + foreach (Effect e in Effects.OrderByDescending(e => e.Priority)) + { + e.GamingQueue = GamingQueue; + e.BeforeSkillCasted(caster, targets, grids, LastCostMP, LastCostEP); + } } /// @@ -762,13 +771,25 @@ namespace Milimoe.FunGame.Core.Entity } } } - foreach (Effect e in Effects) + foreach (Effect e in Effects.OrderByDescending(e => e.Priority)) { e.GamingQueue = GamingQueue; e.OnSkillCasted(caster, targets, grids, Values); } } + /// + /// 技能效果触发后 + /// + public void AfterSkillCasted(Character caster, List targets, List grids) + { + foreach (Effect e in Effects.OrderByDescending(e => e.Priority)) + { + e.GamingQueue = GamingQueue; + e.AfterSkillCasted(caster, targets, grids); + } + } + /// /// 对目标触发技能效果 /// @@ -776,7 +797,7 @@ namespace Milimoe.FunGame.Core.Entity /// public void OnSkillCasted(User user, List targets) { - foreach (Effect e in Effects) + foreach (Effect e in Effects.OrderByDescending(e => e.Priority)) { e.OnSkillCasted(user, targets, Values); } diff --git a/Library/Common/Addon/Example/ExampleSkill.cs b/Library/Common/Addon/Example/ExampleSkill.cs index c443e1d..c506f02 100644 --- a/Library/Common/Addon/Example/ExampleSkill.cs +++ b/Library/Common/Addon/Example/ExampleSkill.cs @@ -324,7 +324,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example character.ExATK2 += ActualATKBonus; character.PhysicalPenetration += ActualPhysicalPenetrationBonus; character.ExEvadeRate += ActualEvadeRateBonus; - if (character.Effects.FirstOrDefault(e => e is ExamplePassiveSkillEffect) is ExamplePassiveSkillEffect e) + if (character.Effects.FirstOrDefault(e => e is ExamplePassiveSkillEffect && e.Skill.Character == character) is ExamplePassiveSkillEffect e) { e.CD = 3; if (e.CurrentCD > e.CD) e.CurrentCD = e.CD; @@ -337,7 +337,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example character.ExATK2 -= ActualATKBonus; character.PhysicalPenetration -= ActualPhysicalPenetrationBonus; character.ExEvadeRate -= ActualEvadeRateBonus; - if (character.Effects.FirstOrDefault(e => e is ExamplePassiveSkillEffect) is ExamplePassiveSkillEffect e) + if (character.Effects.FirstOrDefault(e => e is ExamplePassiveSkillEffect && e.Skill.Character == character) is ExamplePassiveSkillEffect e) { e.CD = 10; } diff --git a/Model/DamageCalculationOptions.cs b/Model/DamageCalculationOptions.cs index 9e38a6a..450a5a2 100644 --- a/Model/DamageCalculationOptions.cs +++ b/Model/DamageCalculationOptions.cs @@ -1,4 +1,5 @@ using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Library.Constant; namespace Milimoe.FunGame.Core.Model { @@ -74,6 +75,11 @@ namespace Milimoe.FunGame.Core.Model /** == 调试数据记录 == **/ + /// + /// 生成伤害记录 + /// + public DamageRecord GetDamageRecord(DamageType type, DamageResult result) => new(type, result, ExpectedDamage, BeforeDamageBonus, CriticalDamage, DefenseReduction, AfterDamageBonus, MagicEfficacyDamage, FinalDamage, ShieldReduction, ActualDamage); + /// /// 伤害基底(期望) /// diff --git a/Model/DamageRecord.cs b/Model/DamageRecord.cs new file mode 100644 index 0000000..1dac148 --- /dev/null +++ b/Model/DamageRecord.cs @@ -0,0 +1,100 @@ +using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Library.Constant; + +namespace Milimoe.FunGame.Core.Model +{ + /// + /// 记录所有伤害的组成部分 + /// + public readonly struct DamageRecord + { + /// + /// 记录所有伤害的组成部分 + /// + public DamageRecord() + { + ExpectedDamage = 0; + BeforeDamageBonus = []; + CriticalDamage = 0; + DefenseReduction = 0; + AfterDamageBonus = []; + MagicEfficacyDamage = 0; + FinalDamage = 0; + ShieldReduction = 0; + ActualDamage = 0; + } + + /// + /// 记录所有伤害的组成部分 + /// + public DamageRecord(DamageType type, DamageResult result, double expectedDamage, Dictionary beforeDamageBonus, double criticalDamage, double defenseReduction, Dictionary afterDamageBonus, double magicEfficacyDamage, double finalDamage, double shieldReduction, double actualDamage) + { + DamageType = type; + DamageResult = result; + ExpectedDamage = expectedDamage; + BeforeDamageBonus = beforeDamageBonus; + CriticalDamage = criticalDamage; + DefenseReduction = defenseReduction; + AfterDamageBonus = afterDamageBonus; + MagicEfficacyDamage = magicEfficacyDamage; + FinalDamage = finalDamage; + ShieldReduction = shieldReduction; + ActualDamage = actualDamage; + } + + /// + /// 伤害类型 + /// + public DamageType DamageType { get; } = DamageType.Physical; + + /// + /// 伤害结果 + /// + public DamageResult DamageResult { get; } = DamageResult.Normal; + + /// + /// 伤害基底(期望) + /// + public double ExpectedDamage { get; } + + /// + /// 特效伤害加成记录(乘区1:暴击和减伤计算前) + /// + public Dictionary BeforeDamageBonus { get; } + + /// + /// 暴击伤害 + /// + public double CriticalDamage { get; } + + /// + /// 伤害减免 + /// + public double DefenseReduction { get; } + + /// + /// 特效伤害加成记录(乘区2:暴击和减伤计算后) + /// + public Dictionary AfterDamageBonus { get; } + + /// + /// 魔法效能修正 + /// + public double MagicEfficacyDamage { get; } + + /// + /// 最终伤害 + /// + public double FinalDamage { get; } + + /// + /// 护盾减免 + /// + public double ShieldReduction { get; } + + /// + /// 实际造成伤害 + /// + public double ActualDamage { get; } + } +} diff --git a/Model/GamingQueue.cs b/Model/GamingQueue.cs index a53ee69..ae57b98 100644 --- a/Model/GamingQueue.cs +++ b/Model/GamingQueue.cs @@ -1583,7 +1583,7 @@ namespace Milimoe.FunGame.Core.Model effect.AfterCharacterStartCasting(character, skill, targets); } - skill.BeforeSkillCasted(); + skill.BeforeSkillCasted(character, targets, grids); character.EP -= cost; baseTime += skill.RealHardnessTime; @@ -1596,6 +1596,8 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasted(this, character, targets, grids); + skill.AfterSkillCasted(character, targets, grids); + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { @@ -1659,7 +1661,7 @@ namespace Milimoe.FunGame.Core.Model LastRound.ActionTypes.Add(CharacterActionType.CastSkill); _castingSkills.Remove(character); - skill.BeforeSkillCasted(); + skill.BeforeSkillCasted(character, targets, grids); character.MP -= cost; baseTime += skill.RealHardnessTime; @@ -1672,6 +1674,8 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasted(this, character, targets, grids); + skill.AfterSkillCasted(character, targets, grids); + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { @@ -1730,7 +1734,7 @@ namespace Milimoe.FunGame.Core.Model CheckSkilledImmune(character, targets, skill); LastRound.Targets[CharacterActionType.CastSuperSkill] = [.. targets]; - skill.BeforeSkillCasted(); + skill.BeforeSkillCasted(character, targets, grids); character.EP -= cost; baseTime += skill.RealHardnessTime; @@ -1744,6 +1748,8 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasted(this, character, targets, grids); + skill.AfterSkillCasted(character, targets, grids); + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { @@ -3106,7 +3112,7 @@ namespace Milimoe.FunGame.Core.Model effect.AfterCharacterStartCasting(character, skill, targets); } - skill.BeforeSkillCasted(); + skill.BeforeSkillCasted(character, targets, grids); skill.CurrentCD = skill.RealCD; skill.Enable = false; @@ -3135,6 +3141,8 @@ namespace Milimoe.FunGame.Core.Model skill.OnSkillCasted(this, character, targets, grids); + skill.AfterSkillCasted(character, targets, grids); + effects = [.. character.Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)]; foreach (Effect effect in effects) { diff --git a/Model/PrefabricatedEntity/CourageCommandSkill.cs b/Model/PrefabricatedEntity/CourageCommandSkill.cs index c138fa0..10dc3b1 100644 --- a/Model/PrefabricatedEntity/CourageCommandSkill.cs +++ b/Model/PrefabricatedEntity/CourageCommandSkill.cs @@ -1,11 +1,12 @@ using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Library.Constant; namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity { /// /// 继承此类以表示勇气指令技能 /// - public class CourageCommandSkill(long id, string name, Dictionary args, Character? character = null) : OpenSkill(id, name, args, character) + public abstract class CourageCommandSkill(Character? character = null) : Skill(SkillType.Skill, character) { } diff --git a/Model/PrefabricatedEntity/MagicCardPack.cs b/Model/PrefabricatedEntity/MagicCardPack.cs index d19a338..3db5bff 100644 --- a/Model/PrefabricatedEntity/MagicCardPack.cs +++ b/Model/PrefabricatedEntity/MagicCardPack.cs @@ -6,7 +6,7 @@ namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity /// /// 魔法卡包的基础实现 /// - public class MagicCardPack : OpenItem + public class MagicCardPack : Item { public override ItemType ItemType => ItemType.MagicCardPack; @@ -50,10 +50,12 @@ namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity /// private PrimaryAttribute _originalAttribute = PrimaryAttribute.None; - public MagicCardPack(long id, string name, Dictionary args) : base(id, name, args) + public MagicCardPack(Dictionary? args = null) : base(ItemType.MagicCardPack) { + args ??= []; foreach (string key in args.Keys) { + Others[key] = args[key]; switch (key.ToLower()) { case "exstr": diff --git a/Model/PrefabricatedEntity/NeuralCalibrationEffect.cs b/Model/PrefabricatedEntity/NeuralCalibrationEffect.cs index d238f12..da06890 100644 --- a/Model/PrefabricatedEntity/NeuralCalibrationEffect.cs +++ b/Model/PrefabricatedEntity/NeuralCalibrationEffect.cs @@ -6,7 +6,7 @@ namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity /// /// 继承此类以表示神经校准特效 /// - public class NeuralCalibrationEffect : Effect + public abstract class NeuralCalibrationEffect : Effect { public WeaponType SupportedWeaponType { get; set; } = WeaponType.None; } diff --git a/Model/PrefabricatedEntity/SoulboundSkill.cs b/Model/PrefabricatedEntity/SoulboundSkill.cs index b589668..60fa8d3 100644 --- a/Model/PrefabricatedEntity/SoulboundSkill.cs +++ b/Model/PrefabricatedEntity/SoulboundSkill.cs @@ -1,18 +1,62 @@ using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Library.Common.Addon; +using Milimoe.FunGame.Core.Library.Constant; namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity { /// /// 继承此类以表示灵魂绑定技能 /// - public class SoulboundSkill(long id, string name, Dictionary args, Character? character = null) : OpenSkill(id, name, args, character) + /// + /// 灵魂绑定:一个至少消耗 100 能量、每额外消耗 20 能量效果增强 10% 的爆发技 + /// + /// + public abstract class SoulboundSkill(Character? character = null) : Skill(SkillType.SuperSkill, character) { public override bool CostAllEP => true; public override double MinCostEP => 100; + } + + /// + /// 灵魂绑定专有特效 + /// + public abstract class SoulboundEffect(SoulboundSkill skill) : Effect(skill) + { + /// + /// 所属的灵魂绑定技能 + /// + public SoulboundSkill SoulboundSkill => skill; /// - /// 每额外消耗 20 能量效果增强 10% + /// 增强系数,每额外消耗 20 能量效果增强 10% /// - public virtual double Improvement => (LastCostEP - MinCostEP) / 20 * 0.1; + public double Improvement + { + get + { + double improvement = 0; + if (_improvement != null) + { + improvement = _improvement.Value; + } + else if (Skill.Character != null) + { + improvement = (Skill.Character.EP - skill.MinCostEP) / 20.0 * 0.1; + } + return improvement; + } + } + + private double? _improvement = null; + + public override void BeforeSkillCasted(Character caster, List targets, List grids, double mpCost = 0, double epCost = 0) + { + _improvement = (epCost - skill.MinCostEP) / 20.0 * 0.1; + } + + public override void AfterSkillCasted(Character caster, List targets, List grids) + { + _improvement = null; + } } }