添加免疫、驱散;顺序表、爆发技、助攻修改 (#129)

* 特效底层支持直接修改硬直时间;添加驱散类型

* 添加 debuff

* 明确了驱散定义;添加助攻窗口期;修改预释放爆发技为不可驱散;预释放爆发技一定是最先行动;修复复活时导致硬直时间变成负数的问题

* 调整驱散描述

* 实现驱散系统;修复角色百分比公式错误;添加非伤害类助攻;添加辅助数据统计;修改一些文本显示

* 添加免疫、吸血、护盾机制

* 继续完善免疫和驱散、护盾和特效钩子等

* 添加新特效类型
This commit is contained in:
milimoe 2025-04-26 03:07:10 +08:00 committed by GitHub
parent e233479c5b
commit 769d0e4281
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 1944 additions and 385 deletions

View File

@ -552,7 +552,7 @@ namespace Milimoe.FunGame.Core.Controller
/// 获取服务器已发送的信息为SocketObject数组 [ Socket Only ] /// 获取服务器已发送的信息为SocketObject数组 [ Socket Only ]
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
protected SocketObject[] GetServerMessage() protected SocketObject[] GetServerMessages()
{ {
if (_Socket != null && _Socket.Connected) if (_Socket != null && _Socket.Connected)
{ {
@ -571,7 +571,7 @@ namespace Milimoe.FunGame.Core.Controller
SocketMessageType result = SocketMessageType.Unknown; SocketMessageType result = SocketMessageType.Unknown;
try try
{ {
SocketObject[] messages = GetServerMessage(); SocketObject[] messages = GetServerMessages();
foreach (SocketObject obj in messages) foreach (SocketObject obj in messages)
{ {
@ -660,14 +660,14 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收服务器断开连接的通知 /// 客户端接收服务器断开连接的通知
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected abstract void SocketHandler_Disconnect(SocketObject ServerMessage); protected abstract void SocketHandler_Disconnect(SocketObject obj);
/// <summary> /// <summary>
/// 客户端接收并处理服务器系统消息 /// 客户端接收并处理服务器系统消息
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_System(SocketObject ServerMessage) protected virtual void SocketHandler_System(SocketObject obj)
{ {
} }
@ -675,8 +675,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收并处理服务器心跳 /// 客户端接收并处理服务器心跳
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_HeartBeat(SocketObject ServerMessage) protected virtual void SocketHandler_HeartBeat(SocketObject obj)
{ {
} }
@ -684,8 +684,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收强制退出登录的通知 /// 客户端接收强制退出登录的通知
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_ForceLogout(SocketObject ServerMessage) protected virtual void SocketHandler_ForceLogout(SocketObject obj)
{ {
} }
@ -693,8 +693,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收并处理聊天信息 /// 客户端接收并处理聊天信息
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_Chat(SocketObject ServerMessage) protected virtual void SocketHandler_Chat(SocketObject obj)
{ {
} }
@ -702,8 +702,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收并处理更换房主信息 /// 客户端接收并处理更换房主信息
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_UpdateRoomMaster(SocketObject ServerMessage) protected virtual void SocketHandler_UpdateRoomMaster(SocketObject obj)
{ {
} }
@ -711,8 +711,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收并处理匹配房间成功信息 /// 客户端接收并处理匹配房间成功信息
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_MatchRoom(SocketObject ServerMessage) protected virtual void SocketHandler_MatchRoom(SocketObject obj)
{ {
} }
@ -720,8 +720,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收并处理开始游戏信息 /// 客户端接收并处理开始游戏信息
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_StartGame(SocketObject ServerMessage) protected virtual void SocketHandler_StartGame(SocketObject obj)
{ {
} }
@ -729,8 +729,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收并处理游戏结束信息 /// 客户端接收并处理游戏结束信息
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_EndGame(SocketObject ServerMessage) protected virtual void SocketHandler_EndGame(SocketObject obj)
{ {
} }
@ -738,8 +738,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收并处理局内消息 /// 客户端接收并处理局内消息
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_Gaming(SocketObject ServerMessage) protected virtual void SocketHandler_Gaming(SocketObject obj)
{ {
} }
@ -747,8 +747,8 @@ namespace Milimoe.FunGame.Core.Controller
/// <summary> /// <summary>
/// 客户端接收并处理匿名服务器的消息 /// 客户端接收并处理匿名服务器的消息
/// </summary> /// </summary>
/// <param name="ServerMessage"></param> /// <param name="obj"></param>
protected virtual void SocketHandler_AnonymousGameServer(SocketObject ServerMessage) protected virtual void SocketHandler_AnonymousGameServer(SocketObject obj)
{ {
} }

View File

@ -5,13 +5,28 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 用于记录对哪个角色造成了多少伤害 /// 用于记录对哪个角色造成了多少伤害
/// </summary> /// </summary>
public class AssistDetail : Dictionary<Character, double> public class AssistDetail
{ {
/// <summary> /// <summary>
/// 此详情类属于哪个角色 /// 此详情类属于哪个角色
/// </summary> /// </summary>
public Character Character { get; } public Character Character { get; }
/// <summary>
/// 对敌人造成的伤害
/// </summary>
public Dictionary<Character, double> Damages { get; } = [];
/// <summary>
/// 最后一次造成伤害的时间
/// </summary>
public Dictionary<Character, double> DamageLastTime { get; } = [];
/// <summary>
/// 对某角色最后一次友方非伤害辅助的时间
/// </summary>
public Dictionary<Character, double> NotDamageAssistLastTime { get; } = [];
/// <summary> /// <summary>
/// 初始化一个助攻详情类 /// 初始化一个助攻详情类
/// </summary> /// </summary>
@ -27,21 +42,23 @@ namespace Milimoe.FunGame.Core.Entity
} }
/// <summary> /// <summary>
/// 获取和设置对 <paramref name="enemy"/> 的伤害 /// 获取和设置对 <paramref name="enemy"/> 的伤害,并设置时间
/// </summary> /// </summary>
/// <param name="enemy"></param> /// <param name="enemy"></param>
/// <param name="time"></param>
/// <returns></returns> /// <returns></returns>
public new double this[Character enemy] public double this[Character enemy, double? time = null]
{ {
get get
{ {
return base[enemy]; return Damages[enemy];
} }
set set
{ {
if (!base.TryAdd(enemy, Calculation.Round2Digits(value))) Damages[enemy] = Calculation.Round2Digits(value);
if (time.HasValue)
{ {
base[enemy] = Calculation.Round2Digits(value); DamageLastTime[enemy] = time.Value;
} }
} }
} }
@ -53,7 +70,35 @@ namespace Milimoe.FunGame.Core.Entity
/// <returns>目标的 <see cref="Character.MaxHP"/> 的百分比形式</returns> /// <returns>目标的 <see cref="Character.MaxHP"/> 的百分比形式</returns>
public double GetPercentage(Character enemy) public double GetPercentage(Character enemy)
{ {
return Calculation.Round2Digits(base[enemy] / enemy.MaxHP); return Calculation.Round2Digits(Damages[enemy] / enemy.MaxHP);
}
/// <summary>
/// 获取对 <paramref name="enemy"/> 造成伤害的最后时间
/// </summary>
/// <param name="enemy"></param>
/// <returns>-1 意味着没有时间</returns>
public double GetLastTime(Character enemy)
{
if (DamageLastTime.TryGetValue(enemy, out double time))
{
return time;
}
return -1;
}
/// <summary>
/// 获取对某角色友方非伤害辅助的最后时间
/// </summary>
/// <param name="character"></param>
/// <returns>-1 意味着没有时间</returns>
public double GetNotDamageAssistLastTime(Character character)
{
if (NotDamageAssistLastTime.TryGetValue(character, out double time))
{
return time;
}
return -1;
} }
} }
} }

View File

@ -161,6 +161,11 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public Dictionary<Effect, List<EffectType>> CharacterEffectTypes { get; } = []; public Dictionary<Effect, List<EffectType>> CharacterEffectTypes { get; } = [];
/// <summary>
/// 角色目前被特效施加的免疫状态 [ 战斗相关 ]
/// </summary>
public Dictionary<Effect, List<ImmuneType>> CharacterImmuneTypes { get; } = [];
/// <summary> /// <summary>
/// 角色是否是中立的 [ 战斗相关 ] /// 角色是否是中立的 [ 战斗相关 ]
/// </summary> /// </summary>
@ -171,6 +176,11 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public bool IsUnselectable { get; set; } = false; public bool IsUnselectable { get; set; } = false;
/// <summary>
/// 角色是否具备免疫状态 [ 战斗相关 ]
/// </summary>
public ImmuneType ImmuneType { get; set; } = ImmuneType.None;
/// <summary> /// <summary>
/// 初始生命值 [ 初始设定 ] /// 初始生命值 [ 初始设定 ]
/// </summary> /// </summary>
@ -195,7 +205,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 额外生命值3 [ 额外生命值% ] /// 额外生命值3 [ 额外生命值% ]
/// </summary> /// </summary>
public double ExHP3 => (BaseHP + ExHP + ExHP2) * ExHPPercentage; public double ExHP3 => BaseHP * ExHPPercentage;
/// <summary> /// <summary>
/// 额外生命值% [ 与技能和物品相关 ] /// 额外生命值% [ 与技能和物品相关 ]
@ -248,7 +258,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 额外魔法值3 [ 额外魔法值% ] /// 额外魔法值3 [ 额外魔法值% ]
/// </summary> /// </summary>
public double ExMP3 => (BaseMP + ExMP + ExMP2) * ExMPPercentage; public double ExMP3 => BaseMP * ExMPPercentage;
/// <summary> /// <summary>
/// 额外魔法值% [ 与技能和物品相关 ] /// 额外魔法值% [ 与技能和物品相关 ]
@ -353,7 +363,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 额外攻击力3 [ 额外攻击力% ] /// 额外攻击力3 [ 额外攻击力% ]
/// </summary> /// </summary>
public double ExATK3 => (BaseATK + ExATK + ExATK2) * ExATKPercentage; public double ExATK3 => BaseATK * ExATKPercentage;
/// <summary> /// <summary>
/// 额外攻击力% [ 与技能和物品相关 ] /// 额外攻击力% [ 与技能和物品相关 ]
@ -389,7 +399,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 额外物理护甲3 [ 额外物理护甲% ] /// 额外物理护甲3 [ 额外物理护甲% ]
/// </summary> /// </summary>
public double ExDEF3 => (BaseDEF + ExDEF + ExDEF2) * ExDEFPercentage; public double ExDEF3 => BaseDEF * ExDEFPercentage;
/// <summary> /// <summary>
/// 额外物理护甲% [ 与技能和物品相关 ] /// 额外物理护甲% [ 与技能和物品相关 ]
@ -607,17 +617,17 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 额外力量2 [ 额外力量% ] /// 额外力量2 [ 额外力量% ]
/// </summary> /// </summary>
public double ExSTR2 => (BaseSTR + ExSTR) * ExSTRPercentage; public double ExSTR2 => BaseSTR * ExSTRPercentage;
/// <summary> /// <summary>
/// 额外敏捷2 [ 额外敏捷% ] /// 额外敏捷2 [ 额外敏捷% ]
/// </summary> /// </summary>
public double ExAGI2 => (BaseAGI + ExAGI) * ExAGIPercentage; public double ExAGI2 => BaseAGI * ExAGIPercentage;
/// <summary> /// <summary>
/// 额外智力2 [ 额外智力% ] /// 额外智力2 [ 额外智力% ]
/// </summary> /// </summary>
public double ExINT2 => (BaseINT + ExINT) * ExINTPercentage; public double ExINT2 => BaseINT * ExINTPercentage;
/// <summary> /// <summary>
/// 额外力量% [ 与技能和物品相关 ] /// 额外力量% [ 与技能和物品相关 ]
@ -787,6 +797,16 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public double ExEvadeRate { get; set; } = 0; public double ExEvadeRate { get; set; } = 0;
/// <summary>
/// 生命偷取 [ 与技能和物品相关 ]
/// </summary>
public double Lifesteal { get; set; } = 0;
/// <summary>
/// 护盾值 [ 与技能和物品相关 ]
/// </summary>
public Shield Shield { get; set; }
/// <summary> /// <summary>
/// 普通攻击对象 /// 普通攻击对象
/// </summary> /// </summary>
@ -851,6 +871,7 @@ namespace Milimoe.FunGame.Core.Entity
InitialDEF = GameplayEquilibriumConstant.InitialDEF; InitialDEF = GameplayEquilibriumConstant.InitialDEF;
EquipSlot = new(); EquipSlot = new();
MDF = new(); MDF = new();
Shield = new();
NormalAttack = new(this); NormalAttack = new(this);
} }
@ -1187,7 +1208,7 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public void OnAttributeChanged() public void OnAttributeChanged()
{ {
List<Effect> effects = [.. Effects.Where(e => e.Level > 0)]; List<Effect> effects = [.. Effects.Where(e => e.Level > 0 && !e.IsBeingTemporaryDispelled)];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
effect.OnAttributeChanged(this); effect.OnAttributeChanged(this);
@ -1322,7 +1343,10 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}"); builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
} }
double exHP = ExHP + ExHP2 + ExHP3; double exHP = ExHP + ExHP2 + ExHP3;
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "")); List<string> shield = [];
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial: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; double exMP = ExMP + ExMP2 + ExMP3;
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}");
@ -1330,10 +1354,7 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
double exDEF = ExDEF + ExDEF2 + ExDEF3; double exDEF = ExDEF + ExDEF2 + ExDEF3;
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)"); builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary + builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD; 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($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}");
@ -1348,6 +1369,7 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine($"暴击率:{CritRate * 100:0.##}%"); builder.AppendLine($"暴击率:{CritRate * 100:0.##}%");
builder.AppendLine($"暴击伤害:{CritDMG * 100:0.##}%"); builder.AppendLine($"暴击伤害:{CritDMG * 100:0.##}%");
builder.AppendLine($"闪避率:{EvadeRate * 100:0.##}%"); builder.AppendLine($"闪避率:{EvadeRate * 100:0.##}%");
builder.AppendLine($"生命偷取:{Lifesteal * 100:0.##}%");
builder.AppendLine($"冷却缩减:{CDR * 100:0.##}%"); builder.AppendLine($"冷却缩减:{CDR * 100:0.##}%");
builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:0.##}%"); builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:0.##}%");
builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%"); builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%");
@ -1453,7 +1475,10 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}"); builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
} }
double exHP = ExHP + ExHP2 + ExHP3; double exHP = ExHP + ExHP2 + ExHP3;
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "")); List<string> shield = [];
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial: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; double exMP = ExMP + ExMP2 + ExMP3;
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}");
@ -1461,10 +1486,7 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
double exDEF = ExDEF + ExDEF2 + ExDEF3; double exDEF = ExDEF + ExDEF2 + ExDEF3;
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)"); builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary + builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
if (showBasicOnly) if (showBasicOnly)
{ {
builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}");
@ -1559,7 +1581,10 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine(ToStringWithLevel()); builder.AppendLine(ToStringWithLevel());
double exHP = ExHP + ExHP2 + ExHP3; double exHP = ExHP + ExHP2 + ExHP3;
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "")); List<string> shield = [];
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial: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; double exMP = ExMP + ExMP2 + ExMP3;
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}");
@ -1607,7 +1632,10 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine(ToStringWithLevel()); builder.AppendLine(ToStringWithLevel());
double exHP = ExHP + ExHP2 + ExHP3; double exHP = ExHP + ExHP2 + ExHP3;
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "")); List<string> shield = [];
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial: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; double exMP = ExMP + ExMP2 + ExMP3;
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}");
@ -1689,7 +1717,10 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}"); builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
} }
double exHP = ExHP + ExHP2 + ExHP3; double exHP = ExHP + ExHP2 + ExHP3;
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "")); List<string> shield = [];
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial: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; double exMP = ExMP + ExMP2 + ExMP3;
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}"); builder.AppendLine($"能量值:{EP:0.##} / {GameplayEquilibriumConstant.MaxEP:0.##}");
@ -1697,10 +1728,7 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
double exDEF = ExDEF + ExDEF2 + ExDEF3; double exDEF = ExDEF + ExDEF2 + ExDEF3;
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)"); builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary + builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD; 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($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}");
@ -1715,6 +1743,7 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine($"暴击率:{CritRate * 100:0.##}%"); builder.AppendLine($"暴击率:{CritRate * 100:0.##}%");
builder.AppendLine($"暴击伤害:{CritDMG * 100:0.##}%"); builder.AppendLine($"暴击伤害:{CritDMG * 100:0.##}%");
builder.AppendLine($"闪避率:{EvadeRate * 100:0.##}%"); builder.AppendLine($"闪避率:{EvadeRate * 100:0.##}%");
builder.AppendLine($"生命偷取:{Lifesteal * 100:0.##}%");
builder.AppendLine($"冷却缩减:{CDR * 100:0.##}%"); builder.AppendLine($"冷却缩减:{CDR * 100:0.##}%");
builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:0.##}%"); builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:0.##}%");
builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%"); builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%");
@ -1775,52 +1804,77 @@ namespace Milimoe.FunGame.Core.Entity
/// <returns></returns> /// <returns></returns>
public CharacterState UpdateCharacterState() public CharacterState UpdateCharacterState()
{ {
bool isNotActionable = false;
bool isActionRestricted = false;
bool isBattleRestricted = false;
bool isSkillRestricted = false;
bool isAttackRestricted = false;
IEnumerable<CharacterState> states = CharacterEffectStates.Values.SelectMany(list => list); IEnumerable<CharacterState> states = CharacterEffectStates.Values.SelectMany(list => list);
// 根据持有的特效判断角色所处的状态 // 根据持有的特效判断角色所处的状态
isNotActionable = states.Any(state => state == CharacterState.NotActionable); bool isNotActionable = states.Any(state => state == CharacterState.NotActionable);
isActionRestricted = states.Any(state => state == CharacterState.ActionRestricted); bool isActionRestricted = states.Any(state => state == CharacterState.ActionRestricted);
isBattleRestricted = states.Any(state => state == CharacterState.BattleRestricted); bool isBattleRestricted = states.Any(state => state == CharacterState.BattleRestricted);
isSkillRestricted = states.Any(state => state == CharacterState.SkillRestricted); bool isSkillRestricted = states.Any(state => state == CharacterState.SkillRestricted);
isAttackRestricted = states.Any(state => state == CharacterState.AttackRestricted); bool isAttackRestricted = states.Any(state => state == CharacterState.AttackRestricted);
IEnumerable<EffectType> types = CharacterEffectTypes.Values.SelectMany(list => list); IEnumerable<EffectType> types = CharacterEffectTypes.Values.SelectMany(list => list);
// 判断角色的控制效果 // 判断角色的控制效果
IsUnselectable = types.Any(type => type == EffectType.Unselectable); IsUnselectable = types.Any(type => type == EffectType.Unselectable);
IEnumerable<ImmuneType> immunes = CharacterImmuneTypes.Values.SelectMany(list => list);
// 判断角色的免疫状态
bool isAllImmune = immunes.Any(type => type == ImmuneType.All);
bool isPhysicalImmune = immunes.Any(type => type == ImmuneType.Physical);
bool isMagicalImmune = immunes.Any(type => type == ImmuneType.Magical);
bool isSkilledImmune = immunes.Any(type => type == ImmuneType.Skilled);
if (isAllImmune)
{
ImmuneType = ImmuneType.All;
}
else if (isPhysicalImmune)
{
ImmuneType = ImmuneType.Physical;
}
else if (isMagicalImmune)
{
ImmuneType = ImmuneType.Magical;
}
else if (isSkilledImmune)
{
ImmuneType = ImmuneType.Skilled;
}
else
{
ImmuneType = ImmuneType.None;
}
bool isControl = isNotActionable || isActionRestricted || isBattleRestricted || isSkillRestricted || isAttackRestricted; bool isControl = isNotActionable || isActionRestricted || isBattleRestricted || isSkillRestricted || isAttackRestricted;
bool isCasting = CharacterState == CharacterState.Casting; bool isCasting = CharacterState == CharacterState.Casting;
bool isPreCastSuperSkill = CharacterState == CharacterState.PreCastSuperSkill; bool isPreCastSuperSkill = CharacterState == CharacterState.PreCastSuperSkill;
if (isNotActionable) // 预释放爆发技不可驱散,保持原状态
if (!isPreCastSuperSkill)
{ {
CharacterState = CharacterState.NotActionable; if (isNotActionable)
} {
else if (isActionRestricted) CharacterState = CharacterState.NotActionable;
{ }
CharacterState = CharacterState.ActionRestricted; else if (isActionRestricted)
} {
else if (isBattleRestricted || (isSkillRestricted && isAttackRestricted)) CharacterState = CharacterState.ActionRestricted;
{ }
CharacterState = CharacterState.BattleRestricted; else if (isBattleRestricted || (isSkillRestricted && isAttackRestricted))
} {
else if (isSkillRestricted) CharacterState = CharacterState.BattleRestricted;
{ }
CharacterState = CharacterState.SkillRestricted; else if (isSkillRestricted)
} {
else if (isAttackRestricted) CharacterState = CharacterState.SkillRestricted;
{ }
CharacterState = CharacterState.AttackRestricted; else if (isAttackRestricted)
} {
CharacterState = CharacterState.AttackRestricted;
}
if (!isControl && !isCasting && !isPreCastSuperSkill) if (!isControl && !isCasting)
{ {
CharacterState = CharacterState.Actionable; CharacterState = CharacterState.Actionable;
}
} }
return CharacterState; return CharacterState;
@ -1847,6 +1901,7 @@ namespace Milimoe.FunGame.Core.Entity
ThirdRoleType = ThirdRoleType, ThirdRoleType = ThirdRoleType,
Promotion = Promotion, Promotion = Promotion,
PrimaryAttribute = PrimaryAttribute, PrimaryAttribute = PrimaryAttribute,
ImmuneType = ImmuneType,
Level = Level, Level = Level,
LevelBreak = LevelBreak, LevelBreak = LevelBreak,
EXP = EXP, EXP = EXP,
@ -1869,6 +1924,8 @@ namespace Milimoe.FunGame.Core.Entity
INTGrowth = INTGrowth, INTGrowth = INTGrowth,
InitialSPD = InitialSPD, InitialSPD = InitialSPD,
ATR = ATR, ATR = ATR,
Lifesteal = Lifesteal,
Shield = Shield.Copy()
}; };
if (copyEx) if (copyEx)
{ {

View File

@ -1,20 +1,128 @@
namespace Milimoe.FunGame.Core.Entity using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Entity
{ {
/// <summary> /// <summary>
/// 角色的魔法抗性,对不同的魔法类型有不同抗性 /// 角色的魔法抗性,对不同的魔法类型有不同抗性
/// </summary> /// </summary>
public class MagicResistance() public class MagicResistance
{ {
/// <summary>
/// 无属性魔法抗性
/// </summary>
public double None { get; set; } = 0; public double None { get; set; } = 0;
/// <summary>
/// 星痕魔法抗性
/// </summary>
public double Starmark { get; set; } = 0; public double Starmark { get; set; } = 0;
/// <summary>
/// 纯粹结晶魔法抗性
/// </summary>
public double PurityNatural { get; set; } = 0; public double PurityNatural { get; set; } = 0;
/// <summary>
/// 纯现代结晶魔法抗性
/// </summary>
public double PurityContemporary { get; set; } = 0; public double PurityContemporary { get; set; } = 0;
/// <summary>
/// 光魔法抗性
/// </summary>
public double Bright { get; set; } = 0; public double Bright { get; set; } = 0;
/// <summary>
/// 影魔法抗性
/// </summary>
public double Shadow { get; set; } = 0; public double Shadow { get; set; } = 0;
/// <summary>
/// 元素魔法抗性
/// </summary>
public double Element { get; set; } = 0; public double Element { get; set; } = 0;
/// <summary>
/// 紫宛魔法抗性
/// </summary>
public double Fleabane { get; set; } = 0; public double Fleabane { get; set; } = 0;
/// <summary>
/// 时空魔法抗性
/// </summary>
public double Particle { get; set; } = 0; public double Particle { get; set; } = 0;
/// <summary>
/// 平均魔法抗性
/// </summary>
public double Avg
{
get
{
double mdf = Calculation.Round4Digits((None + Starmark + PurityNatural + PurityContemporary + Bright + Shadow + Element + Fleabane + Particle) / 9) * 100;
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
return mdf;
}
}
/// <summary>
/// 获取或设置抗性值
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public double this[MagicType type]
{
get
{
return type switch
{
MagicType.Starmark => Starmark,
MagicType.PurityNatural => PurityNatural,
MagicType.PurityContemporary => PurityContemporary,
MagicType.Bright => Bright,
MagicType.Shadow => Shadow,
MagicType.Element => Element,
MagicType.Fleabane => Fleabane,
MagicType.Particle => Particle,
_ => None
};
}
set
{
switch (type)
{
case MagicType.Starmark:
Starmark = value;
break;
case MagicType.PurityNatural:
PurityNatural = value;
break;
case MagicType.PurityContemporary:
PurityContemporary = value;
break;
case MagicType.Bright:
Bright = value;
break;
case MagicType.Shadow:
Shadow = value;
break;
case MagicType.Element:
Element = value;
break;
case MagicType.Fleabane:
Fleabane = value;
break;
case MagicType.Particle:
Particle = value;
break;
default:
None = value;
break;
}
}
}
/// <summary> /// <summary>
/// 对所有抗性赋值 /// 对所有抗性赋值
/// </summary> /// </summary>

160
Entity/Character/Shield.cs Normal file
View File

@ -0,0 +1,160 @@
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Entity
{
/// <summary>
/// 角色的护盾,对不同的魔法类型有不同值
/// </summary>
public class Shield
{
/// <summary>
/// 物理护盾
/// </summary>
public double Physical { get; set; } = 0;
/// <summary>
/// 无属性魔法护盾
/// </summary>
public double None { get; set; } = 0;
/// <summary>
/// 星痕魔法护盾
/// </summary>
public double Starmark { get; set; } = 0;
/// <summary>
/// 纯粹结晶护盾
/// </summary>
public double PurityNatural { get; set; } = 0;
/// <summary>
/// 纯现代结晶护盾
/// </summary>
public double PurityContemporary { get; set; } = 0;
/// <summary>
/// 光护盾
/// </summary>
public double Bright { get; set; } = 0;
/// <summary>
/// 影护盾
/// </summary>
public double Shadow { get; set; } = 0;
/// <summary>
/// 元素护盾
/// </summary>
public double Element { get; set; } = 0;
/// <summary>
/// 紫宛护盾
/// </summary>
public double Fleabane { get; set; } = 0;
/// <summary>
/// 时空护盾
/// </summary>
public double Particle { get; set; } = 0;
/// <summary>
/// 总计物理护盾
/// </summary>
public double TotalPhysical => Physical;
/// <summary>
/// 总计魔法护盾
/// </summary>
public double TotalMagicial => None + Starmark + PurityNatural + PurityContemporary + Bright + Shadow + Element + Fleabane + Particle;
/// <summary>
/// 获取或设置护盾值
/// </summary>
/// <param name="isMagic"></param>
/// <param name="type"></param>
/// <returns></returns>
public double this[bool isMagic = false, MagicType type = MagicType.None]
{
get
{
if (isMagic)
{
return type switch
{
MagicType.Starmark => Starmark,
MagicType.PurityNatural => PurityNatural,
MagicType.PurityContemporary => PurityContemporary,
MagicType.Bright => Bright,
MagicType.Shadow => Shadow,
MagicType.Element => Element,
MagicType.Fleabane => Fleabane,
MagicType.Particle => Particle,
_ => None
};
}
return Physical;
}
set
{
if (isMagic)
{
switch (type)
{
case MagicType.Starmark:
Starmark = value;
break;
case MagicType.PurityNatural:
PurityNatural = value;
break;
case MagicType.PurityContemporary:
PurityContemporary = value;
break;
case MagicType.Bright:
Bright = value;
break;
case MagicType.Shadow:
Shadow = value;
break;
case MagicType.Element:
Element = value;
break;
case MagicType.Fleabane:
Fleabane = value;
break;
case MagicType.Particle:
Particle = value;
break;
default:
None = value;
break;
}
}
else
{
Physical = value;
}
}
}
/// <summary>
/// 复制一个护盾对象
/// </summary>
/// <returns></returns>
public Shield Copy()
{
return new()
{
Physical = Physical,
None = None,
Starmark = Starmark,
PurityNatural = PurityNatural,
PurityContemporary = PurityContemporary,
Bright = Bright,
Shadow = Shadow,
Element = Element,
Fleabane = Fleabane,
Particle = Particle
};
}
}
}

View File

@ -248,7 +248,7 @@ namespace Milimoe.FunGame.Core.Entity
{ {
foreach (Skill skill in Skills.Passives) foreach (Skill skill in Skills.Passives)
{ {
List<Effect> effects = [.. Character.Effects.Where(e => e.Skill == skill && e.Level > 0)]; List<Effect> effects = [.. Character.Effects.Where(e => e.Skill == skill && e.Level > 0 && !e.IsBeingTemporaryDispelled)];
foreach (Effect e in effects) foreach (Effect e in effects)
{ {
Character.Effects.Remove(e); Character.Effects.Remove(e);

View File

@ -50,11 +50,66 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public int RemainDurationTurn { get; set; } = 0; public int RemainDurationTurn { get; set; } = 0;
/// <summary>
/// 是否是没有具体持续时间的持续性特效
/// </summary>
public virtual bool DurativeWithoutDuration { get; set; } = false;
/// <summary> /// <summary>
/// 魔法类型 /// 魔法类型
/// </summary> /// </summary>
public virtual MagicType MagicType { get; set; } = MagicType.None; public virtual MagicType MagicType { get; set; } = MagicType.None;
/// <summary>
/// 驱散性 [ 能驱散什么特效,默认无驱散 ]
/// </summary>
public virtual DispelType DispelType { get; set; } = DispelType.None;
/// <summary>
/// 被驱散性 [ 能被什么驱散类型驱散,默认弱驱散 ]
/// </summary>
public virtual DispelledType DispelledType { get; set; } = DispelledType.Weak;
/// <summary>
/// 是否是负面效果
/// </summary>
public virtual bool IsDebuff { get; set; } = false;
/// <summary>
/// 驱散性和被驱散性的具体说明
/// </summary>
public virtual string DispelDescription
{
get => GetDispelDescription("\r\n");
set => _dispelDescription = value;
}
/// <summary>
/// 是否具备弱驱散功能(强驱散包含在内)
/// </summary>
public bool CanWeakDispel => DispelType == DispelType.Weak || DispelType == DispelType.DurativeWeak || DispelType == DispelType.TemporaryWeak || CanStrongDispel;
/// <summary>
/// 是否具备强驱散功能
/// </summary>
public bool CanStrongDispel => DispelType == DispelType.Strong || DispelType == DispelType.DurativeStrong || DispelType == DispelType.TemporaryStrong;
/// <summary>
/// 是否是临时驱散 [ 需注意持续性驱散是在持续时间内将特效无效化而不是移除,适用临时驱散机制 ]
/// </summary>
public bool IsTemporaryDispel => DispelType == DispelType.DurativeWeak || DispelType == DispelType.TemporaryWeak || DispelType == DispelType.DurativeStrong || DispelType == DispelType.TemporaryStrong;
/// <summary>
/// 是否处于临时被驱散状态 [ 如果使用后不手动恢复为 false那么行动顺序表会在时间流逝时恢复它 ]
/// <para/>注意看标准实现,需要配合 <see cref="OnEffectLost"/> 和 <see cref="OnEffectGained"/> 使用
/// </summary>
public bool IsBeingTemporaryDispelled { get; set; } = false;
/// <summary>
/// 无视免疫类型
/// </summary>
public virtual ImmuneType IgnoreImmune { get; set; } = ImmuneType.None;
/// <summary> /// <summary>
/// 效果描述 /// 效果描述
/// </summary> /// </summary>
@ -92,6 +147,11 @@ namespace Milimoe.FunGame.Core.Entity
} }
} }
/// <summary>
/// Values 构造动态特效参考这个构造函数
/// </summary>
/// <param name="skill"></param>
/// <param name="args"></param>
protected Effect(Skill skill, Dictionary<string, object>? args = null) protected Effect(Skill skill, Dictionary<string, object>? args = null)
{ {
Skill = skill; Skill = skill;
@ -284,6 +344,20 @@ namespace Milimoe.FunGame.Core.Entity
} }
/// <summary>
/// 在治疗结算前修改治疗值
/// </summary>
/// <param name="actor"></param>
/// <param name="target"></param>
/// <param name="heal"></param>
/// <param name="canRespawn"></param>
/// <param name="totalHealBonus"></param>
/// <returns>返回治疗增减值</returns>
public virtual double AlterHealValueBeforeHealToTarget(Character actor, Character target, double heal, ref bool canRespawn, Dictionary<Effect, double> totalHealBonus)
{
return 0;
}
/// <summary> /// <summary>
/// 在特效持有者的回合开始前 /// 在特效持有者的回合开始前
/// </summary> /// </summary>
@ -438,6 +512,178 @@ namespace Milimoe.FunGame.Core.Entity
return CharacterActionType.None; return CharacterActionType.None;
} }
/// <summary>
/// 可重写对某个特效的驱散实现,适用于特殊驱散类型
/// </summary>
/// <param name="dispeller"></param>
/// <param name="target"></param>
/// <param name="effect"></param>
/// <param name="isEnemy"></param>
public virtual void OnDispellingEffect(Character dispeller, Character target, Effect effect, bool isEnemy)
{
bool isDispel = false;
// 先看特效整体是不是能被驱散的
switch (effect.DispelledType)
{
case DispelledType.Weak:
if (CanWeakDispel)
{
isDispel = true;
}
break;
case DispelledType.Strong:
if (CanStrongDispel)
{
isDispel = true;
}
break;
default:
break;
}
if (isDispel)
{
bool removeEffectTypes = false;
bool removeEffectStates = false;
// 接下来再看看特效给角色施加的特效类型和改变状态是不是能被驱散的
// 检查特效持续性
if (effect.DurativeWithoutDuration || (effect.Durative && effect.Duration > 0) || effect.DurationTurn > 0)
{
// 先从角色身上移除特效类型
if (target.CharacterEffectTypes.TryGetValue(effect, out List<EffectType>? types) && types != null)
{
RemoveEffectTypesByDispel(types, isEnemy);
if (types.Count == 0)
{
target.CharacterEffectTypes.Remove(effect);
removeEffectTypes = true;
}
}
else
{
removeEffectTypes = true;
}
// 友方移除控制状态
if (!isEnemy && effect.IsDebuff)
{
if (target.CharacterEffectStates.TryGetValue(effect, out List<CharacterState>? states) && states != null)
{
RemoveEffectStatesByDispel(states);
if (states.Count == 0)
{
target.CharacterEffectStates.Remove(effect);
removeEffectStates = true;
}
}
else
{
removeEffectStates = true;
}
}
target.UpdateCharacterState();
}
// 移除整个特效
if (removeEffectTypes && removeEffectStates)
{
if (IsTemporaryDispel)
{
effect.IsBeingTemporaryDispelled = true;
}
else
{
effect.RemainDuration = 0;
effect.RemainDurationTurn = 0;
target.Effects.Remove(effect);
}
effect.OnEffectLost(target);
}
}
}
/// <summary>
/// 当特效被驱散时的
/// </summary>
/// <param name="dispeller"></param>
/// <param name="target"></param>
/// <param name="dispellerEffect"></param>
/// <param name="isEnemy"></param>
/// <returns>返回 false 可以阻止驱散</returns>
public virtual bool OnEffectIsBeingDispelled(Character dispeller, Character target, Effect dispellerEffect, bool isEnemy)
{
return true;
}
/// <summary>
/// 当角色触发生命偷取后
/// </summary>
/// <param name="character"></param>
/// <param name="enemy"></param>
/// <param name="damage"></param>
/// <param name="steal"></param>
public virtual void AfterLifesteal(Character character, Character enemy, double damage, double steal)
{
}
/// <summary>
/// 在角色护盾结算前触发
/// </summary>
/// <param name="character"></param>
/// <param name="attacker"></param>
/// <param name="isMagic"></param>
/// <param name="magicType"></param>
/// <param name="damage"></param>
/// <param name="shield"></param>
/// <param name="message"></param>
/// <returns>返回 false 可以阻止后续扣除角色护盾</returns>
public virtual bool BeforeShieldCalculation(Character character, Character attacker, bool isMagic, MagicType magicType, double damage, double shield, ref string message)
{
return true;
}
/// <summary>
/// 当角色护盾破碎时
/// </summary>
/// <param name="character"></param>
/// <param name="attacker"></param>
/// <param name="isMagic"></param>
/// <param name="magicType"></param>
/// <param name="damage"></param>
/// <param name="shield"></param>
/// <param name="overFlowing"></param>
/// <returns>返回 false 可以阻止后续扣除角色生命值</returns>
public virtual bool OnShieldBroken(Character character, Character attacker, bool isMagic, MagicType magicType, double damage, double shield, double overFlowing)
{
return true;
}
/// <summary>
/// 在免疫检定时
/// </summary>
/// <param name="actor"></param>
/// <param name="enemy"></param>
/// <param name="skill"></param>
/// <param name="item"></param>
/// <returns>false免疫检定不通过</returns>
public virtual bool OnImmuneCheck(Character actor, Character enemy, ISkill skill, Item? item = null)
{
return true;
}
/// <summary>
/// 在伤害免疫检定时
/// </summary>
/// <param name="actor"></param>
/// <param name="enemy"></param>
/// <param name="isNormalAttack"></param>
/// <param name="isMagic"></param>
/// <param name="magicType"></param>
/// <param name="damage"></param>
/// <returns>false免疫检定不通过</returns>
public virtual bool OnDamageImmuneCheck(Character actor, Character enemy, bool isNormalAttack, bool isMagic, MagicType magicType, double damage)
{
return true;
}
/// <summary> /// <summary>
/// 对敌人造成技能伤害 [ 强烈建议使用此方法造成伤害而不是自行调用 <see cref="IGamingQueue.DamageToEnemyAsync"/> ] /// 对敌人造成技能伤害 [ 强烈建议使用此方法造成伤害而不是自行调用 <see cref="IGamingQueue.DamageToEnemyAsync"/> ]
/// </summary> /// </summary>
@ -450,7 +696,8 @@ namespace Milimoe.FunGame.Core.Entity
public DamageResult DamageToEnemy(Character actor, Character enemy, bool isMagic, MagicType magicType, double expectedDamage) public DamageResult DamageToEnemy(Character actor, Character enemy, bool isMagic, MagicType magicType, double expectedDamage)
{ {
if (GamingQueue is null) return DamageResult.Evaded; if (GamingQueue is null) return DamageResult.Evaded;
DamageResult result = !isMagic ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out double damage) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage); int changeCount = 0;
DamageResult result = !isMagic ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out double damage, ref changeCount) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage, ref changeCount);
GamingQueue.DamageToEnemyAsync(actor, enemy, damage, false, isMagic, magicType, result); GamingQueue.DamageToEnemyAsync(actor, enemy, damage, false, isMagic, magicType, result);
return result; return result;
} }
@ -493,7 +740,50 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="states"></param> /// <param name="states"></param>
public void AddEffectStatesToCharacter(Character character, List<CharacterState> states) public void AddEffectStatesToCharacter(Character character, List<CharacterState> states)
{ {
character.CharacterEffectStates.Add(this, states); if (character.CharacterEffectStates.TryGetValue(this, out List<CharacterState>? value) && value != null)
{
states.AddRange(value);
}
states = [.. states.Distinct()];
character.CharacterEffectStates[this] = states;
character.UpdateCharacterState();
}
/// <summary>
/// 将特效控制效果设置到角色上 [ 尽可能的调用此方法而不是自己实现 ]
/// <para>施加 EffectType 的同时也会施加 CharacterState参见 <see cref="AddEffectStatesToCharacter"/></para>
/// </summary>
/// <param name="character"></param>
/// <param name="types"></param>
public void AddEffectTypeToCharacter(Character character, List<EffectType> types)
{
if (character.CharacterEffectTypes.TryGetValue(this, out List<EffectType>? value) && value != null)
{
types.AddRange(value);
}
types = [.. types.Distinct()];
character.CharacterEffectTypes[this] = types;
List<CharacterState> states = [];
foreach (EffectType type in types)
{
states.Add(SkillSet.GetCharacterStateByEffectType(type));
}
AddEffectStatesToCharacter(character, states);
}
/// <summary>
/// 将免疫状态设置到角色上 [ 尽可能的调用此方法而不是自己实现 ]
/// </summary>
/// <param name="character"></param>
/// <param name="types"></param>
public void AddImmuneTypesToCharacter(Character character, List<ImmuneType> types)
{
if (character.CharacterImmuneTypes.TryGetValue(this, out List<ImmuneType>? value) && value != null)
{
types.AddRange(value);
}
types = [.. types.Distinct()];
character.CharacterImmuneTypes[this] = types;
character.UpdateCharacterState(); character.UpdateCharacterState();
} }
@ -507,17 +797,6 @@ namespace Milimoe.FunGame.Core.Entity
character.UpdateCharacterState(); character.UpdateCharacterState();
} }
/// <summary>
/// 将特效控制效果设置到角色上 [ 尽可能的调用此方法而不是自己实现 ]
/// </summary>
/// <param name="character"></param>
/// <param name="types"></param>
public void AddEffectTypeToCharacter(Character character, List<EffectType> types)
{
character.CharacterEffectTypes.Add(this, types);
character.UpdateCharacterState();
}
/// <summary> /// <summary>
/// 将特效控制效果从角色身上移除 [ 尽可能的调用此方法而不是自己实现 ] /// 将特效控制效果从角色身上移除 [ 尽可能的调用此方法而不是自己实现 ]
/// </summary> /// </summary>
@ -528,6 +807,128 @@ namespace Milimoe.FunGame.Core.Entity
character.UpdateCharacterState(); character.UpdateCharacterState();
} }
/// <summary>
/// 将免疫状态从角色身上移除 [ 尽可能的调用此方法而不是自己实现 ]
/// </summary>
/// <param name="character"></param>
public void RemoveImmuneTypesFromCharacter(Character character)
{
character.CharacterImmuneTypes.Remove(this);
character.UpdateCharacterState();
}
/// <summary>
/// 从角色身上消除特效类型 [ 如果重写了 <see cref="OnDispellingEffect"/>,则尽可能的调用此方法而不是自己实现 ]
/// </summary>
/// <param name="types"></param>
/// <param name="isEnemy"></param>
public void RemoveEffectTypesByDispel(List<EffectType> types, bool isEnemy)
{
EffectType[] loop = [.. types];
foreach (EffectType type in loop)
{
bool isDebuff = SkillSet.GetIsDebuffByEffectType(type);
if (isEnemy == isDebuff)
{
// 简单判断,敌方不考虑 debuff友方只考虑 debuff
continue;
}
DispelledType dispelledType = SkillSet.GetDispelledTypeByEffectType(type);
bool canDispel = false;
switch (dispelledType)
{
case DispelledType.Weak:
if (CanWeakDispel) canDispel = true;
break;
case DispelledType.Strong:
if (CanStrongDispel) canDispel = true;
break;
default:
break;
}
if (canDispel)
{
types.Remove(type);
}
}
}
/// <summary>
/// 从角色身上消除状态类型 [ 如果重写了 <see cref="OnDispellingEffect"/>,则尽可能的调用此方法而不是自己实现 ]
/// </summary>
/// <param name="states"></param>
public void RemoveEffectStatesByDispel(List<CharacterState> states)
{
CharacterState[] loop = [.. states];
foreach (CharacterState state in loop)
{
DispelledType dispelledType = DispelledType.Weak;
switch (state)
{
case CharacterState.NotActionable:
case CharacterState.ActionRestricted:
case CharacterState.BattleRestricted:
dispelledType = DispelledType.Strong;
break;
case CharacterState.SkillRestricted:
case CharacterState.AttackRestricted:
break;
default:
break;
}
bool canDispel = false;
switch (dispelledType)
{
case DispelledType.Weak:
if (CanWeakDispel) canDispel = true;
break;
case DispelledType.Strong:
if (CanStrongDispel) canDispel = true;
break;
default:
break;
}
if (canDispel)
{
states.Remove(state);
}
}
}
/// <summary>
/// 驱散目标 [ 尽可能的调用此方法而不是自己实现 ]
/// <para>此方法会触发 <see cref="OnDispellingEffect"/></para>
/// </summary>
/// <param name="dispeller"></param>
/// <param name="target"></param>
/// <param name="isEnemy"></param>
public void Dispel(Character dispeller, Character target, bool isEnemy)
{
if (DispelType == DispelType.None)
{
return;
}
Effect[] effects = [.. target.Effects.Where(e => e.Level > 0 && EffectType != EffectType.Item && !e.IsBeingTemporaryDispelled)];
foreach (Effect effect in effects)
{
if (effect.OnEffectIsBeingDispelled(dispeller, target, this, isEnemy))
{
OnDispellingEffect(dispeller, target, effect, isEnemy);
}
}
}
/// <summary>
/// 修改角色的硬直时间 [ 尽可能的调用此方法而不是自己实现 ]
/// </summary>
/// <param name="character">角色</param>
/// <param name="addValue">加值</param>
/// <param name="isCheckProtected">是否使用插队保护机制</param>
public void ChangeCharacterHardnessTime(Character character, double addValue, bool isCheckProtected)
{
GamingQueue?.ChangeCharacterHardnessTime(character, addValue, isCheckProtected);
}
/// <summary> /// <summary>
/// 检查角色是否在 AI 控制状态 /// 检查角色是否在 AI 控制状态
/// </summary> /// </summary>
@ -549,13 +950,20 @@ namespace Milimoe.FunGame.Core.Entity
string isDurative = ""; string isDurative = "";
if (Durative) if (Durative)
{ {
isDurative = $"(剩余:{RemainDuration:0.##} 时间"; isDurative = $"(剩余:{RemainDuration:0.##} {GameplayEquilibriumConstant.InGameTime}";
} }
else if (DurationTurn > 0) else if (DurationTurn > 0)
{ {
isDurative = "(剩余:" + RemainDurationTurn + " 回合)"; isDurative = $"(剩余:{RemainDurationTurn} 回合)";
}
builder.Append($"【{Name} - 等级 {Level}】{Description}{isDurative}");
string dispels = GetDispelDescription("");
if (dispels != "")
{
builder.Append($"{dispels}");
} }
builder.AppendLine("【" + Name + " - 等级 " + Level + "】" + Description + isDurative);
return builder.ToString(); return builder.ToString();
} }
@ -575,7 +983,13 @@ namespace Milimoe.FunGame.Core.Entity
copy.Id = Id; copy.Id = Id;
copy.Name = Name; copy.Name = Name;
copy.Description = Description; copy.Description = Description;
copy.DispelDescription = DispelDescription;
copy.EffectType = EffectType; copy.EffectType = EffectType;
copy.DispelType = DispelType;
copy.DispelledType = DispelledType;
copy.IsDebuff = IsDebuff;
copy.IgnoreImmune = IgnoreImmune;
copy.DurativeWithoutDuration = DurativeWithoutDuration;
copy.Durative = Durative; copy.Durative = Durative;
copy.Duration = Duration; copy.Duration = Duration;
copy.DurationTurn = DurationTurn; copy.DurationTurn = DurationTurn;
@ -593,5 +1007,37 @@ namespace Milimoe.FunGame.Core.Entity
{ {
return other is Effect c && c.Id + "." + Name == Id + "." + Name; return other is Effect c && c.Id + "." + Name == Id + "." + Name;
} }
/// <summary>
/// 获取驱散描述
/// </summary>
/// <param name="separator"></param>
/// <returns></returns>
private string GetDispelDescription(string separator)
{
if (_dispelDescription.Trim() != "")
{
return _dispelDescription;
}
else if (DispelType != DispelType.None || DispelledType != DispelledType.Weak)
{
List<string> dispels = [];
if (DispelType != DispelType.None)
{
dispels.Add($"驱散性:{SkillSet.GetDispelType(DispelType)}");
}
if (DispelledType != DispelledType.Weak)
{
dispels.Add($"被驱散性:{SkillSet.GetDispelledType(DispelledType)}");
}
return string.Join(separator, dispels);
}
return "";
}
/// <summary>
/// 驱散描述
/// </summary>
private string _dispelDescription = "";
} }
} }

