diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs index 3c31303..6b54e16 100644 --- a/Entity/Character/Character.cs +++ b/Entity/Character/Character.cs @@ -1778,6 +1778,7 @@ namespace Milimoe.FunGame.Core.Entity bool isActionRestricted = false; bool isBattleRestricted = false; bool isSkillRestricted = false; + bool isAttackRestricted = false; IEnumerable states = CharacterEffectStates.Values.SelectMany(list => list); // 根据持有的特效判断角色所处的状态 @@ -1785,12 +1786,13 @@ namespace Milimoe.FunGame.Core.Entity isActionRestricted = states.Any(state => state == CharacterState.ActionRestricted); isBattleRestricted = states.Any(state => state == CharacterState.BattleRestricted); isSkillRestricted = states.Any(state => state == CharacterState.SkillRestricted); + isAttackRestricted = states.Any(state => state == CharacterState.AttackRestricted); IEnumerable types = CharacterEffectTypes.Values.SelectMany(list => list); // 判断角色的控制效果 IsUnselectable = types.Any(type => type == EffectType.Unselectable); - bool isControl = isNotActionable || isActionRestricted || isBattleRestricted || isSkillRestricted; + bool isControl = isNotActionable || isActionRestricted || isBattleRestricted || isSkillRestricted || isAttackRestricted; bool isCasting = CharacterState == CharacterState.Casting; bool isPreCastSuperSkill = CharacterState == CharacterState.PreCastSuperSkill; @@ -1810,6 +1812,10 @@ namespace Milimoe.FunGame.Core.Entity { CharacterState = CharacterState.SkillRestricted; } + else if (isAttackRestricted) + { + CharacterState = CharacterState.AttackRestricted; + } if (!isControl && !isCasting && !isPreCastSuperSkill) { diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs index e4c6933..bcdb8e3 100644 --- a/Entity/Skill/Skill.cs +++ b/Entity/Skill/Skill.cs @@ -308,6 +308,7 @@ namespace Milimoe.FunGame.Core.Entity { selectable.AddRange(enemys); } + if (CanSelectTeammate) { selectable.AddRange(teammates); @@ -430,7 +431,7 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine("技能描述:" + (Level == 0 && GeneralDescription.Trim() != "" ? GeneralDescription : Description)); if (CurrentCD > 0) { - builder.AppendLine($"正在冷却:剩余 {CurrentCD:0.##} 时间"); + builder.AppendLine($"正在冷却:剩余 {CurrentCD:0.##} {GameplayEquilibriumConstant.InGameTime}"); } if (!Enable) { diff --git a/Interface/Base/IGamingQueue.cs b/Interface/Base/IGamingQueue.cs index 03af429..7ea52d6 100644 --- a/Interface/Base/IGamingQueue.cs +++ b/Interface/Base/IGamingQueue.cs @@ -130,6 +130,12 @@ namespace Milimoe.FunGame.Core.Interface.Base /// public Task InterruptCastingAsync(Character caster, Character interrupter); + /// + /// 打断施法 [ 用于使敌人目标丢失 ] + /// + /// + public Task InterruptCastingAsync(Character interrupter); + /// /// 使用物品 /// diff --git a/Library/Constant/StateEnum.cs b/Library/Constant/StateEnum.cs index ec24a5f..182bee6 100644 --- a/Library/Constant/StateEnum.cs +++ b/Library/Constant/StateEnum.cs @@ -57,6 +57,11 @@ namespace Milimoe.FunGame.Core.Library.Constant /// 技能受限 [ 战斗相关 ] /// SkillRestricted, + + /// + /// 攻击受限 [ 战斗相关 ] + /// + AttackRestricted, /// /// 处于吟唱中 [ 战斗相关 ] [ 技能相关 ] diff --git a/Model/ActionQueue.cs b/Model/ActionQueue.cs index 95a2df4..e3a339b 100644 --- a/Model/ActionQueue.cs +++ b/Model/ActionQueue.cs @@ -741,6 +741,15 @@ namespace Milimoe.FunGame.Core.Model pCastSkill = 0; } } + else if (character.CharacterState == CharacterState.AttackRestricted) + { + // 攻击受限,无法普通攻击,可以使用技能,可以使用物品 + pNormalAttack = 0; + if (!canUseItem) + { + pUseItem = 0; + } + } // 模组可以通过此事件来决定角色的行动 type = await OnDecideActionAsync(character, enemys, teammates, skills, items); @@ -779,29 +788,39 @@ namespace Milimoe.FunGame.Core.Model if (type == CharacterActionType.NormalAttack) { - // 使用普通攻击逻辑 - List targets = await SelectTargetsAsync(character, character.NormalAttack, enemys, teammates); - if (targets.Count == 0 && _charactersInAI.Contains(character)) + if (character.CharacterState == CharacterState.NotActionable || + character.CharacterState == CharacterState.ActionRestricted || + character.CharacterState == CharacterState.BattleRestricted || + character.CharacterState == CharacterState.AttackRestricted) { - // 如果没有选取目标,且角色在 AI 控制下,则随机选取目标 - if (enemys.Count > character.NormalAttack.CanSelectTargetCount) - targets = [.. enemys.OrderBy(o => Random.Shared.Next(enemys.Count)).Take(character.NormalAttack.CanSelectTargetCount)]; - else - targets = [.. enemys]; + WriteLine($"角色 [ {character} ] 状态为:{CharacterSet.GetCharacterState(character.CharacterState)},无法使用普通攻击!"); } - if (targets.Count > 0) + else { - LastRound.Targets = [.. targets]; - decided = true; - - await OnCharacterNormalAttackAsync(character, targets); - - character.NormalAttack.Attack(this, character, targets); - baseTime = character.NormalAttack.HardnessTime; - effects = [.. character.Effects.Where(e => e.Level > 0)]; - foreach (Effect effect in effects) + // 使用普通攻击逻辑 + List targets = await SelectTargetsAsync(character, character.NormalAttack, enemys, teammates); + if (targets.Count == 0 && _charactersInAI.Contains(character)) { - effect.AlterHardnessTimeAfterNormalAttack(character, ref baseTime, ref isCheckProtected); + // 如果没有选取目标,且角色在 AI 控制下,则随机选取目标 + if (enemys.Count > character.NormalAttack.CanSelectTargetCount) + targets = [.. enemys.OrderBy(o => Random.Shared.Next(enemys.Count)).Take(character.NormalAttack.CanSelectTargetCount)]; + else + targets = [.. enemys]; + } + if (targets.Count > 0) + { + LastRound.Targets = [.. targets]; + decided = true; + + await OnCharacterNormalAttackAsync(character, targets); + + character.NormalAttack.Attack(this, character, targets); + baseTime = character.NormalAttack.HardnessTime; + effects = [.. character.Effects.Where(e => e.Level > 0)]; + foreach (Effect effect in effects) + { + effect.AlterHardnessTimeAfterNormalAttack(character, ref baseTime, ref isCheckProtected); + } } } } @@ -1022,8 +1041,16 @@ namespace Milimoe.FunGame.Core.Model // 统一在回合结束时处理角色的死亡 await ProcessCharacterDeathAsync(character); + // 移除回合奖励 + RemoveRoundRewards(TotalRound, character, rewards); + if (_isGameEnd) { + // 回合结束事件 + await OnTurnEndAsync(character); + + await AfterTurnAsync(character); + return _isGameEnd; } @@ -1069,9 +1096,6 @@ namespace Milimoe.FunGame.Core.Model } } - // 移除回合奖励 - RemoveRoundRewards(TotalRound, character, rewards); - // 有人想要插队吗? await WillPreCastSuperSkill(); @@ -1895,6 +1919,7 @@ namespace Milimoe.FunGame.Core.Model /// public async Task EndGameInfo(Team winner) { + winner.IsWinner = true; WriteLine("[ " + winner + " ] 是胜利者。"); if (!await OnGameEndTeamAsync(winner)) @@ -2095,19 +2120,37 @@ namespace Milimoe.FunGame.Core.Model } if (skill != null) { - WriteLine($"[ {caster} ] 的施法被 [ {interrupter} ] 打断了!!"); - List effects = [.. caster.Effects.Where(e => e.Level > 0)]; + WriteLine($"[ {caster} ] 的{(skill.IsSuperSkill ? "预释放爆发技" : "施法")}被 [ {interrupter} ] 打断了!!"); + List effects = [.. caster.Effects.Union(interrupter.Effects).Where(e => e.Level > 0)]; foreach (Effect effect in effects) { effect.OnSkillCastInterrupted(caster, skill, interrupter); } - effects = [.. interrupter.Effects.Where(e => e.Level > 0)]; - foreach (Effect effect in effects) + await OnInterruptCastingAsync(caster, skill, interrupter); + } + } + + /// + /// 打断施法 [ 用于使敌人目标丢失 ] + /// + /// + public async Task InterruptCastingAsync(Character interrupter) + { + foreach (Character caster in _castingSkills.Keys) + { + SkillTarget skillTarget = _castingSkills[caster]; + if (skillTarget.Targets.Contains(interrupter)) { - effect.OnSkillCastInterrupted(caster, skill, interrupter); + Skill skill = skillTarget.Skill; + WriteLine($"[ {interrupter} ] 打断了 [ {caster} ] 的施法!!"); + List effects = [.. caster.Effects.Union(interrupter.Effects).Where(e => e.Level > 0)]; + foreach (Effect effect in effects) + { + effect.OnSkillCastInterrupted(caster, skill, interrupter); + } + await OnInterruptCastingAsync(caster, skill, interrupter); } } - await OnInterruptCastingAsync(caster, skill, interrupter); } /// @@ -2657,7 +2700,7 @@ namespace Milimoe.FunGame.Core.Model /// /// /// - protected async Task OnInterruptCastingAsync(Character cast, Skill? skill, Character interrupter) + protected async Task OnInterruptCastingAsync(Character cast, Skill skill, Character interrupter) { await (InterruptCasting?.Invoke(this, cast, skill, interrupter) ?? Task.CompletedTask); }