底层支持真实伤害 (#141)

This commit is contained in:
milimoe 2025-06-19 21:20:53 +08:00 committed by GitHub
parent a2fcbce157
commit 6bf3bb09a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 378 additions and 263 deletions

View File

@ -129,11 +129,15 @@ namespace Milimoe.FunGame.Core.Entity
} }
set set
{ {
int past = _Level;
_Level = Math.Min(Math.Max(1, value), GameplayEquilibriumConstant.MaxLevel); _Level = Math.Min(Math.Max(1, value), GameplayEquilibriumConstant.MaxLevel);
if (past != _Level)
{
OnAttributeChanged(); OnAttributeChanged();
Recovery(); Recovery();
} }
} }
}
/// <summary> /// <summary>
/// 经验值 /// 经验值
@ -900,8 +904,8 @@ namespace Milimoe.FunGame.Core.Entity
{ {
if (time > 0) if (time > 0)
{ {
HP = Math.Min(MaxHP, HP + HR * time); HP += HR * time;
MP = Math.Min(MaxMP, MP + MR * time); MP += MR * time;
if (EP != -1) this.EP = EP; if (EP != -1) this.EP = EP;
} }
} }
@ -914,12 +918,18 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="pastMaxHP"></param> /// <param name="pastMaxHP"></param>
/// <param name="pastMaxMP"></param> /// <param name="pastMaxMP"></param>
public void Recovery(double pastHP, double pastMP, double pastMaxHP, double pastMaxMP) public void Recovery(double pastHP, double pastMP, double pastMaxHP, double pastMaxMP)
{
if (pastHP > 0 && pastMaxHP > 0)
{ {
double pHP = pastHP / pastMaxHP; double pHP = pastHP / pastMaxHP;
double pMP = pastMP / pastMaxMP;
HP = MaxHP * pHP; HP = MaxHP * pHP;
}
if (pastMP > 0 && pastMaxMP > 0)
{
double pMP = pastMP / pastMaxMP;
MP = MaxMP * pMP; MP = MaxMP * pMP;
} }
}
/// <summary> /// <summary>
/// 为角色装备物品必须使用此方法而不是自己去给EquipSlot里的物品赋值<para/> /// 为角色装备物品必须使用此方法而不是自己去给EquipSlot里的物品赋值<para/>
@ -1147,6 +1157,32 @@ namespace Milimoe.FunGame.Core.Entity
return result; return result;
} }
/// <summary>
/// 设置角色等级,并默认完全回复状态
/// </summary>
/// <param name="level">新的等级</param>
/// <param name="recovery">false 为按百分比回复</param>
public void SetLevel(int level, bool recovery = true)
{
if (!recovery)
{
double pastHP = HP;
double pastMP = MP;
double pastMaxHP = MaxHP;
double pastMaxMP = MaxMP;
int pastLevel = Level;
Level = level;
if (pastLevel != Level)
{
Recovery(pastHP, pastMP, pastMaxHP, pastMaxMP);
}
}
else
{
Level = level;
}
}
/// <summary> /// <summary>
/// 角色升级 /// 角色升级
/// </summary> /// </summary>

View File

@ -218,9 +218,9 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="character"></param> /// <param name="character"></param>
/// <param name="enemy"></param> /// <param name="enemy"></param>
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="isMagicDamage"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
public virtual void AlterDamageTypeBeforeCalculation(Character character, Character enemy, ref bool isNormalAttack, ref bool isMagicDamage, ref MagicType magicType) public virtual void AlterDamageTypeBeforeCalculation(Character character, Character enemy, ref bool isNormalAttack, ref DamageType damageType, ref MagicType magicType)
{ {
} }
@ -232,11 +232,11 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="enemy"></param> /// <param name="enemy"></param>
/// <param name="damage"></param> /// <param name="damage"></param>
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="isMagicDamage"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="totalDamageBonus"></param> /// <param name="totalDamageBonus"></param>
/// <returns>返回伤害增减值</returns> /// <returns>返回伤害增减值</returns>
public virtual double AlterExpectedDamageBeforeCalculation(Character character, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, Dictionary<Effect, double> totalDamageBonus) public virtual double AlterExpectedDamageBeforeCalculation(Character character, Character enemy, double damage, bool isNormalAttack, DamageType damageType, MagicType magicType, Dictionary<Effect, double> totalDamageBonus)
{ {
return 0; return 0;
} }
@ -248,13 +248,13 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="enemy"></param> /// <param name="enemy"></param>
/// <param name="damage"></param> /// <param name="damage"></param>
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="isMagicDamage"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="damageResult"></param> /// <param name="damageResult"></param>
/// <param name="isEvaded"></param> /// <param name="isEvaded"></param>
/// <param name="totalDamageBonus"></param> /// <param name="totalDamageBonus"></param>
/// <returns>返回伤害增减值</returns> /// <returns>返回伤害增减值</returns>
public virtual double AlterActualDamageAfterCalculation(Character character, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, DamageResult damageResult, ref bool isEvaded, Dictionary<Effect, double> totalDamageBonus) public virtual double AlterActualDamageAfterCalculation(Character character, Character enemy, double damage, bool isNormalAttack, DamageType damageType, MagicType magicType, DamageResult damageResult, ref bool isEvaded, Dictionary<Effect, double> totalDamageBonus)
{ {
return 0; return 0;
} }
@ -335,7 +335,7 @@ namespace Milimoe.FunGame.Core.Entity
} }
/// <summary> /// <summary>
/// 对目标触发技能效果 /// 对目标触发技能效果(局外)
/// </summary> /// </summary>
/// <param name="user"></param> /// <param name="user"></param>
/// <param name="targets"></param> /// <param name="targets"></param>
@ -363,10 +363,10 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="damage"></param> /// <param name="damage"></param>
/// <param name="actualDamage"></param> /// <param name="actualDamage"></param>
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="isMagicDamage"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="damageResult"></param> /// <param name="damageResult"></param>
public virtual void AfterDamageCalculation(Character character, Character enemy, double damage, double actualDamage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, DamageResult damageResult) public virtual void AfterDamageCalculation(Character character, Character enemy, double damage, double actualDamage, bool isNormalAttack, DamageType damageType, MagicType magicType, DamageResult damageResult)
{ {
} }
@ -656,13 +656,13 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
/// <param name="character"></param> /// <param name="character"></param>
/// <param name="attacker"></param> /// <param name="attacker"></param>
/// <param name="isMagic"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="damage"></param> /// <param name="damage"></param>
/// <param name="damageReduce"></param> /// <param name="damageReduce"></param>
/// <param name="message"></param> /// <param name="message"></param>
/// <returns>返回 false 可以跳过护盾结算</returns> /// <returns>返回 false 可以跳过护盾结算</returns>
public virtual bool BeforeShieldCalculation(Character character, Character attacker, bool isMagic, MagicType magicType, double damage, ref double damageReduce, ref string message) public virtual bool BeforeShieldCalculation(Character character, Character attacker, DamageType damageType, MagicType magicType, double damage, ref double damageReduce, ref string message)
{ {
return true; return true;
} }
@ -672,11 +672,11 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
/// <param name="character"></param> /// <param name="character"></param>
/// <param name="attacker"></param> /// <param name="attacker"></param>
/// <param name="isMagic"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="damage"></param> /// <param name="damage"></param>
/// <param name="shieldType"></param> /// <param name="shieldType"></param>
public virtual void OnShieldNeutralizeDamage(Character character, Character attacker, bool isMagic, MagicType magicType, double damage, ShieldType shieldType) public virtual void OnShieldNeutralizeDamage(Character character, Character attacker, DamageType damageType, MagicType magicType, double damage, ShieldType shieldType)
{ {
} }
@ -726,11 +726,11 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="actor"></param> /// <param name="actor"></param>
/// <param name="enemy"></param> /// <param name="enemy"></param>
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="isMagic"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="damage"></param> /// <param name="damage"></param>
/// <returns>false免疫检定不通过</returns> /// <returns>false免疫检定不通过</returns>
public virtual bool OnDamageImmuneCheck(Character actor, Character enemy, bool isNormalAttack, bool isMagic, MagicType magicType, double damage) public virtual bool OnDamageImmuneCheck(Character actor, Character enemy, bool isNormalAttack, DamageType damageType, MagicType magicType, double damage)
{ {
return true; return true;
} }
@ -740,16 +740,21 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
/// <param name="actor"></param> /// <param name="actor"></param>
/// <param name="enemy"></param> /// <param name="enemy"></param>
/// <param name="isMagic"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="expectedDamage"></param> /// <param name="expectedDamage"></param>
/// <returns></returns> /// <returns></returns>
public DamageResult DamageToEnemy(Character actor, Character enemy, bool isMagic, MagicType magicType, double expectedDamage) public DamageResult DamageToEnemy(Character actor, Character enemy, DamageType damageType, MagicType magicType, double expectedDamage)
{ {
if (GamingQueue is null) return DamageResult.Evaded; if (GamingQueue is null) return DamageResult.Evaded;
int changeCount = 0; int changeCount = 0;
DamageResult result = !isMagic ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out double damage, ref changeCount) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage, ref changeCount); DamageResult result = DamageResult.Normal;
GamingQueue.DamageToEnemyAsync(actor, enemy, damage, false, isMagic, magicType, result); double damage = expectedDamage;
if (damageType != DamageType.True)
{
result = damageType == DamageType.Physical ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out damage, ref changeCount) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage, ref changeCount);
}
GamingQueue.DamageToEnemyAsync(actor, enemy, damage, false, damageType, magicType, result);
return result; return result;
} }