View File

@ -1,4 +1,5 @@
using System.Text; using System.Text;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Interface.Entity; using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
@ -52,11 +53,21 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public MagicType MagicType => _MagicType; public MagicType MagicType => _MagicType;
/// <summary>
/// 无视免疫类型
/// </summary>
public ImmuneType IgnoreImmune { get; set; } = ImmuneType.None;
/// <summary> /// <summary>
/// 硬直时间 /// 硬直时间
/// </summary> /// </summary>
public double HardnessTime { get; set; } = 10; public double HardnessTime { get; set; } = 10;
/// <summary>
/// 实际硬直时间
/// </summary>
public double RealHardnessTime => Math.Max(0, HardnessTime * (1 - Calculation.PercentageCheck(Character?.ActionCoefficient ?? 0)));
/// <summary> /// <summary>
/// 可选取自身 /// 可选取自身
/// </summary> /// </summary>
@ -124,7 +135,8 @@ namespace Milimoe.FunGame.Core.Entity
{ {
queue.WriteLine("[ " + Character + $" ] 对 [ {enemy} ] 发起了普通攻击!"); queue.WriteLine("[ " + Character + $" ] 对 [ {enemy} ] 发起了普通攻击!");
double expected = Damage; double expected = Damage;
DamageResult result = IsMagic ? queue.CalculateMagicalDamage(attacker, enemy, true, MagicType, expected, out double damage) : queue.CalculatePhysicalDamage(attacker, enemy, true, expected, out damage); int changeCount = 0;
DamageResult result = IsMagic ? queue.CalculateMagicalDamage(attacker, enemy, true, MagicType, expected, out double damage, ref changeCount) : queue.CalculatePhysicalDamage(attacker, enemy, true, expected, out damage, ref changeCount);
queue.DamageToEnemyAsync(attacker, enemy, damage, true, IsMagic, MagicType, result); queue.DamageToEnemyAsync(attacker, enemy, damage, true, IsMagic, MagicType, result);
} }
} }
@ -141,22 +153,38 @@ namespace Milimoe.FunGame.Core.Entity
_MagicType = magicType; _MagicType = magicType;
} }
/// <summary>
/// 比较两个普攻对象
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public override bool Equals(IBaseEntity? other) public override bool Equals(IBaseEntity? other)
{ {
return other is NormalAttack c && c.Name == Name; return other is NormalAttack c && c.Name == Name;
} }
public override string ToString() /// <summary>
/// 输出信息
/// </summary>
/// <param name="showOriginal"></param>
/// <returns></returns>
public string GetInfo(bool showOriginal = false)
{ {
StringBuilder builder = new(); StringBuilder builder = new();
builder.AppendLine(Name + " - 等级 " + Level); builder.AppendLine($"{Name} - 等级 {Level}");
builder.AppendLine("描述:" + Description); builder.AppendLine($"描述:{Description}");
builder.AppendLine("硬直时间:" + HardnessTime); builder.AppendLine($"硬直时间:{RealHardnessTime:0.##}{(showOriginal && RealHardnessTime != HardnessTime ? $"{HardnessTime}" : "")}");
return builder.ToString(); return builder.ToString();
} }
/// <summary>
/// 输出信息
/// </summary>
/// <returns></returns>
public override string ToString() => GetInfo(true);
/// <summary> /// <summary>
/// 等级 /// 等级
/// </summary> /// </summary>

