添加平衡常数、减少 Round 函数的使用 (#96)

* 添加平衡常数类和减少舍入

* 优化单例表;为服务器插件提供单例 SQLHelper、MailSender 对象接口
This commit is contained in:
milimoe 2024-10-20 13:18:25 +08:00 committed by GitHub
parent 59253948cb
commit d74effcf5c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 590 additions and 191 deletions

View File

@ -1,4 +1,4 @@
using System.Collections;
using System.Collections.Concurrent;
namespace Milimoe.FunGame.Core.Api.Utility
{
@ -8,7 +8,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// </summary>
public class Singleton
{
private static readonly Hashtable SingletonTable = new();
private static readonly ConcurrentDictionary<string, object> SingletonTable = [];
/// <summary>
/// 查询目标的类是否已经有实例
@ -17,31 +17,25 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// <returns></returns>
public static bool IsExist(object single)
{
return SingletonTable.ContainsKey(single.GetType().ToString());
Type type = single.GetType();
string name = type.FullName ?? type.ToString();
return SingletonTable.ContainsKey(name);
}
/// <summary>
/// 将目标和目标的类添加至单例表
/// 将目标和目标的类添加至单例表,如果存在,将更新此类单例
/// </summary>
/// <param name="single">单例对象</param>
/// <param name="baseClass">存入基类</param>
/// <returns></returns>
/// <exception cref="SingletonAddException">添加单例到单例表时遇到错误</exception>
public static bool Add(object single)
public static void AddOrUpdate(object single, bool baseClass = false)
{
string type = single.GetType().ToString();
if (!SingletonTable.ContainsKey(type))
if (single != null)
{
try
{
SingletonTable.Add(type, single);
}
catch
{
throw new SingletonAddException();
}
return true;
Type? type = baseClass ? single.GetType().BaseType : single.GetType();
string name = type?.FullName ?? type?.ToString() ?? "";
if (name != "") SingletonTable.AddOrUpdate(name, single, (key, oldValue) => single);
}
return false;
}
/// <summary>
@ -51,16 +45,9 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// <returns></returns>
public static bool Remove(object single)
{
string type = single.GetType().ToString();
if (!SingletonTable.ContainsKey(type))
{
return false;
}
else
{
SingletonTable.Remove(type);
return true;
}
Type type = single.GetType();
string name = type.FullName ?? type.ToString();
return SingletonTable.TryRemove(name, out _);
}
/// <summary>
@ -68,24 +55,14 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// </summary>
/// <typeparam name="T">目标类</typeparam>
/// <returns></returns>
/// <exception cref="SingletonGetException">不能从单例表中获取到指定的单例</exception>
public static T? Get<T>()
{
T? single = default;
string type = typeof(T).ToString();
if (SingletonTable.ContainsKey(type))
string name = typeof(T).FullName ?? typeof(T).ToString();
if (SingletonTable.TryGetValue(name, out object? value) && value is T single)
{
try
{
single = (T?)SingletonTable[type];
}
catch
{
throw new SingletonGetException();
}
if (single != null) return single;
return single;
}
return single;
return default;
}
/// <summary>
@ -93,23 +70,14 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// </summary>
/// <param name="type">目标类</param>
/// <returns></returns>
/// <exception cref="SingletonGetException">不能从单例表中获取到指定的单例</exception>
public static object? Get(Type type)
{
object? single = default;
if (SingletonTable.ContainsKey(type))
string name = type.FullName ?? type.ToString();
if (SingletonTable.TryGetValue(name, out var value))
{
try
{
single = SingletonTable[type];
}
catch
{
throw new SingletonGetException();
}
if (single != null) return single;
return value;
}
return single;
return null;
}
}
}

View File

@ -69,31 +69,31 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
if (Promotion > 998)
if (Promotion > General.GameplayEquilibriumConstant.PromotionThresholdSUpperLimit)
{
return RoleRating.X;
}
else if (Promotion > 850 && Promotion <= 998)
else if (Promotion > General.GameplayEquilibriumConstant.PromotionThresholdAPlusUpperLimit && Promotion <= General.GameplayEquilibriumConstant.PromotionThresholdSUpperLimit)
{
return RoleRating.S;
}
else if (Promotion > 700 && Promotion <= 850)
else if (Promotion > General.GameplayEquilibriumConstant.PromotionThresholdAUpperLimit && Promotion <= General.GameplayEquilibriumConstant.PromotionThresholdAPlusUpperLimit)
{
return RoleRating.APlus;
}
else if (Promotion > 550 && Promotion <= 700)
else if (Promotion > General.GameplayEquilibriumConstant.PromotionThresholdBUpperLimit && Promotion <= General.GameplayEquilibriumConstant.PromotionThresholdAUpperLimit)
{
return RoleRating.A;
}
else if (Promotion > 400 && Promotion <= 550)
else if (Promotion > General.GameplayEquilibriumConstant.PromotionThresholdCUpperLimit && Promotion <= General.GameplayEquilibriumConstant.PromotionThresholdBUpperLimit)
{
return RoleRating.B;
}
else if (Promotion > 300 && Promotion <= 400)
else if (Promotion > General.GameplayEquilibriumConstant.PromotionThresholdDUpperLimit && Promotion <= General.GameplayEquilibriumConstant.PromotionThresholdCUpperLimit)
{
return RoleRating.C;
}
else if (Promotion > 200 && Promotion <= 300)
else if (Promotion > General.GameplayEquilibriumConstant.PromotionThresholdEUpperLimit && Promotion <= General.GameplayEquilibriumConstant.PromotionThresholdDUpperLimit)
{
return RoleRating.D;
}
@ -121,11 +121,11 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
return _Level > 0 ? _Level : 1;
return _Level >= 1 ? _Level : 1;
}
set
{
_Level = Math.Min(Math.Max(1, value), 60);
_Level = Math.Min(Math.Max(1, value), General.GameplayEquilibriumConstant.MaxLevel);
OnAttributeChanged();
Recovery();
}
@ -165,17 +165,17 @@ namespace Milimoe.FunGame.Core.Entity
/// 初始生命值 [ 初始设定 ]
/// </summary>
[InitRequired]
public double InitialHP { get; set; } = 60;
public double InitialHP { get; set; } = General.GameplayEquilibriumConstant.InitialHP;
/// <summary>
/// 基础生命值 [ 与初始设定和等级相关 ] [ 与基础力量相关 ]
/// </summary>
public double BaseHP => Calculation.Round2Digits(InitialHP + (Level - 1) * (17 + 0.68 * InitialHP) + BaseSTR * 9);
public double BaseHP => InitialHP + (Level - 1) * (General.GameplayEquilibriumConstant.LevelToHPFactor + General.GameplayEquilibriumConstant.HPGrowthFactor * InitialHP) + BaseSTR * General.GameplayEquilibriumConstant.STRtoHPFactor;
/// <summary>
/// 额外生命值 [ 与额外力量相关 ]
/// </summary>
public double ExHP => Calculation.Round2Digits(ExSTR * 9);
public double ExHP => ExSTR * General.GameplayEquilibriumConstant.STRtoHPFactor;
/// <summary>
/// 额外生命值2 [ 与技能和物品相关 ]
@ -185,7 +185,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 最大生命值 = 基础生命值 + 额外生命值 + 额外生命值2
/// </summary>
public double MaxHP => Calculation.Round2Digits(BaseHP + ExHP + ExHP2);
public double MaxHP => BaseHP + ExHP + ExHP2;
/// <summary>
/// 当前生命值 [ 战斗相关 ]
@ -198,7 +198,7 @@ namespace Milimoe.FunGame.Core.Entity
}
set
{
_HP = Calculation.Round2Digits(value);
_HP = value;
if (_HP > MaxHP) _HP = MaxHP;
else if (_HP < 0) _HP = 0;
}
@ -208,17 +208,17 @@ namespace Milimoe.FunGame.Core.Entity
/// 初始魔法值 [ 初始设定 ]
/// </summary>
[InitRequired]
public double InitialMP { get; set; } = 10;
public double InitialMP { get; set; } = General.GameplayEquilibriumConstant.InitialMP;
/// <summary>
/// 基础魔法值 [ 与初始设定和等级相关 ] [ 与基础智力相关 ]
/// </summary>
public double BaseMP => Calculation.Round2Digits(InitialMP + (Level - 1) * (1.5 + 0.14 * InitialMP) + BaseINT * 8);
public double BaseMP => InitialMP + (Level - 1) * (General.GameplayEquilibriumConstant.LevelToMPFactor + General.GameplayEquilibriumConstant.MPGrowthFactor * InitialMP) + BaseINT * General.GameplayEquilibriumConstant.INTtoMPFactor;
/// <summary>
/// 额外魔法值 [ 与额外智力相关 ]
/// </summary>
public double ExMP => Calculation.Round2Digits(ExINT * 8);
public double ExMP => ExINT * General.GameplayEquilibriumConstant.INTtoMPFactor;
/// <summary>
/// 额外魔法值2 [ 与技能和物品相关 ]
@ -228,7 +228,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 最大魔法值 = 基础魔法值 + 额外魔法值 + 额外魔法值2
/// </summary>
public double MaxMP => Calculation.Round2Digits(BaseMP + ExMP + ExMP2);
public double MaxMP => BaseMP + ExMP + ExMP2;
/// <summary>
/// 当前魔法值 [ 战斗相关 ]
@ -241,7 +241,7 @@ namespace Milimoe.FunGame.Core.Entity
}
set
{
_MP = Calculation.Round2Digits(value);
_MP = value;
if (_MP > MaxMP) _MP = MaxMP;
else if (_MP < 0) _MP = 0;
}
@ -254,12 +254,12 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
return _EP < 0 ? 0 : (_EP > 200 ? 200 : _EP);
return _EP < 0 ? 0 : (_EP > General.GameplayEquilibriumConstant.MaxEP ? General.GameplayEquilibriumConstant.MaxEP : _EP);
}
set
{
_EP = Calculation.Round2Digits(value);
if (_EP > 200) _EP = 200;
_EP = value;
if (_EP > General.GameplayEquilibriumConstant.MaxEP) _EP = General.GameplayEquilibriumConstant.MaxEP;
else if (_EP < 0) _EP = 0;
}
}
@ -268,7 +268,7 @@ namespace Milimoe.FunGame.Core.Entity
/// 初始攻击力 [ 初始设定 ]
/// </summary>
[InitRequired]
public double InitialATK { get; set; } = 15;
public double InitialATK { get; set; } = General.GameplayEquilibriumConstant.InitialATK;
/// <summary>
/// 基础攻击力 [ 与初始设定和等级相关 ] [ 与核心属性相关 ]
@ -277,18 +277,18 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
double atk = Calculation.Round2Digits(InitialATK + (Level - 1) * (0.95 + 0.045 * InitialATK));
double atk = InitialATK + (Level - 1) * (General.GameplayEquilibriumConstant.LevelToATKFactor + General.GameplayEquilibriumConstant.ATKGrowthFactor * InitialATK);
if (PrimaryAttribute == PrimaryAttribute.AGI)
{
return Calculation.Round2Digits(atk + BaseAGI);
return atk + BaseAGI;
}
else if (PrimaryAttribute == PrimaryAttribute.INT)
{
return Calculation.Round2Digits(atk + BaseINT);
return atk + BaseINT;
}
else // 默认STR
{
return Calculation.Round2Digits(atk + BaseSTR);
return atk + BaseSTR;
}
}
}
@ -323,23 +323,23 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 攻击力 = 基础攻击力 + 额外攻击力 + 额外攻击力2
/// </summary>
public double ATK => Calculation.Round2Digits(BaseATK + ExATK + ExATK2);
public double ATK => BaseATK + ExATK + ExATK2;
/// <summary>
/// 初始物理护甲 [ 初始设定 ]
/// </summary>
[InitRequired]
public double InitialDEF { get; set; } = 5;
public double InitialDEF { get; set; } = General.GameplayEquilibriumConstant.InitialDEF;
/// <summary>
/// 基础物理护甲 [ 与初始设定相关 ] [ 与基础力量相关 ]
/// </summary>
public double BaseDEF => Calculation.Round2Digits(InitialDEF + BaseSTR * 0.75);
public double BaseDEF => InitialDEF + BaseSTR * General.GameplayEquilibriumConstant.STRtoDEFFactor;
/// <summary>
/// 额外物理护甲 [ 与额外力量相关 ]
/// </summary>
public double ExDEF => Calculation.Round2Digits(ExSTR * 0.75);
public double ExDEF => ExSTR * General.GameplayEquilibriumConstant.STRtoDEFFactor;
/// <summary>
/// 额外物理护甲2 [ 与技能和物品相关 ]
@ -349,7 +349,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 物理护甲 = 基础物理护甲 + 额外物理护甲 + 额外物理护甲2
/// </summary>
public double DEF => Calculation.Round2Digits(BaseDEF + ExDEF + ExDEF2);
public double DEF => BaseDEF + ExDEF + ExDEF2;
/// <summary>
/// 物理伤害减免(%) = [ 与物理护甲相关 ] + 额外物理伤害减免(%)
@ -358,7 +358,7 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
double value = Calculation.Round4Digits((DEF / (DEF + 120)) + ExPDR);
double value = (DEF / (DEF + General.GameplayEquilibriumConstant.DEFReductionFactor)) + ExPDR;
return Calculation.PercentageCheck(value);
}
}
@ -384,7 +384,7 @@ namespace Milimoe.FunGame.Core.Entity
}
set
{
_PhysicalPenetration = Calculation.PercentageCheck(Calculation.Round4Digits(value));
_PhysicalPenetration = Calculation.PercentageCheck(value);
}
}
@ -399,7 +399,7 @@ namespace Milimoe.FunGame.Core.Entity
}
set
{
_MagicalPenetration = Calculation.PercentageCheck(Calculation.Round4Digits(value));
_MagicalPenetration = Calculation.PercentageCheck(value);
}
}
@ -412,7 +412,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 生命回复力 = [ 与初始设定相关 ] [ 与力量相关 ] + 额外生命回复力
/// </summary>
public double HR => Calculation.Round2Digits(InitialHR + STR * 0.25 + ExHR);
public double HR => InitialHR + STR * General.GameplayEquilibriumConstant.STRtoHRFactor + ExHR;
/// <summary>
/// 额外生命回复力 [ 与技能和物品相关 ]
@ -428,7 +428,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 魔法回复力 = [ 与初始设定相关 ] [ 与智力相关 ] + 额外魔法回复力
/// </summary>
public double MR => Calculation.Round2Digits(InitialMR + INT * 0.1 + ExMR);
public double MR => InitialMR + INT * General.GameplayEquilibriumConstant.INTtoMRFactor + ExMR;
/// <summary>
/// 额外魔法回复力 [ 与技能和物品相关 ]
@ -527,17 +527,17 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 基础力量 [ 与初始设定和等级相关 ]
/// </summary>
public double BaseSTR => Calculation.Round2Digits(InitialSTR + STRGrowth * (Level - 1));
public double BaseSTR => InitialSTR + STRGrowth * (Level - 1);
/// <summary>
/// 基础敏捷 [ 与初始设定和等级相关 ]
/// </summary>
public double BaseAGI => Calculation.Round2Digits(InitialAGI + AGIGrowth * (Level - 1));
public double BaseAGI => InitialAGI + AGIGrowth * (Level - 1);
/// <summary>
/// 基础智力 [ 与初始设定和等级相关 ]
/// </summary>
public double BaseINT => Calculation.Round2Digits(InitialINT + INTGrowth * (Level - 1));
public double BaseINT => InitialINT + INTGrowth * (Level - 1);
/// <summary>
/// 额外力量 [ 与技能和物品相关 ]
@ -557,17 +557,17 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 力量 = 基础力量 + 额外力量
/// </summary>
public double STR => Calculation.Round2Digits(BaseSTR + ExSTR);
public double STR => BaseSTR + ExSTR;
/// <summary>
/// 敏捷 = 基础敏捷 + 额外敏捷
/// </summary>
public double AGI => Calculation.Round2Digits(BaseAGI + ExAGI);
public double AGI => BaseAGI + ExAGI;
/// <summary>
/// 智力 = 基础智力 + 额外智力
/// </summary>
public double INT => Calculation.Round2Digits(BaseINT + ExINT);
public double INT => BaseINT + ExINT;
/// <summary>
/// 力量成长值(+BaseSTR/Lv)
@ -593,7 +593,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 行动速度 = [ 与初始设定相关 ][ 与敏捷相关 ] + 额外行动速度
/// </summary>
public double SPD => Calculation.Round2Digits(InitialSPD + AGI * 0.65 + ExSPD);
public double SPD => InitialSPD + AGI * General.GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
/// <summary>
/// 额外行动速度 [ 与技能和物品相关 ]
@ -607,7 +607,7 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
double value = Calculation.Round4Digits(SPD / 1500.00 + ExActionCoefficient);
double value = SPD / General.GameplayEquilibriumConstant.SPDUpperLimit + ExActionCoefficient;
return Calculation.PercentageCheck(value);
}
}
@ -629,7 +629,7 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
double value = Calculation.Round4Digits(INT * 0.0025 + ExCDR);
double value = INT * General.GameplayEquilibriumConstant.INTtoCDRMultiplier + ExCDR;
return Calculation.PercentageCheck(value);
}
}
@ -652,7 +652,7 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
double value = Calculation.Round4Digits(0.05 + AGI * 0.0025 + ExCritRate);
double value = General.GameplayEquilibriumConstant.CritRate + AGI * General.GameplayEquilibriumConstant.AGItoCritRateMultiplier + ExCritRate;
return Calculation.PercentageCheck(value);
}
}
@ -669,7 +669,7 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
return Calculation.Round4Digits(1.25 + STR * 0.00575 + ExCritDMG);
return General.GameplayEquilibriumConstant.CritDMG + STR * General.GameplayEquilibriumConstant.STRtoCritDMGMultiplier + ExCritDMG;
}
}
@ -685,7 +685,7 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
double value = Calculation.Round4Digits(0.05 + AGI * 0.0025 + ExEvadeRate);
double value = General.GameplayEquilibriumConstant.EvadeRate + AGI * General.GameplayEquilibriumConstant.AGItoEvadeRateMultiplier + ExEvadeRate;
return Calculation.PercentageCheck(value);
}
}
@ -783,8 +783,8 @@ namespace Milimoe.FunGame.Core.Entity
{
if (time > 0)
{
HP = Math.Min(MaxHP, Calculation.Round2Digits(HP + HR * time));
MP = Math.Min(MaxMP, Calculation.Round2Digits(MP + MR * time));
HP = Math.Min(MaxHP, HP + HR * time);
MP = Math.Min(MaxMP, MP + MR * time);
if (EP != -1) this.EP = EP;
}
}
@ -798,10 +798,10 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="pastMaxMP"></param>
public void Recovery(double pastHP, double pastMP, double pastMaxHP, double pastMaxMP)
{
double pHP = Calculation.Round4Digits(pastHP / pastMaxHP);
double pMP = Calculation.Round4Digits(pastMP / pastMaxMP);
HP = Calculation.Round2Digits(MaxHP * pHP);
MP = Calculation.Round2Digits(MaxMP * pMP);
double pHP = pastHP / pastMaxHP;
double pMP = pastMP / pastMaxMP;
HP = MaxHP * pHP;
MP = MaxMP * pMP;
}
/// <summary>
@ -1070,22 +1070,22 @@ namespace Milimoe.FunGame.Core.Entity
StringBuilder builder = new();
builder.AppendLine(ToStringWithLevel());
builder.AppendLine($"生命值:{HP} / {MaxHP}" + (ExHP + ExHP2 > 0 ? $" [{BaseHP} + {ExHP + ExHP2}]" : ""));
builder.AppendLine($"魔法值:{MP} / {MaxMP}" + (ExMP + ExMP2 > 0 ? $" [{BaseMP} + {ExMP + ExMP2}]" : ""));
builder.AppendLine($"能量值:{EP} / 200");
builder.AppendLine($"攻击力:{ATK}" + (ExATK + ExATK2 > 0 ? $" [{BaseATK} + {ExATK + ExATK2}]" : ""));
builder.AppendLine($"物理护甲:{DEF}" + (ExDEF + ExDEF2 > 0 ? $" [{BaseDEF} + {ExDEF + ExDEF2}]" : "") + $" ({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);
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (ExHP + ExHP2 > 0 ? $" [{BaseHP:0.##} + {(ExHP + ExHP2):0.##}]" : ""));
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (ExMP + ExMP2 > 0 ? $" [{BaseMP:0.##} + {(ExMP + ExMP2):0.##}]" : ""));
builder.AppendLine($"能量值:{EP:0.##} / {General.GameplayEquilibriumConstant.MaxEP:0.##}");
builder.AppendLine($"攻击力:{ATK:0.##}" + (ExATK + ExATK2 > 0 ? $" [{BaseATK:0.##} + {ExATK + ExATK2:0.##}]" : ""));
builder.AppendLine($"物理护甲:{DEF:0.##}" + (ExDEF + ExDEF2 > 0 ? $" [{BaseDEF:0.##} + {ExDEF + ExDEF2:0.##}]" : "") + $" ({PDR * 100:0.##}%)");
double mdf = (MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary +
MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9;
builder.AppendLine($"魔法抗性:{mdf * 100:0.##}%(平均)");
double exSPD = Calculation.Round2Digits(AGI * 0.65 + ExSPD);
builder.AppendLine($"行动速度:{SPD}" + (exSPD > 0 ? $" [{InitialSPD} + {exSPD}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
double exSPD = AGI * General.GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD > 0 ? $" [{InitialSPD:0.##} + {exSPD:0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}");
builder.AppendLine($"力量:{STR}" + (ExSTR > 0 ? $" [{BaseSTR} + {ExSTR}]" : ""));
builder.AppendLine($"敏捷:{AGI}" + (ExAGI > 0 ? $" [{BaseAGI} + {ExAGI}]" : ""));
builder.AppendLine($"智力:{INT}" + (ExINT > 0 ? $" [{BaseINT} + {ExINT}]" : ""));
builder.AppendLine($"生命回复:{HR}" + (ExHR > 0 ? $" [{Calculation.Round2Digits(InitialHR + STR * 0.25)} + {ExHR}]" : ""));
builder.AppendLine($"魔法回复:{MR}" + (ExMR > 0 ? $" [{Calculation.Round2Digits(InitialMR + INT * 0.1)} + {ExMR}]" : ""));
builder.AppendLine($"力量:{STR:0.##}" + (ExSTR > 0 ? $" [{BaseSTR:0.##} + {ExSTR:0.##}]" : ""));
builder.AppendLine($"敏捷:{AGI:0.##}" + (ExAGI > 0 ? $" [{BaseAGI:0.##} + {ExAGI:0.##}]" : ""));
builder.AppendLine($"智力:{INT:0.##}" + (ExINT > 0 ? $" [{BaseINT:0.##} + {ExINT:0.##}]" : ""));
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR > 0 ? $" [{InitialHR + STR * 0.25:0.##} + {ExHR:0.##}]" : ""));
builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR > 0 ? $" [{InitialMR + INT * 0.1:0.##} + {ExMR:0.##}]" : ""));
builder.AppendLine($"暴击率:{CritRate * 100:0.##}%");
builder.AppendLine($"暴击伤害:{CritDMG * 100:0.##}%");
builder.AppendLine($"闪避率:{EvadeRate * 100:0.##}%");
@ -1189,11 +1189,11 @@ namespace Milimoe.FunGame.Core.Entity
StringBuilder builder = new();
builder.AppendLine(ToStringWithLevel());
builder.AppendLine($"生命值:{HP} / {MaxHP}" + (ExHP + ExHP2 > 0 ? $" [{BaseHP} + {ExHP + ExHP2}]" : ""));
builder.AppendLine($"魔法值:{MP} / {MaxMP}" + (ExMP + ExMP2 > 0 ? $" [{BaseMP} + {ExMP + ExMP2}]" : ""));
builder.AppendLine($"能量值:{EP} / 200");
builder.AppendLine($"攻击力:{ATK}" + (ExATK + ExATK2 > 0 ? $" [{BaseATK} + {ExATK + ExATK2}]" : ""));
builder.AppendLine($"核心属性:{PrimaryAttributeValue}" + (ExPrimaryAttributeValue > 0 ? $" [{BasePrimaryAttributeValue} + {ExPrimaryAttributeValue}]" : ""));
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (ExHP + ExHP2 > 0 ? $" [{BaseHP:0.##} + {ExHP + ExHP2:0.##}]" : ""));
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (ExMP + ExMP2 > 0 ? $" [{BaseMP:0.##} + {ExMP + ExMP2:0.##}]" : ""));
builder.AppendLine($"能量值:{EP:0.##} / {General.GameplayEquilibriumConstant.MaxEP:0.##}");
builder.AppendLine($"攻击力:{ATK:0.##}" + (ExATK + ExATK2 > 0 ? $" [{BaseATK:0.##} + {ExATK + ExATK2:0.##}]" : ""));
builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}" + (ExPrimaryAttributeValue > 0 ? $" [{BasePrimaryAttributeValue:0.##} + {ExPrimaryAttributeValue:0.##}]" : ""));
if (CharacterState != CharacterState.Actionable)
{
@ -1210,7 +1210,7 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine("角色是不可选中的");
}
builder.AppendLine($"硬直时间:{hardnessTimes}");
builder.AppendLine($"硬直时间:{hardnessTimes:0.##}");
if (Effects.Count > 0)
{

View File

@ -1,8 +1,8 @@
using System.Text;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Common.Addon;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Model;
namespace Milimoe.FunGame.Core.Entity
{
@ -307,7 +307,7 @@ namespace Milimoe.FunGame.Core.Entity
StringBuilder builder = new();
builder.AppendLine($"【{Name}】");
builder.AppendLine($"{ItemSet.GetItemTypeName(ItemType)}" + (IsPurchasable && Price > 0 ? $" 售价:{Price}" : ""));
builder.AppendLine($"{ItemSet.GetItemTypeName(ItemType)}" + (IsPurchasable && Price > 0 ? $" 售价:{Price:0.##}" : ""));
if (RemainUseTimes > 0)
{

View File

@ -2,6 +2,7 @@
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Model;
namespace Milimoe.FunGame.Core.Entity
{
@ -423,7 +424,7 @@ namespace Milimoe.FunGame.Core.Entity
string isDurative = "";
if (Durative)
{
isDurative = "(剩余:" + RemainDuration + " 时间)";
isDurative = $"(剩余:{RemainDuration:0.##} 时间)";
}
else if (DurationTurn > 0)
{

View File

@ -2,6 +2,7 @@
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Model;
namespace Milimoe.FunGame.Core.Entity
{
@ -15,7 +16,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 普通攻击说明
/// </summary>
public string Description => $"对目标敌人造成 {Calculation.Round4Digits((1.0 + 0.05 * (Level - 1)) * 100)}% [ {Damage} ] 点{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "")}。";
public string Description => $"对目标敌人造成 {(1.0 + 0.05 * (Level - 1)) * 100:0.##}% [ {Damage:0.##} ] 点{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "")}。";
/// <summary>
/// 所属的角色
@ -25,7 +26,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 普通攻击的伤害
/// </summary>
public double Damage => Calculation.Round2Digits(Character.ATK * (1.0 + 0.05 * (Level - 1)));
public double Damage => Character.ATK * (1.0 + 0.05 * (Level - 1));
/// <summary>
/// 普通攻击等级
@ -38,7 +39,7 @@ namespace Milimoe.FunGame.Core.Entity
}
set
{
_Level = Math.Min(Math.Max(1, value), 8);
_Level = Math.Min(Math.Max(1, value), General.GameplayEquilibriumConstant.MaxNormalAttackLevel);
}
}

View File

@ -2,6 +2,7 @@
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Model;
namespace Milimoe.FunGame.Core.Entity
{
@ -36,7 +37,7 @@ namespace Milimoe.FunGame.Core.Entity
}
set
{
int max = IsSuperSkill ? 6 : (IsMagic ? 8 : 6);
int max = SkillSet.GetSkillMaxLevel(SkillType);
_Level = Math.Min(Math.Max(0, value), max);
OnLevelUp();
}
@ -79,7 +80,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 实际魔法消耗 [ 魔法 ]
/// </summary>
public double RealMPCost => Calculation.Round2Digits(Math.Max(0, MPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00125))));
public double RealMPCost => Math.Max(0, MPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00125)));
/// <summary>
/// 魔法消耗 [ 魔法 ]
@ -90,7 +91,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 实际吟唱时间 [ 魔法 ]
/// </summary>
public double RealCastTime => Calculation.Round2Digits(Math.Max(0, CastTime * (1 - Calculation.PercentageCheck(Character?.AccelerationCoefficient ?? 0))));
public double RealCastTime => Math.Max(0, CastTime * (1 - Calculation.PercentageCheck(Character?.AccelerationCoefficient ?? 0)));
/// <summary>
/// 吟唱时间 [ 魔法 ]
@ -101,7 +102,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 实际能量消耗 [ 战技 ]
/// </summary>
public double RealEPCost => IsSuperSkill ? EPCost : Calculation.Round2Digits(Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00075))));
public double RealEPCost => IsSuperSkill ? EPCost : Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00075)));
/// <summary>
/// 能量消耗 [ 战技 ]
@ -112,7 +113,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 实际冷却时间
/// </summary>
public double RealCD => Calculation.Round2Digits(Math.Max(0, CD * (1 - Character?.CDR ?? 0)));
public double RealCD => Math.Max(0, CD * (1 - Character?.CDR ?? 0));
/// <summary>
/// 冷却时间
@ -245,7 +246,7 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine("技能描述:" + Description);
if (CurrentCD > 0)
{
builder.AppendLine("正在冷却:剩余 " + CurrentCD + " 时间");
builder.AppendLine($"正在冷却:剩余 {CurrentCD:0.##} 时间");
}
if (!Enable)
{
@ -261,34 +262,34 @@ namespace Milimoe.FunGame.Core.Entity
{
if (RealMPCost > 0)
{
builder.AppendLine("魔法消耗:" + RealMPCost);
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}");
}
if (RealEPCost > 0)
{
builder.AppendLine("能量消耗:" + RealEPCost);
builder.AppendLine($"能量消耗:{RealEPCost:0.##}");
}
}
else
{
if (IsSuperSkill)
{
builder.AppendLine("能量消耗:" + RealEPCost);
builder.AppendLine($"能量消耗:{RealEPCost:0.##}");
}
else
{
if (IsMagic)
{
builder.AppendLine("魔法消耗:" + RealMPCost);
builder.AppendLine("吟唱时间:" + RealCastTime);
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}");
builder.AppendLine($"吟唱时间:{RealCastTime:0.##}");
}
else
{
builder.AppendLine("能量消耗:" + RealEPCost);
builder.AppendLine($"能量消耗:{RealEPCost::0.##}");
}
}
}
builder.AppendLine("冷却时间:" + RealCD);
builder.AppendLine("硬直时间:" + HardnessTime);
builder.AppendLine($"冷却时间:{RealCD:0.##}");
builder.AppendLine($"硬直时间:{HardnessTime:0.##}");
}
return builder.ToString();

