对行动顺序表中的部分特效钩子做修改;添加判断角色是否处于 AI 控制下的工具方法

This commit is contained in:
milimoe 2025-04-16 01:24:04 +08:00
parent e19be862da
commit 56d2dc6756
Signed by: milimoe
GPG Key ID: 05D280912DA6C69E
5 changed files with 113 additions and 53 deletions

View File

@ -341,10 +341,11 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 闪避检定前触发 /// 闪避检定前触发
/// </summary> /// </summary>
/// <param name="character"></param> /// <param name="actor"></param>
/// <param name="enemy"></param>
/// <param name="throwingBonus"></param> /// <param name="throwingBonus"></param>
/// <returns>返回 false 表示不进行闪避检定</returns> /// <returns>返回 false 表示不进行闪避检定</returns>
public virtual bool BeforeEvadeCheck(Character character, ref double throwingBonus) public virtual bool BeforeEvadeCheck(Character actor, Character enemy, ref double throwingBonus)
{ {
return true; return true;
} }
@ -352,11 +353,11 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 在触发闪避时 /// 在触发闪避时
/// </summary> /// </summary>
/// <param name="attacker"></param> /// <param name="actor"></param>
/// <param name="evader"></param> /// <param name="enemy"></param>
/// <param name="dice"></param> /// <param name="dice"></param>
/// <returns>返回 true 表示无视闪避</returns> /// <returns>返回 true 表示无视闪避</returns>
public virtual bool OnEvadedTriggered(Character attacker, Character evader, double dice) public virtual bool OnEvadedTriggered(Character actor, Character enemy, double dice)
{ {
return false; return false;
} }
@ -364,10 +365,11 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 暴击检定前触发 /// 暴击检定前触发
/// </summary> /// </summary>
/// <param name="character"></param> /// <param name="actor"></param>
/// <param name="enemy"></param>
/// <param name="throwingBonus"></param> /// <param name="throwingBonus"></param>
/// <returns>返回 false 表示不进行暴击检定</returns> /// <returns>返回 false 表示不进行暴击检定</returns>
public virtual bool BeforeCriticalCheck(Character character, ref double throwingBonus) public virtual bool BeforeCriticalCheck(Character actor, Character enemy, ref double throwingBonus)
{ {
return true; return true;
} }
@ -375,9 +377,10 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 在触发暴击时 /// 在触发暴击时
/// </summary> /// </summary>
/// <param name="character"></param> /// <param name="actor"></param>
/// <param name="enemy"></param>
/// <param name="dice"></param> /// <param name="dice"></param>
public virtual void OnCriticalDamageTriggered(Character character, double dice) public virtual void OnCriticalDamageTriggered(Character actor, Character enemy, double dice)
{ {
} }
@ -401,10 +404,22 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="skills"></param> /// <param name="skills"></param>
/// <param name="continuousKilling"></param> /// <param name="continuousKilling"></param>
/// <param name="earnedMoney"></param> /// <param name="earnedMoney"></param>
/// <returns>返回 true 表示更改生效</returns> public virtual void AlterSelectListBeforeAction(Character character, List<Character> enemys, List<Character> teammates, List<Skill> skills, Dictionary<Character, int> continuousKilling, Dictionary<Character, int> earnedMoney)
public virtual bool AlterEnemyListBeforeAction(Character character, List<Character> enemys, List<Character> teammates, List<Skill> skills, Dictionary<Character, int> continuousKilling, Dictionary<Character, int> earnedMoney)
{ {
return false;
}
/// <summary>
/// 开始选择目标前,修改可选择的 <paramref name="enemys"/>, <paramref name="teammates"/> 列表<para/>
/// <see cref="ISkill"/> 有两种,使用时注意判断是 <see cref="Entity.Skill"/> 还是 <see cref="NormalAttack"/>
/// </summary>
/// <param name="character"></param>
/// <param name="skill"></param>
/// <param name="enemys"></param>
/// <param name="teammates"></param>
public virtual void AlterSelectListBeforeSelection(Character character, ISkill skill, List<Character> enemys, List<Character> teammates)
{
} }
/// <summary> /// <summary>
@ -462,6 +477,16 @@ namespace Milimoe.FunGame.Core.Entity
GamingQueue?.InterruptCastingAsync(caster, interrupter); GamingQueue?.InterruptCastingAsync(caster, interrupter);
} }
/// <summary>
/// 检查角色是否在 AI 控制状态
/// </summary>
/// <param name="character"></param>
/// <returns></returns>
public bool IsCharacterInAIControlling(Character character)
{
return GamingQueue?.IsCharacterInAIControlling(character) ?? false;
}
/// <summary> /// <summary>
/// 返回特效详情 /// 返回特效详情
/// </summary> /// </summary>