View File

@ -26,12 +26,6 @@ namespace Milimoe.FunGame.Core.Entity
SkillType = SkillType.Item; SkillType = SkillType.Item;
} }
break; break;
case "debuff":
if (bool.TryParse(args[str].ToString(), out bool isDebuff) && isDebuff)
{
IsDebuff = isDebuff;
}
break;
case "self": case "self":
if (bool.TryParse(args[str].ToString(), out bool self)) if (bool.TryParse(args[str].ToString(), out bool self))
{ {

View File

@ -32,6 +32,11 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public virtual string GeneralDescription { get; set; } = ""; public virtual string GeneralDescription { get; set; } = "";
/// <summary>
/// 驱散性和被驱散性的描述
/// </summary>
public virtual string DispelDescription { get; set; } = "";
/// <summary> /// <summary>
/// 释放技能时的口号 /// 释放技能时的口号
/// </summary> /// </summary>
@ -88,11 +93,6 @@ namespace Milimoe.FunGame.Core.Entity
[InitRequired] [InitRequired]
public bool IsMagic => SkillType == SkillType.Magic; public bool IsMagic => SkillType == SkillType.Magic;
/// <summary>
/// 是否属于 Debuff
/// </summary>
public bool IsDebuff { get; set; } = false;
/// <summary> /// <summary>
/// 可选取自身 /// 可选取自身
/// </summary> /// </summary>
@ -134,17 +134,17 @@ namespace Milimoe.FunGame.Core.Entity
[InitOptional] [InitOptional]
public virtual double MPCost { get; set; } = 0; public virtual double MPCost { get; set; } = 0;
/// <summary>
/// 实际吟唱时间 [ 魔法 ]
/// </summary>
public double RealCastTime => Math.Max(0, CastTime * (1 - Calculation.PercentageCheck(Character?.AccelerationCoefficient ?? 0)));
/// <summary> /// <summary>
/// 吟唱时间 [ 魔法 ] /// 吟唱时间 [ 魔法 ]
/// </summary> /// </summary>
[InitOptional] [InitOptional]
public virtual double CastTime { get; set; } = 0; public virtual double CastTime { get; set; } = 0;
/// <summary>
/// 实际吟唱时间 [ 魔法 ]
/// </summary>
public double RealCastTime => Math.Max(0, CastTime * (1 - Calculation.PercentageCheck(Character?.AccelerationCoefficient ?? 0)));
/// <summary> /// <summary>
/// 实际能量消耗 [ 战技 ] /// 实际能量消耗 [ 战技 ]
/// </summary> /// </summary>
@ -198,6 +198,11 @@ namespace Milimoe.FunGame.Core.Entity
[InitRequired] [InitRequired]
public virtual double HardnessTime { get; set; } = 0; public virtual double HardnessTime { get; set; } = 0;
/// <summary>
/// 实际硬直时间
/// </summary>
public double RealHardnessTime => Math.Max(0, HardnessTime * (1 - Calculation.PercentageCheck(Character?.ActionCoefficient ?? 0)));
/// <summary> /// <summary>
/// 效果列表 /// 效果列表
/// </summary> /// </summary>
@ -420,8 +425,9 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 返回技能的详细说明 /// 返回技能的详细说明
/// </summary> /// </summary>
/// <param name="showOriginal"></param>
/// <returns></returns> /// <returns></returns>
public override string ToString() public string GetInfo(bool showOriginal = false)
{ {
StringBuilder builder = new(); StringBuilder builder = new();
@ -441,45 +447,55 @@ namespace Milimoe.FunGame.Core.Entity
{ {
builder.AppendLine("效果结束前不可用"); builder.AppendLine("效果结束前不可用");
} }
if (DispelDescription != "")
{
builder.AppendLine($"{DispelDescription}");
}
if (IsActive && (Item?.IsInGameItem ?? true)) if (IsActive && (Item?.IsInGameItem ?? true))
{ {
if (SkillType == SkillType.Item) if (SkillType == SkillType.Item)
{ {
if (RealMPCost > 0) if (RealMPCost > 0)
{ {
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}"); builder.AppendLine($"魔法消耗:{RealMPCost:0.##}{(showOriginal && RealMPCost != MPCost ? $"{MPCost}" : "")}");
} }
if (RealEPCost > 0) if (RealEPCost > 0)
{ {
builder.AppendLine($"能量消耗:{RealEPCost:0.##}"); builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"{EPCost}" : "")}");
} }
} }
else else
{ {
if (IsSuperSkill) if (IsSuperSkill)
{ {
builder.AppendLine($"能量消耗:{RealEPCost:0.##}"); builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"{EPCost}" : "")}");
} }
else else
{ {
if (IsMagic) if (IsMagic)
{ {
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}"); builder.AppendLine($"魔法消耗:{RealMPCost:0.##}{(showOriginal && RealMPCost != MPCost ? $"{MPCost}" : "")}");
builder.AppendLine($"吟唱时间:{RealCastTime:0.##}"); builder.AppendLine($"吟唱时间:{RealCastTime:0.##}{(showOriginal && RealCastTime != CastTime ? $"{CastTime}" : "")}");
} }
else else
{ {
builder.AppendLine($"能量消耗:{RealEPCost:0.##}"); builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"{EPCost}" : "")}");
} }
} }
} }
builder.AppendLine($"冷却时间:{RealCD:0.##}"); builder.AppendLine($"冷却时间:{RealCD:0.##}{(showOriginal && RealCD != CD ? $"{CD}" : "")}");
builder.AppendLine($"硬直时间:{HardnessTime:0.##}"); builder.AppendLine($"硬直时间:{RealHardnessTime:0.##}{(showOriginal && RealHardnessTime != HardnessTime ? $"{HardnessTime}" : "")}");
} }
return builder.ToString(); return builder.ToString();
} }
/// <summary>
/// 返回技能的详细说明
/// </summary>
/// <returns></returns>
public override string ToString() => GetInfo(true);
/// <summary> /// <summary>
/// 判断两个技能是否相同 检查Id.Name /// 判断两个技能是否相同 检查Id.Name
/// </summary> /// </summary>
@ -516,6 +532,7 @@ namespace Milimoe.FunGame.Core.Entity
skill.Name = skillDefined.Name; skill.Name = skillDefined.Name;
skill.Description = skillDefined.Description; skill.Description = skillDefined.Description;
skill.GeneralDescription = skillDefined.GeneralDescription; skill.GeneralDescription = skillDefined.GeneralDescription;
skill.DispelDescription = skillDefined.DispelDescription;
skill.SkillType = skillDefined.SkillType; skill.SkillType = skillDefined.SkillType;
skill.MPCost = skillDefined.MPCost; skill.MPCost = skillDefined.MPCost;
skill.CastTime = skillDefined.CastTime; skill.CastTime = skillDefined.CastTime;

