添加 DamageRecord;完善了预制技能灵魂绑定;添加更多钩子 (#149)

This commit is contained in:
milimoe 2026-03-02 02:00:43 +08:00 committed by GitHub
parent 915de4bc36
commit 5194fe39e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 239 additions and 30 deletions

View File

@ -455,7 +455,20 @@ namespace Milimoe.FunGame.Core.Entity
}
/// <summary>
/// 在技能释放前触发
/// 在技能释放前触发 [ 技能的特效组 ]
/// </summary>
/// <param name="caster"></param>
/// <param name="targets"></param>
/// <param name="grids"></param>
/// <param name="mpCost"></param>
/// <param name="epCost"></param>
public virtual void BeforeSkillCasted(Character caster, List<Character> targets, List<Grid> grids, double mpCost = 0, double epCost = 0)
{
}
/// <summary>
/// 在技能释放前触发 [ 状态栏特效 ]
/// </summary>
/// <param name="caster"></param>
/// <param name="skill"></param>
@ -468,6 +481,17 @@ namespace Milimoe.FunGame.Core.Entity
return true;
}
/// <summary>
/// 在技能释放后触发 [ 技能的特效组 ]
/// </summary>
/// <param name="caster"></param>
/// <param name="targets"></param>
/// <param name="grids"></param>
public virtual void AfterSkillCasted(Character caster, List<Character> targets, List<Grid> grids)
{
}
/// <summary>
/// 在时间流逝期间应用生命/魔法回复前修改 [ 允许取消回复 ]
/// </summary>
@ -1051,9 +1075,10 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="expectedDamage"></param>
/// <param name="options"></param>
/// <returns></returns>
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 != null)
{
if (GamingQueue is null) return DamageResult.Evaded;
int changeCount = 0;
DamageResult result = DamageResult.Normal;
double damage = expectedDamage;
@ -1065,7 +1090,9 @@ namespace Milimoe.FunGame.Core.Entity
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 result;
return options?.GetDamageRecord(damageType, result) ?? new();
}
return new();
}
/// <summary>

View File

@ -385,6 +385,10 @@ namespace Milimoe.FunGame.Core.Entity
SkillType = type;
CastAnywhere = SkillType == SkillType.Magic;
Character = character;
if (SkillType == SkillType.SuperSkill)
{
EPCost = 100;
}
}
/// <summary>
@ -712,7 +716,7 @@ namespace Milimoe.FunGame.Core.Entity
public void OnSkillCasting(IGamingQueue queue, Character caster, List<Character> targets, List<Grid> 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
/// <summary>
/// 技能效果触发前
/// </summary>
public void BeforeSkillCasted()
public void BeforeSkillCasted(Character caster, List<Character> targets, List<Grid> grids)
{
LastCostMP = RealMPCost;
LastCostEP = RealEPCost;
foreach (Effect e in Effects.OrderByDescending(e => e.Priority))
{
e.GamingQueue = GamingQueue;
e.BeforeSkillCasted(caster, targets, grids, LastCostMP, LastCostEP);
}
}
/// <summary>
@ -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);
}
}
/// <summary>
/// 技能效果触发后
/// </summary>
public void AfterSkillCasted(Character caster, List<Character> targets, List<Grid> grids)
{
foreach (Effect e in Effects.OrderByDescending(e => e.Priority))
{
e.GamingQueue = GamingQueue;
e.AfterSkillCasted(caster, targets, grids);
}
}
/// <summary>
/// 对目标触发技能效果
/// </summary>
@ -776,7 +797,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="targets"></param>
public void OnSkillCasted(User user, List<Character> targets)
{
foreach (Effect e in Effects)
foreach (Effect e in Effects.OrderByDescending(e => e.Priority))
{
e.OnSkillCasted(user, targets, Values);
}

View File

@ -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;
}

View File

@ -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
/** == 调试数据记录 == **/
/// <summary>
/// 生成伤害记录
/// </summary>
public DamageRecord GetDamageRecord(DamageType type, DamageResult result) => new(type, result, ExpectedDamage, BeforeDamageBonus, CriticalDamage, DefenseReduction, AfterDamageBonus, MagicEfficacyDamage, FinalDamage, ShieldReduction, ActualDamage);
/// <summary>
/// 伤害基底(期望)
/// </summary>

100
Model/DamageRecord.cs Normal file
View File