View File

@ -4,7 +4,7 @@ using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Interface.Addons
{
public interface IGameModuleServer : IAddon, IAddonController<IGameModuleServer>, IGameModuleDepend
public interface IGameModuleServer : IAddon, IServerAddon, IAddonController<IGameModuleServer>, IGameModuleDepend
{
public bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> ServerModels, params object[] args);

View File

@ -0,0 +1,10 @@
using Milimoe.FunGame.Core.Api.Transmittal;
namespace Milimoe.FunGame.Core.Interface.Addons
{
public interface IServerAddon
{
public SQLHelper? SQLHelper { get; }
public MailSender? MailSender { get; }
}
}

View File

@ -0,0 +1,103 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Interface.Base
{
/// <summary>
/// 回合制游戏的基础队列
/// </summary>
public interface IGamingQueue
{
/// <summary>
/// 用于文本输出
/// </summary>
public Action<string> WriteLine { get; }
/// <summary>
/// 当前的行动顺序
/// </summary>
public List<Character> Queue { get; }
/// <summary>
/// 当前已死亡的角色顺序(第一个是最早死的)
/// </summary>
public List<Character> Eliminated { get; }
/// <summary>
/// 角色数据
/// </summary>
public Dictionary<Character, CharacterStatistics> CharacterStatistics { get; }
/// <summary>
/// 游戏运行的时间
/// </summary>
public double TotalTime { get; }
/// <summary>
/// 游戏运行的回合
/// 对于某角色而言,在其行动的回合叫 Turn而所有角色行动的回合都称之为 Round。
/// </summary>
public int TotalRound { get; }
/// <summary>
/// 显示队列信息
/// </summary>
public void DisplayQueue();
/// <summary>
/// 处理回合动作
/// </summary>
/// <param name="character"></param>
/// <returns></returns>
public bool ProcessTurn(Character character);
/// <summary>
/// 造成伤害
/// </summary>
/// <param name="actor"></param>
/// <param name="enemy"></param>
/// <param name="damage"></param>
/// <param name="isNormalAttack"></param>
/// <param name="isMagicDamage"></param>
/// <param name="magicType"></param>
/// <param name="damageResult"></param>
public void DamageToEnemy(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage = false, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal);
/// <summary>
/// 计算物理伤害
/// </summary>
/// <param name="actor"></param>
/// <param name="enemy"></param>
/// <param name="isNormalAttack"></param>
/// <param name="expectedDamage"></param>
/// <param name="finalDamage"></param>
/// <returns></returns>
public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage);
/// <summary>
/// 计算魔法伤害
/// </summary>
/// <param name="actor"></param>
/// <param name="enemy"></param>
/// <param name="isNormalAttack"></param>
/// <param name="magicType"></param>
/// <param name="expectedDamage"></param>
/// <param name="finalDamage"></param>
/// <returns></returns>
public DamageResult CalculateMagicalDamage(Character actor, Character enemy, bool isNormalAttack, MagicType magicType, double expectedDamage, out double finalDamage);
/// <summary>
/// 死亡结算
/// </summary>
/// <param name="killer"></param>
/// <param name="death"></param>
public void DeathCalculation(Character killer, Character death);
/// <summary>
/// 打断施法
/// </summary>
/// <param name="caster"></param>
/// <param name="interrupter"></param>
public void InterruptCasting(Character caster, Character interrupter);
}
}