View File

@ -18,12 +18,16 @@
public double AvgTakenPhysicalDamage { get; set; } = 0; public double AvgTakenPhysicalDamage { get; set; } = 0;
public double AvgTakenMagicDamage { get; set; } = 0; public double AvgTakenMagicDamage { get; set; } = 0;
public double AvgTakenRealDamage { get; set; } = 0; public double AvgTakenRealDamage { get; set; } = 0;
public double TotalHeal { get; set; } = 0;
public double AvgHeal { get; set; } = 0;
public int LiveRound { get; set; } = 0; public int LiveRound { get; set; } = 0;
public int AvgLiveRound { get; set; } = 0; public int AvgLiveRound { get; set; } = 0;
public int ActionTurn { get; set; } = 0; public int ActionTurn { get; set; } = 0;
public int AvgActionTurn { get; set; } = 0; public int AvgActionTurn { get; set; } = 0;
public double LiveTime { get; set; } = 0; public double LiveTime { get; set; } = 0;
public double AvgLiveTime { get; set; } = 0; public double AvgLiveTime { get; set; } = 0;
public double ControlTime { get; set; } = 0;
public double AvgControlTime { get; set; } = 0;
public double DamagePerRound { get; set; } = 0; public double DamagePerRound { get; set; } = 0;
public double DamagePerTurn { get; set; } = 0; public double DamagePerTurn { get; set; } = 0;
public double DamagePerSecond { get; set; } = 0; public double DamagePerSecond { get; set; } = 0;