View File

@ -181,7 +181,7 @@ namespace Milimoe.FunGame.Core.Entity
double expected = Damage; double expected = Damage;
int changeCount = 0; int changeCount = 0;
DamageResult result = IsMagic ? queue.CalculateMagicalDamage(attacker, enemy, true, MagicType, expected, out double damage, ref changeCount) : queue.CalculatePhysicalDamage(attacker, enemy, true, expected, out damage, ref changeCount); DamageResult result = IsMagic ? queue.CalculateMagicalDamage(attacker, enemy, true, MagicType, expected, out double damage, ref changeCount) : queue.CalculatePhysicalDamage(attacker, enemy, true, expected, out damage, ref changeCount);
queue.DamageToEnemyAsync(attacker, enemy, damage, true, IsMagic, MagicType, result); queue.DamageToEnemyAsync(attacker, enemy, damage, true, IsMagic ? DamageType.Magical : DamageType.Physical, MagicType, result);
} }
} }
} }

View File

@ -5,19 +5,19 @@
public double TotalDamage { get; set; } = 0; public double TotalDamage { get; set; } = 0;
public double TotalPhysicalDamage { get; set; } = 0; public double TotalPhysicalDamage { get; set; } = 0;
public double TotalMagicDamage { get; set; } = 0; public double TotalMagicDamage { get; set; } = 0;
public double TotalRealDamage { get; set; } = 0; public double TotalTrueDamage { get; set; } = 0;
public double TotalTakenDamage { get; set; } = 0; public double TotalTakenDamage { get; set; } = 0;
public double TotalTakenPhysicalDamage { get; set; } = 0; public double TotalTakenPhysicalDamage { get; set; } = 0;
public double TotalTakenMagicDamage { get; set; } = 0; public double TotalTakenMagicDamage { get; set; } = 0;
public double TotalTakenRealDamage { get; set; } = 0; public double TotalTakenTrueDamage { get; set; } = 0;
public double AvgDamage { get; set; } = 0; public double AvgDamage { get; set; } = 0;
public double AvgPhysicalDamage { get; set; } = 0; public double AvgPhysicalDamage { get; set; } = 0;
public double AvgMagicDamage { get; set; } = 0; public double AvgMagicDamage { get; set; } = 0;
public double AvgRealDamage { get; set; } = 0; public double AvgTrueDamage { get; set; } = 0;
public double AvgTakenDamage { get; set; } = 0; public double AvgTakenDamage { get; set; } = 0;
public double AvgTakenPhysicalDamage { get; set; } = 0; public double AvgTakenPhysicalDamage { get; set; } = 0;
public double AvgTakenMagicDamage { get; set; } = 0; public double AvgTakenMagicDamage { get; set; } = 0;
public double AvgTakenRealDamage { get; set; } = 0; public double AvgTakenTrueDamage { get; set; } = 0;
public double TotalHeal { get; set; } = 0; public double TotalHeal { get; set; } = 0;
public double AvgHeal { get; set; } = 0; public double AvgHeal { get; set; } = 0;
public double TotalShield { get; set; } = 0; public double TotalShield { get; set; } = 0;

View File

