diff --git a/Api/Utility/Attribute.cs b/Api/Utility/Attribute.cs index da00955..1ba7ff9 100644 --- a/Api/Utility/Attribute.cs +++ b/Api/Utility/Attribute.cs @@ -1,4 +1,5 @@ using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Interface.Addons; namespace Milimoe.FunGame.Core.Api.Utility { @@ -19,4 +20,13 @@ namespace Milimoe.FunGame.Core.Api.Utility { public InitRequired() { } } + + /// + /// 此标记意味着字段需要满足 x.x.x 的格式。适用于 的版本号 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = true)] + public class AddonVersion : Attribute + { + public AddonVersion() { } + } } diff --git a/Model/ActionQueue.cs b/Model/ActionQueue.cs index b8999d0..80a6c04 100644 --- a/Model/ActionQueue.cs +++ b/Model/ActionQueue.cs @@ -540,7 +540,7 @@ namespace Milimoe.FunGame.Core.Model return _isGameEnd; } - List effects = character.Effects.Where(e => e.Level > 0).ToList(); + List effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.OnTurnStart(character); @@ -590,7 +590,7 @@ namespace Milimoe.FunGame.Core.Model if (character.CharacterState != CharacterState.Casting && character.CharacterState != CharacterState.PreCastSuperSkill) { CharacterActionType actionTypeTemp = CharacterActionType.None; - effects = character.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect e in effects) { actionTypeTemp = e.AlterActionTypeBeforeAction(character, character.CharacterState, ref canUseItem, ref canCastSkill, ref pUseItem, ref pCastSkill, ref pNormalAttack); @@ -605,71 +605,77 @@ namespace Milimoe.FunGame.Core.Model { if (character.CharacterState != CharacterState.NotActionable && character.CharacterState != CharacterState.Casting && character.CharacterState != CharacterState.PreCastSuperSkill) { - if (character.CharacterState == CharacterState.Actionable) + // 模组可以通过以下事件来决定角色的行动 + type = OnDecideAction(character, pUseItem, pCastSkill, pNormalAttack); + if (type != CharacterActionType.None) { - // 可以任意行动 - if (canUseItem && canCastSkill) + // 若事件未完成决策,则将通过概率对角色进行自动化决策 + if (character.CharacterState == CharacterState.Actionable) { - // 不做任何处理 + // 可以任意行动 + if (canUseItem && canCastSkill) + { + // 不做任何处理 + } + else if (canUseItem && !canCastSkill) + { + pCastSkill = 0; + } + else if (!canUseItem && canCastSkill) + { + pUseItem = 0; + } + else + { + pUseItem = 0; + pCastSkill = 0; + } } - else if (canUseItem && !canCastSkill) + else if (character.CharacterState == CharacterState.ActionRestricted) { - pCastSkill = 0; + // 行动受限,只能使用特殊物品 + if (canUseItem) + { + pCastSkill = 0; + pNormalAttack = 0; + } + else + { + pUseItem = 0; + pCastSkill = 0; + pNormalAttack = 0; + } } - else if (!canUseItem && canCastSkill) + else if (character.CharacterState == CharacterState.BattleRestricted) { - pUseItem = 0; + // 战斗不能,只能使用物品 + if (canUseItem) + { + pCastSkill = 0; + pNormalAttack = 0; + } + else + { + pUseItem = 0; + pCastSkill = 0; + pNormalAttack = 0; + } } - else + else if (character.CharacterState == CharacterState.SkillRestricted) { - pUseItem = 0; - pCastSkill = 0; + // 技能受限,无法使用技能,可以使用物品 + if (canUseItem) + { + pCastSkill = 0; + } + else + { + pUseItem = 0; + pCastSkill = 0; + } } + type = GetActionType(pUseItem, pCastSkill, pNormalAttack); } - else if (character.CharacterState == CharacterState.ActionRestricted) - { - // 行动受限,只能使用特殊物品 - if (canUseItem) - { - pCastSkill = 0; - pNormalAttack = 0; - } - else - { - pUseItem = 0; - pCastSkill = 0; - pNormalAttack = 0; - } - } - else if (character.CharacterState == CharacterState.BattleRestricted) - { - // 战斗不能,只能使用物品 - if (canUseItem) - { - pCastSkill = 0; - pNormalAttack = 0; - } - else - { - pUseItem = 0; - pCastSkill = 0; - pNormalAttack = 0; - } - } - else if (character.CharacterState == CharacterState.SkillRestricted) - { - // 技能受限,无法使用技能,可以使用物品 - if (canUseItem) - { - pCastSkill = 0; - } - else - { - pUseItem = 0; - pCastSkill = 0; - } - } - type = GetActionType(pUseItem, pCastSkill, pNormalAttack); _stats[character].ActionTurn += 1; } else if (character.CharacterState == CharacterState.Casting) @@ -689,19 +695,19 @@ namespace Milimoe.FunGame.Core.Model } } - List enemysTemp = new(enemys); - List teammatesTemp = new(teammates); - List skillsTemp = new(skills); + List enemysTemp = [.. enemys]; + List teammatesTemp = [.. teammates]; + List skillsTemp = [.. skills]; Dictionary continuousKillingTemp = new(_continuousKilling); Dictionary earnedMoneyTemp = new(_earnedMoney); - effects = character.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect e in effects) { if (e.AlterEnemyListBeforeAction(character, enemysTemp, teammatesTemp, skillsTemp, continuousKillingTemp, earnedMoneyTemp)) { - enemys = enemysTemp.Distinct().ToList(); - teammates = teammatesTemp.Distinct().ToList(); - skills = skillsTemp.Distinct().ToList(); + enemys = [.. enemysTemp.Distinct()]; + teammates = [.. teammatesTemp.Distinct()]; + skills = [.. skillsTemp.Distinct()]; } } @@ -710,12 +716,12 @@ namespace Milimoe.FunGame.Core.Model // 使用普通攻击逻辑 Character[] targets = [.. SelectTargets(character, character.NormalAttack, enemys, teammates, out bool cancel)]; LastRound.Targets = [.. targets]; - if (!cancel && targets.Length > 0) + if (!cancel) { decided = true; character.NormalAttack.Attack(this, character, targets); baseTime = character.NormalAttack.HardnessTime; - effects = character.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterNormalAttack(character, ref baseTime, ref isCheckProtected); @@ -760,7 +766,7 @@ namespace Milimoe.FunGame.Core.Model WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量,释放了{(skill.IsSuperSkill ? "爆发技" : "战技")} [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}"); skill.OnSkillCasted(this, character, targets); - effects = character.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected); @@ -803,7 +809,7 @@ namespace Milimoe.FunGame.Core.Model baseTime = 3; } - effects = character.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected); @@ -843,7 +849,7 @@ namespace Milimoe.FunGame.Core.Model baseTime = 3; } - effects = character.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected); @@ -889,7 +895,7 @@ namespace Milimoe.FunGame.Core.Model // 有人想要插队吗? WillPreCastSuperSkill(character); - effects = character.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.OnTurnEnd(character); @@ -1022,7 +1028,7 @@ namespace Milimoe.FunGame.Core.Model } // 移除到时间的特效 - List effects = character.Effects.Where(e => e.Level > 0).ToList(); + List effects = [.. character.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { if (effect.Level == 0) @@ -1082,7 +1088,7 @@ namespace Milimoe.FunGame.Core.Model bool isEvaded = damageResult == DamageResult.Evaded; Dictionary totalDamageBonus = []; - List effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList(); + List effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; foreach (Effect effect in effects) { double damageBonus = effect.AlterActualDamageAfterCalculation(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, damageResult, ref isEvaded, totalDamageBonus); @@ -1121,7 +1127,7 @@ namespace Milimoe.FunGame.Core.Model } actor.EP += ep; ep = GetEP(damage, 0.015, 15); - effects = enemy.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. enemy.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.AlterEPAfterGetDamage(enemy, ref ep); @@ -1129,7 +1135,7 @@ namespace Milimoe.FunGame.Core.Model enemy.EP += ep; } - effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.AfterDamageCalculation(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, damageResult); @@ -1210,7 +1216,7 @@ namespace Milimoe.FunGame.Core.Model { bool isMagic = false; MagicType magicType = MagicType.None; - List effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList(); + List effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.AlterDamageTypeBeforeCalculation(actor, enemy, ref isNormalAttack, ref isMagic, ref magicType); @@ -1221,7 +1227,7 @@ namespace Milimoe.FunGame.Core.Model } Dictionary totalDamageBonus = []; - effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; foreach (Effect effect in effects) { double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, false, MagicType.None, totalDamageBonus); @@ -1235,7 +1241,7 @@ namespace Milimoe.FunGame.Core.Model bool checkCritical = true; if (isNormalAttack) { - effects = actor.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { checkEvade = effect.BeforeEvadeCheck(actor, ref throwingBonus); @@ -1249,7 +1255,7 @@ namespace Milimoe.FunGame.Core.Model finalDamage = 0; List characters = [actor, enemy]; bool isAlterEvaded = false; - effects = characters.SelectMany(c => c.Effects.Where(e => e.Level > 0)).ToList(); + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))]; foreach (Effect effect in effects) { if (effect.OnEvadedTriggered(actor, enemy, dice)) @@ -1276,7 +1282,7 @@ namespace Milimoe.FunGame.Core.Model finalDamage = expectedDamage * (1 - Calculation.PercentageCheck(physicalDamageReduction + enemy.ExPDR)); // 暴击判定 - effects = actor.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { checkCritical = effect.BeforeCriticalCheck(actor, ref throwingBonus); @@ -1289,7 +1295,7 @@ namespace Milimoe.FunGame.Core.Model { finalDamage *= actor.CritDMG; // 暴击伤害倍率加成 WriteLine("暴击生效!!"); - effects = actor.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.OnCriticalDamageTriggered(actor, dice); @@ -1315,7 +1321,7 @@ namespace Milimoe.FunGame.Core.Model public DamageResult CalculateMagicalDamage(Character actor, Character enemy, bool isNormalAttack, MagicType magicType, double expectedDamage, out double finalDamage) { bool isMagic = true; - List effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList(); + List effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.AlterDamageTypeBeforeCalculation(actor, enemy, ref isNormalAttack, ref isMagic, ref magicType); @@ -1326,7 +1332,7 @@ namespace Milimoe.FunGame.Core.Model } Dictionary totalDamageBonus = []; - effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; foreach (Effect effect in effects) { double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, true, magicType, totalDamageBonus); @@ -1340,7 +1346,7 @@ namespace Milimoe.FunGame.Core.Model bool checkCritical = true; if (isNormalAttack) { - effects = actor.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { checkEvade = effect.BeforeEvadeCheck(actor, ref throwingBonus); @@ -1354,7 +1360,7 @@ namespace Milimoe.FunGame.Core.Model finalDamage = 0; List characters = [actor, enemy]; bool isAlterEvaded = false; - effects = characters.SelectMany(c => c.Effects.Where(e => e.Level > 0)).ToList(); + effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))]; foreach (Effect effect in effects) { if (effect.OnEvadedTriggered(actor, enemy, dice)) @@ -1391,7 +1397,7 @@ namespace Milimoe.FunGame.Core.Model finalDamage = expectedDamage * (1 - MDF); // 暴击判定 - effects = actor.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { checkCritical = effect.BeforeCriticalCheck(actor, ref throwingBonus); @@ -1404,7 +1410,7 @@ namespace Milimoe.FunGame.Core.Model { finalDamage *= actor.CritDMG; // 暴击伤害倍率加成 WriteLine("暴击生效!!"); - effects = actor.Effects.Where(e => e.Level > 0).ToList(); + effects = [.. actor.Effects.Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.OnCriticalDamageTriggered(actor, dice); @@ -1426,7 +1432,7 @@ namespace Milimoe.FunGame.Core.Model foreach (Character enemy in _roundDeaths) { // 给所有角色的特效广播角色死亡结算 - List effects = _queue.SelectMany(c => c.Effects.Where(e => e.Level > 0)).ToList(); + List effects = [.. _queue.SelectMany(c => c.Effects.Where(e => e.Level > 0))]; foreach (Effect effect in effects) { effect.AfterDeathCalculation(enemy, character, _continuousKilling, _earnedMoney); @@ -1440,7 +1446,7 @@ namespace Milimoe.FunGame.Core.Model if (MaxRespawnTimes != 0) { - string[] teamActive = Teams.OrderByDescending(kv => kv.Value.Score).Select(kv => + string[] teamActive = [.. Teams.OrderByDescending(kv => kv.Value.Score).Select(kv => { int activeCount = kv.Value.GetActiveCharacters(this).Count; if (kv.Value == killTeam) @@ -1448,7 +1454,7 @@ namespace Milimoe.FunGame.Core.Model activeCount += 1; } return kv.Key + ":" + kv.Value.Score + "(剩余存活人数:" + activeCount + ")"; - }).ToArray(); + })]; WriteLine($"\r\n=== 当前死亡竞赛比分 ===\r\n{string.Join("\r\n", teamActive)}"); } @@ -1521,7 +1527,7 @@ namespace Milimoe.FunGame.Core.Model _stats[death].Deaths += 1; int money = Random.Shared.Next(250, 350); - Character[] assists = _assistDamage.Keys.Where(c => c != death && _assistDamage[c].GetPercentage(death) > 0.10).ToArray(); + Character[] assists = [.. _assistDamage.Keys.Where(c => c != death && _assistDamage[c].GetPercentage(death) > 0.10)]; double totalDamagePercentage = _assistDamage.Keys.Where(assists.Contains).Select(c => _assistDamage[c].GetPercentage(death)).Sum(); int totalMoney = Math.Min(Convert.ToInt32(money * totalDamagePercentage), 425); // 防止刷伤害设置金钱上限 @@ -1844,7 +1850,7 @@ namespace Milimoe.FunGame.Core.Model // 有 65% 欲望插队 if (Random.Shared.NextDouble() < 0.65) { - List skills = other.Skills.Where(s => s.Level > 0 && s.SkillType == SkillType.SuperSkill && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && other.EP >= s.RealEPCost).ToList(); + List skills = [.. other.Skills.Where(s => s.Level > 0 && s.SkillType == SkillType.SuperSkill && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && other.EP >= s.RealEPCost)]; if (skills.Count > 0) { Skill skill = skills[Random.Shared.Next(skills.Count)]; @@ -1887,7 +1893,7 @@ namespace Milimoe.FunGame.Core.Model if (skill != null) { WriteLine($"[ {caster} ] 的施法被 [ {interrupter} ] 打断了!!"); - List effects = skill.Effects.Where(e => e.Level > 0).ToList(); + List effects = [.. skill.Effects.Where(e => e.Level > 0)]; foreach (Effect e in effects) { e.OnSkillCastInterrupted(caster, skill, interrupter); @@ -2035,13 +2041,12 @@ namespace Milimoe.FunGame.Core.Model /// public virtual List SelectTargets(Character caster, Skill skill, List enemys, List teammates, out bool cancel) { - cancel = false; - if (skill.SkillType == SkillType.SuperSkill) cancel = false; - List targets = skill.SelectTargets(caster, enemys, teammates); + List targets = OnSelectSkillTargets(caster, skill, enemys, teammates); if (targets.Count == 0) { - cancel = true; + targets = skill.SelectTargets(caster, enemys, teammates); } + cancel = targets.Count == 0; return targets; } @@ -2056,13 +2061,58 @@ namespace Milimoe.FunGame.Core.Model /// public virtual List SelectTargets(Character character, NormalAttack attack, List enemys, List teammates, out bool cancel) { - cancel = false; - if (enemys.Count > 0) + List targets = OnSelectNormalAttackTargets(character, attack, enemys, teammates); + if (targets.Count == 0 && enemys.Count > 0) { - List targets = [enemys[Random.Shared.Next(enemys.Count)]]; - return targets; + targets = [enemys[Random.Shared.Next(enemys.Count)]]; } - return []; + cancel = targets.Count == 0; + return targets; + } + + public delegate CharacterActionType DecideActionEventHandler(Character character, double pUseItem, double pCastSkill, double pNormalAttack); + public event DecideActionEventHandler? DecideAction; + /// + /// 决定角色的行动事件 + /// + /// + /// + /// + /// + /// + public CharacterActionType OnDecideAction(Character character, double pUseItem, double pCastSkill, double pNormalAttack) + { + return DecideAction?.Invoke(character, pUseItem, pCastSkill, pNormalAttack) ?? CharacterActionType.None; + } + + public delegate List SelectSkillTargetsEventHandler(Character caster, Skill skill, List enemys, List teammates); + public event SelectSkillTargetsEventHandler? SelectSkillTargets; + /// + /// 选取技能目标事件 + /// + /// + /// + /// + /// + /// + public List OnSelectSkillTargets(Character caster, Skill skill, List enemys, List teammates) + { + return SelectSkillTargets?.Invoke(caster, skill, enemys, teammates) ?? []; + } + + public delegate List SelectNormalAttackTargetsEventHandler(Character character, NormalAttack attack, List enemys, List teammates); + public event SelectNormalAttackTargetsEventHandler? SelectNormalAttackTargets; + /// + /// 选取普通攻击目标事件 + /// + /// + /// + /// + /// + /// + public List OnSelectNormalAttackTargets(Character character, NormalAttack attack, List enemys, List teammates) + { + return SelectNormalAttackTargets?.Invoke(character, attack, enemys, teammates) ?? []; } } }