View File

@ -93,7 +93,6 @@ namespace Milimoe.FunGame.Core.Entity
internal Inventory(User user) internal Inventory(User user)
{ {
User = user; User = user;
Name = user.Username + "的库存";
} }
public override string ToString() public override string ToString()

View File

@ -16,8 +16,10 @@ namespace Milimoe.FunGame.Core.Entity
public bool HasKill { get; set; } = false; public bool HasKill { get; set; } = false;
public Dictionary<Character, double> Damages { get; set; } = []; public Dictionary<Character, double> Damages { get; set; } = [];
public Dictionary<Character, bool> IsCritical { get; set; } = []; public Dictionary<Character, bool> IsCritical { get; set; } = [];
public Dictionary<Character, bool> IsEvaded { get; set; } = [];
public Dictionary<Character, bool> IsImmune { get; set; } = [];
public Dictionary<Character, double> Heals { get; set; } = []; public Dictionary<Character, double> Heals { get; set; } = [];
public Dictionary<Character, EffectType> Effects { get; set; } = []; public Dictionary<Character, List<EffectType>> Effects { get; set; } = [];
public List<string> ActorContinuousKilling { get; set; } = []; public List<string> ActorContinuousKilling { get; set; } = [];
public List<string> DeathContinuousKilling { get; set; } = []; public List<string> DeathContinuousKilling { get; set; } = [];
public double CastTime { get; set; } = 0; public double CastTime { get; set; } = 0;
@ -108,15 +110,22 @@ namespace Milimoe.FunGame.Core.Entity
{ {
hasHeal = $"治疗:{heals:0.##}"; hasHeal = $"治疗:{heals:0.##}";
} }
if (Effects.TryGetValue(target, out EffectType effectType)) if (Effects.TryGetValue(target, out List<EffectType>? effectTypes) && effectTypes != null)
{ {
hasEffect = $"施加:{SkillSet.GetEffectTypeName(effectType)}"; hasEffect = $"施加:{string.Join(" + ", effectTypes.Select(SkillSet.GetEffectTypeName))}";
} }
if (ActionType == CharacterActionType.NormalAttack && hasDamage == "") if (IsEvaded.ContainsKey(target))
{ {
hasDamage = "完美闪避"; if (ActionType == CharacterActionType.NormalAttack)
{
hasDamage = "完美闪避";
}
else if ((ActionType == CharacterActionType.PreCastSkill || ActionType == CharacterActionType.CastSkill || ActionType == CharacterActionType.CastSuperSkill))
{
hasDamage = "技能免疫";
}
} }
if ((ActionType == CharacterActionType.PreCastSkill || ActionType == CharacterActionType.CastSkill || ActionType == CharacterActionType.CastSuperSkill) && hasDamage == "" && target != Actor) if (IsImmune.ContainsKey(target) && hasDamage != "" && target != Actor)
{ {
hasDamage = "免疫"; hasDamage = "免疫";
} }