@ -1,15 +1,15 @@
namespace Milimoe.FunGame.Core.Entity namespace Milimoe.FunGame.Core.Entity
{ {
public class GameStatistics public class GameStatistics(Room Room)
{ {
public long Id => Room.Id; public long Id => Room.Id;
public Room Room { get; } public Room Room { get; } = Room;
public DateTime RecordTime { get; set; } = DateTime.Now; public DateTime RecordTime { get; set; } = DateTime.Now;
public string Record { get; set; } = ""; public string Record { get; set; } = "";
public Dictionary<User, double> DamageStats { get; set; } = new(); public Dictionary<User, double> DamageStats { get; set; } = [];
public Dictionary<User, double> PhysicalDamageStats { get; } = new(); public Dictionary<User, double> PhysicalDamageStats { get; } = [];
public Dictionary<User, double> MagicDamageStats { get; } = new(); public Dictionary<User, double> MagicDamageStats { get; } = [];
public Dictionary<User, double> RealDamageStats { get; } = new(); public Dictionary<User, double> TrueDamageStats { get; } = [];
public double AvgDamageStats public double AvgDamageStats
{ {
get get
@ -46,30 +46,25 @@
return Math.Round(total / MagicDamageStats.Count, 2); return Math.Round(total / MagicDamageStats.Count, 2);
} }
} }
public double AvgRealDamageStats public double AvgTrueDamageStats
{ {
get get
{ {
double total = 0; double total = 0;
foreach (User user in RealDamageStats.Keys) foreach (User user in TrueDamageStats.Keys)
{ {
total += RealDamageStats[user]; total += TrueDamageStats[user];
} }
return Math.Round(total / RealDamageStats.Count, 2); return Math.Round(total / TrueDamageStats.Count, 2);
} }
} }
public Dictionary<User, double> KillStats { get; } = new(); public Dictionary<User, double> KillStats { get; } = [];
public Dictionary<User, Dictionary<User, int>> KillDetailStats { get; } = new(); // 子字典记录的是被击杀者以及被击杀次数 public Dictionary<User, Dictionary<User, int>> KillDetailStats { get; } = []; // 子字典记录的是被击杀者以及被击杀次数
public Dictionary<User, double> DeathStats { get; } = new(); public Dictionary<User, double> DeathStats { get; } = [];
public Dictionary<User, Dictionary<User, int>> DeathDetailStats { get; } = new(); // 子字典记录的是击杀者以及击杀次数 public Dictionary<User, Dictionary<User, int>> DeathDetailStats { get; } = []; // 子字典记录的是击杀者以及击杀次数
public Dictionary<User, long> AssistStats { get; } = new(); public Dictionary<User, long> AssistStats { get; } = [];
public Dictionary<User, double> RatingStats { get; } = new(); // 结算后的Rating public Dictionary<User, double> RatingStats { get; } = []; // 结算后的Rating
public Dictionary<User, double> EloStats { get; } = new(); // Elo分数变化(+/-) public Dictionary<User, double> EloStats { get; } = []; // Elo分数变化(+/-)
public Dictionary<User, string> RankStats { get; } = new(); // 结算后的Rank非比赛前 public Dictionary<User, string> RankStats { get; } = []; // 结算后的Rank非比赛前
public GameStatistics(Room Room)
{
this.Room = Room;
}
} }
} }

View File

@ -11,7 +11,7 @@ namespace Milimoe.FunGame.Core.Entity
public Dictionary<long, double> DamageStats { get; } = []; public Dictionary<long, double> DamageStats { get; } = [];
public Dictionary<long, double> PhysicalDamageStats { get; } = []; public Dictionary<long, double> PhysicalDamageStats { get; } = [];
public Dictionary<long, double> MagicDamageStats { get; } = []; public Dictionary<long, double> MagicDamageStats { get; } = [];
public Dictionary<long, double> RealDamageStats { get; } = []; public Dictionary<long, double> TrueDamageStats { get; } = [];
public Dictionary<long, double> AvgDamageStats public Dictionary<long, double> AvgDamageStats
{ {
get get
@ -66,7 +66,7 @@ namespace Milimoe.FunGame.Core.Entity
return avgdamage; return avgdamage;
} }
} }
public Dictionary<long, double> AvgRealDamageStats public Dictionary<long, double> AvgTrueDamageStats
{ {
get get
{ {
@ -75,9 +75,9 @@ namespace Milimoe.FunGame.Core.Entity
{ {
long plays = Plays[key]; long plays = Plays[key];
double total = 0; double total = 0;
if (RealDamageStats.ContainsKey(key)) if (TrueDamageStats.ContainsKey(key))
{ {
total = RealDamageStats.Values.Sum(); total = TrueDamageStats.Values.Sum();
} }
avgdamage.Add(key, Math.Round(total / plays, 2)); avgdamage.Add(key, Math.Round(total / plays, 2));
} }

View File

@ -79,10 +79,10 @@ namespace Milimoe.FunGame.Core.Interface.Base
/// <param name="enemy"></param> /// <param name="enemy"></param>
/// <param name="damage"></param> /// <param name="damage"></param>
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="isMagicDamage"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="damageResult"></param> /// <param name="damageResult"></param>
public Task DamageToEnemyAsync(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage = false, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal); public Task DamageToEnemyAsync(Character actor, Character enemy, double damage, bool isNormalAttack, DamageType damageType = DamageType.Physical, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal);
/// <summary> /// <summary>
/// 治疗一个目标 /// 治疗一个目标
@ -198,5 +198,15 @@ namespace Milimoe.FunGame.Core.Interface.Base
/// <param name="isPercentage">是否是百分比</param> /// <param name="isPercentage">是否是百分比</param>
/// <param name="isCheckProtected">是否使用插队保护机制</param> /// <param name="isCheckProtected">是否使用插队保护机制</param>
public void ChangeCharacterHardnessTime(Character character, double addValue, bool isPercentage, bool isCheckProtected); public void ChangeCharacterHardnessTime(Character character, double addValue, bool isPercentage, bool isCheckProtected);
/// <summary>
/// 计算角色的数据
/// </summary>
/// <param name="character"></param>
/// <param name="characterTaken"></param>
/// <param name="damage"></param>
/// <param name="damageType"></param>
/// <param name="takenDamage"></param>
public void CalculateCharacterDamageStatistics(Character character, Character characterTaken, double damage, DamageType damageType, double takenDamage = -1);
} }
} }

View File

@ -455,6 +455,16 @@ namespace Milimoe.FunGame.Core.Library.Constant
_ => "★" _ => "★"
}; };
} }
public static string GetDamageTypeName(DamageType damageType, MagicType magicType = MagicType.None)
{
return damageType switch
{
DamageType.Magical => GetMagicDamageName(magicType),
DamageType.True => "真实伤害",
_ => "物理伤害"
};
}
} }
public class ItemSet public class ItemSet

View File

@ -312,12 +312,12 @@ namespace Milimoe.FunGame.Core.Library.Constant
Poison, Poison,
/// <summary> /// <summary>
/// 燃烧,目标受到火焰伤害,持续一段时间 /// 燃烧,目标受到伤害,持续一段时间
/// </summary> /// </summary>
Burn, Burn,
/// <summary> /// <summary>
/// 流血,目标持续受到物理伤害 /// 流血,目标持续受到伤害
/// </summary> /// </summary>
Bleed, Bleed,
@ -1039,4 +1039,11 @@ namespace Milimoe.FunGame.Core.Library.Constant
Mix, Mix,
Effect Effect
} }
public enum DamageType
{
Physical,
Magical,
True
}
} }

