From 2c0153ef5fd726292cc4ab4a8c6b4bcedfd5a41d Mon Sep 17 00:00:00 2001
From: milimoe <110188673+milimoe@users.noreply.github.com>
Date: Sat, 12 Apr 2025 00:21:16 +0800
Subject: [PATCH] =?UTF-8?q?=E5=BC=82=E6=AD=A5=E7=89=88=E8=A1=8C=E5=8A=A8?=
=?UTF-8?q?=E9=A1=BA=E5=BA=8F=E8=A1=A8=20(#126)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Entity/Item/Item.cs | 4 +-
Entity/Skill/Effect.cs | 12 +-
Entity/Skill/NormalAttack.cs | 2 +-
Interface/Base/IGamingQueue.cs | 20 +-
Model/ActionQueue.cs | 554 ++++++++++++++++++++++++---------
5 files changed, 431 insertions(+), 161 deletions(-)
diff --git a/Entity/Item/Item.cs b/Entity/Item/Item.cs
index 2e07bda..7e14082 100644
--- a/Entity/Item/Item.cs
+++ b/Entity/Item/Item.cs
@@ -307,7 +307,7 @@ namespace Milimoe.FunGame.Core.Entity
/// 局内使用物品触发
///
///
- public bool UseItem(IGamingQueue queue, Character character, List enemys, List teammates)
+ public async Task UseItem(IGamingQueue queue, Character character, List enemys, List teammates)
{
bool cancel = false;
bool used = false;
@@ -318,7 +318,7 @@ namespace Milimoe.FunGame.Core.Entity
}
if (result && Skills.Active != null)
{
- used = queue.UseItem(this, character, enemys, teammates);
+ used = await queue.UseItemAsync(this, character, enemys, teammates);
}
if (used)
{
diff --git a/Entity/Skill/Effect.cs b/Entity/Skill/Effect.cs
index 4bf9ee4..3ea8b0f 100644
--- a/Entity/Skill/Effect.cs
+++ b/Entity/Skill/Effect.cs
@@ -420,7 +420,7 @@ namespace Milimoe.FunGame.Core.Entity
}
///
- /// 对敌人造成技能伤害 [ 强烈建议使用此方法造成伤害而不是自行调用 ]
+ /// 对敌人造成技能伤害 [ 强烈建议使用此方法造成伤害而不是自行调用 ]
///
///
///
@@ -432,12 +432,12 @@ namespace Milimoe.FunGame.Core.Entity
{
if (GamingQueue is null) return DamageResult.Evaded;
DamageResult result = !isMagic ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out double damage) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage);
- GamingQueue.DamageToEnemy(actor, enemy, damage, false, isMagic, magicType, result);
+ GamingQueue.DamageToEnemyAsync(actor, enemy, damage, false, isMagic, magicType, result);
return result;
}
///
- /// 治疗一个目标 [ 强烈建议使用此方法而不是自行调用 ]
+ /// 治疗一个目标 [ 强烈建议使用此方法而不是自行调用 ]
///
///
///
@@ -445,17 +445,17 @@ namespace Milimoe.FunGame.Core.Entity
///
public void HealToTarget(Character actor, Character target, double heal, bool canRespawn = false)
{
- GamingQueue?.HealToTarget(actor, target, heal, canRespawn);
+ GamingQueue?.HealToTargetAsync(actor, target, heal, canRespawn);
}
///
- /// 打断施法 [ 尽可能的调用此方法而不是直接调用 ,以防止中断性变更 ]
+ /// 打断施法 [ 尽可能的调用此方法而不是直接调用 ,以防止中断性变更 ]
///
///
///
public void InterruptCasting(Character caster, Character interrupter)
{
- GamingQueue?.InterruptCasting(caster, interrupter);
+ GamingQueue?.InterruptCastingAsync(caster, interrupter);
}
///
diff --git a/Entity/Skill/NormalAttack.cs b/Entity/Skill/NormalAttack.cs
index 8089464..46b1657 100644
--- a/Entity/Skill/NormalAttack.cs
+++ b/Entity/Skill/NormalAttack.cs
@@ -72,7 +72,7 @@ namespace Milimoe.FunGame.Core.Entity
queue.WriteLine("[ " + Character + $" ] 对 [ {enemy} ] 发起了普通攻击!");
double expected = Damage;
DamageResult result = IsMagic ? queue.CalculateMagicalDamage(attacker, enemy, true, MagicType, expected, out double damage) : queue.CalculatePhysicalDamage(attacker, enemy, true, expected, out damage);
- queue.DamageToEnemy(attacker, enemy, damage, true, IsMagic, MagicType, result);
+ queue.DamageToEnemyAsync(attacker, enemy, damage, true, IsMagic, MagicType, result);
}
}
}
diff --git a/Interface/Base/IGamingQueue.cs b/Interface/Base/IGamingQueue.cs
index 160a236..2486ddc 100644
--- a/Interface/Base/IGamingQueue.cs
+++ b/Interface/Base/IGamingQueue.cs
@@ -70,7 +70,7 @@ namespace Milimoe.FunGame.Core.Interface.Base
///
///
///
- public bool ProcessTurn(Character character);
+ public Task ProcessTurnAsync(Character character);
///
/// 造成伤害
@@ -82,8 +82,8 @@ namespace Milimoe.FunGame.Core.Interface.Base
///
///
///
- public void DamageToEnemy(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, bool isMagicDamage = false, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal);
+
///
/// 治疗一个目标
///
@@ -91,8 +91,8 @@ namespace Milimoe.FunGame.Core.Interface.Base
///
///
///
- public void HealToTarget(Character actor, Character target, double heal, bool canRespawn = false);
-
+ public Task HealToTargetAsync(Character actor, Character target, double heal, bool canRespawn = false);
+
///
/// 计算物理伤害
///
@@ -121,14 +121,14 @@ namespace Milimoe.FunGame.Core.Interface.Base
///
///
///
- public void DeathCalculation(Character killer, Character death);
+ public Task DeathCalculationAsync(Character killer, Character death);
///
/// 打断施法
///
///
///
- public void InterruptCasting(Character caster, Character interrupter);
+ public Task InterruptCastingAsync(Character caster, Character interrupter);
///
/// 使用物品
@@ -138,7 +138,7 @@ namespace Milimoe.FunGame.Core.Interface.Base
///
///
///
- public bool UseItem(Item item, Character caster, List enemys, List teammates);
+ public Task UseItemAsync(Item item, Character caster, List enemys, List teammates);
///
/// 选取技能目标
@@ -148,7 +148,7 @@ namespace Milimoe.FunGame.Core.Interface.Base
///
///
///
- public List SelectTargets(Character caster, Skill skill, List enemys, List teammates);
+ public Task> SelectTargetsAsync(Character caster, Skill skill, List enemys, List teammates);
///
/// 选取普通攻击目标
@@ -158,6 +158,6 @@ namespace Milimoe.FunGame.Core.Interface.Base
///
///
///
- public List SelectTargets(Character character, NormalAttack attack, List enemys, List teammates);
+ public Task> SelectTargetsAsync(Character character, NormalAttack attack, List enemys, List teammates);
}
}
diff --git a/Model/ActionQueue.cs b/Model/ActionQueue.cs
index e01da10..b878476 100644
--- a/Model/ActionQueue.cs
+++ b/Model/ActionQueue.cs
@@ -542,9 +542,9 @@ namespace Milimoe.FunGame.Core.Model
/// 回合开始前触发
///
///
- public virtual bool BeforeTurn(Character character)
+ public virtual async Task BeforeTurnAsync(Character character)
{
- return true;
+ return await Task.FromResult(true);
}
///
@@ -552,12 +552,12 @@ namespace Milimoe.FunGame.Core.Model
///
///
/// 是否结束游戏
- public bool ProcessTurn(Character character)
+ public async Task ProcessTurnAsync(Character character)
{
LastRound.Actor = character;
_roundDeaths.Clear();
- if (!BeforeTurn(character))
+ if (!await BeforeTurnAsync(character))
{
return _isGameEnd;
}
@@ -587,7 +587,7 @@ namespace Milimoe.FunGame.Core.Model
i.Skills.Active.SkillType == SkillType.Item && i.Skills.Active.Enable && !i.Skills.Active.IsInEffect && i.Skills.Active.CurrentCD == 0 && i.Skills.Active.RealMPCost <= character.MP && i.Skills.Active.RealEPCost <= character.EP)];
// 回合开始事件,允许事件返回 false 接管回合操作
- if (!OnTurnStart(character, enemys, teammates, skills, items))
+ if (!await OnTurnStartAsync(character, enemys, teammates, skills, items))
{
return _isGameEnd;
}
@@ -634,8 +634,8 @@ namespace Milimoe.FunGame.Core.Model
if (character.CharacterState != CharacterState.NotActionable && character.CharacterState != CharacterState.Casting && character.CharacterState != CharacterState.PreCastSuperSkill)
{
// 模组可以通过以下事件来决定角色的行动
- type = OnDecideAction(character, pUseItem, pCastSkill, pNormalAttack);
- if (type != CharacterActionType.None)
+ type = await OnDecideActionAsync(character, enemys, teammates, skills, items);
+ if (type == CharacterActionType.None)
{
// 若事件未完成决策,则将通过概率对角色进行自动化决策
if (character.CharacterState == CharacterState.Actionable)
@@ -742,7 +742,7 @@ namespace Milimoe.FunGame.Core.Model
if (type == CharacterActionType.NormalAttack)
{
// 使用普通攻击逻辑
- List targets = SelectTargets(character, character.NormalAttack, enemys, teammates);
+ List targets = await SelectTargetsAsync(character, character.NormalAttack, enemys, teammates);
if (targets.Count == 0 && _charactersInAI.Contains(character) && enemys.Count > 0)
{
// 如果没有选取目标,且角色在 AI 控制下,则随机选取一个目标
@@ -752,6 +752,9 @@ namespace Milimoe.FunGame.Core.Model
{
LastRound.Targets = [.. targets];
decided = true;
+
+ await OnCharacterActingAsync(character, CharacterActionType.NormalAttack, targets);
+
character.NormalAttack.Attack(this, character, targets);
baseTime = character.NormalAttack.HardnessTime;
effects = [.. character.Effects.Where(e => e.Level > 0)];
@@ -764,8 +767,8 @@ namespace Milimoe.FunGame.Core.Model
else if (type == CharacterActionType.PreCastSkill)
{
// 预使用技能,即开始吟唱逻辑
- Skill? skill = OnSelectSkill(character, skills);
- if (_charactersInAI.Contains(character))
+ Skill? skill = await OnSelectSkillAsync(character, skills);
+ if (skill is null && _charactersInAI.Contains(character) && skills.Count > 0)
{
skill = skills[Random.Shared.Next(skills.Count)];
}
@@ -774,7 +777,7 @@ namespace Milimoe.FunGame.Core.Model
// 吟唱前需要先选取目标
if (skill.SkillType == SkillType.Magic)
{
- List targets = SelectTargets(character, skill, enemys, teammates);
+ List targets = await SelectTargetsAsync(character, skill, enemys, teammates);
if (targets.Count == 0 && _charactersInAI.Contains(character) && enemys.Count > 0)
{
// 如果没有选取目标,且角色在 AI 控制下,则随机选取一个目标
@@ -784,8 +787,12 @@ namespace Milimoe.FunGame.Core.Model
{
LastRound.Targets = [.. targets];
decided = true;
+
character.CharacterState = CharacterState.Casting;
- _castingSkills.Add(character, new(skill, targets));
+ SkillTarget skillTarget = new(skill, targets);
+ await OnCharacterActingAsync(character, CharacterActionType.PreCastSkill, skillTarget);
+
+ _castingSkills.Add(character, skillTarget);
baseTime = skill.CastTime;
skill.OnSkillCasting(this, character, targets);
}
@@ -795,7 +802,7 @@ namespace Milimoe.FunGame.Core.Model
// 只有魔法需要吟唱,战技和爆发技直接释放
if (CheckCanCast(character, skill, out double cost))
{
- List targets = SelectTargets(character, skill, enemys, teammates);
+ List targets = await SelectTargetsAsync(character, skill, enemys, teammates);
if (targets.Count == 0 && _charactersInAI.Contains(character) && enemys.Count > 0)
{
// 如果没有选取目标,且角色在 AI 控制下,则随机选取一个目标
@@ -805,6 +812,10 @@ namespace Milimoe.FunGame.Core.Model
{
LastRound.Targets = [.. targets];
decided = true;
+
+ SkillTarget skillTarget = new(skill, targets);
+ await OnCharacterActingAsync(character, CharacterActionType.PreCastSkill, skillTarget);
+
skill.OnSkillCasting(this, character, targets);
skill.BeforeSkillCasted();
@@ -813,8 +824,10 @@ namespace Milimoe.FunGame.Core.Model
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
LastRound.SkillCost = $"{-cost:0.##} EP";
-
WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量,释放了{(skill.IsSuperSkill ? "爆发技" : "战技")} [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
+
+ await OnCharacterActingAsync(character, CharacterActionType.CastSkill, skillTarget, cost);
+
skill.OnSkillCasted(this, character, targets);
effects = [.. character.Effects.Where(e => e.Level > 0)];
foreach (Effect effect in effects)
@@ -849,8 +862,10 @@ namespace Milimoe.FunGame.Core.Model
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
LastRound.SkillCost = $"{-cost:0.##} MP";
-
WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点魔法值,释放了魔法 [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
+
+ await OnCharacterActingAsync(character, CharacterActionType.CastSkill, skillTarget, cost);
+
skill.OnSkillCasted(this, character, targets);
}
else
@@ -879,7 +894,7 @@ namespace Milimoe.FunGame.Core.Model
if (CheckCanCast(character, skill, out double cost))
{
// 预释放的爆发技不可取消
- List targets = SelectTargets(character, skill, enemys, teammates);
+ List targets = await SelectTargetsAsync(character, skill, enemys, teammates);
LastRound.Targets = [.. targets];
skill.BeforeSkillCasted();
@@ -889,8 +904,11 @@ namespace Milimoe.FunGame.Core.Model
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
LastRound.SkillCost = $"{-cost:0.##} EP";
-
WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量值,释放了爆发技 [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
+
+ SkillTarget skillTarget = new(skill, targets);
+ await OnCharacterActingAsync(character, CharacterActionType.CastSkill, skillTarget, cost);
+
skill.OnSkillCasted(this, character, targets);
}
else
@@ -909,11 +927,16 @@ namespace Milimoe.FunGame.Core.Model
else if (type == CharacterActionType.UseItem)
{
// 使用物品逻辑
- Item? item = OnSelectItem(character, items);
+ Item? item = await OnSelectItemAsync(character, items);
+ if (item is null && _charactersInAI.Contains(character) && items.Count > 0)
+ {
+ // AI 控制下随机选取一个物品
+ item = items[Random.Shared.Next(items.Count)];
+ }
if (item != null && item.Skills.Active != null)
{
Skill skill = item.Skills.Active;
- if (UseItem(item, character, enemys, teammates))
+ if (await UseItemAsync(item, character, enemys, teammates))
{
decided = true;
LastRound.Item = item;
@@ -926,17 +949,24 @@ namespace Milimoe.FunGame.Core.Model
}
}
}
+ else if (type == CharacterActionType.EndTurn)
+ {
+ decided = true;
+ WriteLine("[ " + character + $" ] 结束了回合!");
+ await OnCharacterActingAsync(character, CharacterActionType.EndTurn);
+ }
}
if (!decided || type == CharacterActionType.None)
{
WriteLine("[ " + character + $" ] 放弃了行动!");
+ await OnCharacterActingAsync(character, CharacterActionType.None);
}
LastRound.ActionType = type;
// 统一在回合结束时处理角色的死亡
- ProcessCharacterDeath(character);
+ await ProcessCharacterDeathAsync(character);
if (_isGameEnd)
{
@@ -957,6 +987,7 @@ namespace Milimoe.FunGame.Core.Model
LastRound.CastTime = newHardnessTime;
}
AddCharacter(character, newHardnessTime, isCheckProtected);
+ await OnQueueUpdatedAsync(_queue, character, "设置角色行动后的硬直时间。");
LastRound.HardnessTime = newHardnessTime;
effects = [.. character.Effects.Where(e => e.Level > 0)];
@@ -985,12 +1016,12 @@ namespace Milimoe.FunGame.Core.Model
}
// 有人想要插队吗?
- WillPreCastSuperSkill(character);
+ await WillPreCastSuperSkill(character);
// 回合结束事件
- OnTurnEnd(character);
+ await OnTurnEndAsync(character);
- AfterTurn(character);
+ await AfterTurnAsync(character);
WriteLine("");
return _isGameEnd;
@@ -1000,16 +1031,16 @@ namespace Milimoe.FunGame.Core.Model
/// 回合结束后触发
///
///
- public virtual void AfterTurn(Character character)
+ public virtual async Task AfterTurnAsync(Character character)
{
-
+ await Task.CompletedTask;
}
///
/// 时间进行流逝,减少硬直时间,减少技能冷却时间,角色也会因此回复状态
///
/// 流逝的时间
- public double TimeLapse()
+ public async Task TimeLapse()
{
if (_queue.Count == 0) return 0;
@@ -1034,16 +1065,7 @@ namespace Milimoe.FunGame.Core.Model
_respawnCountdown[character] = Calculation.Round2Digits(_respawnCountdown[character] - timeToReduce);
if (_respawnCountdown[character] <= 0)
{
- double hardnessTime = 5;
- character.Respawn(_original[character.Guid]);
- WriteLine($"[ {character} ] 已复活!获得 {hardnessTime} {GameplayEquilibriumConstant.InGameTime}的硬直时间。");
- AddCharacter(character, hardnessTime, false);
- LastRound.Respawns.Add(character);
- _respawnCountdown.Remove(character);
- if (!_respawnTimes.TryAdd(character, 1))
- {
- _respawnTimes[character] += 1;
- }
+ await SetCharacterRespawn(character);
}
}
@@ -1143,7 +1165,7 @@ namespace Milimoe.FunGame.Core.Model
///
///
///
- public void DamageToEnemy(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, bool isMagicDamage = false, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal)
{
// 如果敌人在结算伤害之前就已经死亡,将不会继续下去
if (enemy.HP <= 0)
@@ -1205,6 +1227,8 @@ namespace Milimoe.FunGame.Core.Model
enemy.EP += ep;
}
+ await OnDamageToEnemyAsync(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, damageResult);
+
effects = [.. actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0)];
foreach (Effect effect in effects)
{
@@ -1215,7 +1239,7 @@ namespace Milimoe.FunGame.Core.Model
{
LastRound.HasKill = true;
_roundDeaths.Add(enemy);
- DeathCalculation(actor, enemy);
+ await DeathCalculationAsync(actor, enemy);
}
}
@@ -1226,7 +1250,7 @@ namespace Milimoe.FunGame.Core.Model
///
///
///
- public void HealToTarget(Character actor, Character target, double heal, bool canRespawn = false)
+ public async Task HealToTargetAsync(Character actor, Character target, double heal, bool canRespawn = false)
{
if (target.HP == target.MaxHP)
{
@@ -1245,7 +1269,8 @@ namespace Milimoe.FunGame.Core.Model
}
}
- if (isDead && canRespawn)
+ bool isRespawn = isDead && canRespawn;
+ if (isRespawn)
{
if (target != actor)
{
@@ -1255,11 +1280,14 @@ namespace Milimoe.FunGame.Core.Model
{
WriteLine($"[ {target} ] 复苏了,并回复了 {heal:0.##} 点生命值!!");
}
+ await SetCharacterRespawn(target);
}
else
{
WriteLine($"[ {target} ] 回复了 {heal:0.##} 点生命值!");
}
+
+ await OnHealToTargetAsync(actor, target, heal, isRespawn);
}
///
@@ -1497,22 +1525,27 @@ namespace Milimoe.FunGame.Core.Model
/// 处理角色死亡
///
///
- public void ProcessCharacterDeath(Character character)
+ public async Task ProcessCharacterDeathAsync(Character character)
{
- foreach (Character enemy in _roundDeaths)
+ foreach (Character death in _roundDeaths)
{
+ if(!await OnCharacterDeathAsync(character, death))
+ {
+ continue;
+ }
+
// 给所有角色的特效广播角色死亡结算
List effects = [.. _queue.SelectMany(c => c.Effects.Where(e => e.Level > 0))];
foreach (Effect effect in effects)
{
- effect.AfterDeathCalculation(enemy, character, _continuousKilling, _earnedMoney);
+ effect.AfterDeathCalculation(death, character, _continuousKilling, _earnedMoney);
}
// 将死者移出队列
- _queue.Remove(enemy);
+ _queue.Remove(death);
if (_isTeamMode)
{
Team? killTeam = GetTeam(character);
- Team? deathTeam = GetTeam(enemy);
+ Team? deathTeam = GetTeam(death);
if (MaxRespawnTimes != 0)
{
@@ -1556,7 +1589,7 @@ namespace Milimoe.FunGame.Core.Model
if (!_teams.Keys.Where(str => str != killTeam.Name).Any())
{
// 没有其他的团队了,游戏结束
- EndGameInfo(killTeam);
+ await EndGameInfo(killTeam);
return;
}
if (MaxScoreToWin > 0 && killTeam.Score >= MaxScoreToWin)
@@ -1565,7 +1598,7 @@ namespace Milimoe.FunGame.Core.Model
combinedTeams.Remove(killTeam);
_eliminatedTeams.Clear();
_eliminatedTeams.AddRange(combinedTeams.OrderByDescending(t => t.Score));
- EndGameInfo(killTeam);
+ await EndGameInfo(killTeam);
return;
}
}
@@ -1575,7 +1608,7 @@ namespace Milimoe.FunGame.Core.Model
if (!_queue.Where(c => c != character).Any())
{
// 没有其他的角色了,游戏结束
- EndGameInfo(character);
+ await EndGameInfo(character);
}
}
}
@@ -1586,8 +1619,13 @@ namespace Milimoe.FunGame.Core.Model
///
///
///
- public void DeathCalculation(Character killer, Character death)
+ public async Task DeathCalculationAsync(Character killer, Character death)
{
+ if (!await OnDeathCalculationAsync(killer, death))
+ {
+ return;
+ }
+
if (!_continuousKilling.TryAdd(killer, 1)) _continuousKilling[killer] += 1;
if (!_maxContinuousKilling.TryAdd(killer, 1) && _continuousKilling[killer] > _maxContinuousKilling[killer])
{
@@ -1741,11 +1779,17 @@ namespace Milimoe.FunGame.Core.Model
///
/// 游戏结束信息
///
- public void EndGameInfo(Character winner)
+ public async Task EndGameInfo(Character winner)
{
WriteLine("[ " + winner + " ] 是胜利者。");
_queue.Remove(winner);
_eliminated.Add(winner);
+
+ if (!await OnGameEndAsync(winner))
+ {
+ return;
+ }
+
int top = 1;
WriteLine("");
WriteLine("=== 排名 ===");
@@ -1792,10 +1836,15 @@ namespace Milimoe.FunGame.Core.Model
///
/// 游戏结束信息 [ 团队版 ]
///
- public void EndGameInfo(Team winner)
+ public async Task EndGameInfo(Team winner)
{
WriteLine("[ " + winner + " ] 是胜利者。");
+ if (!await OnGameEndTeamAsync(winner))
+ {
+ return;
+ }
+
int top = 1;
WriteLine("");
WriteLine("=== 排名 ===");
@@ -1953,7 +2002,7 @@ namespace Milimoe.FunGame.Core.Model
///
/// 当前正在行动的角色
///
- public void WillPreCastSuperSkill(Character character)
+ public async Task WillPreCastSuperSkill(Character character)
{
// 选取除了回合内角色之外的 AI 控制角色
foreach (Character other in _queue.Where(c => c != character && c.CharacterState == CharacterState.Actionable && _charactersInAI.Contains(c)).ToList())
@@ -1965,7 +2014,7 @@ namespace Milimoe.FunGame.Core.Model
if (skills.Count > 0)
{
Skill skill = skills[Random.Shared.Next(skills.Count)];
- SetCharacterPreCastSuperSkill(other, skill);
+ await SetCharacterPreCastSuperSkill(other, skill);
}
}
}
@@ -1976,7 +2025,7 @@ namespace Milimoe.FunGame.Core.Model
///
///
///
- public void InterruptCasting(Character caster, Character interrupter)
+ public async Task InterruptCastingAsync(Character caster, Character interrupter)
{
Skill? skill = null;
if (_castingSkills.TryGetValue(caster, out SkillTarget target))
@@ -1997,6 +2046,7 @@ namespace Milimoe.FunGame.Core.Model
e.OnSkillCastInterrupted(caster, skill, interrupter);
}
}
+ await OnInterruptCastingAsync(caster, skill, interrupter);
}
///
@@ -2136,14 +2186,14 @@ namespace Milimoe.FunGame.Core.Model
///
///
///
- public bool UseItem(Item item, Character character, List enemys, List teammates)
+ public async Task UseItemAsync(Item item, Character character, List enemys, List teammates)
{
- Skill? skill = item.Skills.Active;
- if (skill != null)
+ if (CheckCanCast(character, item, out double costMP, out double costEP))
{
- if (CheckCanCast(character, skill, out double cost))
+ Skill? skill = item.Skills.Active;
+ if (skill != null)
{
- List targets = SelectTargets(character, skill, enemys, teammates);
+ List targets = await SelectTargetsAsync(character, skill, enemys, teammates);
if (targets.Count == 0 && _charactersInAI.Contains(character) && enemys.Count > 0)
{
// 如果没有选取目标,且角色在 AI 控制下,则随机选取一个目标
@@ -2153,15 +2203,37 @@ namespace Milimoe.FunGame.Core.Model
{
LastRound.Targets = [.. targets];
+ await OnCharacterActingAsync(character, CharacterActionType.UseItem, item, targets);
+
+ string line = $"[ {character} ] 使用了物品 [ {item.Name} ]!\r\n[ {character} ] ";
+
skill.OnSkillCasting(this, character, targets);
skill.BeforeSkillCasted();
- character.EP -= cost;
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
- LastRound.SkillCost = $"{-cost:0.##} EP";
- WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量,释放了{(skill.IsSuperSkill ? "爆发技" : "战技")} [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
+ if (costMP > 0)
+ {
+ character.MP -= costMP;
+ LastRound.SkillCost = $"{-costMP:0.##} MP";
+ line += $"消耗了 {costMP:0.##} 点魔法值,";
+ }
+
+ if (costEP > 0)
+ {
+ character.EP -= costEP;
+ if (LastRound.SkillCost != "") LastRound.SkillCost += " / ";
+ LastRound.SkillCost += $"{-costEP:0.##} EP";
+ line += $"消耗了 {costEP:0.##} 点能量,";
+ }
+
+ line += $"释放了物品技能 [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}";
+ WriteLine(line);
+
+ SkillTarget skillTarget = new(skill, targets);
+ await OnCharacterActingAsync(character, CharacterActionType.CastSkill, skillTarget, costMP, costEP);
+
skill.OnSkillCasted(this, character, targets);
return true;
}
@@ -2170,12 +2242,31 @@ namespace Milimoe.FunGame.Core.Model
return false;
}
+ ///
+ /// 设置角色复活
+ ///
+ ///
+ public async Task SetCharacterRespawn(Character character)
+ {
+ double hardnessTime = 5;
+ character.Respawn(_original[character.Guid]);
+ WriteLine($"[ {character} ] 已复活!获得 {hardnessTime} {GameplayEquilibriumConstant.InGameTime}的硬直时间。");
+ AddCharacter(character, hardnessTime, false);
+ await OnQueueUpdatedAsync(_queue, character, "设置角色复活后的硬直时间。");
+ LastRound.Respawns.Add(character);
+ _respawnCountdown.Remove(character);
+ if (!_respawnTimes.TryAdd(character, 1))
+ {
+ _respawnTimes[character] += 1;
+ }
+ }
+
///
/// 设置角色将预释放爆发技
///
///
///
- public void SetCharacterPreCastSuperSkill(Character character, Skill skill)
+ public async Task SetCharacterPreCastSuperSkill(Character character, Skill skill)
{
if (character.CharacterState == CharacterState.Actionable)
{
@@ -2184,6 +2275,7 @@ namespace Milimoe.FunGame.Core.Model
_queue.Remove(character);
_cutCount.Remove(character);
AddCharacter(character, 0, false);
+ await OnQueueUpdatedAsync(_queue, character, "设置角色预释放爆发技的硬直时间。");
WriteLine("[ " + character + " ] 预释放了爆发技!!");
foreach (Character c in _hardnessTimes.Keys)
{
@@ -2224,10 +2316,10 @@ namespace Milimoe.FunGame.Core.Model
///
///
///
- public virtual List SelectTargets(Character caster, Skill skill, List enemys, List teammates)
+ public virtual async Task> SelectTargetsAsync(Character caster, Skill skill, List enemys, List teammates)
{
- List targets = OnSelectSkillTargets(caster, skill, enemys, teammates);
- if (targets.Count == 0)
+ List targets = await OnSelectSkillTargetsAsync(caster, skill, enemys, teammates);
+ if (targets.Count == 0 && _charactersInAI.Contains(caster))
{
targets = skill.SelectTargets(caster, enemys, teammates);
}
@@ -2242,84 +2334,18 @@ namespace Milimoe.FunGame.Core.Model
///
///
///
- public virtual List SelectTargets(Character character, NormalAttack attack, List enemys, List teammates)
+ public virtual async Task> SelectTargetsAsync(Character character, NormalAttack attack, List enemys, List teammates)
{
- List targets = OnSelectNormalAttackTargets(character, attack, enemys, teammates);
+ List targets = await OnSelectNormalAttackTargetsAsync(character, attack, enemys, teammates);
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;
- }
+ #region 事件
- public delegate Skill SelectSkillEventHandler(Character character, List skills);
- public event SelectSkillEventHandler? SelectSkill;
+ public delegate Task TurnStartEventHandler(Character character, List enemys, List teammates, List skills, List- items);
///
- /// 角色需要选择一个技能
+ /// 回合开始事件
///
- ///
- ///
- ///
- public Skill? OnSelectSkill(Character character, List skills)
- {
- return SelectSkill?.Invoke(character, skills);
- }
-
- public delegate Item SelectItemEventHandler(Character character, List
- items);
- public event SelectItemEventHandler? SelectItem;
- ///
- /// 角色需要选择一个物品
- ///
- ///
- ///
- ///
- public Item? OnSelectItem(Character character, List
- items)
- {
- return SelectItem?.Invoke(character, items);
- }
-
- 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) ?? [];
- }
-
- public delegate bool TurnStartEventHandler(Character character, List enemys, List teammates, List skills, List
- items);
public event TurnStartEventHandler? TurnStart;
///
/// 回合开始事件
@@ -2330,21 +2356,265 @@ namespace Milimoe.FunGame.Core.Model
///
///
///
- public bool OnTurnStart(Character character, List enemys, List teammates, List skills, List
- items)
+ public async Task OnTurnStartAsync(Character character, List enemys, List teammates, List skills, List
- items)
{
- return TurnStart?.Invoke(character, enemys, teammates, skills, items) ?? true;
+ return await (TurnStart?.Invoke(character, enemys, teammates, skills, items) ?? Task.FromResult(true));
}
- public delegate void TurnEndEventHandler(Character character);
+ public delegate Task TurnEndEventHandler(Character character);
+ ///
+ /// 回合结束事件
+ ///
public event TurnEndEventHandler? TurnEnd;
///
/// 回合结束事件
///
///
///
- public void OnTurnEnd(Character character)
+ public async Task OnTurnEndAsync(Character character)
{
- TurnEnd?.Invoke(character);
+ await (TurnEnd?.Invoke(character) ?? Task.CompletedTask);
}
+
+ public delegate Task DecideActionEventHandler(Character character, List enemys, List teammates, List skills, List
- items);
+ ///
+ /// 决定角色的行动事件
+ ///
+ public event DecideActionEventHandler? DecideAction;
+ ///
+ /// 决定角色的行动事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task OnDecideActionAsync(Character character, List enemys, List teammates, List skills, List
- items)
+ {
+ return await (DecideAction?.Invoke(character, enemys, teammates, skills, items) ?? Task.FromResult(CharacterActionType.None));
+ }
+
+ public delegate Task SelectSkillEventHandler(Character character, List skills);
+ ///
+ /// 角色需要选择一个技能
+ ///
+ public event SelectSkillEventHandler? SelectSkill;
+ ///
+ /// 角色需要选择一个技能
+ ///
+ ///
+ ///
+ ///
+ public async Task OnSelectSkillAsync(Character character, List skills)
+ {
+ return await (SelectSkill?.Invoke(character, skills) ?? Task.FromResult(null));
+ }
+
+ public delegate Task
- SelectItemEventHandler(Character character, List
- items);
+ ///
+ /// 角色需要选择一个物品
+ ///
+ public event SelectItemEventHandler? SelectItem;
+ ///
+ /// 角色需要选择一个物品
+ ///
+ ///
+ ///
+ ///
+ public async Task
- OnSelectItemAsync(Character character, List
- items)
+ {
+ return await (SelectItem?.Invoke(character, items) ?? Task.FromResult
- (null));
+ }
+
+ public delegate Task
> SelectSkillTargetsEventHandler(Character caster, Skill skill, List enemys, List teammates);
+ ///
+ /// 选取技能目标事件
+ ///
+ public event SelectSkillTargetsEventHandler? SelectSkillTargets;
+ ///
+ /// 选取技能目标事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> OnSelectSkillTargetsAsync(Character caster, Skill skill, List enemys, List teammates)
+ {
+ return await (SelectSkillTargets?.Invoke(caster, skill, enemys, teammates) ?? Task.FromResult(new List()));
+ }
+
+ public delegate Task> SelectNormalAttackTargetsEventHandler(Character character, NormalAttack attack, List enemys, List teammates);
+ ///
+ /// 选取普通攻击目标事件
+ ///
+ public event SelectNormalAttackTargetsEventHandler? SelectNormalAttackTargets;
+ ///
+ /// 选取普通攻击目标事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> OnSelectNormalAttackTargetsAsync(Character character, NormalAttack attack, List enemys, List teammates)
+ {
+ return await (SelectNormalAttackTargets?.Invoke(character, attack, enemys, teammates) ?? Task.FromResult(new List()));
+ }
+
+ public delegate Task InterruptCastingEventHandler(Character cast, Skill? skill, Character interrupter);
+ ///
+ /// 打断施法事件
+ ///
+ public event InterruptCastingEventHandler? InterruptCasting;
+ ///
+ /// 打断施法事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task OnInterruptCastingAsync(Character cast, Skill? skill, Character interrupter)
+ {
+ await (InterruptCasting?.Invoke(cast, skill, interrupter) ?? Task.CompletedTask);
+ }
+
+ public delegate Task DeathCalculationEventHandler(Character killer, Character death);
+ ///
+ /// 死亡结算事件
+ ///
+ public event DeathCalculationEventHandler? DeathCalculation;
+ ///
+ /// 死亡结算事件
+ ///
+ ///
+ ///
+ ///
+ public async Task OnDeathCalculationAsync(Character killer, Character death)
+ {
+ return await (DeathCalculation?.Invoke(killer, death) ?? Task.FromResult(true));
+ }
+
+ public delegate Task CharacterDeathEventHandler(Character current, Character death);
+ ///
+ /// 角色死亡事件,此事件位于 之后
+ ///
+ public event CharacterDeathEventHandler? CharacterDeath;
+ ///
+ /// 角色死亡事件,此事件位于 之后
+ ///
+ ///
+ ///
+ ///
+ public async Task OnCharacterDeathAsync(Character current, Character death)
+ {
+ return await (CharacterDeath?.Invoke(current, death) ?? Task.FromResult(true));
+ }
+
+ public delegate Task HealToTargetEventHandler(Character actor, Character target, double heal, bool isRespawn);
+ ///
+ /// 治疗事件
+ ///
+ public event HealToTargetEventHandler? HealToTarget;
+ ///
+ /// 治疗事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task OnHealToTargetAsync(Character actor, Character target, double heal, bool isRespawn)
+ {
+ await (HealToTarget?.Invoke(actor, target, heal, isRespawn) ?? Task.CompletedTask);
+ }
+
+ public delegate Task DamageToEnemyEventHandler(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, DamageResult damageResult);
+ ///
+ /// 造成伤害事件
+ ///
+ public event DamageToEnemyEventHandler? DamageToEnemy;
+ ///
+ /// 造成伤害事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task OnDamageToEnemyAsync(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, DamageResult damageResult)
+ {
+ await (DamageToEnemy?.Invoke(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, damageResult) ?? Task.CompletedTask);
+ }
+
+ public delegate Task CharacterActingEventHandler(Character actor, CharacterActionType type, params object[] args);
+ ///
+ /// 角色行动事件
+ ///
+ public event CharacterActingEventHandler? CharacterActing;
+ ///
+ /// 角色行动事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task OnCharacterActingAsync(Character actor, CharacterActionType type, params object[] args)
+ {
+ await (CharacterActing?.Invoke(actor, type, args) ?? Task.CompletedTask);
+ }
+
+ public delegate Task GameEndEventHandler(Character winner);
+ ///
+ /// 游戏结束事件
+ ///
+ public event GameEndEventHandler? GameEnd;
+ ///
+ /// 游戏结束事件
+ ///
+ ///
+ ///
+ public async Task OnGameEndAsync(Character winner)
+ {
+ return await (GameEnd?.Invoke(winner) ?? Task.FromResult(true));
+ }
+
+ public delegate Task GameEndTeamEventHandler(Team winner);
+ ///
+ /// 游戏结束事件(团队版)
+ ///
+ public event GameEndTeamEventHandler? GameEndTeam;
+ ///
+ /// 游戏结束事件(团队版)
+ ///
+ ///
+ ///
+ public async Task OnGameEndTeamAsync(Team winner)
+ {
+ return await (GameEndTeam?.Invoke(winner) ?? Task.FromResult(true));
+ }
+
+ public delegate Task QueueUpdatedEventHandler(List queue, Character character, string reason);
+ ///
+ /// 行动顺序表更新事件
+ ///
+ public event QueueUpdatedEventHandler? QueueUpdated;
+ ///
+ /// 行动顺序表更新事件
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task OnQueueUpdatedAsync(List queue, Character character, string reason)
+ {
+ await (QueueUpdated?.Invoke(queue, character, reason) ?? Task.CompletedTask);
+ }
+
+ #endregion
}
}