View File

@ -101,8 +101,9 @@ namespace Milimoe.FunGame.Core.Interface.Base
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="expectedDamage"></param> /// <param name="expectedDamage"></param>
/// <param name="finalDamage"></param> /// <param name="finalDamage"></param>
/// <param name="changeCount"></param>
/// <returns></returns> /// <returns></returns>
public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage); public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage, ref int changeCount);
/// <summary> /// <summary>
/// 计算魔法伤害 /// 计算魔法伤害
@ -113,8 +114,9 @@ namespace Milimoe.FunGame.Core.Interface.Base
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="expectedDamage"></param> /// <param name="expectedDamage"></param>
/// <param name="finalDamage"></param> /// <param name="finalDamage"></param>
/// <param name="changeCount"></param>
/// <returns></returns> /// <returns></returns>
public DamageResult CalculateMagicalDamage(Character actor, Character enemy, bool isNormalAttack, MagicType magicType, double expectedDamage, out double finalDamage); public DamageResult CalculateMagicalDamage(Character actor, Character enemy, bool isNormalAttack, MagicType magicType, double expectedDamage, out double finalDamage, ref int changeCount);
/// <summary> /// <summary>
/// 死亡结算 /// 死亡结算
@ -171,5 +173,13 @@ namespace Milimoe.FunGame.Core.Interface.Base
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public bool IsCharacterInAIControlling(Character character); public bool IsCharacterInAIControlling(Character character);
/// <summary>
/// 修改角色的硬直时间
/// </summary>
/// <param name="character">角色</param>
/// <param name="addValue">加值</param>
/// <param name="isCheckProtected">是否使用插队保护机制</param>
public void ChangeCharacterHardnessTime(Character character, double addValue, bool isCheckProtected);
} }
} }

