添加使用物品、角色升级、角色突破 (#103)

* 添加升级、突破

* 添加经验值平衡常数

* 修复了传入 skillsDefined 时没有按定义的 args 构造特效;添加经验值相关的功能

* 添加复制等级数据

* 添加使用物品、角色升级、角色突破

* 修复升级和突破的BUG;添加智力提升加速系数;添加突破材料

* 修改物品相关

* 更新库存相关

---------

Co-authored-by: milimoe <mili@wrss.org>
This commit is contained in:
yeziuku 2024-12-24 00:07:54 +08:00 committed by GitHub
parent 4f9a7b3ca7
commit db1cad04bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 435 additions and 119 deletions

View File

@ -650,6 +650,31 @@ namespace Milimoe.FunGame.Core.Api.Utility
await Task.Delay(milliseconds);
}).OnCompleted(action);
}
/// <summary>
/// 添加任务计划,使用 <paramref name="time"/> 的时分秒。如果用 <see cref="TimeSpan"/>,请直接在 <see cref="TaskScheduler.Shared"/> 中添加
/// </summary>
/// <param name="name"></param>
/// <param name="time"></param>
/// <param name="action"></param>
public static void AddSchedulerTask(string name, DateTime time, Action action)
{
TaskScheduler.Shared.AddTask(name, new TimeSpan(time.Hour, time.Minute, time.Second), action);
}
/// <summary>
/// 添加循环任务。如果用 <see cref="TimeSpan"/>,请直接在 <see cref="TaskScheduler.Shared"/> 中添加
/// </summary>
/// <param name="name"></param>
/// <param name="seconds"></param>
/// <param name="action"></param>
/// <param name="hours"></param>
/// <param name="minutes"></param>
/// <param name="startNow"></param>
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

View File

@ -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
/// 在使用时仅需要调用 <see cref="Copy"/> 方法即可获得相同对象<para />
/// 不建议继承
/// </summary>
public class Character : BaseEntity, ICopyable<Character>
public class Character : BaseEntity
{
/// <summary>
/// 角色的姓
@ -135,6 +135,11 @@ namespace Milimoe.FunGame.Core.Entity
/// 经验值
/// </summary>
public double EXP { get; set; } = 0;
/// <summary>
/// 等级突破进度 [ 对应 <see cref="Model.EquilibriumConstant.LevelBreakList"/> 中的索引 ]
/// </summary>
public int LevelBreak { get; set; } = -1;
/// <summary>
/// 角色目前所处的状态 [ 战斗相关 ]
@ -688,9 +693,21 @@ namespace Milimoe.FunGame.Core.Entity
public double ExActionCoefficient { get; set; } = 0;
/// <summary>
/// 加速系数(%) [ 与技能和物品相关 ]
/// 加速系数(%) = [ 与智力相关 ] + 额外加速系数(%)
/// </summary>
public double AccelerationCoefficient { get; set; } = 0;
public double AccelerationCoefficient
{
get
{
double value = INT * General.GameplayEquilibriumConstant.INTtoAccelerationCoefficientMultiplier + ExActionCoefficient;
return Calculation.PercentageCheck(value);
}
}
/// <summary>
/// 额外加速系数(%) [ 与技能和物品相关 ]
/// </summary>
public double ExAccelerationCoefficient { get; set; } = 0;
/// <summary>
/// 冷却缩减(%) = [ 与智力相关 ] + 额外冷却缩减(%)
@ -1100,6 +1117,62 @@ namespace Milimoe.FunGame.Core.Entity
return result;
}
/// <summary>
/// 角色升级
/// </summary>
/// <param name="level"></param>
/// <param name="checkLevelBreak"></param>
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;
}
}
}
/// <summary>
/// 角色突破,允许继续升级
/// </summary>
public void OnLevelBreak()
{
if (General.GameplayEquilibriumConstant.UseLevelBreak)
{
// 检查角色突破进度
int[] levels = [.. General.GameplayEquilibriumConstant.LevelBreakList];
while (LevelBreak + 1 < levels.Length && Level >= levels[LevelBreak + 1])
{
LevelBreak++;
}
}
}
/// <summary>
/// 角色的属性发生变化,会影响特殊效果的计算
/// </summary>
@ -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
/// [ 推荐从模组中复制后使用对象 ]
/// </summary>
/// <returns></returns>
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);
}
}
}
}