@ -0,0 +1,100 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Model
{
/// <summary>
/// 记录所有伤害的组成部分
/// </summary>
public readonly struct DamageRecord
{
/// <summary>
/// 记录所有伤害的组成部分
/// </summary>
public DamageRecord()
{
ExpectedDamage = 0;
BeforeDamageBonus = [];
CriticalDamage = 0;
DefenseReduction = 0;
AfterDamageBonus = [];
MagicEfficacyDamage = 0;
FinalDamage = 0;
ShieldReduction = 0;
ActualDamage = 0;
}
/// <summary>
/// 记录所有伤害的组成部分
/// </summary>
public DamageRecord(DamageType type, DamageResult result, double expectedDamage, Dictionary<Effect, double> beforeDamageBonus, double criticalDamage, double defenseReduction, Dictionary<Effect, double> 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;
}
/// <summary>
/// 伤害类型
/// </summary>
public DamageType DamageType { get; } = DamageType.Physical;
/// <summary>
/// 伤害结果
/// </summary>
public DamageResult DamageResult { get; } = DamageResult.Normal;
/// <summary>
/// 伤害基底(期望)
/// </summary>
public double ExpectedDamage { get; }
/// <summary>
/// 特效伤害加成记录乘区1暴击和减伤计算前
/// </summary>
public Dictionary<Effect, double> BeforeDamageBonus { get; }
/// <summary>
/// 暴击伤害
/// </summary>
public double CriticalDamage { get; }
/// <summary>
/// 伤害减免
/// </summary>
public double DefenseReduction { get; }
/// <summary>
/// 特效伤害加成记录乘区2暴击和减伤计算后
/// </summary>
public Dictionary<Effect, double> AfterDamageBonus { get; }
/// <summary>
/// 魔法效能修正
/// </summary>
public double MagicEfficacyDamage { get; }
/// <summary>
/// 最终伤害
/// </summary>
public double FinalDamage { get; }
/// <summary>
/// 护盾减免
/// </summary>
public double ShieldReduction { get; }
/// <summary>
/// 实际造成伤害
/// </summary>
public double ActualDamage { get; }
}
}

View File

@ -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)
{

View File

@ -1,11 +1,12 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity
{
/// <summary>
/// 继承此类以表示勇气指令技能
/// </summary>
public class CourageCommandSkill(long id, string name, Dictionary<string, object> args, Character? character = null) : OpenSkill(id, name, args, character)
public abstract class CourageCommandSkill(Character? character = null) : Skill(SkillType.Skill, character)
{
}

View File

@ -6,7 +6,7 @@ namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity
/// <summary>
/// 魔法卡包的基础实现
/// </summary>
public class MagicCardPack : OpenItem
public class MagicCardPack : Item
{
public override ItemType ItemType => ItemType.MagicCardPack;
@ -50,10 +50,12 @@ namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity
/// </summary>
private PrimaryAttribute _originalAttribute = PrimaryAttribute.None;
public MagicCardPack(long id, string name, Dictionary<string, object> args) : base(id, name, args)
public MagicCardPack(Dictionary<string, object>? args = null) : base(ItemType.MagicCardPack)
{
args ??= [];
foreach (string key in args.Keys)
{
Others[key] = args[key];
switch (key.ToLower())
{
case "exstr":

View File

@ -6,7 +6,7 @@ namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity
/// <summary>
/// 继承此类以表示神经校准特效
/// </summary>
public class NeuralCalibrationEffect : Effect
public abstract class NeuralCalibrationEffect : Effect
{
public WeaponType SupportedWeaponType { get; set; } = WeaponType.None;
}

View File

@ -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
{
/// <summary>
/// 继承此类以表示灵魂绑定技能
/// </summary>
public class SoulboundSkill(long id, string name, Dictionary<string, object> args, Character? character = null) : OpenSkill(id, name, args, character)
/// <remarks>
/// 灵魂绑定:一个至少消耗 100 能量、每额外消耗 20 能量效果增强 10% 的爆发技
/// </remarks>
/// <param name="character"></param>
public abstract class SoulboundSkill(Character? character = null) : Skill(SkillType.SuperSkill, character)
{
public override bool CostAllEP => true;
public override double MinCostEP => 100;
}
/// <summary>
/// 每额外消耗 20 能量效果增强 10%
/// 灵魂绑定专有特效
/// </summary>
public virtual double Improvement => (LastCostEP - MinCostEP) / 20 * 0.1;
public abstract class SoulboundEffect(SoulboundSkill skill) : Effect(skill)
{
/// <summary>
/// 所属的灵魂绑定技能
/// </summary>
public SoulboundSkill SoulboundSkill => skill;
/// <summary>
/// 增强系数,每额外消耗 20 能量效果增强 10%
/// </summary>
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<Character> targets, List<Grid> grids, double mpCost = 0, double epCost = 0)
{
_improvement = (epCost - skill.MinCostEP) / 20.0 * 0.1;
}
public override void AfterSkillCasted(Character caster, List<Character> targets, List<Grid> grids)
{
_improvement = null;
}
}
}