diff --git a/Api/Utility/General.cs b/Api/Utility/General.cs index d19c9a8..dc1a84a 100644 --- a/Api/Utility/General.cs +++ b/Api/Utility/General.cs @@ -650,6 +650,31 @@ namespace Milimoe.FunGame.Core.Api.Utility await Task.Delay(milliseconds); }).OnCompleted(action); } + + /// + /// 添加任务计划,使用 的时分秒。如果用 ,请直接在 中添加 + /// + /// + /// + /// + public static void AddSchedulerTask(string name, DateTime time, Action action) + { + TaskScheduler.Shared.AddTask(name, new TimeSpan(time.Hour, time.Minute, time.Second), action); + } + + /// + /// 添加循环任务。如果用 ,请直接在 中添加 + /// + /// + /// + /// + /// + /// + /// + public static void AddRecurringTask(string name, int seconds, Action action, int hours = 0, int minutes = 0, bool startNow = false) + { + TaskScheduler.Shared.AddRecurringTask(name, new TimeSpan(hours, minutes, seconds), action, startNow); + } } #endregion diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs index d96fee6..601e1ce 100644 --- a/Entity/Character/Character.cs +++ b/Entity/Character/Character.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Interface.Entity; using Milimoe.FunGame.Core.Library.Constant; @@ -10,7 +10,7 @@ namespace Milimoe.FunGame.Core.Entity /// 在使用时仅需要调用 方法即可获得相同对象 /// 不建议继承 /// - public class Character : BaseEntity, ICopyable + public class Character : BaseEntity { /// /// 角色的姓 @@ -135,6 +135,11 @@ namespace Milimoe.FunGame.Core.Entity /// 经验值 /// public double EXP { get; set; } = 0; + + /// + /// 等级突破进度 [ 对应 中的索引 ] + /// + public int LevelBreak { get; set; } = -1; /// /// 角色目前所处的状态 [ 战斗相关 ] @@ -688,9 +693,21 @@ namespace Milimoe.FunGame.Core.Entity public double ExActionCoefficient { get; set; } = 0; /// - /// 加速系数(%) [ 与技能和物品相关 ] + /// 加速系数(%) = [ 与智力相关 ] + 额外加速系数(%) /// - public double AccelerationCoefficient { get; set; } = 0; + public double AccelerationCoefficient + { + get + { + double value = INT * General.GameplayEquilibriumConstant.INTtoAccelerationCoefficientMultiplier + ExActionCoefficient; + return Calculation.PercentageCheck(value); + } + } + + /// + /// 额外加速系数(%) [ 与技能和物品相关 ] + /// + public double ExAccelerationCoefficient { get; set; } = 0; /// /// 冷却缩减(%) = [ 与智力相关 ] + 额外冷却缩减(%) @@ -1100,6 +1117,62 @@ namespace Milimoe.FunGame.Core.Entity return result; } + /// + /// 角色升级 + /// + /// + /// + public void OnLevelUp(int level = 0, bool checkLevelBreak = true) + { + int count = 0; + while (true) + { + // 传入 level 表示最多升级多少次,0 为用完所有溢出的经验值 + if (level != 0 && count++ >= level) + { + break; + } + if (General.GameplayEquilibriumConstant.UseLevelBreak && checkLevelBreak) + { + // 检查角色突破进度 + int[] breaks = [.. General.GameplayEquilibriumConstant.LevelBreakList]; + int nextBreak = LevelBreak + 1; + if (nextBreak < breaks.Length && Level >= breaks[nextBreak]) + { + // 需要突破才能继续升级 + break; + } + } + if (Level > 0 && Level < General.GameplayEquilibriumConstant.MaxLevel && General.GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) && EXP >= need) + { + EXP -= need; + Level++; + OnAttributeChanged(); + Recovery(); + } + else + { + break; + } + } + } + + /// + /// 角色突破,允许继续升级 + /// + public void OnLevelBreak() + { + if (General.GameplayEquilibriumConstant.UseLevelBreak) + { + // 检查角色突破进度 + int[] levels = [.. General.GameplayEquilibriumConstant.LevelBreakList]; + while (LevelBreak + 1 < levels.Length && Level >= levels[LevelBreak + 1]) + { + LevelBreak++; + } + } + } + /// /// 角色的属性发生变化,会影响特殊效果的计算 /// @@ -1222,17 +1295,17 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser()); if (showEXP) { - builder.AppendLine($"等级:{Level} / {General.GameplayEquilibriumConstant.MaxLevel}"); - builder.AppendLine($"经验值:{EXP}{(Level > 0 && Level <= General.GameplayEquilibriumConstant.EXPUpperLimit.Keys.Max() ? " / " + General.GameplayEquilibriumConstant.EXPUpperLimit[Level] : "")}"); + builder.AppendLine($"等级:{Level} / {General.GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {General.GameplayEquilibriumConstant.LevelBreakList.Count})"); + builder.AppendLine($"经验值:{EXP}{(Level != General.GameplayEquilibriumConstant.MaxLevel && General.GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}"); } double exHP = ExHP + ExHP2 + ExHP3; builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "")); double exMP = ExMP + ExMP2 + ExMP3; builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"能量值:{EP:0.##} / {General.GameplayEquilibriumConstant.MaxEP:0.##}"); - double exATK = ExATK + ExATK2; + double exATK = ExATK + ExATK2 + ExATK3; builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); - double exDEF = ExDEF + ExDEF2; + double exDEF = ExDEF + ExDEF2 + ExDEF3; 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 + MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100; @@ -1241,9 +1314,12 @@ namespace Milimoe.FunGame.Core.Entity double exSPD = AGI * General.GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD; builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)"); builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); - builder.AppendLine($"力量:{STR:0.##}" + (ExSTR != 0 ? $" [{BaseSTR:0.##} {(ExSTR >= 0 ? "+" : "-")} {Math.Abs(ExSTR):0.##}]" : "") + (showGrowth ? $"({(STRGrowth >= 0 ? "+" : "-")}{Math.Abs(STRGrowth)}/Lv)" : "")); - builder.AppendLine($"敏捷:{AGI:0.##}" + (ExAGI != 0 ? $" [{BaseAGI:0.##} {(ExAGI >= 0 ? "+" : "-")} {Math.Abs(ExAGI):0.##}]" : "") + (showGrowth ? $"({(AGIGrowth >= 0 ? "+" : "-")}{Math.Abs(AGIGrowth)}/Lv)" : "")); - builder.AppendLine($"智力:{INT:0.##}" + (ExINT != 0 ? $" [{BaseINT:0.##} {(ExINT >= 0 ? "+" : "-")} {Math.Abs(ExINT):0.##}]" : "") + (showGrowth ? $"({(INTGrowth >= 0 ? "+" : "-")}{Math.Abs(INTGrowth)}/Lv)" : "")); + double exSTR = ExSTR + ExSTR2; + builder.AppendLine($"力量:{STR:0.##}" + (exSTR != 0 ? $" [{BaseSTR:0.##} {(exSTR >= 0 ? "+" : "-")} {Math.Abs(exSTR):0.##}]" : "") + (showGrowth ? $"({(STRGrowth >= 0 ? "+" : "-")}{Math.Abs(STRGrowth)}/Lv)" : "")); + double exAGI = ExAGI + ExAGI2; + builder.AppendLine($"敏捷:{AGI:0.##}" + (exAGI != 0 ? $" [{BaseAGI:0.##} {(exAGI >= 0 ? "+" : "-")} {Math.Abs(exAGI):0.##}]" : "") + (showGrowth ? $"({(AGIGrowth >= 0 ? "+" : "-")}{Math.Abs(AGIGrowth)}/Lv)" : "")); + double exINT = ExINT + ExINT2; + builder.AppendLine($"智力:{INT:0.##}" + (exINT != 0 ? $" [{BaseINT:0.##} {(exINT >= 0 ? "+" : "-")} {Math.Abs(exINT):0.##}]" : "") + (showGrowth ? $"({(INTGrowth >= 0 ? "+" : "-")}{Math.Abs(INTGrowth)}/Lv)" : "")); builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * General.GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : "")); builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * General.GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : "")); builder.AppendLine($"暴击率:{CritRate * 100:0.##}%"); @@ -1253,8 +1329,8 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:0.##}%"); builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%"); builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%"); - builder.AppendLine($"魔法消耗减少:{INT * 0.00125 * 100:0.##}%"); - builder.AppendLine($"能量消耗减少:{INT * 0.00075 * 100:0.##}%"); + builder.AppendLine($"魔法消耗减少:{INT * General.GameplayEquilibriumConstant.INTtoCastMPReduce * 100:0.##}%"); + builder.AppendLine($"能量消耗减少:{INT * General.GameplayEquilibriumConstant.INTtoCastEPReduce * 100:0.##}%"); if (CharacterState != CharacterState.Actionable) { @@ -1350,17 +1426,17 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser()); if (showEXP) { - builder.AppendLine($"等级:{Level} / {General.GameplayEquilibriumConstant.MaxLevel}"); - builder.AppendLine($"经验值:{EXP}{(Level > 0 && Level <= General.GameplayEquilibriumConstant.EXPUpperLimit.Keys.Max() ? " / " + General.GameplayEquilibriumConstant.EXPUpperLimit[Level] : "")}"); + builder.AppendLine($"等级:{Level} / {General.GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {General.GameplayEquilibriumConstant.LevelBreakList.Count})"); + builder.AppendLine($"经验值:{EXP}{(Level != General.GameplayEquilibriumConstant.MaxLevel && General.GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}"); } double exHP = ExHP + ExHP2 + ExHP3; builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "")); double exMP = ExMP + ExMP2 + ExMP3; builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"能量值:{EP:0.##} / {General.GameplayEquilibriumConstant.MaxEP:0.##}"); - double exATK = ExATK + ExATK2; + double exATK = ExATK + ExATK2 + ExATK3; builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); - double exDEF = ExDEF + ExDEF2; + double exDEF = ExDEF + ExDEF2 + ExDEF3; 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 + MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100; @@ -1369,9 +1445,12 @@ namespace Milimoe.FunGame.Core.Entity double exSPD = AGI * General.GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD; builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)"); builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); - builder.AppendLine($"力量:{STR:0.##}" + (ExSTR != 0 ? $" [{BaseSTR:0.##} {(ExSTR >= 0 ? "+" : "-")} {Math.Abs(ExSTR):0.##}]" : "") + (showGrowth ? $"({(STRGrowth >= 0 ? "+" : "-")}{Math.Abs(STRGrowth)}/Lv)" : "")); - builder.AppendLine($"敏捷:{AGI:0.##}" + (ExAGI != 0 ? $" [{BaseAGI:0.##} {(ExAGI >= 0 ? "+" : "-")} {Math.Abs(ExAGI):0.##}]" : "") + (showGrowth ? $"({(AGIGrowth >= 0 ? "+" : "-")}{Math.Abs(AGIGrowth)}/Lv)" : "")); - builder.AppendLine($"智力:{INT:0.##}" + (ExINT != 0 ? $" [{BaseINT:0.##} {(ExINT >= 0 ? "+" : "-")} {Math.Abs(ExINT):0.##}]" : "") + (showGrowth ? $"({(INTGrowth >= 0 ? "+" : "-")}{Math.Abs(INTGrowth)}/Lv)" : "")); + double exSTR = ExSTR + ExSTR2; + builder.AppendLine($"力量:{STR:0.##}" + (exSTR != 0 ? $" [{BaseSTR:0.##} {(exSTR >= 0 ? "+" : "-")} {Math.Abs(exSTR):0.##}]" : "") + (showGrowth ? $"({(STRGrowth >= 0 ? "+" : "-")}{Math.Abs(STRGrowth)}/Lv)" : "")); + double exAGI = ExAGI + ExAGI2; + builder.AppendLine($"敏捷:{AGI:0.##}" + (exAGI != 0 ? $" [{BaseAGI:0.##} {(exAGI >= 0 ? "+" : "-")} {Math.Abs(exAGI):0.##}]" : "") + (showGrowth ? $"({(AGIGrowth >= 0 ? "+" : "-")}{Math.Abs(AGIGrowth)}/Lv)" : "")); + double exINT = ExINT + ExINT2; + builder.AppendLine($"智力:{INT:0.##}" + (exINT != 0 ? $" [{BaseINT:0.##} {(exINT >= 0 ? "+" : "-")} {Math.Abs(exINT):0.##}]" : "") + (showGrowth ? $"({(INTGrowth >= 0 ? "+" : "-")}{Math.Abs(INTGrowth)}/Lv)" : "")); builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * General.GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : "")); builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * General.GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : "")); @@ -1451,7 +1530,7 @@ namespace Milimoe.FunGame.Core.Entity double exMP = ExMP + ExMP2 + ExMP3; builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"能量值:{EP:0.##} / {General.GameplayEquilibriumConstant.MaxEP:0.##}"); - double exATK = ExATK + ExATK2; + double exATK = ExATK + ExATK2 + ExATK3; builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}" + (ExPrimaryAttributeValue != 0 ? $" [{BasePrimaryAttributeValue:0.##} {(ExPrimaryAttributeValue >= 0 ? "+" : "-")} {Math.Abs(ExPrimaryAttributeValue):0.##}]" : "")); @@ -1499,7 +1578,7 @@ namespace Milimoe.FunGame.Core.Entity double exMP = ExMP + ExMP2 + ExMP3; builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : "")); builder.AppendLine($"能量值:{EP:0.##} / {General.GameplayEquilibriumConstant.MaxEP:0.##}"); - double exATK = ExATK + ExATK2; + double exATK = ExATK + ExATK2 + ExATK3; builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : "")); builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}" + (ExPrimaryAttributeValue != 0 ? $" [{BasePrimaryAttributeValue:0.##} {(ExPrimaryAttributeValue >= 0 ? "+" : "-")} {Math.Abs(ExPrimaryAttributeValue):0.##}]" : "")); builder.AppendLine($"硬直时间:{hardnessTimes:0.##}"); @@ -1569,7 +1648,7 @@ namespace Milimoe.FunGame.Core.Entity /// [ 推荐从模组中复制后使用对象 ] /// /// - public Character Copy() + public Character Copy(bool copyEx = false) { Character c = new() { @@ -1586,50 +1665,54 @@ namespace Milimoe.FunGame.Core.Entity Promotion = Promotion, PrimaryAttribute = PrimaryAttribute, Level = Level, + LevelBreak = LevelBreak, EXP = EXP, InitialHP = InitialHP, - ExHP2 = ExHP2, - ExHPPercentage = ExHPPercentage, InitialMP = InitialMP, - ExMP2 = ExMP2, - ExMPPercentage = ExMPPercentage, EP = EP, InitialATK = InitialATK, - ExATK2 = ExATK2, - ExATKPercentage = ExATKPercentage, InitialDEF = InitialDEF, - ExDEF2 = ExDEF2, - ExDEFPercentage = ExDEFPercentage, MDF = MDF.Copy(), PhysicalPenetration = PhysicalPenetration, MagicalPenetration = MagicalPenetration, InitialHR = InitialHR, - ExHR = ExHR, InitialMR = InitialMR, - ExMR = ExMR, ER = ER, InitialSTR = InitialSTR, InitialAGI = InitialAGI, InitialINT = InitialINT, - ExSTR = ExSTR, - ExAGI = ExAGI, - ExINT = ExINT, - ExSTRPercentage = ExSTRPercentage, - ExAGIPercentage = ExAGIPercentage, - ExINTPercentage = ExINTPercentage, STRGrowth = STRGrowth, AGIGrowth = AGIGrowth, INTGrowth = INTGrowth, InitialSPD = InitialSPD, - ExSPD = ExSPD, - ExActionCoefficient = ExActionCoefficient, - AccelerationCoefficient = AccelerationCoefficient, - ExCDR = ExCDR, ATR = ATR, - ExCritRate = ExCritRate, - ExCritDMG = ExCritDMG, - ExEvadeRate = ExEvadeRate }; + if (copyEx) + { + c.ExHP2 = ExHP2; + c.ExHPPercentage = ExHPPercentage; + c.ExMP2 = ExMP2; + c.ExMPPercentage = ExMPPercentage; + c.ExATK2 = ExATK2; + c.ExATKPercentage = ExATKPercentage; + c.ExDEF2 = ExDEF2; + c.ExDEFPercentage = ExDEFPercentage; + c.ExHR = ExHR; + c.ExMR = ExMR; + c.ExSTRPercentage = ExSTRPercentage; + c.ExAGIPercentage = ExAGIPercentage; + c.ExINTPercentage = ExINTPercentage; + c.ExSTR = ExSTR; + c.ExAGI = ExAGI; + c.ExINT = ExINT; + c.ExSPD = ExSPD; + c.ExActionCoefficient = ExActionCoefficient; + c.ExAccelerationCoefficient = ExAccelerationCoefficient; + c.ExCDR = ExCDR; + c.ExCritRate = ExCritRate; + c.ExCritDMG = ExCritDMG; + c.ExEvadeRate = ExEvadeRate; + } foreach (Skill skill in Skills) { Skill newskill = skill.Copy(); @@ -1684,6 +1767,7 @@ namespace Milimoe.FunGame.Core.Entity Promotion = c.Promotion; PrimaryAttribute = c.PrimaryAttribute; Level = c.Level; + LevelBreak = c.LevelBreak; EXP = c.EXP; CharacterState = c.CharacterState; CharacterEffectStates.Clear(); @@ -1721,7 +1805,7 @@ namespace Milimoe.FunGame.Core.Entity InitialSPD = c.InitialSPD; ExSPD = c.ExSPD; ExActionCoefficient = c.ExActionCoefficient; - AccelerationCoefficient = c.AccelerationCoefficient; + ExAccelerationCoefficient = c.ExAccelerationCoefficient; ExCDR = c.ExCDR; ATR = c.ATR; ExCritRate = c.ExCritRate; @@ -1750,4 +1834,4 @@ namespace Milimoe.FunGame.Core.Entity Recovery(0D); } } -} \ No newline at end of file +} diff --git a/Entity/Character/CharacterBuilder.cs b/Entity/Character/CharacterBuilder.cs index 777743e..4ccf8c4 100644 --- a/Entity/Character/CharacterBuilder.cs +++ b/Entity/Character/CharacterBuilder.cs @@ -95,17 +95,17 @@ namespace Milimoe.FunGame.Core.Entity /// /// 基于初始条件构建新的角色 - /// 需要传入等级、技能、物品,可选构建装备 + /// 需要传入技能、物品,可选构建装备 /// - /// /// /// /// /// + /// /// /// /// 构建的新角色 - public Character Build(int level, IEnumerable skills, IEnumerable items, bool newItemGuid = true, EquipSlot? equips = null, IEnumerable? itemsDefined = null, IEnumerable? skillsDefined = null) + public Character Build(IEnumerable skills, IEnumerable items, bool newItemGuid = true, EquipSlot? equips = null, Inventory? inventory = null, IEnumerable? itemsDefined = null, IEnumerable? skillsDefined = null) { Character character = Factory.GetCharacter(); character.Id = Id; @@ -126,10 +126,6 @@ namespace Milimoe.FunGame.Core.Entity character.InitialSPD = InitialSPD; character.InitialHR = InitialHR; character.InitialMR = InitialMR; - if (level > 1) - { - character.Level = level; - } foreach (Skill skill in skills) { // 主动技能的Guid表示与其关联的物品 @@ -169,35 +165,65 @@ namespace Milimoe.FunGame.Core.Entity Item? s = equips.Shoes; Item? ac1 = equips.Accessory1; Item? ac2 = equips.Accessory2; - if (mcp != null) + if (inventory != null) { - mcp = mcp.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); - character.Equip(mcp); + if (inventory.Items.FirstOrDefault(i => i.Guid == mcp?.Guid) is Item newmcp) + { + character.Equip(newmcp); + } + if (inventory.Items.FirstOrDefault(i => i.Guid == w?.Guid) is Item neww) + { + character.Equip(neww); + } + if (inventory.Items.FirstOrDefault(i => i.Guid == a?.Guid) is Item newa) + { + character.Equip(newa); + } + if (inventory.Items.FirstOrDefault(i => i.Guid == s?.Guid) is Item news) + { + character.Equip(news); + } + if (inventory.Items.FirstOrDefault(i => i.Guid == ac1?.Guid) is Item newac1) + { + character.Equip(newac1); + } + if (inventory.Items.FirstOrDefault(i => i.Guid == ac2?.Guid) is Item newac2) + { + character.Equip(newac2); + } } - if (w != null) + else { - w = w.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); - character.Equip(w); - } - if (a != null) - { - a = a.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); - character.Equip(a); - } - if (s != null) - { - s = s.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); - character.Equip(s); - } - if (ac1 != null) - { - ac1 = ac1.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); - character.Equip(ac1); - } - if (ac2 != null) - { - ac2 = ac2.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); - character.Equip(ac2); + if (mcp != null) + { + mcp = mcp.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); + character.Equip(mcp); + } + if (w != null) + { + w = w.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); + character.Equip(w); + } + if (a != null) + { + a = a.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); + character.Equip(a); + } + if (s != null) + { + s = s.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); + character.Equip(s); + } + if (ac1 != null) + { + ac1 = ac1.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); + character.Equip(ac1); + } + if (ac2 != null) + { + ac2 = ac2.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined); + character.Equip(ac2); + } } } character.Recovery(); @@ -210,13 +236,21 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// + /// + /// /// 对于动态扩展的物品而言,传入已定义的物品表,不使用被复制物品的数据 /// 对于动态扩展的技能而言,传入已定义的技能表,不使用被复制技能的数据 /// 构建的新角色 - public static Character Build(Character reference, bool newItemGuid = true, IEnumerable? itemsDefined = null, IEnumerable? skillsDefined = null) + public static Character Build(Character reference, bool newItemGuid = true, bool copyLevel = true, Inventory? inventory = null, IEnumerable? itemsDefined = null, IEnumerable? skillsDefined = null) { - Character character = new CharacterBuilder(reference).Build(reference.Level, reference.Skills, reference.Items, newItemGuid, reference.EquipSlot, itemsDefined, skillsDefined); - character.NormalAttack.Level = reference.Level; + Character character = new CharacterBuilder(reference).Build(reference.Skills, reference.Items, newItemGuid, reference.EquipSlot, inventory, itemsDefined, skillsDefined); + if (copyLevel) + { + character.Level = reference.Level; + character.LevelBreak = reference.LevelBreak; + character.EXP = reference.EXP; + } + character.NormalAttack.Level = reference.NormalAttack.Level; character.NormalAttack.SetMagicType(reference.NormalAttack.IsMagic, reference.NormalAttack.MagicType); return character; } diff --git a/Entity/Item/Item.cs b/Entity/Item/Item.cs index b584869..89f8962 100644 --- a/Entity/Item/Item.cs +++ b/Entity/Item/Item.cs @@ -143,10 +143,21 @@ namespace Milimoe.FunGame.Core.Entity public DateTime NextTradableTime { get; set; } = DateTime.MinValue; /// - /// 剩余使用次数(消耗品才会用到) + /// 剩余使用次数 + /// 对于永久性主动物品而言,如果是 物品,可以不设置此值;反之,强烈建议设置为 1. /// public int RemainUseTimes { get; set; } = 0; + /// + /// 使用后减少使用次数 + /// + public bool IsReduceTimesAfterUse { get; set; } = true; + + /// + /// 用完后删除物品 + /// + public bool IsRemoveAfterUse { get; set; } = true; + /// /// 物品所属的角色(只有装备物品,才需要设置) /// @@ -290,11 +301,17 @@ namespace Milimoe.FunGame.Core.Entity /// /// 局内使用物品触发 对某个角色使用 /// - public void UseItem(IGamingQueue queue, Character character, List enemys, List teammates) + /// + public bool UseItem(IGamingQueue queue, Character character, List enemys, List teammates) { bool cancel = false; bool used = false; - if (Skills.Active != null) + bool result = OnItemUsed(character, this, ref cancel); + if (cancel) + { + return result; + } + if (result && Skills.Active != null) { Skill skill = Skills.Active; List targets = queue.SelectTargets(character, skill, enemys, teammates, out cancel); @@ -304,15 +321,45 @@ namespace Milimoe.FunGame.Core.Entity used = true; } } - OnItemUsed(character, this, cancel, used); + if (used) + { + ReduceTimesAndRemove(); + } + return result && used; } /// /// 局外(库存)使用物品触发 /// - public void UseItem() + /// + public bool UseItem(Dictionary args) { - if (User != null) OnItemUsed(User, this); + if (User != null) + { + bool result = OnItemUsed(args); + if (result) + { + ReduceTimesAndRemove(); + } + return result; + } + return false; + } + + public void ReduceTimesAndRemove() + { + if (User != null) + { + if (IsReduceTimesAfterUse) + { + RemainUseTimes--; + } + if (RemainUseTimes < 0) RemainUseTimes = 0; + if (IsRemoveAfterUse && RemainUseTimes == 0) + { + User.Inventory.Items.Remove(this); + } + } } /// @@ -321,20 +368,20 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// - /// - protected virtual void OnItemUsed(Character character, Item item, bool cancel, bool used) + /// + protected virtual bool OnItemUsed(Character character, Item item, ref bool cancel) { - + return false; } /// /// 当物品被玩家使用时 /// - /// - /// - protected virtual void OnItemUsed(User user, Item item) + /// + /// + protected virtual bool OnItemUsed(Dictionary args) { - + return false; } /// @@ -359,7 +406,6 @@ namespace Milimoe.FunGame.Core.Entity } - protected Item(ItemType type, bool isInGame = true) { ItemType = type; @@ -474,12 +520,15 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine("== 魔法卡 ==\r\n" + string.Join("\r\n", Skills.Magics.Select(m => m.ToString().Trim()))); } - builder.AppendLine("== 物品技能 =="); - - if (Skills.Active != null) builder.AppendLine($"{Skills.Active.ToString().Trim()}"); - foreach (Skill skill in Skills.Passives) + if (Skills.Active != null || Skills.Passives.Count > 0) { - builder.AppendLine($"{skill.ToString().Trim()}"); + builder.AppendLine("== 物品技能 =="); + + if (Skills.Active != null) builder.AppendLine($"{Skills.Active.ToString().Trim()}"); + foreach (Skill skill in Skills.Passives) + { + builder.AppendLine($"{skill.ToString().Trim()}"); + } } if (BackgroundStory != "") @@ -588,13 +637,13 @@ namespace Milimoe.FunGame.Core.Entity item.IsInGameItem = itemDefined.IsInGameItem; if (item is OpenItem) { - item.Skills.Active = Skills.Active?.Copy(true, skillsDefined); + item.Skills.Active = itemDefined.Skills.Active?.Copy(true, skillsDefined); if (item.Skills.Active != null) { - item.Skills.Active.Level = copyLevel ? (Skills.Active?.Level ?? 1) : 1; + item.Skills.Active.Level = copyLevel ? (itemDefined.Skills.Active?.Level ?? 1) : 1; item.Skills.Active.Guid = item.Guid; } - foreach (Skill skill in Skills.Passives) + foreach (Skill skill in itemDefined.Skills.Passives) { Skill newskill = skill.Copy(true, skillsDefined); newskill.Item = item; @@ -602,7 +651,7 @@ namespace Milimoe.FunGame.Core.Entity newskill.Guid = item.Guid; item.Skills.Passives.Add(newskill); } - foreach (Skill skill in Skills.Magics) + foreach (Skill skill in itemDefined.Skills.Magics) { Skill newskill = skill.Copy(true, skillsDefined); newskill.Item = item; diff --git a/Entity/Skill/Effect.cs b/Entity/Skill/Effect.cs index 0e624fb..b68f0f9 100644 --- a/Entity/Skill/Effect.cs +++ b/Entity/Skill/Effect.cs @@ -247,6 +247,16 @@ namespace Milimoe.FunGame.Core.Entity public virtual void OnSkillCasted(Character caster, List targets, Dictionary others) { + } + + /// + /// 对目标触发技能效果 + /// + /// + /// + public virtual void OnSkillCasted(List targets, Dictionary others) + { + } /// diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs index 3907085..b10a183 100644 --- a/Entity/Skill/Skill.cs +++ b/Entity/Skill/Skill.cs @@ -357,6 +357,18 @@ namespace Milimoe.FunGame.Core.Entity e.OnSkillCasted(caster, targets, Values); } } + + /// + /// 对目标触发技能效果 + /// + /// + public void OnSkillCasted(List targets) + { + foreach (Effect e in Effects) + { + e.OnSkillCasted(targets, Values); + } + } /// /// 被动技能,需要重写此方法,返回被动特效给角色 [ 此方法会在技能学习时触发 ] @@ -391,7 +403,7 @@ namespace Milimoe.FunGame.Core.Entity { builder.AppendLine("效果结束前不可用"); } - if (IsActive) + if (IsActive && (Item?.IsInGameItem ?? true)) { if (SkillType == SkillType.Item) { @@ -469,7 +481,7 @@ namespace Milimoe.FunGame.Core.Entity args["values"] = skillDefined.Values; } Skill skill = Factory.OpenFactory.GetInstance(Id, Name, args); - skillDefined ??= skill; + skillDefined ??= this; if (copyProperty) SetPropertyToItemModuleNew(skill); skill.Id = skillDefined.Id; skill.Name = skillDefined.Name; @@ -484,7 +496,7 @@ namespace Milimoe.FunGame.Core.Entity skill.GamingQueue = skillDefined.GamingQueue; if (skill is OpenSkill) { - foreach (Effect e in Effects) + foreach (Effect e in skillDefined.Effects) { Effect neweffect = e.Copy(skill); skill.Effects.Add(neweffect); diff --git a/Entity/System/Inventory.cs b/Entity/System/Inventory.cs index 15ff057..863469a 100644 --- a/Entity/System/Inventory.cs +++ b/Entity/System/Inventory.cs @@ -41,6 +41,42 @@ namespace Milimoe.FunGame.Core.Entity /// public HashSet Items { get; } = []; + /// + /// 主战角色 + /// + public Character MainCharacter + { + get + { + if (_character != null) + { + return _character; + } + else if (Characters.Count > 0) + { + _character = Characters.First(); + return _character; + } + throw new GetInstanceException(); + } + set + { + _character = value; + } + } + + /// + /// 小队 + /// + public HashSet Squad { get; set; } = []; + + /// + /// 练级中的角色 + /// + public Dictionary Training { get; set; } = []; + + private Character? _character; + internal Inventory(User user) { User = user; diff --git a/Library/Common/JsonConverter/CharacterConverter.cs b/Library/Common/JsonConverter/CharacterConverter.cs index ae9c3f4..e4ef40c 100644 --- a/Library/Common/JsonConverter/CharacterConverter.cs +++ b/Library/Common/JsonConverter/CharacterConverter.cs @@ -56,6 +56,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter case nameof(Character.Level): result.Level = reader.GetInt32(); break; + case nameof(Character.LevelBreak): + result.LevelBreak = reader.GetInt32(); + break; case nameof(Character.EXP): result.EXP = reader.GetDouble(); break; @@ -176,8 +179,8 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter case nameof(Character.ExActionCoefficient): result.ExActionCoefficient = reader.GetDouble(); break; - case nameof(Character.AccelerationCoefficient): - result.AccelerationCoefficient = reader.GetDouble(); + case nameof(Character.ExAccelerationCoefficient): + result.ExAccelerationCoefficient = reader.GetDouble(); break; case nameof(Character.ExCDR): result.ExCDR = reader.GetDouble(); @@ -229,6 +232,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter writer.WriteNumber(nameof(Character.Promotion), value.Promotion); writer.WriteNumber(nameof(Character.PrimaryAttribute), (int)value.PrimaryAttribute); writer.WriteNumber(nameof(Character.Level), value.Level); + writer.WriteNumber(nameof(Character.LevelBreak), value.LevelBreak); writer.WriteNumber(nameof(Character.EXP), value.EXP); writer.WriteBoolean(nameof(Character.IsNeutral), value.IsNeutral); writer.WriteBoolean(nameof(Character.IsUnselectable), value.IsUnselectable); @@ -270,7 +274,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter writer.WriteNumber(nameof(Character.InitialSPD), value.InitialSPD); writer.WriteNumber(nameof(Character.ExSPD), value.ExSPD); writer.WriteNumber(nameof(Character.ExActionCoefficient), value.ExActionCoefficient); - writer.WriteNumber(nameof(Character.AccelerationCoefficient), value.AccelerationCoefficient); + writer.WriteNumber(nameof(Character.ExAccelerationCoefficient), value.ExAccelerationCoefficient); writer.WriteNumber(nameof(Character.ExCDR), value.ExCDR); writer.WriteNumber(nameof(Character.ATR), value.ATR); writer.WriteNumber(nameof(Character.ExCritRate), value.ExCritRate); diff --git a/Library/Common/JsonConverter/InventoryConverter.cs b/Library/Common/JsonConverter/InventoryConverter.cs index 0cdcc69..c343d4e 100644 --- a/Library/Common/JsonConverter/InventoryConverter.cs +++ b/Library/Common/JsonConverter/InventoryConverter.cs @@ -39,6 +39,27 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter result.Items.Add(item); } break; + case nameof(Inventory.MainCharacter): + Character? mc = NetworkUtility.JsonDeserialize(ref reader, options); + if (mc != null) + { + result.MainCharacter = mc; + } + break; + case nameof(Inventory.Squad): + HashSet squad = NetworkUtility.JsonDeserialize>(ref reader, options) ?? []; + foreach (Character character in squad) + { + result.Squad.Add(character); + } + break; + case nameof(Inventory.Training): + Dictionary training = NetworkUtility.JsonDeserialize>(ref reader, options) ?? []; + foreach (Character character in training.Keys) + { + result.Training.Add(character, training[character]); + } + break; } } @@ -53,6 +74,12 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter JsonSerializer.Serialize(writer, value.Characters, options); writer.WritePropertyName(nameof(Inventory.Items)); JsonSerializer.Serialize(writer, value.Items, options); + writer.WritePropertyName(nameof(Inventory.MainCharacter)); + JsonSerializer.Serialize(writer, value.MainCharacter, options); + writer.WritePropertyName(nameof(Inventory.Squad)); + JsonSerializer.Serialize(writer, value.Squad, options); + writer.WritePropertyName(nameof(Inventory.Training)); + JsonSerializer.Serialize(writer, value.Training, options); writer.WriteEndObject(); } diff --git a/Library/Common/JsonConverter/SkillConverter.cs b/Library/Common/JsonConverter/SkillConverter.cs index 3197324..c3b44e8 100644 --- a/Library/Common/JsonConverter/SkillConverter.cs +++ b/Library/Common/JsonConverter/SkillConverter.cs @@ -114,11 +114,11 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter writer.WritePropertyName(nameof(Skill.Guid)); JsonSerializer.Serialize(writer, value.Guid, options); } + writer.WriteNumber(nameof(Skill.SkillType), (int)value.SkillType); writer.WriteString(nameof(Skill.Description), value.Description); if (value.GeneralDescription.Length > 0) writer.WriteString(nameof(Skill.GeneralDescription), value.GeneralDescription); if (value.Slogan.Length > 0) writer.WriteString(nameof(Skill.Slogan), value.Slogan); if (value.Level > 0) writer.WriteNumber(nameof(Skill.Level), value.Level); - writer.WriteNumber(nameof(Skill.SkillType), (int)value.SkillType); if (value.CanSelectSelf) writer.WriteBoolean(nameof(Skill.CanSelectSelf), value.CanSelectSelf); if (!value.CanSelectEnemy) writer.WriteBoolean(nameof(Skill.CanSelectEnemy), value.CanSelectEnemy); if (value.CanSelectTeammate) writer.WriteBoolean(nameof(Skill.CanSelectTeammate), value.CanSelectTeammate); diff --git a/Library/Common/JsonConverter/UserConverter.cs b/Library/Common/JsonConverter/UserConverter.cs index fed1d8a..adbd1d6 100644 --- a/Library/Common/JsonConverter/UserConverter.cs +++ b/Library/Common/JsonConverter/UserConverter.cs @@ -75,6 +75,15 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter { result.Inventory.Items.Add(item); } + result.Inventory.MainCharacter = inventory.MainCharacter; + foreach (Character character in inventory.Squad) + { + result.Inventory.Squad.Add(character); + } + foreach (Character character in inventory.Training.Keys) + { + result.Inventory.Training[character] = inventory.Training[character]; + } break; } } diff --git a/Library/Constant/ConstantSet.cs b/Library/Constant/ConstantSet.cs index 5241663..4590273 100644 --- a/Library/Constant/ConstantSet.cs +++ b/Library/Constant/ConstantSet.cs @@ -510,6 +510,8 @@ namespace Milimoe.FunGame.Core.Library.Constant _ => QualityType.White }; } + + public static string[] QualityTypeNameArray => ["普通", "优秀", "稀有", "史诗", "传说", "神话", "不朽"]; } public class SkillSet diff --git a/Model/EquilibriumConstant.cs b/Model/EquilibriumConstant.cs index 935e210..38a2539 100644 --- a/Model/EquilibriumConstant.cs +++ b/Model/EquilibriumConstant.cs @@ -1,4 +1,4 @@ -namespace Milimoe.FunGame.Core.Model +namespace Milimoe.FunGame.Core.Model { /// /// 游戏平衡常数 @@ -48,7 +48,26 @@ /// /// 经验值上限 /// - public Dictionary EXPUpperLimit { get; set; } = []; + public Dictionary EXPUpperLimit { get; set; } = new() + { + { 1, 1000 }, { 2, 1000 }, { 3, 1000 }, { 4, 1000 }, { 5, 1000 }, { 6, 1000 }, { 7, 1000 }, { 8, 1000 }, { 9, 1000 }, + { 10, 1500 }, { 11, 1500 }, { 12, 1500 }, { 13, 1500 }, { 14, 1500 }, { 15, 1500 }, { 16, 1500 }, { 17, 1500 }, { 18, 1500 }, { 19, 1500 }, + { 20, 2000 }, { 21, 2000 }, { 22, 2000 }, { 23, 2000 }, { 24, 2000 }, { 25, 2000 }, { 26, 2000 }, { 27, 2000 }, { 28, 2000 }, { 29, 2000 }, + { 30, 3000 }, { 31, 3000 }, { 32, 3000 }, { 33, 3000 }, { 34, 3000 }, { 35, 3000 }, { 36, 3000 }, { 37, 3000 }, { 38, 3000 }, { 39, 3000 }, + { 40, 4000 }, { 41, 4000 }, { 42, 4000 }, { 43, 4000 }, { 44, 4000 }, { 45, 4000 }, { 46, 4000 }, { 47, 4000 }, { 48, 4000 }, { 49, 4000 }, + { 50, 5000 }, { 51, 5000 }, { 52, 5000 }, { 53, 5000 }, { 54, 5000 }, { 55, 5000 }, { 56, 5000 }, { 57, 5000 }, { 58, 5000 }, { 59, 5000 }, + { 60, 9999999999999 } + }; + + /// + /// 使用等级突破机制 + /// + public bool UseLevelBreak { get; set; } = true; + + /// + /// 使用等级突破机制后,角色处于这些等级时需要突破才能继续升级 + /// + public HashSet LevelBreakList { get; set; } = [10, 20, 30, 40, 50, 60]; /// /// 魔法最高等级 @@ -183,7 +202,7 @@ /// /// 每 1 点力量增加生命回复力 /// - public double STRtoHRFactor { get; set; } = 0.025; + public double STRtoHRFactor { get; set; } = 0.1; /// /// 每 1 点力量增加物理护甲 @@ -208,7 +227,7 @@ /// /// 每 1 点智力增加魔法回复力 /// - public double INTtoMRFactor { get; set; } = 0.01; + public double INTtoMRFactor { get; set; } = 0.04; /// /// 每 1 点智力减少魔法消耗 @@ -219,6 +238,11 @@ /// 每 1 点智力减少能量消耗 /// public double INTtoCastEPReduce { get; set; } = 0.00075; + + /// + /// 每 1 点智力增加加速系数 + /// + public double INTtoAccelerationCoefficientMultiplier { get; set; } = 0.00125; /// /// 每 1 点敏捷增加行动速度 @@ -233,6 +257,6 @@ /// /// 每 1 点敏捷增加闪避率 /// - public double AGItoEvadeRateMultiplier { get; set; } = 0.0025; + public double AGItoEvadeRateMultiplier { get; set; } = 0.00175; } }