View File

@ -95,17 +95,17 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 基于初始条件构建新的角色
/// <para>需要传入等级、技能、物品,可选构建装备</para>
/// <para>需要传入技能、物品,可选构建装备</para>
/// </summary>
/// <param name="level"></param>
/// <param name="skills"></param>
/// <param name="items"></param>
/// <param name="newItemGuid"></param>
/// <param name="equips"></param>
/// <param name="inventory"></param>
/// <param name="itemsDefined"></param>
/// <param name="skillsDefined"></param>
/// <returns>构建的新角色</returns>
public Character Build(int level, IEnumerable<Skill> skills, IEnumerable<Item> items, bool newItemGuid = true, EquipSlot? equips = null, IEnumerable<Item>? itemsDefined = null, IEnumerable<Skill>? skillsDefined = null)
public Character Build(IEnumerable<Skill> skills, IEnumerable<Item> items, bool newItemGuid = true, EquipSlot? equips = null, Inventory? inventory = null, IEnumerable<Item>? itemsDefined = null, IEnumerable<Skill>? 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
/// </summary>
/// <param name="reference"></param>
/// <param name="newItemGuid"></param>
/// <param name="copyLevel"></param>
/// <param name="inventory"></param>
/// <param name="itemsDefined">对于动态扩展的物品而言,传入已定义的物品表,不使用被复制物品的数据</param>
/// <param name="skillsDefined">对于动态扩展的技能而言,传入已定义的技能表,不使用被复制技能的数据</param>
/// <returns>构建的新角色</returns>
public static Character Build(Character reference, bool newItemGuid = true, IEnumerable<Item>? itemsDefined = null, IEnumerable<Skill>? skillsDefined = null)
public static Character Build(Character reference, bool newItemGuid = true, bool copyLevel = true, Inventory? inventory = null, IEnumerable<Item>? itemsDefined = null, IEnumerable<Skill>? 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;
}

View File

@ -143,10 +143,21 @@ namespace Milimoe.FunGame.Core.Entity
public DateTime NextTradableTime { get; set; } = DateTime.MinValue;
/// <summary>
/// 剩余使用次数(消耗品才会用到)
/// 剩余使用次数<para/>
/// 对于永久性主动物品而言,如果是 <see cref="IsInGameItem"/> 物品,可以不设置此值;反之,强烈建议设置为 1.
/// </summary>
public int RemainUseTimes { get; set; } = 0;
/// <summary>
/// 使用后减少使用次数
/// </summary>
public bool IsReduceTimesAfterUse { get; set; } = true;
/// <summary>
/// 用完后删除物品
/// </summary>
public bool IsRemoveAfterUse { get; set; } = true;
/// <summary>
/// 物品所属的角色(只有装备物品,才需要设置)
/// </summary>
@ -290,11 +301,17 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 局内使用物品触发 对某个角色使用
/// </summary>
public void UseItem(IGamingQueue queue, Character character, List<Character> enemys, List<Character> teammates)
/// <returns></returns>
public bool UseItem(IGamingQueue queue, Character character, List<Character> enemys, List<Character> 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<Character> 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;
}
/// <summary>
/// 局外(库存)使用物品触发
/// </summary>
public void UseItem()
/// <returns></returns>
public bool UseItem(Dictionary<string, object> 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);
}
}
}
/// <summary>
@ -321,20 +368,20 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="character"></param>
/// <param name="item"></param>
/// <param name="cancel"></param>
/// <param name="used"></param>
protected virtual void OnItemUsed(Character character, Item item, bool cancel, bool used)
/// <returns></returns>
protected virtual bool OnItemUsed(Character character, Item item, ref bool cancel)
{
return false;
}
/// <summary>
/// 当物品被玩家使用时
/// </summary>
/// <param name="user"></param>
/// <param name="item"></param>
protected virtual void OnItemUsed(User user, Item item)
/// <param name="args"></param>
/// <returns></returns>
protected virtual bool OnItemUsed(Dictionary<string, object> args)
{
return false;
}
/// <summary>
@ -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;

View File

@ -247,6 +247,16 @@ namespace Milimoe.FunGame.Core.Entity
public virtual void OnSkillCasted(Character caster, List<Character> targets, Dictionary<string, object> others)
{
}
/// <summary>
/// 对目标触发技能效果
/// </summary>
/// <param name="targets"></param>
/// <param name="others"></param>
public virtual void OnSkillCasted(List<Character> targets, Dictionary<string, object> others)
{
}
/// <summary>