View File

@ -370,7 +370,7 @@ namespace Milimoe.FunGame.Core.Entity
} }
/// <summary> /// <summary>
/// 触发技能效果 /// 触发技能效果 [ 局内版 ]
/// </summary> /// </summary>
/// <param name="queue"></param> /// <param name="queue"></param>
/// <param name="caster"></param> /// <param name="caster"></param>
@ -397,6 +397,16 @@ namespace Milimoe.FunGame.Core.Entity
} }
} }
/// <summary>
/// 检查角色是否在 AI 控制状态
/// </summary>
/// <param name="character"></param>
/// <returns></returns>
public bool IsCharacterInAIControlling(Character character)
{
return GamingQueue?.IsCharacterInAIControlling(character) ?? false;
}
/// <summary> /// <summary>
/// 被动技能,需要重写此方法,返回被动特效给角色 [ 此方法会在技能学习时触发 ] /// 被动技能,需要重写此方法,返回被动特效给角色 [ 此方法会在技能学习时触发 ]
/// </summary> /// </summary>

View File

@ -159,5 +159,11 @@ namespace Milimoe.FunGame.Core.Interface.Base
/// <param name="teammates"></param> /// <param name="teammates"></param>
/// <returns></returns> /// <returns></returns>
public Task<List<Character>> SelectTargetsAsync(Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates); public Task<List<Character>> SelectTargetsAsync(Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates);
/// <summary>
/// 检查角色是否在 AI 控制状态
/// </summary>
/// <returns></returns>
public bool IsCharacterInAIControlling(Character character);
} }
} }

View File

@ -122,7 +122,7 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
return $"{Command_Delete} {Command_From} {TableName} {builder}"; return $"{Command_Delete} {Command_From} {TableName} {builder}";
} }
} }
return $"{Command_Delete} {Command_From} {TableName} {Command_Where} 1 = 0"; return $"{Command_Delete} {Command_From} {TableName}";
} }
public static string Delete_QuitRoom(SQLHelper SQLHelper, string Roomid, long RoomMaster) public static string Delete_QuitRoom(SQLHelper SQLHelper, string Roomid, long RoomMaster)

View File