View File

@ -226,6 +226,11 @@ namespace Milimoe.FunGame.Core.Model
/// </summary> /// </summary>
protected bool _isGameEnd = false; protected bool _isGameEnd = false;
/// <summary>
/// 是否在回合内
/// </summary>
protected bool _isInRound = false;
#endregion #endregion
#region #region
@ -537,7 +542,8 @@ namespace Milimoe.FunGame.Core.Model
TotalTime = Calculation.Round2Digits(TotalTime + timeToReduce); TotalTime = Calculation.Round2Digits(TotalTime + timeToReduce);
WriteLine("时间流逝:" + timeToReduce); WriteLine("时间流逝:" + timeToReduce);
foreach (Character character in _queue) Character[] characters = [.. _queue];
foreach (Character character in characters)
{ {
// 减少所有角色的硬直时间 // 减少所有角色的硬直时间
_hardnessTimes[character] = Calculation.Round2Digits(_hardnessTimes[character] - timeToReduce); _hardnessTimes[character] = Calculation.Round2Digits(_hardnessTimes[character] - timeToReduce);
@ -635,15 +641,17 @@ namespace Milimoe.FunGame.Core.Model
if (effect.Durative) if (effect.Durative)
{ {
effect.RemainDuration -= timeToReduce; if (effect.RemainDuration < timeToReduce)
if (effect.RemainDuration <= 0)
{ {
// 移除特效前也完成剩余时间内的效果
effect.OnTimeElapsed(character, effect.RemainDuration);
effect.RemainDuration = 0; effect.RemainDuration = 0;
character.Effects.Remove(effect); character.Effects.Remove(effect);
effect.OnEffectLost(character); effect.OnEffectLost(character);
} }
else else
{ {
effect.RemainDuration -= timeToReduce;
effect.OnTimeElapsed(character, timeToReduce); effect.OnTimeElapsed(character, timeToReduce);
} }
} }
@ -688,11 +696,13 @@ namespace Milimoe.FunGame.Core.Model
/// <returns>是否结束游戏</returns> /// <returns>是否结束游戏</returns>
public async Task<bool> ProcessTurnAsync(Character character) public async Task<bool> ProcessTurnAsync(Character character)
{ {
_isInRound = true;
LastRound.Actor = character; LastRound.Actor = character;
_roundDeaths.Clear(); _roundDeaths.Clear();
if (!await BeforeTurnAsync(character)) if (!await BeforeTurnAsync(character))
{ {
_isInRound = false;
return _isGameEnd; return _isGameEnd;
} }
@ -723,6 +733,7 @@ namespace Milimoe.FunGame.Core.Model
// 如果事件全程接管回合操作,需要注意触发特效 // 如果事件全程接管回合操作,需要注意触发特效
if (!await OnTurnStartAsync(character, enemys, teammates, skills, items)) if (!await OnTurnStartAsync(character, enemys, teammates, skills, items))
{ {
_isInRound = false;
return _isGameEnd; return _isGameEnd;
} }
@ -806,7 +817,9 @@ namespace Milimoe.FunGame.Core.Model
} }
else if (character.CharacterState == CharacterState.ActionRestricted) else if (character.CharacterState == CharacterState.ActionRestricted)
{ {
// 行动受限,只能使用特殊物品 // 行动受限,只能使用消耗品
items = [.. items.Where(i => i.ItemType == ItemType.Consumable)];
canUseItem = items.Count > 0;
if (canUseItem) if (canUseItem)
{ {
pCastSkill = 0; pCastSkill = 0;
@ -1131,7 +1144,7 @@ namespace Milimoe.FunGame.Core.Model
{ {
decided = true; decided = true;
LastRound.Item = item; LastRound.Item = item;
baseTime = skill.RealHardnessTime; baseTime = skill.RealHardnessTime > 0 ? skill.RealHardnessTime : 5;
effects = [.. character.Effects.Where(e => e.IsInEffect)]; effects = [.. character.Effects.Where(e => e.IsInEffect)];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
@ -1148,7 +1161,7 @@ namespace Milimoe.FunGame.Core.Model
character.CharacterState == CharacterState.BattleRestricted) character.CharacterState == CharacterState.BattleRestricted)
{ {
baseTime += 5; baseTime += 5;
WriteLine($"角色 [ {character} ] 状态为:{CharacterSet.GetCharacterState(character.CharacterState)},放弃行动将额外获得 5 {GameplayEquilibriumConstant.InGameTime}硬直时间!"); WriteLine($"[ {character} ] {CharacterSet.GetCharacterState(character.CharacterState)},放弃行动将额外获得 5 {GameplayEquilibriumConstant.InGameTime}硬直时间!");
} }
decided = true; decided = true;
WriteLine($"[ {character} ] 结束了回合!"); WriteLine($"[ {character} ] 结束了回合!");
@ -1185,6 +1198,7 @@ namespace Milimoe.FunGame.Core.Model
await AfterTurnAsync(character); await AfterTurnAsync(character);
_isInRound = false;
return _isGameEnd; return _isGameEnd;
} }
@ -1242,6 +1256,7 @@ namespace Milimoe.FunGame.Core.Model
await AfterTurnAsync(character); await AfterTurnAsync(character);
WriteLine(""); WriteLine("");
_isInRound = false;
return _isGameEnd; return _isGameEnd;
} }
@ -1348,10 +1363,10 @@ namespace Milimoe.FunGame.Core.Model
/// <param name="enemy"></param> /// <param name="enemy"></param>
/// <param name="damage"></param> /// <param name="damage"></param>
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="isMagicDamage"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="damageResult"></param> /// <param name="damageResult"></param>
public async Task DamageToEnemyAsync(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage = false, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal) public async Task DamageToEnemyAsync(Character actor, Character enemy, double damage, bool isNormalAttack, DamageType damageType = DamageType.Physical, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal)
{ {
// 如果敌人在结算伤害之前就已经死亡,将不会继续下去 // 如果敌人在结算伤害之前就已经死亡,将不会继续下去
if (enemy.HP <= 0) if (enemy.HP <= 0)
@ -1368,11 +1383,16 @@ namespace Milimoe.FunGame.Core.Model
List<Character> characters = [actor, enemy]; List<Character> characters = [actor, enemy];
bool isEvaded = damageResult == DamageResult.Evaded; bool isEvaded = damageResult == DamageResult.Evaded;
List<Effect> effects = [];
// 真实伤害跳过伤害加成区间
if (damageType != DamageType.True)
{
Dictionary<Effect, double> totalDamageBonus = []; Dictionary<Effect, double> totalDamageBonus = [];
List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
double damageBonus = effect.AlterActualDamageAfterCalculation(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, damageResult, ref isEvaded, totalDamageBonus); double damageBonus = effect.AlterActualDamageAfterCalculation(actor, enemy, damage, isNormalAttack, damageType, magicType, damageResult, ref isEvaded, totalDamageBonus);
totalDamageBonus[effect] = damageBonus; totalDamageBonus[effect] = damageBonus;
if (isEvaded) if (isEvaded)
{ {
@ -1380,16 +1400,21 @@ namespace Milimoe.FunGame.Core.Model
} }
} }
damage += totalDamageBonus.Sum(kv => kv.Value); damage += totalDamageBonus.Sum(kv => kv.Value);
}
double actualDamage = damage; double actualDamage = damage;
// 闪避了就没伤害了 // 闪避了就没伤害了
if (damageResult != DamageResult.Evaded) if (damageResult != DamageResult.Evaded)
{ {
// 开始计算伤害免疫 // 开始计算伤害免疫
bool isImmune = false;
// 真实伤害跳过免疫
if (damageType != DamageType.True)
{
// 此变量为是否无视免疫 // 此变量为是否无视免疫
bool ignore = false; bool ignore = false;
// 技能免疫无法免疫普通攻击,但是魔法免疫和物理免疫可以 // 技能免疫无法免疫普通攻击,但是魔法免疫和物理免疫可以
bool isImmune = (isNormalAttack && (enemy.ImmuneType == ImmuneType.All || enemy.ImmuneType == ImmuneType.Physical || enemy.ImmuneType == ImmuneType.Magical)) || isImmune = (isNormalAttack && (enemy.ImmuneType == ImmuneType.All || enemy.ImmuneType == ImmuneType.Physical || enemy.ImmuneType == ImmuneType.Magical)) ||
(!isNormalAttack && (enemy.ImmuneType == ImmuneType.All || enemy.ImmuneType == ImmuneType.Physical || enemy.ImmuneType == ImmuneType.Magical || enemy.ImmuneType == ImmuneType.Skilled)); (!isNormalAttack && (enemy.ImmuneType == ImmuneType.All || enemy.ImmuneType == ImmuneType.Physical || enemy.ImmuneType == ImmuneType.Magical || enemy.ImmuneType == ImmuneType.Skilled));
if (isImmune) if (isImmune)
{ {
@ -1399,16 +1424,16 @@ namespace Milimoe.FunGame.Core.Model
if (isNormalAttack) if (isNormalAttack)
{ {
if (actor.NormalAttack.IgnoreImmune == ImmuneType.All || if (actor.NormalAttack.IgnoreImmune == ImmuneType.All ||
(!isMagicDamage && actor.NormalAttack.IgnoreImmune == ImmuneType.Physical) || (damageType == DamageType.Physical && actor.NormalAttack.IgnoreImmune == ImmuneType.Physical) ||
(isMagicDamage && actor.NormalAttack.IgnoreImmune == ImmuneType.Magical) || (damageType == DamageType.Magical && actor.NormalAttack.IgnoreImmune == ImmuneType.Magical) ||
!effect.OnDamageImmuneCheck(actor, enemy, isNormalAttack, isMagicDamage, magicType, damage)) !effect.OnDamageImmuneCheck(actor, enemy, isNormalAttack, damageType, magicType, damage))
{ {
ignore = true; ignore = true;
} }
} }
else else
{ {
if (!effect.OnDamageImmuneCheck(actor, enemy, isNormalAttack, isMagicDamage, magicType, damage)) if (!effect.OnDamageImmuneCheck(actor, enemy, isNormalAttack, damageType, magicType, damage))
{ {
ignore = true; ignore = true;
} }
@ -1430,20 +1455,26 @@ namespace Milimoe.FunGame.Core.Model
WriteLine($"[ {enemy} ] 免疫了此伤害!"); WriteLine($"[ {enemy} ] 免疫了此伤害!");
actualDamage = 0; actualDamage = 0;
} }
else }
// 继续计算伤害
if (!isImmune)
{ {
if (damage < 0) damage = 0; if (damage < 0) damage = 0;
string damageType = isMagicDamage ? CharacterSet.GetMagicDamageName(magicType) : "物理伤害"; string damageTypeString = CharacterSet.GetDamageTypeName(damageType, magicType);
string shieldMsg = "";
// 真实伤害跳过护盾结算
if (damageType != DamageType.True)
{
// 在护盾结算前,特效可以有自己的逻辑 // 在护盾结算前,特效可以有自己的逻辑
bool change = false; bool change = false;
string shieldMsg = "";
effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
double damageReduce = 0; double damageReduce = 0;
if (!effect.BeforeShieldCalculation(enemy, actor, isMagicDamage, magicType, damage, ref damageReduce, ref shieldMsg)) if (!effect.BeforeShieldCalculation(enemy, actor, damageType, magicType, damage, ref damageReduce, ref shieldMsg))
{ {
change = true; change = true;
} }
@ -1464,18 +1495,18 @@ namespace Milimoe.FunGame.Core.Model
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
ShieldOfEffect soe = enemy.Shield.ShieldOfEffects[effect]; ShieldOfEffect soe = enemy.Shield.ShieldOfEffects[effect];
if (soe.IsMagic == isMagicDamage && (!isMagicDamage || soe.MagicType == magicType) && soe.Shield > 0) if (soe.IsMagic == (damageType == DamageType.Magical) && (damageType == DamageType.Physical || soe.MagicType == magicType) && soe.Shield > 0)
{ {
double effectShield = soe.Shield; double effectShield = soe.Shield;
// 判断护盾余额 // 判断护盾余额
if (enemy.Shield.CalculateShieldOfEffect(effect, remain) > 0) if (enemy.Shield.CalculateShieldOfEffect(effect, remain) > 0)
{ {
WriteLine($"[ {enemy} ] 发动了 [ {effect.Skill.Name} ] 的护盾效果,抵消了 {remain:0.##} 点{damageType}"); WriteLine($"[ {enemy} ] 发动了 [ {effect.Skill.Name} ] 的护盾效果,抵消了 {remain:0.##} 点{damageTypeString}");
remain = 0; remain = 0;
} }
else else
{ {
WriteLine($"[ {enemy} ] 发动了 [ {effect.Skill.Name} ] 的护盾效果,抵消了 {effectShield:0.##} 点{damageType},护盾已破碎!"); WriteLine($"[ {enemy} ] 发动了 [ {effect.Skill.Name} ] 的护盾效果,抵消了 {effectShield:0.##} 点{damageTypeString},护盾已破碎!");
remain -= effectShield; remain -= effectShield;
Effect[] effects2 = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; Effect[] effects2 = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
foreach (Effect effect2 in effects2) foreach (Effect effect2 in effects2)
@ -1492,7 +1523,7 @@ namespace Milimoe.FunGame.Core.Model
Effect[] effects2 = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; Effect[] effects2 = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
foreach (Effect effect2 in effects2) foreach (Effect effect2 in effects2)
{ {
effect2.OnShieldNeutralizeDamage(enemy, actor, isMagicDamage, magicType, damage, ShieldType.Effect); effect2.OnShieldNeutralizeDamage(enemy, actor, damageType, magicType, damage, ShieldType.Effect);
} }
break; break;
} }
@ -1503,6 +1534,7 @@ namespace Milimoe.FunGame.Core.Model
if (remain > 0) if (remain > 0)
{ {
// 检查指定类型的护盾值 // 检查指定类型的护盾值
bool isMagicDamage = damageType == DamageType.Magical;
double shield = enemy.Shield[isMagicDamage, magicType]; double shield = enemy.Shield[isMagicDamage, magicType];
if (shield > 0) if (shield > 0)
{ {
@ -1511,18 +1543,18 @@ namespace Milimoe.FunGame.Core.Model
ShieldType shieldType = isMagicDamage ? ShieldType.Magical : ShieldType.Physical; ShieldType shieldType = isMagicDamage ? ShieldType.Magical : ShieldType.Physical;
if (shield > 0) if (shield > 0)
{ {
WriteLine($"[ {enemy} ] 的{shieldTypeString}护盾抵消了 {remain:0.##} 点{damageType}"); WriteLine($"[ {enemy} ] 的{shieldTypeString}护盾抵消了 {remain:0.##} 点{damageTypeString}");
enemy.Shield[isMagicDamage, magicType] -= remain; enemy.Shield[isMagicDamage, magicType] -= remain;
remain = 0; remain = 0;
effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
effect.OnShieldNeutralizeDamage(enemy, actor, isMagicDamage, magicType, damage, shieldType); effect.OnShieldNeutralizeDamage(enemy, actor, damageType, magicType, damage, shieldType);
} }
} }
else else
{ {
WriteLine($"[ {enemy} ] 的{shieldTypeString}护盾抵消了 {enemy.Shield[isMagicDamage, magicType]:0.##} 点{damageType}并破碎!"); WriteLine($"[ {enemy} ] 的{shieldTypeString}护盾抵消了 {enemy.Shield[isMagicDamage, magicType]:0.##} 点{damageTypeString}并破碎!");
remain -= enemy.Shield[isMagicDamage, magicType]; remain -= enemy.Shield[isMagicDamage, magicType];
enemy.Shield[isMagicDamage, magicType] = 0; enemy.Shield[isMagicDamage, magicType] = 0;
if (isMagicDamage && enemy.Shield.TotalMagicial <= 0 || !isMagicDamage && enemy.Shield.TotalPhysical <= 0) if (isMagicDamage && enemy.Shield.TotalMagicial <= 0 || !isMagicDamage && enemy.Shield.TotalPhysical <= 0)
@ -1547,18 +1579,18 @@ namespace Milimoe.FunGame.Core.Model
shield -= remain; shield -= remain;
if (shield > 0) if (shield > 0)
{ {
WriteLine($"[ {enemy} ] 的混合护盾抵消了 {remain:0.##} 点{damageType}"); WriteLine($"[ {enemy} ] 的混合护盾抵消了 {remain:0.##} 点{damageTypeString}");
enemy.Shield.Mix -= remain; enemy.Shield.Mix -= remain;
remain = 0; remain = 0;
effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
effect.OnShieldNeutralizeDamage(enemy, actor, isMagicDamage, magicType, damage, ShieldType.Mix); effect.OnShieldNeutralizeDamage(enemy, actor, damageType, magicType, damage, ShieldType.Mix);
} }
} }
else else
{ {
WriteLine($"[ {enemy} ] 的混合护盾抵消了 {enemy.Shield.Mix:0.##} 点{damageType}并破碎!"); WriteLine($"[ {enemy} ] 的混合护盾抵消了 {enemy.Shield.Mix:0.##} 点{damageTypeString}并破碎!");
remain -= enemy.Shield.Mix; remain -= enemy.Shield.Mix;
enemy.Shield.Mix = 0; enemy.Shield.Mix = 0;
effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
@ -1582,9 +1614,10 @@ namespace Milimoe.FunGame.Core.Model
{ {
stats.TotalShield += damage - actualDamage; stats.TotalShield += damage - actualDamage;
} }
}
enemy.HP -= actualDamage; enemy.HP -= actualDamage;
WriteLine($"[ {enemy} ] 受到了 {actualDamage:0.##} 点{damageType}{shieldMsg}"); WriteLine($"[ {enemy} ] 受到了 {actualDamage:0.##} 点{damageTypeString}{shieldMsg}");
// 生命偷取,攻击者为全额 // 生命偷取,攻击者为全额
double steal = damage * actor.Lifesteal; double steal = damage * actor.Lifesteal;
@ -1618,7 +1651,7 @@ namespace Milimoe.FunGame.Core.Model
} }
// 统计伤害 // 统计伤害
CalculateCharacterDamageStatistics(actor, enemy, damage, isMagicDamage, actualDamage); CalculateCharacterDamageStatistics(actor, enemy, damage, damageType, actualDamage);
// 计算助攻 // 计算助攻
_assistDetail[actor][enemy, TotalTime] += damage; _assistDetail[actor][enemy, TotalTime] += damage;
@ -1630,12 +1663,12 @@ namespace Milimoe.FunGame.Core.Model
actualDamage = 0; actualDamage = 0;
} }
await OnDamageToEnemyAsync(actor, enemy, damage, actualDamage, isNormalAttack, isMagicDamage, magicType, damageResult); await OnDamageToEnemyAsync(actor, enemy, damage, actualDamage, isNormalAttack, damageType, magicType, damageResult);
effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
effect.AfterDamageCalculation(actor, enemy, damage, actualDamage, isNormalAttack, isMagicDamage, magicType, damageResult); effect.AfterDamageCalculation(actor, enemy, damage, actualDamage, isNormalAttack, damageType, magicType, damageResult);
} }
if (enemy.HP <= 0 && !_eliminated.Contains(enemy) && !_respawnCountdown.ContainsKey(enemy)) if (enemy.HP <= 0 && !_eliminated.Contains(enemy) && !_respawnCountdown.ContainsKey(enemy))
@ -1680,8 +1713,14 @@ namespace Milimoe.FunGame.Core.Model
return; return;
} }
double realHeal = heal;
if (target.HP > 0 || (isDead && canRespawn)) if (target.HP > 0 || (isDead && canRespawn))
{ {
// 用于数据统计,不能是全额,溢出的部分需要扣除
if (target.HP + heal > target.MaxHP)
{
realHeal = target.MaxHP - target.HP;
}
target.HP += heal; target.HP += heal;
if (!LastRound.Heals.TryAdd(target, heal)) if (!LastRound.Heals.TryAdd(target, heal))
{ {
@ -1717,7 +1756,7 @@ namespace Milimoe.FunGame.Core.Model
// 统计数据 // 统计数据
if (_stats.TryGetValue(actor, out CharacterStatistics? stats) && stats != null) if (_stats.TryGetValue(actor, out CharacterStatistics? stats) && stats != null)
{ {
stats.TotalHeal += heal; stats.TotalHeal += realHeal;
} }
await OnHealToTargetAsync(actor, target, heal, isRespawn); await OnHealToTargetAsync(actor, target, heal, isRespawn);
@ -1928,8 +1967,8 @@ namespace Milimoe.FunGame.Core.Model
{ {
caster.CharacterState = CharacterState.Actionable; caster.CharacterState = CharacterState.Actionable;
} }
WriteLine($"[ {caster} ] 终止了 [ {st.Skill.Name} ] 的施法" + (_hardnessTimes[caster] > 3 ? $",并获得了 3 {GameplayEquilibriumConstant.InGameTime}的硬直时间的补偿。" : "。")); WriteLine($"[ {caster} ] 终止了 [ {st.Skill.Name} ] 的施法" + (_hardnessTimes[caster] > 3 && _isInRound ? $",并获得了 3 {GameplayEquilibriumConstant.InGameTime}的硬直时间的补偿。" : "。"));
if (_hardnessTimes[caster] > 3) if (_hardnessTimes[caster] > 3 && _isInRound)
{ {
AddCharacter(caster, 3, false); AddCharacter(caster, 3, false);
} }
@ -1966,16 +2005,21 @@ namespace Milimoe.FunGame.Core.Model
{ {
LastRound.Targets = [.. targets]; LastRound.Targets = [.. targets];
WriteLine($"[ {character} ] 使用了物品 [ {item.Name} ]");
item.ReduceTimesAndRemove();
if (item.IsReduceTimesAfterUse && item.RemainUseTimes == 0)
{
character.Items.Remove(item);
}
await OnCharacterUseItemAsync(character, item, targets); await OnCharacterUseItemAsync(character, item, targets);
string line = $"[ {character} ] 使用了物品 [ {item.Name} ]\r\n[ {character} ] ";
skill.OnSkillCasting(this, character, targets); skill.OnSkillCasting(this, character, targets);
skill.BeforeSkillCasted(); skill.BeforeSkillCasted();
skill.CurrentCD = skill.RealCD; skill.CurrentCD = skill.RealCD;
skill.Enable = false; skill.Enable = false;
string line = $"[ {character} ] ";
if (costMP > 0) if (costMP > 0)
{ {
character.MP -= costMP; character.MP -= costMP;
@ -2017,7 +2061,7 @@ namespace Milimoe.FunGame.Core.Model
{ {
if (pUseItem == 0 && pCastSkill == 0 && pNormalAttack == 0) if (pUseItem == 0 && pCastSkill == 0 && pNormalAttack == 0)
{ {
return CharacterActionType.None; return CharacterActionType.EndTurn;
} }
double total = pUseItem + pCastSkill + pNormalAttack; double total = pUseItem + pCastSkill + pNormalAttack;
@ -2048,7 +2092,7 @@ namespace Milimoe.FunGame.Core.Model
return CharacterActionType.NormalAttack; return CharacterActionType.NormalAttack;
} }
return CharacterActionType.None; return CharacterActionType.EndTurn;
} }
/// <summary> /// <summary>
@ -2113,7 +2157,7 @@ namespace Milimoe.FunGame.Core.Model
if (skill.SkillType == SkillType.Magic) if (skill.SkillType == SkillType.Magic)
{ {
cost = skill.RealMPCost; cost = skill.RealMPCost;
if (cost > 0 && cost <= caster.MP) if (cost >= 0 && cost <= caster.MP)
{ {
return true; return true;
} }
@ -2125,7 +2169,7 @@ namespace Milimoe.FunGame.Core.Model
else else
{ {
cost = skill.RealEPCost; cost = skill.RealEPCost;
if (cost > 0 && cost <= caster.EP) if (cost >= 0 && cost <= caster.EP)
{ {
return true; return true;
} }
@ -2158,7 +2202,7 @@ namespace Milimoe.FunGame.Core.Model
costEP = skill.RealEPCost; costEP = skill.RealEPCost;
bool isMPOk = false; bool isMPOk = false;
bool isEPOk = false; bool isEPOk = false;
if (costMP > 0 && costMP <= caster.MP) if (costMP >= 0 && costMP <= caster.MP)
{ {
isMPOk = true; isMPOk = true;
} }
@ -2167,7 +2211,7 @@ namespace Milimoe.FunGame.Core.Model
WriteLine("[ " + caster + $" ] 魔法不足!"); WriteLine("[ " + caster + $" ] 魔法不足!");
} }
costEP = skill.RealEPCost; costEP = skill.RealEPCost;
if (costEP > 0 && costEP <= caster.EP) if (costEP >= 0 && costEP <= caster.EP)
{ {
isEPOk = true; isEPOk = true;
} }
@ -2191,16 +2235,16 @@ namespace Milimoe.FunGame.Core.Model
public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage, ref int changeCount) public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage, ref int changeCount)
{ {
List<Character> characters = [actor, enemy]; List<Character> characters = [actor, enemy];
bool isMagic = false; DamageType damageType = DamageType.Physical;
MagicType magicType = MagicType.None; MagicType magicType = MagicType.None;
List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
if (changeCount < 3) if (changeCount < 3)
{ {
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
effect.AlterDamageTypeBeforeCalculation(actor, enemy, ref isNormalAttack, ref isMagic, ref magicType); effect.AlterDamageTypeBeforeCalculation(actor, enemy, ref isNormalAttack, ref damageType, ref magicType);
} }
if (isMagic) if (damageType == DamageType.Magical)
{ {
changeCount++; changeCount++;
return CalculateMagicalDamage(actor, enemy, isNormalAttack, magicType, expectedDamage, out finalDamage, ref changeCount); return CalculateMagicalDamage(actor, enemy, isNormalAttack, magicType, expectedDamage, out finalDamage, ref changeCount);
@ -2211,7 +2255,7 @@ namespace Milimoe.FunGame.Core.Model
effects = [.. actor.Effects.Union(enemy.Effects).Distinct().Where(e => e.IsInEffect)]; effects = [.. actor.Effects.Union(enemy.Effects).Distinct().Where(e => e.IsInEffect)];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, false, MagicType.None, totalDamageBonus); double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, DamageType.Physical, MagicType.None, totalDamageBonus);
totalDamageBonus[effect] = damageBonus; totalDamageBonus[effect] = damageBonus;
} }
expectedDamage += totalDamageBonus.Sum(kv => kv.Value); expectedDamage += totalDamageBonus.Sum(kv => kv.Value);
@ -2308,15 +2352,15 @@ namespace Milimoe.FunGame.Core.Model
public DamageResult CalculateMagicalDamage(Character actor, Character enemy, bool isNormalAttack, MagicType magicType, double expectedDamage, out double finalDamage, ref int changeCount) public DamageResult CalculateMagicalDamage(Character actor, Character enemy, bool isNormalAttack, MagicType magicType, double expectedDamage, out double finalDamage, ref int changeCount)
{ {
List<Character> characters = [actor, enemy]; List<Character> characters = [actor, enemy];
bool isMagic = true; DamageType damageType = DamageType.Magical;
List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
if (changeCount < 3) if (changeCount < 3)
{ {
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
effect.AlterDamageTypeBeforeCalculation(actor, enemy, ref isNormalAttack, ref isMagic, ref magicType); effect.AlterDamageTypeBeforeCalculation(actor, enemy, ref isNormalAttack, ref damageType, ref magicType);
} }
if (!isMagic) if (damageType == DamageType.Physical)
{ {
changeCount++; changeCount++;
return CalculatePhysicalDamage(actor, enemy, isNormalAttack, expectedDamage, out finalDamage, ref changeCount); return CalculatePhysicalDamage(actor, enemy, isNormalAttack, expectedDamage, out finalDamage, ref changeCount);
@ -2327,7 +2371,7 @@ namespace Milimoe.FunGame.Core.Model
effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.IsInEffect)).Distinct()];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, true, magicType, totalDamageBonus); double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, DamageType.Magical, magicType, totalDamageBonus);
totalDamageBonus[effect] = damageBonus; totalDamageBonus[effect] = damageBonus;
} }
expectedDamage += totalDamageBonus.Sum(kv => kv.Value); expectedDamage += totalDamageBonus.Sum(kv => kv.Value);
@ -2812,12 +2856,16 @@ namespace Milimoe.FunGame.Core.Model
/// <summary> /// <summary>
/// 计算角色的数据 /// 计算角色的数据
/// </summary> /// </summary>
public void CalculateCharacterDamageStatistics(Character character, Character characterTaken, double damage, bool isMagic, double takenDamage = -1) public void CalculateCharacterDamageStatistics(Character character, Character characterTaken, double damage, DamageType damageType, double takenDamage = -1)
{ {
if (takenDamage == -1) takenDamage = damage; if (takenDamage == -1) takenDamage = damage;
if (_stats.TryGetValue(character, out CharacterStatistics? stats) && stats != null) if (_stats.TryGetValue(character, out CharacterStatistics? stats) && stats != null)
{ {
if (isMagic) if (damageType == DamageType.True)
{
stats.TotalTrueDamage += damage;
}
if (damageType == DamageType.Magical)
{ {
stats.TotalMagicDamage += damage; stats.TotalMagicDamage += damage;
} }
@ -2829,7 +2877,11 @@ namespace Milimoe.FunGame.Core.Model
} }
if (_stats.TryGetValue(characterTaken, out CharacterStatistics? statsTaken) && statsTaken != null) if (_stats.TryGetValue(characterTaken, out CharacterStatistics? statsTaken) && statsTaken != null)
{ {
if (isMagic) if (damageType == DamageType.True)
{
statsTaken.TotalTakenTrueDamage = Calculation.Round2Digits(statsTaken.TotalTakenTrueDamage + takenDamage);
}
if (damageType == DamageType.Magical)
{ {
statsTaken.TotalTakenMagicDamage = Calculation.Round2Digits(statsTaken.TotalTakenMagicDamage + takenDamage); statsTaken.TotalTakenMagicDamage = Calculation.Round2Digits(statsTaken.TotalTakenMagicDamage + takenDamage);
} }
@ -3090,7 +3142,7 @@ namespace Milimoe.FunGame.Core.Model
await (HealToTarget?.Invoke(this, actor, target, heal, isRespawn) ?? Task.CompletedTask); await (HealToTarget?.Invoke(this, actor, target, heal, isRespawn) ?? Task.CompletedTask);
} }
public delegate Task DamageToEnemyEventHandler(GamingQueue queue, Character actor, Character enemy, double damage, double actualDamage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, DamageResult damageResult); public delegate Task DamageToEnemyEventHandler(GamingQueue queue, Character actor, Character enemy, double damage, double actualDamage, bool isNormalAttack, DamageType damageType, MagicType magicType, DamageResult damageResult);
/// <summary> /// <summary>
/// 造成伤害事件 /// 造成伤害事件
/// </summary> /// </summary>
@ -3103,13 +3155,13 @@ namespace Milimoe.FunGame.Core.Model
/// <param name="damage"></param> /// <param name="damage"></param>
/// <param name="actualDamage"></param> /// <param name="actualDamage"></param>
/// <param name="isNormalAttack"></param> /// <param name="isNormalAttack"></param>
/// <param name="isMagicDamage"></param> /// <param name="damageType"></param>
/// <param name="magicType"></param> /// <param name="magicType"></param>
/// <param name="damageResult"></param> /// <param name="damageResult"></param>
/// <returns></returns> /// <returns></returns>
protected async Task OnDamageToEnemyAsync(Character actor, Character enemy, double damage, double actualDamage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, DamageResult damageResult) protected async Task OnDamageToEnemyAsync(Character actor, Character enemy, double damage, double actualDamage, bool isNormalAttack, DamageType damageType, MagicType magicType, DamageResult damageResult)
{ {
await (DamageToEnemy?.Invoke(this, actor, enemy, damage, actualDamage, isNormalAttack, isMagicDamage, magicType, damageResult) ?? Task.CompletedTask); await (DamageToEnemy?.Invoke(this, actor, enemy, damage, actualDamage, isNormalAttack, damageType, magicType, damageResult) ?? Task.CompletedTask);
} }
public delegate Task CharacterNormalAttackEventHandler(GamingQueue queue, Character actor, List<Character> targets); public delegate Task CharacterNormalAttackEventHandler(GamingQueue queue, Character actor, List<Character> targets);