View File

@ -71,6 +71,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
case nameof(Character.IsUnselectable): case nameof(Character.IsUnselectable):
result.IsUnselectable = reader.GetBoolean(); result.IsUnselectable = reader.GetBoolean();
break; break;
case nameof(Character.ImmuneType):
result.ImmuneType = (ImmuneType)reader.GetInt32();
break;
case nameof(Character.InitialHP): case nameof(Character.InitialHP):
result.InitialHP = reader.GetDouble(); result.InitialHP = reader.GetDouble();
break; break;
@ -206,6 +209,12 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
case nameof(Character.ExEvadeRate): case nameof(Character.ExEvadeRate):
result.ExEvadeRate = reader.GetDouble(); result.ExEvadeRate = reader.GetDouble();
break; break;
case nameof(Character.Lifesteal):
result.Lifesteal = reader.GetDouble();
break;
case nameof(Character.Shield):
result.Shield = NetworkUtility.JsonDeserialize<Shield>(ref reader, options) ?? new();
break;
case nameof(Character.NormalAttack): case nameof(Character.NormalAttack):
NormalAttack normalAttack = NetworkUtility.JsonDeserialize<NormalAttack>(ref reader, options) ?? new NormalAttack(result); NormalAttack normalAttack = NetworkUtility.JsonDeserialize<NormalAttack>(ref reader, options) ?? new NormalAttack(result);
result.NormalAttack.Level = normalAttack.Level; result.NormalAttack.Level = normalAttack.Level;
@ -253,6 +262,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
writer.WriteNumber(nameof(Character.EXP), value.EXP); writer.WriteNumber(nameof(Character.EXP), value.EXP);
writer.WriteBoolean(nameof(Character.IsNeutral), value.IsNeutral); writer.WriteBoolean(nameof(Character.IsNeutral), value.IsNeutral);
writer.WriteBoolean(nameof(Character.IsUnselectable), value.IsUnselectable); writer.WriteBoolean(nameof(Character.IsUnselectable), value.IsUnselectable);
writer.WriteNumber(nameof(Character.ImmuneType), (int)value.ImmuneType);
writer.WriteNumber(nameof(Character.CharacterState), (int)value.CharacterState); writer.WriteNumber(nameof(Character.CharacterState), (int)value.CharacterState);
writer.WriteNumber(nameof(Character.InitialHP), value.InitialHP); writer.WriteNumber(nameof(Character.InitialHP), value.InitialHP);
writer.WriteNumber(nameof(Character.ExHP2), value.ExHP2); writer.WriteNumber(nameof(Character.ExHP2), value.ExHP2);
@ -299,6 +309,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
writer.WriteNumber(nameof(Character.ExCritRate), value.ExCritRate); writer.WriteNumber(nameof(Character.ExCritRate), value.ExCritRate);
writer.WriteNumber(nameof(Character.ExCritDMG), value.ExCritDMG); writer.WriteNumber(nameof(Character.ExCritDMG), value.ExCritDMG);
writer.WriteNumber(nameof(Character.ExEvadeRate), value.ExEvadeRate); writer.WriteNumber(nameof(Character.ExEvadeRate), value.ExEvadeRate);
writer.WriteNumber(nameof(Character.Lifesteal), value.Lifesteal);
writer.WritePropertyName(nameof(Character.Shield));
JsonSerializer.Serialize(writer, value.Shield, options);
writer.WritePropertyName(nameof(Character.NormalAttack)); writer.WritePropertyName(nameof(Character.NormalAttack));
JsonSerializer.Serialize(writer, value.NormalAttack, options); JsonSerializer.Serialize(writer, value.NormalAttack, options);
writer.WritePropertyName(nameof(Character.Skills)); writer.WritePropertyName(nameof(Character.Skills));

View File

@ -29,6 +29,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
case nameof(NormalAttack.MagicType): case nameof(NormalAttack.MagicType):
result.SetMagicType(result.IsMagic, (MagicType)reader.GetInt32()); result.SetMagicType(result.IsMagic, (MagicType)reader.GetInt32());
break; break;
case nameof(NormalAttack.IgnoreImmune):
result.IgnoreImmune = (ImmuneType)reader.GetInt32();
break;
} }
} }
@ -40,6 +43,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
writer.WriteNumber(nameof(NormalAttack.HardnessTime), value.HardnessTime); writer.WriteNumber(nameof(NormalAttack.HardnessTime), value.HardnessTime);
writer.WriteBoolean(nameof(NormalAttack.IsMagic), value.IsMagic); writer.WriteBoolean(nameof(NormalAttack.IsMagic), value.IsMagic);
writer.WriteNumber(nameof(NormalAttack.MagicType), (int)value.MagicType); writer.WriteNumber(nameof(NormalAttack.MagicType), (int)value.MagicType);
writer.WriteNumber(nameof(NormalAttack.IgnoreImmune), (int)value.IgnoreImmune);
writer.WriteEndObject(); writer.WriteEndObject();
} }

View File

@ -0,0 +1,69 @@
using System.Text.Json;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Common.Architecture;
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
{
public class ShieldConverter : BaseEntityConverter<Shield>
{
public override Shield NewInstance()
{
return new();
}
public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref Shield result, Dictionary<string, object> convertingContext)
{
switch (propertyName)
{
case nameof(Shield.Physical):
result.Physical = reader.GetDouble();
break;
case nameof(Shield.None):
result.None = reader.GetDouble();
break;
case nameof(Shield.Starmark):
result.Starmark = reader.GetDouble();
break;
case nameof(Shield.PurityNatural):
result.PurityNatural = reader.GetDouble();
break;
case nameof(Shield.PurityContemporary):
result.PurityContemporary = reader.GetDouble();
break;
case nameof(Shield.Bright):
result.Bright = reader.GetDouble();
break;
case nameof(Shield.Shadow):
result.Shadow = reader.GetDouble();
break;
case nameof(Shield.Element):
result.Element = reader.GetDouble();
break;
case nameof(Shield.Fleabane):
result.Fleabane = reader.GetDouble();
break;
case nameof(Shield.Particle):
result.Particle = reader.GetDouble();
break;
}
}
public override void Write(Utf8JsonWriter writer, Shield value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteNumber(nameof(Shield.Physical), value.Physical);
writer.WriteNumber(nameof(Shield.None), value.None);
writer.WriteNumber(nameof(Shield.Starmark), value.Starmark);
writer.WriteNumber(nameof(Shield.PurityNatural), value.PurityNatural);
writer.WriteNumber(nameof(Shield.PurityContemporary), value.PurityContemporary);
writer.WriteNumber(nameof(Shield.Bright), value.Bright);
writer.WriteNumber(nameof(Shield.Shadow), value.Shadow);
writer.WriteNumber(nameof(Shield.Element), value.Element);
writer.WriteNumber(nameof(Shield.Fleabane), value.Fleabane);
writer.WriteNumber(nameof(Shield.Particle), value.Particle);
writer.WriteEndObject();
}
}
}

View File

