diff --git a/Api/Utility/ActionQueue.cs b/Api/Utility/ActionQueue.cs index d9ad16d..38f7719 100644 --- a/Api/Utility/ActionQueue.cs +++ b/Api/Utility/ActionQueue.cs @@ -91,6 +91,11 @@ namespace Milimoe.FunGame.Core.Api.Utility Character character = group.First(); AddCharacter(character, Calculation.Round2Digits(_queue.Count * 0.1), false); _assistDamage.Add(character, new AssistDetail(character, characters.Where(c => c != character))); + // 初始化技能 + foreach (Skill skill in character.Skills) + { + skill.OnSkillGained(this); + } } else { @@ -139,6 +144,11 @@ namespace Milimoe.FunGame.Core.Api.Utility { AddCharacter(selectedCharacter, Calculation.Round2Digits(_queue.Count * 0.1), false); _assistDamage.Add(selectedCharacter, new AssistDetail(selectedCharacter, characters.Where(c => c != selectedCharacter))); + // 初始化技能 + foreach (Skill skill in selectedCharacter.Skills) + { + skill.OnSkillGained(this); + } WriteLine("decided: " + selectedCharacter.Name + "\r\n"); sortedList.Remove(selectedCharacter); } @@ -276,16 +286,16 @@ namespace Milimoe.FunGame.Core.Api.Utility { if (!BeforeTurn(character)) { - return false; + return _isGameEnd; } - foreach (Effect effect in character.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in character.Effects.Where(e => e.Level > 0).ToList()) { effect.OnTurnStart(character); } - // 假设基础硬直时间 - double baseTime = new Random().Next(10, 30); + // 基础硬直时间 + double baseTime = 10; // 敌人列表 List enemys = [.. _queue.Where(c => c != character && !c.IsUnselectable)]; @@ -294,8 +304,8 @@ namespace Milimoe.FunGame.Core.Api.Utility List teammates = []; // 技能列表 - List skills = [.. character.Skills.Where(s => s.Level > 0 && s.IsActive && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && - ((s.IsSuperSkill && s.EPCost <= character.EP) || (!s.IsSuperSkill && s.IsMagic && s.MPCost <= character.MP) || (!s.IsSuperSkill && !s.IsMagic && s.EPCost <= character.EP)))]; + List 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.EPCost <= character.EP) || (s.SkillType == SkillType.Magic && s.MPCost <= character.MP)))]; // 作出了什么行动 CharacterActionType type = CharacterActionType.None; @@ -395,8 +405,6 @@ namespace Milimoe.FunGame.Core.Api.Utility } else { - // 完全行动不能会获得10时间硬直 - baseTime = 10; WriteLine("[ " + character + $" ] 完全行动不能!"); } @@ -409,12 +417,9 @@ namespace Milimoe.FunGame.Core.Api.Utility Character enemy = enemys[new Random().Next(enemys.Count)]; character.NormalAttack.Attack(this, character, enemy); baseTime = character.NormalAttack.HardnessTime; - foreach (Effect effect in character.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in character.Effects.Where(e => e.Level > 0).ToList()) { - if (effect.AlterHardnessTimeAfterNormalAttack(character, baseTime, out double newTime)) - { - baseTime = newTime; - } + effect.AlterHardnessTimeAfterNormalAttack(character, ref baseTime); } } } @@ -424,12 +429,12 @@ namespace Milimoe.FunGame.Core.Api.Utility // 注意:FastAuto 模式下,此吟唱逻辑删减了选取目标的逻辑,将选取逻辑放在了实际释放的环节 // 在正常交互式模式下,吟唱前需要先选取目标 Skill skill = skills[new Random().Next(skills.Count)]; - if (skill.IsMagic && !skill.IsSuperSkill) + if (skill.SkillType == SkillType.Magic) { character.CharacterState = CharacterState.Casting; _castingSkills.Add(character, skill); baseTime = skill.CastTime; - foreach (Effect effect in character.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in character.Effects.Where(e => e.Level > 0).ToList()) { effect.OnSkillCasting(character); } @@ -445,12 +450,9 @@ namespace Milimoe.FunGame.Core.Api.Utility WriteLine("[ " + character + $" ] 消耗了 {cost:f2} 点能量,释放了{(skill.IsSuperSkill ? "爆发技" : "战技")} {skill.Name}!"); skill.Trigger(this, character, enemys, teammates); - foreach (Effect effect in character.Effects) + foreach (Effect effect in character.Effects.Where(e => e.Level > 0).ToList()) { - if (effect.AlterHardnessTimeAfterCastSkill(character, baseTime, out double newTime)) - { - baseTime = newTime; - } + effect.AlterHardnessTimeAfterCastSkill(character, ref baseTime); } } } @@ -480,12 +482,9 @@ namespace Milimoe.FunGame.Core.Api.Utility baseTime = 3; } - foreach (Effect effect in character.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in character.Effects.Where(e => e.Level > 0).ToList()) { - if (effect.AlterHardnessTimeAfterCastSkill(character, baseTime, out double newTime)) - { - baseTime = newTime; - } + effect.AlterHardnessTimeAfterCastSkill(character, ref baseTime); } } else if (type == CharacterActionType.CastSuperSkill) @@ -513,12 +512,9 @@ namespace Milimoe.FunGame.Core.Api.Utility baseTime = 3; } - foreach (Effect effect in character.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in character.Effects.Where(e => e.Level > 0).ToList()) { - if (effect.AlterHardnessTimeAfterCastSkill(character, baseTime, out double newTime)) - { - baseTime = newTime; - } + effect.AlterHardnessTimeAfterCastSkill(character, ref baseTime); } } else if (type == CharacterActionType.UseItem) @@ -532,7 +528,7 @@ namespace Milimoe.FunGame.Core.Api.Utility if (_isGameEnd) { - return true; + return _isGameEnd; } // 减少硬直时间 @@ -552,15 +548,34 @@ namespace Milimoe.FunGame.Core.Api.Utility // 有人想要插队吗? WillPreCastSuperSkill(character); - foreach (Effect effect in character.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in character.Effects.Where(e => e.Level > 0).ToList()) { effect.OnTurnEnd(character); + + // 自身被动不会考虑 + if (effect.ControlType == EffectControlType.None && effect.Skill.SkillType == SkillType.Passive) + { + continue; + } + + // 在回合结束时移除技能持续回合,而不是等时间流逝 + if (!effect.Durative && effect.DurationTurn > 0) + { + // 按回合移除特效 + effect.RemainDurationTurn--; + if (effect.RemainDurationTurn <= 0) + { + effect.RemainDurationTurn = 0; + character.Effects.Remove(effect); + effect.OnEffectLost(character); + } + } } AfterTurn(character); WriteLine(""); - return false; + return _isGameEnd; } /// @@ -631,19 +646,29 @@ namespace Milimoe.FunGame.Core.Api.Utility // 移除到时间的特效 foreach (Effect effect in character.Effects.ToList()) { - if (!effect.Skill.IsActive) continue; - if (!effect.Durative || effect.Level == 0) + if (effect.Level == 0) { character.Effects.Remove(effect); continue; } + effect.OnTimeElapsed(character, timeToReduce); - effect.RemainDuration = Calculation.Round2Digits(effect.RemainDuration - timeToReduce); - if (effect.RemainDuration <= 0) + + // 自身被动不会考虑 + if (effect.ControlType == EffectControlType.None && effect.Skill.SkillType == SkillType.Passive) { - effect.RemainDuration = 0; - character.Effects.Remove(effect); - effect.OnEffectLost(character); + continue; + } + + if (effect.Durative) + { + effect.RemainDuration = Calculation.Round2Digits(effect.RemainDuration - timeToReduce); + if (effect.RemainDuration <= 0) + { + effect.RemainDuration = 0; + character.Effects.Remove(effect); + effect.OnEffectLost(character); + } } } } @@ -664,12 +689,9 @@ namespace Milimoe.FunGame.Core.Api.Utility /// public void DamageToEnemy(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage = false, MagicType magicType = MagicType.None, bool isCritical = false) { - foreach (Effect effect in actor.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList()) { - if (effect.AlterActualDamageAfterCalculation(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, isCritical, out double newDamage)) - { - damage = newDamage; - } + effect.AlterActualDamageAfterCalculation(actor, enemy, ref damage, isNormalAttack, isMagicDamage, magicType, isCritical); } if (damage < 0) damage = 0; if (isMagicDamage) @@ -687,31 +709,25 @@ namespace Milimoe.FunGame.Core.Api.Utility double ep = GetEP(damage, 0.2, 40); foreach (Effect effect in actor.Effects) { - if (effect.AlterEPAfterDamage(actor, ep, out double newep)) - { - ep = newep; - } + effect.AlterEPAfterDamage(actor, ref ep); } actor.EP += ep; ep = GetEP(damage, 0.1, 20); - foreach (Effect effect in enemy.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in enemy.Effects.Where(e => e.Level > 0).ToList()) { - if (effect.AlterEPAfterGetDamage(enemy, ep, out double newep)) - { - ep = newep; - } + effect.AlterEPAfterGetDamage(enemy, ref ep); } enemy.EP += ep; - foreach (Effect effect in actor.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList()) { - effect.AfterDamageCalculation(actor, enemy, damage, isMagicDamage, magicType); + effect.AfterDamageCalculation(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, isCritical); } if (enemy.HP < 0) { DeathCalculation(actor, enemy); // 给所有角色的特效广播角色死亡结算 - foreach (Effect effect in _queue.SelectMany(c => c.Effects.Where(e => e.Level > 0))) + foreach (Effect effect in _queue.SelectMany(c => c.Effects.Where(e => e.Level > 0).ToList())) { effect.AfterDeathCalculation(enemy, actor, _continuousKilling, _earnedMoney); } @@ -738,31 +754,28 @@ namespace Milimoe.FunGame.Core.Api.Utility /// 计算物理伤害 /// /// - /// + /// /// /// /// /// - public DamageResult CalculatePhysicalDamage(Character actor, Character target, bool isNormalAttack, double expectedDamage, out double finalDamage) + public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage) { - foreach (Effect effect in actor.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList()) { - if (effect.AlterExpectedDamageBeforeCalculation(actor, target, expectedDamage, isNormalAttack, false, MagicType.None, out double newDamage)) - { - expectedDamage = newDamage; - } + effect.AlterExpectedDamageBeforeCalculation(actor, enemy, ref expectedDamage, isNormalAttack, false, MagicType.None); } double dice = new Random().NextDouble(); // 闪避判定 - if (dice < target.EvadeRate) + if (dice < enemy.EvadeRate) { finalDamage = 0; - List characters = [actor, target]; + List characters = [actor, enemy]; bool isAlterEvaded = false; - foreach (Effect effect in characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))) + foreach (Effect effect in characters.SelectMany(c => c.Effects.Where(e => e.Level > 0).ToList())) { - isAlterEvaded = effect.OnEvadedTriggered(actor, target, dice); + isAlterEvaded = effect.OnEvadedTriggered(actor, enemy, dice); } if (!isAlterEvaded) { @@ -772,7 +785,7 @@ namespace Milimoe.FunGame.Core.Api.Utility } // 物理穿透后的护甲 - double penetratedDEF = Calculation.Round2Digits((1 - actor.PhysicalPenetration) * target.DEF); + double penetratedDEF = Calculation.Round2Digits((1 - actor.PhysicalPenetration) * enemy.DEF); // 物理伤害减免 double physicalDamageReduction = Calculation.Round4Digits(penetratedDEF / (penetratedDEF + 120)); @@ -786,7 +799,7 @@ namespace Milimoe.FunGame.Core.Api.Utility { finalDamage = Calculation.Round2Digits(finalDamage * actor.CritDMG); // 暴击伤害倍率加成 WriteLine("暴击生效!!"); - foreach (Effect effect in actor.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in actor.Effects.Where(e => e.Level > 0).ToList()) { effect.OnCriticalDamageTriggered(actor, dice); } @@ -801,33 +814,30 @@ namespace Milimoe.FunGame.Core.Api.Utility /// 计算魔法伤害 /// /// - /// + /// /// /// /// /// /// - public DamageResult CalculateMagicalDamage(Character actor, Character target, bool isNormalAttack, MagicType magicType, double expectedDamage, out double finalDamage) + public DamageResult CalculateMagicalDamage(Character actor, Character enemy, bool isNormalAttack, MagicType magicType, double expectedDamage, out double finalDamage) { - foreach (Effect effect in actor.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList()) { - if (effect.AlterExpectedDamageBeforeCalculation(actor, target, expectedDamage, isNormalAttack, true, magicType, out double newDamage)) - { - expectedDamage = newDamage; - } + effect.AlterExpectedDamageBeforeCalculation(actor, enemy, ref expectedDamage, isNormalAttack, true, magicType); } MagicResistance magicResistance = magicType switch { - MagicType.Starmark => target.MDF.Starmark, - MagicType.PurityNatural => target.MDF.PurityNatural, - MagicType.PurityContemporary => target.MDF.PurityContemporary, - MagicType.Bright => target.MDF.Bright, - MagicType.Shadow => target.MDF.Shadow, - MagicType.Element => target.MDF.Element, - MagicType.Fleabane => target.MDF.Fleabane, - MagicType.Particle => target.MDF.Particle, - _ => target.MDF.None + MagicType.Starmark => enemy.MDF.Starmark, + MagicType.PurityNatural => enemy.MDF.PurityNatural, + MagicType.PurityContemporary => enemy.MDF.PurityContemporary, + MagicType.Bright => enemy.MDF.Bright, + MagicType.Shadow => enemy.MDF.Shadow, + MagicType.Element => enemy.MDF.Element, + MagicType.Fleabane => enemy.MDF.Fleabane, + MagicType.Particle => enemy.MDF.Particle, + _ => enemy.MDF.None }; // 魔法穿透后的魔法抗性 @@ -842,7 +852,7 @@ namespace Milimoe.FunGame.Core.Api.Utility { finalDamage = Calculation.Round2Digits(finalDamage * actor.CritDMG); // 暴击伤害倍率加成 WriteLine("暴击生效!!"); - foreach (Effect effect in actor.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in actor.Effects.Where(e => e.Level > 0).ToList()) { effect.OnCriticalDamageTriggered(actor, dice); } @@ -972,7 +982,7 @@ namespace Milimoe.FunGame.Core.Api.Utility /// public bool CheckCanCast(Character caster, Skill skill, out double cost) { - if (skill.IsMagic && !skill.IsSuperSkill) + if (skill.SkillType == SkillType.Magic) { cost = skill.MPCost; if (cost > 0 && cost <= caster.MP) @@ -1006,14 +1016,13 @@ namespace Milimoe.FunGame.Core.Api.Utility /// public void WillPreCastSuperSkill(Character character) { - CharacterState[] checkStates = [CharacterState.Actionable]; // 选取在顺序表一半之后的角色 - foreach (Character other in _queue.Where(c => c != character && checkStates.Contains(c.CharacterState) && _queue.IndexOf(c) >= _queue.Count / 2).ToList()) + foreach (Character other in _queue.Where(c => c != character && c.CharacterState == CharacterState.Actionable && _queue.IndexOf(c) >= _queue.Count / 2).ToList()) { // 有 65% 欲望插队 if (new Random().NextDouble() < 0.65) { - List skills = other.Skills.Where(s => s.IsSuperSkill && s.Level > 0 && s.IsActive && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && other.EP >= s.EPCost).ToList(); + List skills = other.Skills.Where(s => s.Level > 0 && s.SkillType == SkillType.SuperSkill && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && other.EP >= s.EPCost).ToList(); if (skills.Count > 0) { Skill skill = skills[new Random().Next(skills.Count)]; @@ -1030,7 +1039,7 @@ namespace Milimoe.FunGame.Core.Api.Utility _hardnessTimes[c] = Calculation.Round2Digits(_hardnessTimes[c] + 0.01); } } - foreach (Effect effect in character.Effects.Where(e => e.Level > 0)) + foreach (Effect effect in character.Effects.Where(e => e.Level > 0).ToList()) { effect.OnSkillCasting(character); } @@ -1038,5 +1047,30 @@ namespace Milimoe.FunGame.Core.Api.Utility } } } + + /// + /// 打断施法 + /// + /// + /// + public void InterruptCasting(Character caster, Character interrupter) + { + if (_castingSkills.TryGetValue(caster, out Skill? cast)) + { + _castingSkills.Remove(caster); + } + else if (_castingSuperSkills.TryGetValue(caster, out cast)) + { + _castingSuperSkills.Remove(caster); + } + if (cast != null) + { + WriteLine($"[ {caster} ] 的施法被 [ {interrupter} ] 打断了!!"); + foreach (Effect e in cast.Effects.Where(e => e.Level > 0).ToList()) + { + e.OnSkillCastInterrupted(caster, interrupter); + } + } + } } } diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs index 03797a9..48b4062 100644 --- a/Entity/Character/Character.cs +++ b/Entity/Character/Character.cs @@ -121,6 +121,7 @@ namespace Milimoe.FunGame.Core.Entity set { _Level = Math.Min(Math.Max(1, value), 60); + OnAttributeChanged(); Recovery(); } } @@ -135,6 +136,11 @@ namespace Milimoe.FunGame.Core.Entity /// public CharacterState CharacterState { get; set; } = CharacterState.Actionable; + /// + /// 角色目前被特效施加的状态 + /// + public Dictionary CharacterEffectStates { get; } = []; + /// /// 角色是否是中立的/无敌的 [ 战斗相关 ] /// @@ -739,17 +745,14 @@ namespace Milimoe.FunGame.Core.Entity } /// - /// 提升角色的等级 + /// 角色的属性发生变化,会影响特殊效果的计算 /// - /// 可为负数 - /// - public int LevelUp(int up = 1) + public void OnAttributeChanged() { - if (up != 0) + foreach (Effect effect in Effects) { - Level += up; + effect.OnAttributeChanged(this); } - return Level; } /// @@ -892,6 +895,11 @@ namespace Milimoe.FunGame.Core.Entity return builder.ToString(); } + /// + /// 获取战斗状态的信息 + /// + /// + /// public string GetInBattleInfo(double hardnessTimes) { StringBuilder builder = new(); @@ -900,6 +908,8 @@ namespace Milimoe.FunGame.Core.Entity 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}]" : "")); if (CharacterState != CharacterState.Actionable) { @@ -930,6 +940,66 @@ namespace Milimoe.FunGame.Core.Entity return builder.ToString(); } + /// + /// 更新角色的状态 + /// + /// + public CharacterState UpdateCharacterState() + { + bool isNotActionable = false; + bool isActionRestricted = false; + bool isBattleRestricted = false; + bool isSkillRestricted = false; + + foreach (CharacterState state in CharacterEffectStates.Values) + { + if (state == CharacterState.NotActionable) + { + isNotActionable = true; + } + else if (state == CharacterState.ActionRestricted) + { + isActionRestricted = true; + } + else if (state == CharacterState.BattleRestricted) + { + isBattleRestricted = true; + } + else if (state == CharacterState.SkillRestricted) + { + isSkillRestricted = true; + } + } + + bool isControl = isNotActionable || isActionRestricted || isBattleRestricted || isSkillRestricted; + bool isCasting = CharacterState == CharacterState.Casting; + bool isPreCastSuperSkill = CharacterState == CharacterState.PreCastSuperSkill; + + if (isNotActionable) + { + CharacterState = CharacterState.NotActionable; + } + else if (isActionRestricted) + { + CharacterState = CharacterState.ActionRestricted; + } + else if (isBattleRestricted) + { + CharacterState = CharacterState.BattleRestricted; + } + else if (isSkillRestricted) + { + CharacterState = CharacterState.SkillRestricted; + } + + if (!isControl && !isCasting && !isPreCastSuperSkill) + { + CharacterState = CharacterState.Actionable; + } + + return CharacterState; + } + /// /// 复制一个角色 /// [ 推荐从模组中复制后使用对象 ] diff --git a/Entity/Skill/Effect.cs b/Entity/Skill/Effect.cs index 4094c24..8b66164 100644 --- a/Entity/Skill/Effect.cs +++ b/Entity/Skill/Effect.cs @@ -15,6 +15,12 @@ namespace Milimoe.FunGame.Core.Entity /// public Skill Skill { get; } = skill; + /// + /// 特殊效果类型 + /// 注意:如果技能特效没有原生施加控制效果,请始终保持此属性为 。 + /// + public virtual EffectControlType ControlType { get; } = EffectControlType.None; + /// /// 作用于自身 /// @@ -46,7 +52,7 @@ namespace Milimoe.FunGame.Core.Entity /// 持续时间(回合) /// 使用此属性需要将 设置为 false。 /// - public virtual double DurationTurn { get; } = 0; + public virtual int DurationTurn { get; } = 0; /// /// 剩余持续时间 @@ -56,7 +62,7 @@ namespace Milimoe.FunGame.Core.Entity /// /// 剩余持续时间(回合) /// - public double RemainDurationTurn { get; set; } = 0; + public int RemainDurationTurn { get; set; } = 0; /// /// 魔法类型 @@ -76,7 +82,24 @@ namespace Milimoe.FunGame.Core.Entity /// /// 此特效的施加者,用于溯源 /// - public Character? Source { get; set; } = null; + public virtual Character? Source { get; } = null; + + /// + /// 游戏中的行动顺序表实例,在技能效果被触发时,此实例会获得赋值,使用时需要判断其是否存在 + /// + public ActionQueue? ActionQueue { get; set; } = null; + + /// + /// 输出文本或日志 + /// + public Action WriteLine + { + get + { + if (ActionQueue is null) return Console.WriteLine; + else return ActionQueue.WriteLine; + } + } /// /// 获得此特效时 @@ -105,12 +128,9 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// - /// - /// 返回 true 表示修改了伤害 - public virtual bool AlterExpectedDamageBeforeCalculation(Character character, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, out double newDamage) + public virtual void AlterExpectedDamageBeforeCalculation(Character character, Character enemy, ref double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType) { - newDamage = damage; - return false; + } /// @@ -123,12 +143,9 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// - /// - /// 返回 true 表示修改了伤害 - public virtual bool AlterActualDamageAfterCalculation(Character character, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, bool isCritical, out double newDamage) + public virtual void AlterActualDamageAfterCalculation(Character character, Character enemy, ref double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, bool isCritical) { - newDamage = damage; - return false; + } /// @@ -136,12 +153,9 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// - /// - /// 返回 true 表示修改了硬直时间 - public virtual bool AlterHardnessTimeAfterNormalAttack(Character character, double baseHardnessTime, out double newHardnessTime) + public virtual void AlterHardnessTimeAfterNormalAttack(Character character, ref double baseHardnessTime) { - newHardnessTime = baseHardnessTime; - return false; + } /// @@ -149,12 +163,9 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// - /// - /// 返回 true 表示修改了硬直时间 - public virtual bool AlterHardnessTimeAfterCastSkill(Character character, double baseHardnessTime, out double newHardnessTime) + public virtual void AlterHardnessTimeAfterCastSkill(Character character, ref double baseHardnessTime) { - newHardnessTime = baseHardnessTime; - return false; + } /// @@ -162,12 +173,9 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// - /// - /// 返回 true 表示修改了获得的能量 - public virtual bool AlterEPAfterDamage(Character character, double baseEP, out double newEP) + public virtual void AlterEPAfterDamage(Character character, ref double baseEP) { - newEP = baseEP; - return false; + } /// @@ -175,12 +183,9 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// - /// - /// 返回 true 表示修改了获得的能量 - public virtual bool AlterEPAfterGetDamage(Character character, double baseEP, out double newEP) + public virtual void AlterEPAfterGetDamage(Character character, ref double baseEP) { - newEP = baseEP; - return false; + } /// @@ -205,12 +210,11 @@ namespace Milimoe.FunGame.Core.Entity /// /// 吟唱结束后释放技能(魔法)/ 直接释放技能(战技/爆发技) /// - /// /// /// /// /// - public virtual void OnSkillCasted(ActionQueue queue, Character caster, List enemys, List teammates, Dictionary others) + public virtual void OnSkillCasted(Character caster, List enemys, List teammates, Dictionary others) { } @@ -231,9 +235,11 @@ namespace Milimoe.FunGame.Core.Entity /// /// /// + /// /// /// - public virtual void AfterDamageCalculation(Character character, Character enemy, double damage, bool isMagicDamage, MagicType magicType) + /// + public virtual void AfterDamageCalculation(Character character, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, bool isCritical) { } @@ -248,7 +254,7 @@ namespace Milimoe.FunGame.Core.Entity } /// - /// 在特效持有者的回合开始后 + /// 在特效持有者的回合结束后 /// /// public virtual void OnTurnEnd(Character character) @@ -310,6 +316,45 @@ namespace Milimoe.FunGame.Core.Entity } + /// + /// 角色属性发生变化 + /// + public virtual void OnAttributeChanged(Character character) + { + + } + + /// + /// 对敌人造成技能伤害 [ 强烈建议使用此方法造成伤害而不是自行调用 ] + /// + /// + /// + /// + /// + /// + /// + public DamageResult DamageToEnemy(Character actor, Character enemy, bool isMagic, MagicType magicType, double expectedDamage) + { + if (ActionQueue is null) return DamageResult.Evaded; + DamageResult result = !isMagic ? ActionQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out double damage) : ActionQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage); + if (result != DamageResult.Evaded) + { + ActionQueue.DamageToEnemy(actor, enemy, damage, false, isMagic, magicType, result == DamageResult.Critical); + return result; + } + return result; + } + + /// + /// 打断施法 [ 尽可能的调用此方法而不是直接调用 ,以防止中断性变更 ] + /// + /// + /// + public void InterruptCasting(Character caster, Character interrupter) + { + ActionQueue?.InterruptCasting(caster, interrupter); + } + public override string ToString() { StringBuilder builder = new(); diff --git a/Entity/Skill/NormalAttack.cs b/Entity/Skill/NormalAttack.cs index 179830f..8484c00 100644 --- a/Entity/Skill/NormalAttack.cs +++ b/Entity/Skill/NormalAttack.cs @@ -15,7 +15,7 @@ namespace Milimoe.FunGame.Core.Entity /// /// 普通攻击说明 /// - public string Description => $"对目标敌人造成 {Calculation.Round4Digits((1.0 + 0.05 * (Level - 1)) * 100)}% [ {Damage} ] 点{(IsMagic ? CharacterSet.GetMagicName(MagicType) : "物理")}伤害。"; + public string Description => $"对目标敌人造成 {Calculation.Round4Digits((1.0 + 0.05 * (Level - 1)) * 100)}% [ {Damage} ] 点{(IsMagic ? CharacterSet.GetMagicName(MagicType) : "物理伤害")}。"; /// /// 所属的角色 @@ -45,12 +45,12 @@ namespace Milimoe.FunGame.Core.Entity /// /// 是否是魔法伤害 /// - public bool IsMagic { get; } = isMagic; + public bool IsMagic => _IsMagic; /// /// 魔法伤害需要指定魔法类型 /// - public MagicType MagicType { get; } = magicType; + public MagicType MagicType => _MagicType; /// /// 硬直时间 @@ -77,6 +77,17 @@ namespace Milimoe.FunGame.Core.Entity } } + /// + /// 修改伤害类型 + /// + /// + /// + public void SetMagicType(bool isMagic, MagicType magicType) + { + _IsMagic = isMagic; + _MagicType = magicType; + } + public override bool Equals(IBaseEntity? other) { return other is NormalAttack c && c.Name == Name; @@ -97,5 +108,15 @@ namespace Milimoe.FunGame.Core.Entity /// 等级 /// private int _Level = 0; + + /// + /// 是否是魔法伤害 + /// + private bool _IsMagic = isMagic; + + /// + /// 魔法类型 + /// + private MagicType _MagicType = magicType; } } diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs index c61d7bb..8fa3452 100644 --- a/Entity/Skill/Skill.cs +++ b/Entity/Skill/Skill.cs @@ -1,6 +1,7 @@ using System.Text; using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Interface.Entity; +using Milimoe.FunGame.Core.Library.Constant; namespace Milimoe.FunGame.Core.Entity { @@ -42,18 +43,24 @@ namespace Milimoe.FunGame.Core.Entity } /// - /// 是否是主动技能 [ 此项为最高优先级 ] + /// 技能 [ 此项为最高优先级 ] /// [InitRequired] - public bool IsActive { get; set; } = true; + public SkillType SkillType { get; set; } + + /// + /// 是否是主动技能 [ 此项为高优先级 ] + /// + [InitRequired] + public bool IsActive => SkillType != SkillType.Passive; /// - /// 是否可用 [ 此项为最高优先级 ] + /// 是否可用 [ 此项为高优先级 ] /// public bool Enable { get; set; } = true; /// - /// 效果持续生效中 [ 此项设置为true后不允许再次释放,防止重复释放 ] + /// 效果持续生效中 [ 此项为高优先级 ] [ 此项设置为true后不允许再次释放,防止重复释放 ] /// public bool IsInEffect { get; set; } = false; @@ -61,13 +68,13 @@ namespace Milimoe.FunGame.Core.Entity /// 是否是爆发技 [ 此项为高优先级 ] /// [InitRequired] - public bool IsSuperSkill { get; set; } = false; + public bool IsSuperSkill => SkillType == SkillType.SuperSkill; /// /// 是否属于魔法 [ 必须为 true ],反之为战技 /// [InitRequired] - public bool IsMagic { get; set; } = true; + public bool IsMagic => SkillType == SkillType.Magic; /// /// 魔法消耗 [ 魔法 ] @@ -126,51 +133,65 @@ namespace Milimoe.FunGame.Core.Entity /// public Dictionary OtherArgs { get; } = []; - protected Skill(bool active = true, bool magic = true, Character? character = null) + /// + /// 游戏中的行动顺序表实例,在技能效果被触发时,此实例会获得赋值,使用时需要判断其是否存在 + /// + public ActionQueue? ActionQueue { get; set; } = null; + + protected Skill(SkillType type, Character? character = null) { - IsActive = active; - IsMagic = magic; + SkillType = type; Character = character; } - protected Skill(bool super = false, Character? character = null) + internal Skill() { - IsSuperSkill = super; - Character = character; + SkillType = SkillType.Passive; } - internal Skill() { } - /// /// 触发技能升级 /// public void OnLevelUp() { - if (!IsActive) + if (!IsActive && Level > 0) { foreach (Effect e in AddInactiveEffectToCharacter()) { if (Character != null && !Character.Effects.Contains(e)) { Character.Effects.Add(e); + e.OnEffectGained(Character); } } } } + /// + /// 当获得技能时 + /// + /// + public void OnSkillGained(ActionQueue queue) + { + ActionQueue = queue; + OnLevelUp(); + } + /// /// 触发技能效果 /// public void Trigger(ActionQueue queue, Character actor, List enemys, List teammates) { + ActionQueue = queue; foreach (Effect e in Effects) { - e.OnSkillCasted(queue, actor, enemys, teammates, OtherArgs); + e.ActionQueue = ActionQueue; + e.OnSkillCasted(actor, enemys, teammates, OtherArgs); } } /// - /// 被动技能,需要重写此方法,返回被动特效给角色 [ 此方法会在游戏开始时和技能升级时调用 ] + /// 被动技能,需要重写此方法,返回被动特效给角色 [ 此方法会在技能学习时触发 ] /// /// public virtual IEnumerable AddInactiveEffectToCharacter() @@ -178,6 +199,10 @@ namespace Milimoe.FunGame.Core.Entity return []; } + /// + /// 返回技能的详细说明 + /// + /// public override string ToString() { StringBuilder builder = new(); diff --git a/Interface/Entity/Property/IActiveEnable.cs b/Interface/Entity/Property/IActiveEnable.cs index 13c37df..5fb1cae 100644 --- a/Interface/Entity/Property/IActiveEnable.cs +++ b/Interface/Entity/Property/IActiveEnable.cs @@ -2,7 +2,7 @@ { public interface IActiveEnable { - public bool IsActive { get; set; } - public bool Enable { get; set; } + public bool IsActive { get; } + public bool Enable { get; } } } diff --git a/Library/Constant/ConstantSet.cs b/Library/Constant/ConstantSet.cs index 5355657..1c514ce 100644 --- a/Library/Constant/ConstantSet.cs +++ b/Library/Constant/ConstantSet.cs @@ -326,19 +326,23 @@ namespace Milimoe.FunGame.Core.Library.Constant public static string GetContinuousKilling(int kills) { - return kills switch + if (kills > 10) return "超越神的杀戮"; + else { - 2 => "双杀", - 3 => "三杀", - 4 => "大杀特杀", - 5 => "杀人如麻", - 6 => "主宰比赛", - 7 => "无人能挡", - 8 => "变态杀戮", - 9 => "如同神一般", - 10 => "超越神的杀戮", - _ => "" - }; + return kills switch + { + 2 => "双杀", + 3 => "三杀", + 4 => "大杀特杀", + 5 => "杀人如麻", + 6 => "主宰比赛", + 7 => "无人能挡", + 8 => "变态杀戮", + 9 => "如同神一般", + 10 => "超越神的杀戮", + _ => "" + }; + } } public static string GetCharacterState(CharacterState state) diff --git a/Library/Constant/TypeEnum.cs b/Library/Constant/TypeEnum.cs index 2dde4c8..c2ddbb0 100644 --- a/Library/Constant/TypeEnum.cs +++ b/Library/Constant/TypeEnum.cs @@ -182,10 +182,218 @@ namespace Milimoe.FunGame.Core.Library.Constant public enum SkillType { - Active, + /// + /// 魔法,编号 1xxx + /// + Magic, + + /// + /// 战技,编号 2xxx + /// + Skill, + + /// + /// 爆发技,编号 3xxx + /// + SuperSkill, + + /// + /// 被动,编号 4xxx + /// Passive } + /// + /// 注意:具有控制效果的特效,应该和技能本身的特效(一般此项为None)区分开来。此效果被赋值会改变一些判断的结果。 + /// + public enum EffectControlType + { + /// + /// 无特殊效果 + /// + None, + + /// + /// 眩晕,目标无法行动 + /// + Stun, + + /// + /// 冰冻,目标无法行动 + /// + Freeze, + + /// + /// 沉默,目标无法使用技能 + /// + Silence, + + /// + /// 定身 + /// + Root, + + /// + /// 恐惧 + /// + Fear, + + /// + /// 睡眠,目标暂时无法行动,受到伤害后会苏醒 + /// + Sleep, + + /// + /// 击退 + /// + Knockback, + + /// + /// 击倒,目标被击倒在地,暂时无法行动 + /// + Knockdown, + + /// + /// 嘲讽,目标被迫攻击施法者 + /// + Taunt, + + /// + /// 减速,目标行动速度和攻击频率降低 + /// + Slow, + + /// + /// 衰弱,目标的攻击和防御降低 + /// + Weaken, + + /// + /// 中毒,目标在一段时间内持续受到伤害 + /// + Poison, + + /// + /// 燃烧,目标受到火焰伤害,持续一段时间 + /// + Burn, + + /// + /// 流血,目标持续受到物理伤害 + /// + Bleed, + + /// + /// 致盲,目标无法准确攻击,命中率降低 + /// + Blind, + + /// + /// 致残,减少目标的行动或攻击能力 + /// + Cripple, + + /// + /// 护盾,减少受到的伤害或抵消部分伤害 + /// + Shield, + + /// + /// 持续治疗,逐步恢复生命值 + /// + HealOverTime, + + /// + /// 加速,提升行动速度和攻击频率 + /// + Haste, + + /// + /// 无敌,暂时不会受到任何伤害 + /// + Invulnerable, + + /// + /// 伤害提升,增加攻击输出 + /// + DamageBoost, + + /// + /// 防御提升,减少所受伤害 + /// + DefenseBoost, + + /// + /// 暴击提升,增加暴击率或暴击伤害 + /// + CritBoost, + + /// + /// 魔法恢复,增加魔法值回复速度 + /// + ManaRegen, + + /// + /// 破甲,降低目标的防御值 + /// + ArmorBreak, + + /// + /// 降低魔法抗性,目标更容易受到魔法伤害 + /// + MagicResistBreak, + + /// + /// 诅咒,降低目标的属性或给予负面效果 + /// + Curse, + + /// + /// 疲劳,减少目标的攻击或技能效果 + /// + Exhaustion, + + /// + /// 魔力燃烧,消耗目标的魔法值 + /// + ManaBurn, + + /// + /// 魅惑,控制目标替施法者作战 + /// + Charm, + + /// + /// 缴械,目标无法进行普通攻击 + /// + Disarm, + + /// + /// 混乱,目标的行动变得随机化 + /// + Confusion, + + /// + /// 石化,目标无法行动,并大幅增加受到的伤害 + /// + Petrify, + + /// + /// 法术沉默,目标无法施放魔法技能 + /// + SilenceMagic, + + /// + /// 放逐,目标暂时无法被攻击,也无法行动 + /// + Banish, + + /// + /// 毁灭,目标在倒计时结束后受到大量伤害或死亡 + /// + Doom + } + public enum ItemType { Active,