View File

@ -357,6 +357,18 @@ namespace Milimoe.FunGame.Core.Entity
e.OnSkillCasted(caster, targets, Values);
}
}
/// <summary>
/// 对目标触发技能效果
/// </summary>
/// <param name="targets"></param>
public void OnSkillCasted(List<Character> targets)
{
foreach (Effect e in Effects)
{
e.OnSkillCasted(targets, Values);
}
}
/// <summary>
/// 被动技能,需要重写此方法,返回被动特效给角色 [ 此方法会在技能学习时触发 ]
@ -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<Skill>(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);

View File

@ -41,6 +41,42 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary>
public HashSet<Item> Items { get; } = [];
/// <summary>
/// 主战角色
/// </summary>
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;
}
}
/// <summary>
/// 小队
/// </summary>
public HashSet<Character> Squad { get; set; } = [];
/// <summary>
/// 练级中的角色
/// </summary>
public Dictionary<Character, DateTime> Training { get; set; } = [];
private Character? _character;
internal Inventory(User user)
{
User = user;

View File

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

View File

@ -39,6 +39,27 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
result.Items.Add(item);
}
break;
case nameof(Inventory.MainCharacter):
Character? mc = NetworkUtility.JsonDeserialize<Character>(ref reader, options);
if (mc != null)
{
result.MainCharacter = mc;
}
break;
case nameof(Inventory.Squad):
HashSet<Character> squad = NetworkUtility.JsonDeserialize<HashSet<Character>>(ref reader, options) ?? [];
foreach (Character character in squad)
{
result.Squad.Add(character);
}
break;
case nameof(Inventory.Training):
Dictionary<Character, DateTime> training = NetworkUtility.JsonDeserialize<Dictionary<Character, DateTime>>(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();
}

View File

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

View File

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

View File

@ -510,6 +510,8 @@ namespace Milimoe.FunGame.Core.Library.Constant
_ => QualityType.White
};
}
public static string[] QualityTypeNameArray => ["普通", "优秀", "稀有", "史诗", "传说", "神话", "不朽"];
}
public class SkillSet

View File

@ -1,4 +1,4 @@
namespace Milimoe.FunGame.Core.Model
namespace Milimoe.FunGame.Core.Model
{
/// <summary>
/// 游戏平衡常数
@ -48,7 +48,26 @@
/// <summary>
/// 经验值上限
/// </summary>
public Dictionary<int, double> EXPUpperLimit { get; set; } = [];
public Dictionary<int, double> 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 }
};
/// <summary>
/// 使用等级突破机制
/// </summary>
public bool UseLevelBreak { get; set; } = true;
/// <summary>
/// 使用等级突破机制后,角色处于这些等级时需要突破才能继续升级
/// </summary>
public HashSet<int> LevelBreakList { get; set; } = [10, 20, 30, 40, 50, 60];
/// <summary>
/// 魔法最高等级
@ -183,7 +202,7 @@
/// <summary>
/// 每 1 点力量增加生命回复力
/// </summary>
public double STRtoHRFactor { get; set; } = 0.025;
public double STRtoHRFactor { get; set; } = 0.1;
/// <summary>
/// 每 1 点力量增加物理护甲
@ -208,7 +227,7 @@
/// <summary>
/// 每 1 点智力增加魔法回复力
/// </summary>
public double INTtoMRFactor { get; set; } = 0.01;
public double INTtoMRFactor { get; set; } = 0.04;
/// <summary>
/// 每 1 点智力减少魔法消耗
@ -219,6 +238,11 @@
/// 每 1 点智力减少能量消耗
/// </summary>
public double INTtoCastEPReduce { get; set; } = 0.00075;
/// <summary>
/// 每 1 点智力增加加速系数
/// </summary>
public double INTtoAccelerationCoefficientMultiplier { get; set; } = 0.00125;
/// <summary>
/// 每 1 点敏捷增加行动速度
@ -233,6 +257,6 @@
/// <summary>
/// 每 1 点敏捷增加闪避率
/// </summary>
public double AGItoEvadeRateMultiplier { get; set; } = 0.0025;
public double AGItoEvadeRateMultiplier { get; set; } = 0.00175;
}
}