@ -664,8 +664,8 @@ namespace Milimoe.FunGame.Core.Library.Constant
EffectType.DamageBoost => "伤害提升", EffectType.DamageBoost => "伤害提升",
EffectType.DefenseBoost => "防御提升", EffectType.DefenseBoost => "防御提升",
EffectType.CritBoost => "暴击提升", EffectType.CritBoost => "暴击提升",
EffectType.ManaRegen => "魔法恢复", EffectType.MPRegen => "魔法恢复",
EffectType.ArmorBreak => "破甲", EffectType.PenetrationBoost => "穿透提升",
EffectType.MagicResistBreak => "降低魔抗", EffectType.MagicResistBreak => "降低魔抗",
EffectType.Curse => "诅咒", EffectType.Curse => "诅咒",
EffectType.Exhaustion => "疲劳", EffectType.Exhaustion => "疲劳",
@ -677,8 +677,171 @@ namespace Milimoe.FunGame.Core.Library.Constant
EffectType.SilenceMagic => "法术沉默", EffectType.SilenceMagic => "法术沉默",
EffectType.Banish => "放逐", EffectType.Banish => "放逐",
EffectType.Doom => "毁灭", EffectType.Doom => "毁灭",
EffectType.PhysicalImmune => "物理免疫",
EffectType.MagicalImmune => "魔法免疫",
EffectType.SkilledImmune => "技能免疫",
EffectType.AllImmune => "完全免疫",
EffectType.EvadeBoost => "闪避提升",
_ => "未知效果" _ => "未知效果"
}; };
} }
public static DispelledType GetDispelledTypeByEffectType(EffectType type)
{
return type switch
{
EffectType.None => DispelledType.CannotBeDispelled,
EffectType.Item => DispelledType.CannotBeDispelled,
EffectType.Knockback => DispelledType.CannotBeDispelled,
EffectType.Unselectable => DispelledType.CannotBeDispelled,
EffectType.Doom => DispelledType.CannotBeDispelled,
EffectType.Stun => DispelledType.Strong,
EffectType.Freeze => DispelledType.Strong,
EffectType.Silence => DispelledType.Strong,
EffectType.Root => DispelledType.Strong,
EffectType.Fear => DispelledType.Strong,
EffectType.Sleep => DispelledType.Strong,
EffectType.Knockdown => DispelledType.Strong,
EffectType.Taunt => DispelledType.Strong,
EffectType.Invulnerable => DispelledType.Strong,
EffectType.Charm => DispelledType.Strong,
EffectType.Disarm => DispelledType.Strong,
EffectType.Confusion => DispelledType.Strong,
EffectType.Petrify => DispelledType.Strong,
EffectType.SilenceMagic => DispelledType.Strong,
EffectType.Banish => DispelledType.Strong,
EffectType.Mark => DispelledType.Weak,
EffectType.Slow => DispelledType.Weak,
EffectType.Weaken => DispelledType.Weak,
EffectType.Poison => DispelledType.Weak,
EffectType.Burn => DispelledType.Weak,
EffectType.Bleed => DispelledType.Weak,
EffectType.Blind => DispelledType.Weak,
EffectType.Cripple => DispelledType.Weak,
EffectType.Shield => DispelledType.Weak,
EffectType.HealOverTime => DispelledType.Weak,
EffectType.Haste => DispelledType.Weak,
EffectType.DamageBoost => DispelledType.Weak,
EffectType.DefenseBoost => DispelledType.Weak,
EffectType.CritBoost => DispelledType.Weak,
EffectType.MPRegen => DispelledType.Weak,
EffectType.PenetrationBoost => DispelledType.Weak,
EffectType.MagicResistBreak => DispelledType.Weak,
EffectType.Curse => DispelledType.Weak,
EffectType.Exhaustion => DispelledType.Weak,
EffectType.ManaBurn => DispelledType.Weak,
EffectType.PhysicalImmune => DispelledType.Weak,
EffectType.MagicalImmune => DispelledType.Weak,
EffectType.SkilledImmune => DispelledType.Weak,
EffectType.AllImmune => DispelledType.Strong,
EffectType.EvadeBoost => DispelledType.Weak,
EffectType.Lifesteal => DispelledType.Weak,
EffectType.GrievousWound => DispelledType.Weak,
_ => DispelledType.Weak
};
}
public static bool GetIsDebuffByEffectType(EffectType type)
{
return type switch
{
EffectType.None => false,
EffectType.Item => false,
EffectType.Knockback => true,
EffectType.Unselectable => false,
EffectType.Doom => true,
EffectType.Stun => true,
EffectType.Freeze => true,
EffectType.Silence => true,
EffectType.Root => true,
EffectType.Fear => true,
EffectType.Sleep => true,
EffectType.Knockdown => true,
EffectType.Taunt => true,
EffectType.Invulnerable => false,
EffectType.Charm => true,
EffectType.Disarm => true,
EffectType.Confusion => true,
EffectType.Petrify => true,
EffectType.SilenceMagic => true,
EffectType.Banish => true,
EffectType.Mark => true,
EffectType.Slow => true,
EffectType.Weaken => true,
EffectType.Poison => true,
EffectType.Burn => true,
EffectType.Bleed => true,
EffectType.Blind => true,
EffectType.Cripple => true,
EffectType.Shield => false,
EffectType.HealOverTime => false,
EffectType.Haste => false,
EffectType.DamageBoost => false,
EffectType.DefenseBoost => false,
EffectType.CritBoost => false,
EffectType.MPRegen => false,
EffectType.PenetrationBoost => true,
EffectType.MagicResistBreak => true,
EffectType.Curse => true,
EffectType.Exhaustion => true,
EffectType.ManaBurn => true,
EffectType.PhysicalImmune => false,
EffectType.MagicalImmune => false,
EffectType.SkilledImmune => false,
EffectType.AllImmune => false,
EffectType.EvadeBoost => false,
EffectType.Lifesteal => false,
EffectType.GrievousWound => false,
_ => false
};
}
public static CharacterState GetCharacterStateByEffectType(EffectType type)
{
return type switch
{
EffectType.Stun => CharacterState.NotActionable,
EffectType.Freeze => CharacterState.NotActionable,
EffectType.Sleep => CharacterState.NotActionable,
EffectType.Knockdown => CharacterState.NotActionable,
EffectType.Petrify => CharacterState.NotActionable,
EffectType.Banish => CharacterState.NotActionable,
EffectType.Root => CharacterState.ActionRestricted,
EffectType.Fear => CharacterState.ActionRestricted,
EffectType.Taunt => CharacterState.ActionRestricted,
EffectType.Charm => CharacterState.ActionRestricted,
EffectType.Confusion => CharacterState.ActionRestricted,
EffectType.Silence => CharacterState.SkillRestricted,
EffectType.SilenceMagic => CharacterState.SkillRestricted,
EffectType.Disarm => CharacterState.AttackRestricted,
_ => CharacterState.Actionable,
};
}
public static string GetDispelType(DispelType type)
{
return type switch
{
DispelType.Weak => "弱驱散",
DispelType.DurativeWeak => "持续性弱驱散",
DispelType.TemporaryWeak => "临时弱驱散",
DispelType.Strong => "强驱散",
DispelType.DurativeStrong => "持续性强驱散",
DispelType.TemporaryStrong => "临时强驱散",
DispelType.Special => "特殊驱散",
_ => ""
};
}
public static string GetDispelledType(DispelledType type)
{
return type switch
{
DispelledType.Strong => "需强驱散",
DispelledType.Special => "需特殊驱散",
DispelledType.CannotBeDispelled => "不可驱散",
_ => ""
};
}
} }
} }

View File

@ -34,42 +34,42 @@ namespace Milimoe.FunGame.Core.Library.Constant
public enum CharacterState public enum CharacterState
{ {
/// <summary> /// <summary>
/// 可以行动 [ 战斗相关 ] /// 可以行动 [ 战斗相关 ] [ 常态 ]
/// </summary> /// </summary>
Actionable, Actionable,
/// <summary> /// <summary>
/// 完全行动不能 [ 战斗相关 ] /// 完全行动不能 [ 战斗相关 ] [ 控制态 ]
/// </summary> /// </summary>
NotActionable, NotActionable,
/// <summary> /// <summary>
/// 行动受限 [ 战斗相关 ] /// 行动受限 [ 战斗相关 ] [ 控制态 ]
/// </summary> /// </summary>
ActionRestricted, ActionRestricted,
/// <summary> /// <summary>
/// 战斗不能 [ 战斗相关 ] /// 战斗不能 [ 战斗相关 ] [ 控制态 ]
/// </summary> /// </summary>
BattleRestricted, BattleRestricted,
/// <summary> /// <summary>
/// 技能受限 [ 战斗相关 ] /// 技能受限 [ 战斗相关 ] [ 控制态 ]
/// </summary> /// </summary>
SkillRestricted, SkillRestricted,
/// <summary> /// <summary>
/// 攻击受限 [ 战斗相关 ] /// 攻击受限 [ 战斗相关 ] [ 控制态 ]
/// </summary> /// </summary>
AttackRestricted, AttackRestricted,
/// <summary> /// <summary>
/// 处于吟唱中 [ 战斗相关 ] [ 技能相关 ] /// 处于吟唱中 [ 战斗相关 ] [ 技能相关 ] [ 吟唱态 ]
/// </summary> /// </summary>
Casting, Casting,
/// <summary> /// <summary>
/// 预释放爆发技(插队) [ 战斗相关 ] [ 技能相关 ] /// 预释放爆发技(插队) [ 战斗相关 ] [ 技能相关 ] [ 吟唱态 ]
/// </summary> /// </summary>
PreCastSuperSkill PreCastSuperSkill
} }

View File

@ -337,7 +337,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
HealOverTime, HealOverTime,
/// <summary> /// <summary>
/// 加速,提升行动速度和攻击频率 /// 加速,提升行动速度
/// </summary> /// </summary>
Haste, Haste,
@ -357,7 +357,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
DamageBoost, DamageBoost,
/// <summary> /// <summary>
/// 防御提升,减少所受伤害 /// 物理护甲/魔法抗性提升,减少所受伤害
/// </summary> /// </summary>
DefenseBoost, DefenseBoost,
@ -369,12 +369,12 @@ namespace Milimoe.FunGame.Core.Library.Constant
/// <summary> /// <summary>
/// 魔法恢复,增加魔法值回复速度 /// 魔法恢复,增加魔法值回复速度
/// </summary> /// </summary>
ManaRegen, MPRegen,
/// <summary> /// <summary>
/// 破甲,降低目标的防御值 /// 破甲,提高物理/魔法穿透
/// </summary> /// </summary>
ArmorBreak, PenetrationBoost,
/// <summary> /// <summary>
/// 降低魔法抗性,目标更容易受到魔法伤害 /// 降低魔法抗性,目标更容易受到魔法伤害
@ -429,7 +429,42 @@ namespace Milimoe.FunGame.Core.Library.Constant
/// <summary> /// <summary>
/// 毁灭,目标在倒计时结束后受到大量伤害或死亡 /// 毁灭,目标在倒计时结束后受到大量伤害或死亡
/// </summary> /// </summary>
Doom Doom,
/// <summary>
/// 物理免疫
/// </summary>
PhysicalImmune,
/// <summary>
/// 魔法免疫
/// </summary>
MagicalImmune,
/// <summary>
/// 技能免疫
/// </summary>
SkilledImmune,
/// <summary>
/// 完全免疫:物理免疫 + 技能免疫
/// </summary>
AllImmune,
/// <summary>
/// 闪避提升
/// </summary>
EvadeBoost,
/// <summary>
/// 生命偷取
/// </summary>
Lifesteal,
/// <summary>
/// 重伤,目标受到的治疗效果降低
/// </summary>
GrievousWound
} }
public enum ItemType public enum ItemType
@ -901,4 +936,83 @@ namespace Milimoe.FunGame.Core.Library.Constant
PreCastSuperSkill, PreCastSuperSkill,
Respawn Respawn
} }
public enum DispelType
{
/// <summary>
/// 无驱散 [ 默认,不能驱散其他特效 ]
/// </summary>
None,
/// <summary>
/// 弱驱散
/// </summary>
Weak,
/// <summary>
/// 持续性弱驱散
/// </summary>
DurativeWeak,
/// <summary>
/// 临时弱驱散
/// </summary>
TemporaryWeak,
/// <summary>
/// 强驱散
/// </summary>
Strong,
/// <summary>
/// 持续性强驱散
/// </summary>
DurativeStrong,
/// <summary>
/// 临时强驱散
/// </summary>
TemporaryStrong,
/// <summary>
/// 特殊驱散
/// </summary>
Special
}
public enum DispelledType
{
/// <summary>
/// 可弱驱散 [ 默认 ]
/// </summary>
Weak,
/// <summary>
/// 需强驱散
/// </summary>
Strong,
/// <summary>
/// 需特殊驱散
/// </summary>
Special,
/// <summary>
/// 不可驱散 [ 最高优先级 ]
/// </summary>
CannotBeDispelled
}
/// <summary>
/// 标准实现的免疫类型
/// </summary>
public enum ImmuneType
{
None,
Physical,
Magical,
Skilled,
All,
Special
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ namespace Milimoe.FunGame.Core.Service
Converters = { new DateTimeConverter(), new DataTableConverter(), new DataSetConverter(), new UserConverter(), new RoomConverter(), Converters = { new DateTimeConverter(), new DataTableConverter(), new DataSetConverter(), new UserConverter(), new RoomConverter(),
new CharacterConverter(), new MagicResistanceConverter(), new EquipSlotConverter(), new SkillConverter(), new EffectConverter(), new ItemConverter(), new CharacterConverter(), new MagicResistanceConverter(), new EquipSlotConverter(), new SkillConverter(), new EffectConverter(), new ItemConverter(),
new InventoryConverter(), new NormalAttackConverter(), new ClubConverter(), new GoodsConverter(), new StoreConverter(), new InventoryConverter(), new NormalAttackConverter(), new ClubConverter(), new GoodsConverter(), new StoreConverter(),
new NovelOptionConverter(), new NovelNodeConverter() new NovelOptionConverter(), new NovelNodeConverter(), new ShieldConverter()
} }
}; };