View File

@ -1,3 +1,5 @@
using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Controller;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Addons;
@ -53,6 +55,16 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
/// </summary>
private BaseAddonController<IGameModuleServer>? _Controller;
/// <summary>
/// 全局数据库连接器
/// </summary>
public SQLHelper? SQLHelper => Singleton.Get<SQLHelper>();
/// <summary>
/// 全局邮件发送器
/// </summary>
public MailSender? MailSender => Singleton.Get<MailSender>();
/// <summary>
/// 启动服务器监听 请在此处实现服务器逻辑
/// </summary>

View File

@ -1,11 +1,13 @@
using Milimoe.FunGame.Core.Controller;
using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Controller;
using Milimoe.FunGame.Core.Interface;
using Milimoe.FunGame.Core.Interface.Addons;
using Milimoe.FunGame.Core.Library.Common.Event;
namespace Milimoe.FunGame.Core.Library.Common.Addon
{
public abstract class ServerPlugin : IPlugin
public abstract class ServerPlugin : IPlugin, IServerAddon
{
/// <summary>
/// 插件名称
@ -36,6 +38,16 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
set => _Controller = value;
}
/// <summary>
/// 全局数据库连接器
/// </summary>
public SQLHelper? SQLHelper => Singleton.Get<SQLHelper>();
/// <summary>
/// 全局邮件发送器
/// </summary>
public MailSender? MailSender => Singleton.Get<MailSender>();
/// <summary>
/// 控制器内部变量
/// </summary>

View File

@ -1,9 +1,11 @@
using Milimoe.FunGame.Core.Controller;
using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Controller;
using Milimoe.FunGame.Core.Interface.Addons;
namespace Milimoe.FunGame.Core.Library.Common.Addon
{
public abstract class WebAPIPlugin : IAddon, IAddonController<IAddon>
public abstract class WebAPIPlugin : IAddon, IServerAddon, IAddonController<IAddon>
{
/// <summary>
/// 插件名称
@ -39,6 +41,16 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
/// </summary>
private BaseAddonController<IAddon>? _Controller;
/// <summary>
/// 全局数据库连接器
/// </summary>
public SQLHelper? SQLHelper => Singleton.Get<SQLHelper>();
/// <summary>
/// 全局邮件发送器
/// </summary>
public MailSender? MailSender => Singleton.Get<MailSender>();
/// <summary>
/// 加载标记
/// </summary>

View File

@ -519,5 +519,17 @@ namespace Milimoe.FunGame.Core.Library.Constant
_ => SkillType.Passive,
};
}
public static int GetSkillMaxLevel(SkillType type)
{
return type switch
{
SkillType.Magic => General.GameplayEquilibriumConstant.MaxMagicLevel,
SkillType.Skill => General.GameplayEquilibriumConstant.MaxSkillLevel,
SkillType.SuperSkill => General.GameplayEquilibriumConstant.MaxSuperSkillLevel,
SkillType.Item => General.GameplayEquilibriumConstant.MaxSkillLevel,
_ => General.GameplayEquilibriumConstant.MaxPassiveSkillLevel
};
}
}
}