@ -13,7 +13,7 @@ namespace Milimoe.FunGame.Core.Model
/// <summary> /// <summary>
/// 使用的游戏平衡常数 /// 使用的游戏平衡常数
/// </summary> /// </summary>
public EquilibriumConstant GameplayEquilibriumConstant { get; } = General.GameplayEquilibriumConstant; public EquilibriumConstant GameplayEquilibriumConstant { get; set; } = General.GameplayEquilibriumConstant;
/// <summary> /// <summary>
/// 用于文本输出 /// 用于文本输出
@ -658,9 +658,9 @@ namespace Milimoe.FunGame.Core.Model
{ {
CharacterActionType actionTypeTemp = CharacterActionType.None; CharacterActionType actionTypeTemp = CharacterActionType.None;
effects = [.. character.Effects.Where(e => e.Level > 0)]; effects = [.. character.Effects.Where(e => e.Level > 0)];
foreach (Effect e in effects) foreach (Effect effect in effects)
{ {
actionTypeTemp = e.AlterActionTypeBeforeAction(character, character.CharacterState, ref canUseItem, ref canCastSkill, ref pUseItem, ref pCastSkill, ref pNormalAttack); actionTypeTemp = effect.AlterActionTypeBeforeAction(character, character.CharacterState, ref canUseItem, ref canCastSkill, ref pUseItem, ref pCastSkill, ref pNormalAttack);
} }
if (actionTypeTemp != CharacterActionType.None && actionTypeTemp != CharacterActionType.CastSkill && actionTypeTemp != CharacterActionType.CastSuperSkill) if (actionTypeTemp != CharacterActionType.None && actionTypeTemp != CharacterActionType.CastSkill && actionTypeTemp != CharacterActionType.CastSuperSkill)
{ {
@ -769,30 +769,25 @@ namespace Milimoe.FunGame.Core.Model
} }
} }
List<Character> enemysTemp = [.. enemys];
List<Character> teammatesTemp = [.. teammates];
List<Skill> skillsTemp = [.. skills];
Dictionary<Character, int> continuousKillingTemp = new(_continuousKilling); Dictionary<Character, int> continuousKillingTemp = new(_continuousKilling);
Dictionary<Character, int> earnedMoneyTemp = new(_earnedMoney); Dictionary<Character, int> earnedMoneyTemp = new(_earnedMoney);
effects = [.. character.Effects.Where(e => e.Level > 0)]; effects = [.. character.Effects.Where(e => e.Level > 0)];
foreach (Effect e in effects) foreach (Effect effect in effects)
{ {
if (e.AlterEnemyListBeforeAction(character, enemysTemp, teammatesTemp, skillsTemp, continuousKillingTemp, earnedMoneyTemp)) effect.AlterSelectListBeforeAction(character, enemys, teammates, skills, continuousKillingTemp, earnedMoneyTemp);
{
enemys = [.. enemysTemp.Distinct()];
teammates = [.. teammatesTemp.Distinct()];
skills = [.. skillsTemp.Distinct()];
}
} }
if (type == CharacterActionType.NormalAttack) if (type == CharacterActionType.NormalAttack)
{ {
// 使用普通攻击逻辑 // 使用普通攻击逻辑
List<Character> targets = await SelectTargetsAsync(character, character.NormalAttack, enemys, teammates); List<Character> targets = await SelectTargetsAsync(character, character.NormalAttack, enemys, teammates);
if (targets.Count == 0 && _charactersInAI.Contains(character) && enemys.Count > 0) if (targets.Count == 0 && _charactersInAI.Contains(character))
{ {
// 如果没有选取目标,且角色在 AI 控制下,则随机选取一个目标 // 如果没有选取目标,且角色在 AI 控制下,则随机选取目标
targets = [enemys[Random.Shared.Next(enemys.Count)]]; 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) if (targets.Count > 0)
{ {
@ -1078,7 +1073,7 @@ namespace Milimoe.FunGame.Core.Model
RemoveRoundRewards(TotalRound, character, rewards); RemoveRoundRewards(TotalRound, character, rewards);
// 有人想要插队吗? // 有人想要插队吗?
await WillPreCastSuperSkill(character); await WillPreCastSuperSkill();
// 回合结束事件 // 回合结束事件
await OnTurnEndAsync(character); await OnTurnEndAsync(character);
@ -1374,9 +1369,10 @@ namespace Milimoe.FunGame.Core.Model
/// <returns></returns> /// <returns></returns>
public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage) public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage)
{ {
List<Character> characters = [actor, enemy];
bool isMagic = false; bool isMagic = false;
MagicType magicType = MagicType.None; MagicType magicType = MagicType.None;
List<Effect> effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
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 isMagic, ref magicType);
@ -1401,10 +1397,10 @@ namespace Milimoe.FunGame.Core.Model
bool checkCritical = true; bool checkCritical = true;
if (isNormalAttack) if (isNormalAttack)
{ {
effects = [.. actor.Effects.Where(e => e.Level > 0)]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
checkEvade = effect.BeforeEvadeCheck(actor, ref throwingBonus); checkEvade = effect.BeforeEvadeCheck(actor, enemy, ref throwingBonus);
} }
if (checkEvade) if (checkEvade)
@ -1413,7 +1409,6 @@ namespace Milimoe.FunGame.Core.Model
if (dice < (enemy.EvadeRate + throwingBonus)) if (dice < (enemy.EvadeRate + throwingBonus))
{ {
finalDamage = 0; finalDamage = 0;
List<Character> characters = [actor, enemy];
bool isAlterEvaded = false; bool isAlterEvaded = false;
effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects) foreach (Effect effect in effects)
@ -1442,10 +1437,10 @@ namespace Milimoe.FunGame.Core.Model
finalDamage = expectedDamage * (1 - Calculation.PercentageCheck(physicalDamageReduction + enemy.ExPDR)); finalDamage = expectedDamage * (1 - Calculation.PercentageCheck(physicalDamageReduction + enemy.ExPDR));
// 暴击判定 // 暴击判定
effects = [.. actor.Effects.Where(e => e.Level > 0)]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
checkCritical = effect.BeforeCriticalCheck(actor, ref throwingBonus); checkCritical = effect.BeforeCriticalCheck(actor, enemy, ref throwingBonus);
} }
if (checkCritical) if (checkCritical)
@ -1455,10 +1450,10 @@ namespace Milimoe.FunGame.Core.Model
{ {
finalDamage *= actor.CritDMG; // 暴击伤害倍率加成 finalDamage *= actor.CritDMG; // 暴击伤害倍率加成
WriteLine("暴击生效!!"); WriteLine("暴击生效!!");
effects = [.. actor.Effects.Where(e => e.Level > 0)]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
effect.OnCriticalDamageTriggered(actor, dice); effect.OnCriticalDamageTriggered(actor, enemy, dice);
} }
return DamageResult.Critical; return DamageResult.Critical;
} }
@ -1480,8 +1475,9 @@ namespace Milimoe.FunGame.Core.Model
/// <returns></returns> /// <returns></returns>
public DamageResult CalculateMagicalDamage(Character actor, Character enemy, 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)
{ {
List<Character> characters = [actor, enemy];
bool isMagic = true; bool isMagic = true;
List<Effect> effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; List<Effect> effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
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 isMagic, ref magicType);
@ -1492,7 +1488,7 @@ namespace Milimoe.FunGame.Core.Model
} }
Dictionary<Effect, double> totalDamageBonus = []; Dictionary<Effect, double> totalDamageBonus = [];
effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
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, true, magicType, totalDamageBonus);
@ -1506,10 +1502,10 @@ namespace Milimoe.FunGame.Core.Model
bool checkCritical = true; bool checkCritical = true;
if (isNormalAttack) if (isNormalAttack)
{ {
effects = [.. actor.Effects.Where(e => e.Level > 0)]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
checkEvade = effect.BeforeEvadeCheck(actor, ref throwingBonus); checkEvade = effect.BeforeEvadeCheck(actor, enemy, ref throwingBonus);
} }
if (checkEvade) if (checkEvade)
@ -1518,7 +1514,6 @@ namespace Milimoe.FunGame.Core.Model
if (dice < (enemy.EvadeRate + throwingBonus)) if (dice < (enemy.EvadeRate + throwingBonus))
{ {
finalDamage = 0; finalDamage = 0;
List<Character> characters = [actor, enemy];
bool isAlterEvaded = false; bool isAlterEvaded = false;
effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects) foreach (Effect effect in effects)
@ -1557,10 +1552,10 @@ namespace Milimoe.FunGame.Core.Model
finalDamage = expectedDamage * (1 - MDF); finalDamage = expectedDamage * (1 - MDF);
// 暴击判定 // 暴击判定
effects = [.. actor.Effects.Where(e => e.Level > 0)]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
checkCritical = effect.BeforeCriticalCheck(actor, ref throwingBonus); checkCritical = effect.BeforeCriticalCheck(actor, enemy, ref throwingBonus);
} }
if (checkCritical) if (checkCritical)
@ -1570,10 +1565,10 @@ namespace Milimoe.FunGame.Core.Model
{ {
finalDamage *= actor.CritDMG; // 暴击伤害倍率加成 finalDamage *= actor.CritDMG; // 暴击伤害倍率加成
WriteLine("暴击生效!!"); WriteLine("暴击生效!!");
effects = [.. actor.Effects.Where(e => e.Level > 0)]; effects = [.. characters.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects) foreach (Effect effect in effects)
{ {
effect.OnCriticalDamageTriggered(actor, dice); effect.OnCriticalDamageTriggered(actor, enemy, dice);
} }
return DamageResult.Critical; return DamageResult.Critical;
} }
@ -2062,9 +2057,8 @@ namespace Milimoe.FunGame.Core.Model
/// <summary> /// <summary>
/// 是否在回合外释放爆发技插队(仅自动化,手动设置请调用:<see cref="SetCharacterPreCastSuperSkill"/> /// 是否在回合外释放爆发技插队(仅自动化,手动设置请调用:<see cref="SetCharacterPreCastSuperSkill"/>
/// </summary> /// </summary>
/// <param name="character">当前正在行动的角色</param>
/// <returns></returns> /// <returns></returns>
public async Task WillPreCastSuperSkill(Character character) public async Task WillPreCastSuperSkill()
{ {
// 选取所有 AI 控制角色 // 选取所有 AI 控制角色
foreach (Character other in _queue.Where(c => c.CharacterState == CharacterState.Actionable && _charactersInAI.Contains(c)).ToList()) foreach (Character other in _queue.Where(c => c.CharacterState == CharacterState.Actionable && _charactersInAI.Contains(c)).ToList())
@ -2102,10 +2096,15 @@ namespace Milimoe.FunGame.Core.Model
if (skill != null) if (skill != null)
{ {
WriteLine($"[ {caster} ] 的施法被 [ {interrupter} ] 打断了!!"); WriteLine($"[ {caster} ] 的施法被 [ {interrupter} ] 打断了!!");
List<Effect> effects = [.. skill.Effects.Where(e => e.Level > 0)]; List<Effect> effects = [.. caster.Effects.Where(e => e.Level > 0)];
foreach (Effect e in effects) foreach (Effect effect in effects)
{ {
e.OnSkillCastInterrupted(caster, skill, interrupter); effect.OnSkillCastInterrupted(caster, skill, interrupter);
}
effects = [.. 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);
@ -2370,6 +2369,16 @@ namespace Milimoe.FunGame.Core.Model
} }
} }
/// <summary>
/// 检查角色是否在 AI 控制状态
/// </summary>
/// <param name="character"></param>
/// <returns></returns>
public bool IsCharacterInAIControlling(Character character)
{
return _charactersInAI.Contains(character);
}
/// <summary> /// <summary>
/// 初始化回合奖励 /// 初始化回合奖励
/// </summary> /// </summary>
@ -2481,6 +2490,11 @@ namespace Milimoe.FunGame.Core.Model
/// <returns></returns> /// <returns></returns>
public virtual async Task<List<Character>> SelectTargetsAsync(Character caster, Skill skill, List<Character> enemys, List<Character> teammates) public virtual async Task<List<Character>> SelectTargetsAsync(Character caster, Skill skill, List<Character> enemys, List<Character> teammates)
{ {
List<Effect> effects = [.. caster.Effects.Where(e => e.Level > 0)];
foreach (Effect effect in effects)
{
effect.AlterSelectListBeforeSelection(caster, skill, enemys, teammates);
}
List<Character> targets = await OnSelectSkillTargetsAsync(caster, skill, enemys, teammates); List<Character> targets = await OnSelectSkillTargetsAsync(caster, skill, enemys, teammates);
if (targets.Count == 0 && _charactersInAI.Contains(caster)) if (targets.Count == 0 && _charactersInAI.Contains(caster))
{ {
@ -2499,6 +2513,11 @@ namespace Milimoe.FunGame.Core.Model
/// <returns></returns> /// <returns></returns>
public virtual async Task<List<Character>> SelectTargetsAsync(Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates) public virtual async Task<List<Character>> SelectTargetsAsync(Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates)
{ {
List<Effect> effects = [.. character.Effects.Where(e => e.Level > 0)];
foreach (Effect effect in effects)
{
effect.AlterSelectListBeforeSelection(character, attack, enemys, teammates);
}
List<Character> targets = await OnSelectNormalAttackTargetsAsync(character, attack, enemys, teammates); List<Character> targets = await OnSelectNormalAttackTargetsAsync(character, attack, enemys, teammates);
return targets; return targets;
} }