View File

@ -1,5 +1,6 @@
using System.Text;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Model;
namespace Milimoe.FunGame.Core.Library.Constant
{
@ -55,6 +56,11 @@ namespace Milimoe.FunGame.Core.Library.Constant
/// </summary>
public static DateTime DefaultTime => new(1970, 1, 1, 8, 0, 0);
/// <summary>
/// 游戏平衡常数
/// </summary>
public static EquilibriumConstant GameplayEquilibriumConstant { get; set; } = new();
#endregion
#region Const

View File

@ -1,12 +1,14 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Api.Utility
namespace Milimoe.FunGame.Core.Model
{
/// <summary>
/// 行动顺序表
/// </summary>
public class ActionQueue
public class ActionQueue : IGamingQueue
{
/// <summary>
/// 用于文本输出
@ -341,7 +343,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
// 技能列表
List<Skill> skills = [.. character.Skills.Where(s => s.Level > 0 && s.SkillType != SkillType.Passive && s.Enable && !s.IsInEffect && s.CurrentCD == 0 &&
(((s.SkillType == SkillType.SuperSkill || s.SkillType == SkillType.Skill) && s.RealEPCost <= character.EP) || (s.SkillType == SkillType.Magic && s.RealMPCost <= character.MP)))];
((s.SkillType == SkillType.SuperSkill || s.SkillType == SkillType.Skill) && s.RealEPCost <= character.EP || s.SkillType == SkillType.Magic && s.RealMPCost <= character.MP))];
// 物品列表
List<Item> items = [.. character.Items.Where(i => i.IsActive && i.Skills.Active != null && i.Enable && i.IsInGameItem &&
@ -510,7 +512,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
{
skill.OnSkillCasting(this, character);
character.EP = Calculation.Round2Digits(character.EP - cost);
character.EP -= cost;
baseTime = skill.HardnessTime;
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
@ -535,7 +537,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
// 判断是否能够释放技能
if (CheckCanCast(character, skill, out double cost))
{
character.MP = Calculation.Round2Digits(character.MP - cost);
character.MP -= cost;
baseTime = skill.HardnessTime;
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
@ -565,7 +567,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
// 判断是否能够释放技能
if (CheckCanCast(character, skill, out double cost))
{
character.EP = Calculation.Round2Digits(character.EP - cost);
character.EP -= cost;
baseTime = skill.HardnessTime;
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
@ -682,36 +684,36 @@ namespace Milimoe.FunGame.Core.Api.Utility
_stats[character].DamagePerSecond = Calculation.Round2Digits(_stats[character].TotalDamage / _stats[character].LiveTime);
// 回血回蓝
double recoveryHP = Calculation.Round2Digits(character.HR * timeToReduce);
double recoveryMP = Calculation.Round2Digits(character.MR * timeToReduce);
double needHP = Calculation.Round2Digits(character.MaxHP - character.HP);
double needMP = Calculation.Round2Digits(character.MaxMP - character.MP);
double recoveryHP = character.HR * timeToReduce;
double recoveryMP = character.MR * timeToReduce;
double needHP = character.MaxHP - character.HP;
double needMP = character.MaxMP - character.MP;
double reallyReHP = needHP >= recoveryHP ? recoveryHP : needHP;
double reallyReMP = needMP >= recoveryMP ? recoveryMP : needMP;
if (reallyReHP > 0 && reallyReMP > 0)
{
character.HP = Calculation.Round2Digits(character.HP + reallyReHP);
character.MP = Calculation.Round2Digits(character.MP + reallyReMP);
WriteLine("角色 " + character.NickName + " 回血:" + recoveryHP + " / " + "回蓝:" + recoveryMP);
character.HP += reallyReHP;
character.MP += reallyReMP;
WriteLine($"角色 {character.NickName} 回血:{recoveryHP:0.##} / 回蓝:{recoveryMP:0.##}");
}
else
{
if (reallyReHP > 0)
{
character.HP = Calculation.Round2Digits(character.HP + reallyReHP);
WriteLine("角色 " + character.NickName + " 回血:" + recoveryHP);
character.HP += reallyReHP;
WriteLine($"角色 {character.NickName} 回血:{recoveryHP:0.##}");
}
if (reallyReMP > 0)
{
character.MP = Calculation.Round2Digits(character.MP + reallyReMP);
WriteLine("角色 " + character.NickName + " 回蓝:" + recoveryMP);
character.MP += reallyReMP;
WriteLine($"角色 {character.NickName} 回蓝:{recoveryMP:0.##}");
}
}
// 减少所有技能的冷却时间
foreach (Skill skill in character.Skills)
{
skill.CurrentCD = Calculation.Round2Digits(skill.CurrentCD - timeToReduce);
skill.CurrentCD -= timeToReduce;
if (skill.CurrentCD <= 0)
{
skill.CurrentCD = 0;
@ -738,7 +740,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
if (effect.Durative)
{
effect.RemainDuration = Calculation.Round2Digits(effect.RemainDuration - timeToReduce);
effect.RemainDuration -= timeToReduce;
if (effect.RemainDuration <= 0)
{
effect.RemainDuration = 0;
@ -782,10 +784,10 @@ namespace Milimoe.FunGame.Core.Api.Utility
if (isMagicDamage)
{
string dmgType = CharacterSet.GetMagicDamageName(magicType);
WriteLine("[ " + enemy + $" ] 受到了 {damage} 点{dmgType}");
WriteLine("[ " + enemy + $" ] 受到了 {damage:0.##} 点{dmgType}");
}
else WriteLine("[ " + enemy + $" ] 受到了 {damage} 点物理伤害!");
enemy.HP = Calculation.Round2Digits(enemy.HP - damage);
else WriteLine("[ " + enemy + $" ] 受到了 {damage:0.##} 点物理伤害!");
enemy.HP -= damage;
// 统计伤害
CalculateCharacterDamageStatistics(actor, enemy, damage, isMagicDamage);
@ -820,7 +822,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
{
effect.AfterDeathCalculation(enemy, actor, _continuousKilling, _earnedMoney);
}
if (_queue.Remove(enemy) && (!_queue.Where(c => c != actor).Any()))
if (_queue.Remove(enemy) && !_queue.Where(c => c != actor).Any())
{
// 没有其他的角色了,游戏结束
EndGameInfo(actor);
@ -836,7 +838,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// <param name="max">最大获取量</param>
public static double GetEP(double a, double b, double max)
{
return Calculation.Round2Digits(Math.Min((a + Random.Shared.Next(30)) * b, max));
return Math.Min((a + Random.Shared.Next(30)) * b, max);
}
/// <summary>
@ -891,19 +893,19 @@ namespace Milimoe.FunGame.Core.Api.Utility
}
// 物理穿透后的护甲
double penetratedDEF = Calculation.Round2Digits((1 - actor.PhysicalPenetration) * enemy.DEF);
double penetratedDEF = (1 - actor.PhysicalPenetration) * enemy.DEF;
// 物理伤害减免
double physicalDamageReduction = Calculation.Round4Digits(penetratedDEF / (penetratedDEF + 120));
double physicalDamageReduction = penetratedDEF / (penetratedDEF + 120);
// 最终的物理伤害
finalDamage = Calculation.Round2Digits(expectedDamage * (1 - physicalDamageReduction));
finalDamage = expectedDamage * (1 - physicalDamageReduction);
// 暴击判定
dice = Random.Shared.NextDouble();
if (dice < actor.CritRate)
{
finalDamage = Calculation.Round2Digits(finalDamage * actor.CritDMG); // 暴击伤害倍率加成
finalDamage *= actor.CritDMG; // 暴击伤害倍率加成
WriteLine("暴击生效!!");
foreach (Effect effect in actor.Effects.Where(e => e.Level > 0).ToList())
{
@ -981,16 +983,16 @@ namespace Milimoe.FunGame.Core.Api.Utility
};
// 魔法穿透后的魔法抗性
MDF = Calculation.Round2Digits((1 - actor.MagicalPenetration) * MDF);
MDF = (1 - actor.MagicalPenetration) * MDF;
// 最终的魔法伤害
finalDamage = Calculation.Round2Digits(expectedDamage * (1 - MDF));
finalDamage = expectedDamage * (1 - MDF);
// 暴击判定
dice = Random.Shared.NextDouble();
if (dice < actor.CritRate)
{
finalDamage = Calculation.Round2Digits(finalDamage * actor.CritDMG); // 暴击伤害倍率加成
finalDamage *= actor.CritDMG; // 暴击伤害倍率加成
WriteLine("暴击生效!!");
foreach (Effect effect in actor.Effects.Where(e => e.Level > 0).ToList())
{
@ -1016,7 +1018,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
int money = Random.Shared.Next(250, 350);
Character[] assists = _assistDamage.Keys.Where(c => c != death && _assistDamage[c].GetPercentage(death) > 0.10).ToArray();
double totalDamagePercentage = Calculation.Round4Digits(_assistDamage.Keys.Where(assists.Contains).Select(c => _assistDamage[c].GetPercentage(death)).Sum());
double totalDamagePercentage = _assistDamage.Keys.Where(assists.Contains).Select(c => _assistDamage[c].GetPercentage(death)).Sum();
int totalMoney = Math.Min(Convert.ToInt32(money * totalDamagePercentage), 425); // 防止刷伤害设置金钱上限
// 按伤害比分配金钱 只有造成10%伤害以上才能参与
@ -1039,7 +1041,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
{
money += (coefficient + 1) * Random.Shared.Next(50, 100);
string termination = CharacterSet.GetContinuousKilling(coefficient);
string msg = $"[ {killer} ] 终结了 [ {death} ]{(termination != "" ? " " + termination : "")},获得 {money} 金钱";
string msg = $"[ {killer} ] 终结了 [ {death} ]{(termination != "" ? " " + termination : "")},获得 {money} {General.GameplayEquilibriumConstant.InGameCurrency}";
if (assists.Length > 1)
{
msg += "助攻:[ " + string.Join(" ] / [ ", assists.Where(c => c != killer)) + " ]";
@ -1048,7 +1050,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
}
else
{
string msg = $"[ {killer} ] 杀死了 [ {death} ],获得 {money} 金钱";
string msg = $"[ {killer} ] 杀死了 [ {death} ],获得 {money} {General.GameplayEquilibriumConstant.InGameCurrency}";
if (assists.Length > 1)
{
msg += "助攻:[ " + string.Join(" ] / [ ", assists.Where(c => c != killer)) + " ]";
@ -1094,7 +1096,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
for (int i = _eliminated.Count - 1; i >= 0; i--)
{
Character ec = _eliminated[i];
string topCharacter = ec.ToString() + (_continuousKilling.TryGetValue(ec, out int kills) && kills > 1 ? $" [ {CharacterSet.GetContinuousKilling(kills)} ]" : "") + (_earnedMoney.TryGetValue(ec, out int earned) ? $" [ 已赚取 {earned} 金钱 ]" : "");
string topCharacter = ec.ToString() + (_continuousKilling.TryGetValue(ec, out int kills) && kills > 1 ? $" [ {CharacterSet.GetContinuousKilling(kills)} ]" : "") + (_earnedMoney.TryGetValue(ec, out int earned) ? $" [ 已赚取 {earned} {General.GameplayEquilibriumConstant.InGameCurrency} ]" : "");
if (top == 1)
{
WriteLine("冠军:" + topCharacter);
@ -1300,6 +1302,11 @@ namespace Milimoe.FunGame.Core.Api.Utility
}
}
/// <summary>
/// 装备物品
/// </summary>
/// <param name="character"></param>
/// <param name="item"></param>
public void Equip(Character character, Item item)
{
if (character.Equip(item))
@ -1309,6 +1316,12 @@ namespace Milimoe.FunGame.Core.Api.Utility
}
}
/// <summary>
/// 装备物品到指定栏位
/// </summary>
/// <param name="character"></param>
/// <param name="type"></param>
/// <param name="item"></param>
public void Equip(Character character, EquipItemToSlot type, Item item)
{
if (character.Equip(item, type))
@ -1317,6 +1330,11 @@ namespace Milimoe.FunGame.Core.Api.Utility
}
}
/// <summary>
/// 取消装备
/// </summary>
/// <param name="character"></param>
/// <param name="type"></param>
public void UnEquip(Character character, EquipItemToSlot type)
{
Item? item = character.UnEquip(type);

View File

@ -0,0 +1,243 @@
namespace Milimoe.FunGame.Core.Model
{
/// <summary>
/// 游戏平衡常数
/// </summary>
public class EquilibriumConstant
{
/// <summary>
/// 游戏货币名称
/// </summary>
public string InGameCurrency { get; set; } = "金币";
/// <summary>
/// 晋升点数上限
/// </summary>
public int PromotionThresholdXUpperLimit { get; set; } = 999;
/// <summary>
/// 角色评级 S 的晋升点数上限
/// </summary>
public int PromotionThresholdSUpperLimit { get; set; } = 998;
/// <summary>
/// 角色评级 A+ 的晋升点数上限
/// </summary>
public int PromotionThresholdAPlusUpperLimit { get; set; } = 850;
/// <summary>
/// 角色评级 A 的晋升点数上限
/// </summary>
public int PromotionThresholdAUpperLimit { get; set; } = 700;
/// <summary>
/// 角色评级 B 的晋升点数上限
/// </summary>
public int PromotionThresholdBUpperLimit { get; set; } = 550;
/// <summary>
/// 角色评级 C 的晋升点数上限
/// </summary>
public int PromotionThresholdCUpperLimit { get; set; } = 400;
/// <summary>
/// 角色评级 D 的晋升点数上限
/// </summary>
public int PromotionThresholdDUpperLimit { get; set; } = 300;
/// <summary>
/// 角色评级 E 的晋升点数上限
/// </summary>
public int PromotionThresholdEUpperLimit { get; set; } = 200;
/// <summary>
/// 初始生命值
/// </summary>
public double InitialHP { get; set; } = 60;
/// <summary>
/// 初始魔法值
/// </summary>
public double InitialMP { get; set; } = 10;
/// <summary>
/// 角色最高等级
/// </summary>
public int MaxLevel { get; set; } = 60;
/// <summary>
/// 魔法最高等级
/// </summary>
public int MaxMagicLevel { get; set; } = 8;
/// <summary>
/// 战技最高等级
/// </summary>
public int MaxSkillLevel { get; set; } = 6;
/// <summary>
/// 爆发技最高等级
/// </summary>
public int MaxSuperSkillLevel { get; set; } = 6;
/// <summary>
/// 被动最高等级
/// </summary>
public int MaxPassiveSkillLevel { get; set; } = 6;
/// <summary>
/// 普通攻击最高等级
/// </summary>
public int MaxNormalAttackLevel { get; set; } = 8;
/// <summary>
/// 最大能量值
/// </summary>
public double MaxEP { get; set; } = 200;
/// <summary>
/// 初始攻击力
/// </summary>
public double InitialATK { get; set; } = 15;
/// <summary>
/// 初始物理护甲
/// </summary>
public double InitialDEF { get; set; } = 5;
/// <summary>
/// 初始力量
/// </summary>
public double InitialSTR { get; set; } = 0;
/// <summary>
/// 初始敏捷
/// </summary>
public double InitialAGI { get; set; } = 0;
/// <summary>
/// 初始智力
/// </summary>
public double InitialINT { get; set; } = 0;
/// <summary>
/// 力量成长
/// </summary>
public double STRGrowth { get; set; } = 0;
/// <summary>
/// 敏捷成长
/// </summary>
public double AGIGrowth { get; set; } = 0;
/// <summary>
/// 智力成长
/// </summary>
public double INTGrowth { get; set; } = 0;
/// <summary>
/// 初始暴击率
/// </summary>
public double CritRate { get; set; } = 0.05;
/// <summary>
/// 初始暴击伤害
/// </summary>
public double CritDMG { get; set; } = 1.25;
/// <summary>
/// 初始闪避率
/// </summary>
public double EvadeRate { get; set; } = 0.05;
/// <summary>
/// 每级增加基础生命值
/// </summary>
public double LevelToHPFactor { get; set; } = 17;
/// <summary>
/// 生命值增长因子
/// </summary>
public double HPGrowthFactor { get; set; } = 0.68;
/// <summary>
/// 每级增加基础魔法值
/// </summary>
public double LevelToMPFactor { get; set; } = 1.5;
/// <summary>
/// 魔法值增长因子
/// </summary>
public double MPGrowthFactor { get; set; } = 1.5;
/// <summary>
/// 每级增加基础攻击力
/// </summary>
public double LevelToATKFactor { get; set; } = 0.95;
/// <summary>
/// 攻击力增长因子
/// </summary>
public double ATKGrowthFactor { get; set; } = 0.045;
/// <summary>
/// 物理伤害减免因子
/// </summary>
public double DEFReductionFactor { get; set; } = 120;
/// <summary>
/// 行动速度上限
/// </summary>
public double SPDUpperLimit { get; set; } = 1500;
/// <summary>
/// 每 1 点力量增加生命值
/// </summary>
public double STRtoHPFactor { get; set; } = 9;
/// <summary>
/// 每 1 点力量增加生命回复力
/// </summary>
public double STRtoHRFactor { get; set; } = 0.25;
/// <summary>
/// 每 1 点力量增加物理护甲
/// </summary>
public double STRtoDEFFactor { get; set; } = 0.75;
/// <summary>
/// 每 1 点力量增加暴击伤害
/// </summary>
public double STRtoCritDMGMultiplier { get; set; } = 0.00575;
/// <summary>
/// 每 1 点智力增加魔法值
/// </summary>
public double INTtoMPFactor { get; set; } = 8;
/// <summary>
/// 每 1 点智力增加冷却缩减
/// </summary>
public double INTtoCDRMultiplier { get; set; } = 0.0025;
/// <summary>
/// 每 1 点智力增加魔法回复力
/// </summary>
public double INTtoMRFactor { get; set; } = 0.1;
/// <summary>
/// 每 1 点敏捷增加行动速度
/// </summary>
public double AGItoSPDMultiplier { get; set; } = 0.65;
/// <summary>
/// 每 1 点敏捷增加暴击率
/// </summary>
public double AGItoCritRateMultiplier { get; set; } = 0.0025;
/// <summary>
/// 每 1 点敏捷增加闪避率
/// </summary>
public double AGItoEvadeRateMultiplier { get; set; } = 0.0025;
}
}