using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Model
{
///
/// 行动顺序表
///
public class ActionQueue : IGamingQueue
{
///
/// 用于文本输出
///
public Action WriteLine { get; }
///
/// 原始的角色字典
///
public Dictionary Original => _original;
///
/// 当前的行动顺序
///
public List Queue => _queue;
///
/// 当前已死亡的角色顺序(第一个是最早死的)
///
public List Eliminated => _eliminated;
///
/// 当前团灭的团队顺序(第一个是最早死的)
///
public List EliminatedTeams => _eliminatedTeams;
///
/// 角色数据
///
public Dictionary CharacterStatistics => _stats;
///
/// 团队及其成员
///
public Dictionary Teams => _teams;
///
/// 游戏运行的时间
///
public double TotalTime { get; set; } = 0;
///
/// 游戏运行的回合
/// 对于某角色而言,在其行动的回合叫 Turn,而所有角色行动的回合,都称之为 Round。
///
public int TotalRound { get; set; } = 0;
///
/// 第一滴血获得者
///
public Character? FirstKiller { get; set; } = null;
///
/// 最大复活次数
/// 0:不复活 / -1:无限复活
///
public int MaxRespawnTimes { get; set; } = 0;
///
/// 复活次数统计
///
public Dictionary RespawnTimes => _respawnTimes;
///
/// 复活倒计时
///
public Dictionary RespawnCountdown => _respawnCountdown;
///
/// 最大获胜积分 [ 适用于团队模式 ]
/// 设置一个大于0的数以启用
///
public int MaxScoreToWin { get; set; } = 0;
///
/// 上回合记录
///
public RoundRecord LastRound { get; set; } = new(0);
///
/// 所有回合的记录
///
public List Rounds { get; } = [];
///
/// 原始的角色字典
///
protected readonly Dictionary _original = [];
///
/// 当前的行动顺序
///
protected readonly List _queue = [];
///
/// 当前已死亡的角色顺序(第一个是最早死的)
///
protected readonly List _eliminated = [];
///
/// 当前团灭的团队顺序(第一个是最早死的)
///
protected readonly List _eliminatedTeams = [];
///
/// 硬直时间表
///
protected readonly Dictionary _hardnessTimes = [];
///
/// 角色正在吟唱的魔法
///
protected readonly Dictionary _castingSkills = [];
///
/// 角色预释放的爆发技
///
protected readonly Dictionary _castingSuperSkills = [];
///
/// 角色目前赚取的金钱
///
protected readonly Dictionary _earnedMoney = [];
///
/// 角色最高连杀数
///
protected readonly Dictionary _maxContinuousKilling = [];
///
/// 角色目前的连杀数
///
protected readonly Dictionary _continuousKilling = [];
///
/// 角色被插队次数
///
protected readonly Dictionary _cutCount = [];
///
/// 助攻伤害
///
protected readonly Dictionary _assistDamage = [];
///
/// 角色数据
///
protected readonly Dictionary _stats = [];
///
/// 团队及其成员
///
protected readonly Dictionary _teams = [];
///
/// 复活次数统计
///
protected readonly Dictionary _respawnTimes = [];
///
/// 复活倒计时
///
protected readonly Dictionary _respawnCountdown = [];
///
/// 当前回合死亡角色
///
protected readonly List _roundDeaths = [];
///
/// 是否是团队模式
///
protected bool _isTeamMode = false;
///
/// 游戏是否结束
///
protected bool _isGameEnd = false;
///
/// 新建一个行动顺序表
///
/// 是否是团队模式
/// 用于文本输出
public ActionQueue(bool isTeamMdoe = false, Action? writer = null)
{
_isTeamMode = isTeamMdoe;
if (writer != null)
{
WriteLine = writer;
}
WriteLine ??= new Action(Console.WriteLine);
}
///
/// 新建一个行动顺序表并初始化
///
/// 参与本次游戏的角色列表
/// 是否是团队模式
/// 用于文本输出
public ActionQueue(List characters, bool isTeamMdoe = false, Action? writer = null)
{
_isTeamMode = isTeamMdoe;
if (writer != null)
{
WriteLine = writer;
}
WriteLine ??= new Action(Console.WriteLine);
InitCharacterQueue(characters);
}
///
/// 初始化行动顺序表
///
///
public void InitCharacterQueue(List characters)
{
// 保存原始的角色信息。用于复活时还原状态
foreach (Character character in characters)
{
Character original = character.Copy();
original.Guid = Guid.NewGuid();
character.Guid = original.Guid;
_original.Add(original.Guid, original);
}
// 初始排序:按速度排序
List> groupedBySpeed = [.. characters
.GroupBy(c => c.SPD)
.OrderByDescending(g => g.Key)];
Random random = new();
foreach (IGrouping group in groupedBySpeed)
{
if (group.Count() == 1)
{
// 如果只有一个角色,直接加入队列
Character character = group.First();
AddCharacter(character, Calculation.Round2Digits(_queue.Count * 0.1), false);
_assistDamage.Add(character, new AssistDetail(character, characters.Where(c => c != character)));
_stats.Add(character, new());
// 初始化技能
foreach (Skill skill in character.Skills)
{
skill.OnSkillGained(this);
}
}
else
{
// 如果有多个角色,进行先行决定
List sortedList = [.. group];
while (sortedList.Count > 0)
{
Character? selectedCharacter = null;
bool decided = false;
if (sortedList.Count == 1)
{
selectedCharacter = sortedList[0];
decided = true;
}
while (!decided)
{
// 每个角色进行两次随机数抽取
var randomNumbers = sortedList.Select(c => new
{
Character = c,
FirstRoll = random.Next(1, 21),
SecondRoll = random.Next(1, 21)
}).ToList();
randomNumbers.ForEach(a => WriteLine(a.Character.Name + ": " + a.FirstRoll + " / " + a.SecondRoll));
// 找到两次都大于其他角色的角色
int maxFirstRoll = randomNumbers.Max(r => r.FirstRoll);
int maxSecondRoll = randomNumbers.Max(r => r.SecondRoll);
var candidates = randomNumbers
.Where(r => r.FirstRoll == maxFirstRoll && r.SecondRoll == maxSecondRoll)
.ToList();
if (candidates.Count == 1)
{
selectedCharacter = candidates.First().Character;
decided = true;
}
}
// 将决定好的角色加入顺序表
if (selectedCharacter != null)
{
AddCharacter(selectedCharacter, Calculation.Round2Digits(_queue.Count * 0.1), false);
_assistDamage.Add(selectedCharacter, new AssistDetail(selectedCharacter, characters.Where(c => c != selectedCharacter)));
_stats.Add(selectedCharacter, new());
// 初始化技能
foreach (Skill skill in selectedCharacter.Skills)
{
skill.OnSkillGained(this);
}
WriteLine("decided: " + selectedCharacter.Name + "\r\n");
sortedList.Remove(selectedCharacter);
}
}
}
}
}
///
/// 清空行动队列
///
public void ClearQueue()
{
FirstKiller = null;
_original.Clear();
_queue.Clear();
_hardnessTimes.Clear();
_assistDamage.Clear();
_stats.Clear();
_cutCount.Clear();
_castingSkills.Clear();
_castingSuperSkills.Clear();
_maxContinuousKilling.Clear();
_continuousKilling.Clear();
_earnedMoney.Clear();
_eliminated.Clear();
}
///
/// 添加一个团队
///
///
///
public void AddTeam(string teamName, IEnumerable characters)
{
if (teamName != "" && characters.Any())
{
_teams.Add(teamName, new(teamName, characters));
}
}
///
/// 获取角色的团队
///
///
public Team? GetTeam(Character character)
{
foreach (Team team in _teams.Values)
{
if (team.IsOnThisTeam(character))
{
return team;
}
}
return null;
}
///
/// 从已淘汰的团队中获取角色的团队
///
///
public Team? GetTeamFromEliminated(Character character)
{
foreach (Team team in _eliminatedTeams)
{
if (team.IsOnThisTeam(character))
{
return team;
}
}
return null;
}
///
/// 获取某角色的团队成员
///
///
public List GetTeammates(Character character)
{
foreach (string team in _teams.Keys)
{
if (_teams[team].IsOnThisTeam(character))
{
return _teams[team].GetTeammates(character);
}
}
return [];
}
///
/// 将角色加入行动顺序表
///
///
///
///
public void AddCharacter(Character character, double hardnessTime, bool isCheckProtected = true)
{
// 插队机制:按硬直时间排序
int insertIndex = _queue.FindIndex(c => _hardnessTimes[c] > hardnessTime);
if (isCheckProtected)
{
// 查找保护条件 被插队超过此次数便能获得插队补偿 即行动保护
int countProtected = _queue.Count;
// 查找队列中是否有满足插队补偿条件的角色(最后一个)
var list = _queue
.Select((c, index) => new { Character = c, Index = index })
.Where(x => _cutCount.ContainsKey(x.Character) && _cutCount[x.Character] >= countProtected);
// 如果没有找到满足条件的角色,返回 -1
int protectIndex = list.Select(x => x.Index).LastOrDefault(-1);
if (protectIndex != -1)
{
// 获取最后一个符合条件的角色
Character lastProtectedCharacter = list.Last().Character;
double lastProtectedHardnessTime = _hardnessTimes[lastProtectedCharacter];
// 查找与最后一个受保护角色相同硬直时间的其他角色
var sameHardnessList = _queue
.Select((c, index) => new { Character = c, Index = index })
.Where(x => _hardnessTimes[x.Character] == lastProtectedHardnessTime && x.Index > protectIndex);
// 如果找到了相同硬直时间的角色,更新 protectIndex 为它们中最后一个的索引
if (sameHardnessList.Any())
{
protectIndex = sameHardnessList.Select(x => x.Index).Last();
}
// 判断是否需要插入到受保护角色的后面
if (insertIndex != -1 && insertIndex <= protectIndex)
{
// 如果按硬直时间插入的位置在受保护角色之前或相同,则插入到受保护角色的后面一位
insertIndex = protectIndex + 1;
hardnessTime = lastProtectedHardnessTime;
// 列出受保护角色的名单
WriteLine($"由于 [ {string.Join(" ],[ ", list.Select(x => x.Character))} ] 受到行动保护,因此角色 [ {character} ] 将插入至顺序表第 {insertIndex + 1} 位。");
}
}
}
// 如果插入索引无效(为-1 或 大于等于队列长度),则添加到队列尾部
if (insertIndex == -1 || insertIndex >= _queue.Count)
{
_queue.Add(character);
}
else
{
_queue.Insert(insertIndex, character);
}
_hardnessTimes[character] = hardnessTime;
// 为所有被插队的角色增加 _cutCount
if (isCheckProtected && insertIndex != -1 && insertIndex < _queue.Count)
{
for (int i = insertIndex + 1; i < _queue.Count; i++)
{
Character queuedCharacter = _queue[i];
if (!_cutCount.TryAdd(queuedCharacter, 1))
{
_cutCount[queuedCharacter] += 1;
}
}
}
}
///
/// 从行动顺序表取出第一个角色
///
///
public Character? NextCharacter()
{
if (_queue.Count == 0) return null;
// 硬直时间为0的角色将执行行动
Character? character = _queue.FirstOrDefault(c => _hardnessTimes[c] == 0);
if (character != null)
{
_queue.Remove(character);
_cutCount.Remove(character);
// 进入下一回合
TotalRound++;
LastRound = new(TotalRound);
Rounds.Add(LastRound);
return character;
}
return null;
}
///
/// 显示当前所有角色的状态和硬直时间
///
public void DisplayQueue()
{
WriteLine("==== 角色状态 ====");
foreach (Character c in _queue)
{
WriteLine(c.GetInBattleInfo(_hardnessTimes[c]));
}
}
///
/// 回合开始前触发
///
///
public virtual bool BeforeTurn(Character character)
{
return true;
}
///
/// 角色 的回合进行中
///
///
/// 是否结束游戏
public bool ProcessTurn(Character character)
{
LastRound.Actor = character;
_roundDeaths.Clear();
if (!BeforeTurn(character))
{
return _isGameEnd;
}
List effects = character.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.OnTurnStart(character);
}
// 基础硬直时间
double baseTime = 10;
bool isCheckProtected = true;
// 队友列表
List teammates = [.. GetTeammates(character).Where(_queue.Contains)];
// 敌人列表
List enemys = [.. _queue.Where(c => c != character && !c.IsUnselectable && !teammates.Contains(c))];
// 技能列表
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.RealEPCost <= character.EP || s.SkillType == SkillType.Magic && s.RealMPCost <= character.MP))];
// 物品列表
List- items = [.. character.Items.Where(i => i.IsActive && i.Skills.Active != null && i.Enable && i.IsInGameItem &&
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)];
// 此变量用于在取消选择时,能够重新行动
bool decided = false;
// 最大取消次数
int cancelTimes = 3;
// 作出了什么行动
CharacterActionType type = CharacterActionType.None;
while (!decided && cancelTimes > 0)
{
type = CharacterActionType.None;
// 是否能使用物品和释放技能
bool canUseItem = items.Count > 0;
bool canCastSkill = skills.Count > 0;
// 使用物品和释放技能、使用普通攻击的概率
double pUseItem = 0.33;
double pCastSkill = 0.33;
double pNormalAttack = 0.34;
cancelTimes--;
// 不允许在吟唱和预释放状态下,修改角色的行动
if (character.CharacterState != CharacterState.Casting && character.CharacterState != CharacterState.PreCastSuperSkill)
{
CharacterActionType actionTypeTemp = CharacterActionType.None;
effects = character.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect e in effects)
{
actionTypeTemp = e.AlterActionTypeBeforeAction(character, character.CharacterState, ref canUseItem, ref canCastSkill, ref pUseItem, ref pCastSkill, ref pNormalAttack);
}
if (actionTypeTemp != CharacterActionType.None && actionTypeTemp != CharacterActionType.CastSkill && actionTypeTemp != CharacterActionType.CastSuperSkill)
{
type = actionTypeTemp;
}
}
if (type == CharacterActionType.None)
{
if (character.CharacterState != CharacterState.NotActionable && character.CharacterState != CharacterState.Casting && character.CharacterState != CharacterState.PreCastSuperSkill)
{
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 (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)
{
// 如果角色上一次吟唱了魔法,这次的行动则是结算这个魔法
type = CharacterActionType.CastSkill;
}
else if (character.CharacterState == CharacterState.PreCastSuperSkill)
{
// 角色使用回合外爆发技插队
type = CharacterActionType.CastSuperSkill;
}
else
{
WriteLine("[ " + character + $" ] 完全行动不能!");
type = CharacterActionType.None;
}
}
List enemysTemp = new(enemys);
List teammatesTemp = new(teammates);
List skillsTemp = new(skills);
Dictionary continuousKillingTemp = new(_continuousKilling);
Dictionary earnedMoneyTemp = new(_earnedMoney);
effects = character.Effects.Where(e => e.Level > 0).ToList();
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();
}
}
if (type == CharacterActionType.NormalAttack)
{
// 使用普通攻击逻辑
Character[] targets = [.. SelectTargets(character, character.NormalAttack, enemys, teammates, out bool cancel)];
LastRound.Targets = [.. targets];
if (!cancel && targets.Length > 0)
{
decided = true;
character.NormalAttack.Attack(this, character, targets);
baseTime = character.NormalAttack.HardnessTime;
effects = character.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.AlterHardnessTimeAfterNormalAttack(character, ref baseTime, ref isCheckProtected);
}
}
}
else if (type == CharacterActionType.PreCastSkill)
{
// 预使用技能,即开始吟唱逻辑
// 吟唱前需要先选取目标
Skill skill = skills[Random.Shared.Next(skills.Count)];
if (skill.SkillType == SkillType.Magic)
{
List targets = SelectTargets(character, skill, enemys, teammates, out bool cancel);
LastRound.Targets = [.. targets];
if (!cancel)
{
decided = true;
character.CharacterState = CharacterState.Casting;
_castingSkills.Add(character, new(skill, targets));
baseTime = skill.CastTime;
skill.OnSkillCasting(this, character, targets);
}
}
else
{
if (CheckCanCast(character, skill, out double cost))
{
List targets = SelectTargets(character, skill, enemys, teammates, out bool cancel);
LastRound.Targets = [.. targets];
if (!cancel)
{
decided = true;
skill.OnSkillCasting(this, character, targets);
skill.BeforeSkillCasted();
character.EP -= cost;
baseTime = skill.HardnessTime;
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
LastRound.SkillCost = $"{-cost:0.##} EP";
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();
foreach (Effect effect in effects)
{
effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected);
}
}
}
}
LastRound.Skill = skill;
}
else if (type == CharacterActionType.CastSkill)
{
decided = true;
// 使用技能逻辑,结束吟唱状态
character.CharacterState = CharacterState.Actionable;
SkillTarget skillTarget = _castingSkills[character];
Skill skill = skillTarget.Skill;
List targets = skillTarget.Targets;
LastRound.Targets = [.. targets];
LastRound.Skill = skill;
_castingSkills.Remove(character);
// 判断是否能够释放技能
if (CheckCanCast(character, skill, out double cost))
{
skill.BeforeSkillCasted();
character.MP -= cost;
baseTime = skill.HardnessTime;
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
LastRound.SkillCost = $"{-cost:0.##} MP";
WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点魔法值,释放了魔法 [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
skill.OnSkillCasted(this, character, targets);
}
else
{
WriteLine("[ " + character + $" ] 放弃释放技能!");
// 放弃释放技能会获得3的硬直时间
baseTime = 3;
}
effects = character.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected);
}
}
else if (type == CharacterActionType.CastSuperSkill)
{
decided = true;
// 结束预释放爆发技的状态
character.CharacterState = CharacterState.Actionable;
Skill skill = _castingSuperSkills[character];
LastRound.Skill = skill;
_castingSuperSkills.Remove(character);
// 判断是否能够释放技能
if (CheckCanCast(character, skill, out double cost))
{
// 预释放的爆发技不可取消
List targets = SelectTargets(character, skill, enemys, teammates, out _);
LastRound.Targets = [.. targets];
skill.BeforeSkillCasted();
character.EP -= cost;
baseTime = skill.HardnessTime;
skill.CurrentCD = skill.RealCD;
skill.Enable = false;
LastRound.SkillCost = $"{-cost:0.##} EP";
WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量值,释放了爆发技 [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
skill.OnSkillCasted(this, character, targets);
}
else
{
WriteLine("[ " + character + $" ] 因能量不足放弃释放爆发技!");
// 放弃释放技能会获得3的硬直时间
baseTime = 3;
}
effects = character.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.AlterHardnessTimeAfterCastSkill(character, skill, ref baseTime, ref isCheckProtected);
}
}
else if (type == CharacterActionType.UseItem)
{
// 使用物品逻辑
}
}
if (!decided || type == CharacterActionType.None)
{
WriteLine("[ " + character + $" ] 放弃了行动!");
}
LastRound.ActionType = type;
// 统一在回合结束时处理角色的死亡
ProcessCharacterDeath(character);
if (_isGameEnd)
{
return _isGameEnd;
}
// 减少硬直时间
double newHardnessTime = baseTime;
if (character.CharacterState != CharacterState.Casting)
{
newHardnessTime = Math.Max(0, Calculation.Round2Digits(baseTime * (1 - character.ActionCoefficient)));
WriteLine("[ " + character + " ] 回合结束,获得硬直时间: " + newHardnessTime);
}
else
{
newHardnessTime = Math.Max(0, Calculation.Round2Digits(baseTime * (1 - character.AccelerationCoefficient)));
WriteLine("[ " + character + " ] 进行吟唱,持续时间: " + newHardnessTime);
LastRound.CastTime = newHardnessTime;
}
AddCharacter(character, newHardnessTime, isCheckProtected);
LastRound.HardnessTime = newHardnessTime;
// 有人想要插队吗?
WillPreCastSuperSkill(character);
effects = character.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.OnTurnEnd(character);
// 自身被动不会考虑
if (effect.EffectType == EffectType.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 _isGameEnd;
}
///
/// 回合结束后触发
///
///
public virtual void AfterTurn(Character character)
{
}
///
/// 时间进行流逝,减少硬直时间,减少技能冷却时间,角色也会因此回复状态
///
/// 流逝的时间
public double TimeLapse()
{
if (_queue.Count == 0) return 0;
// 获取第一个角色的硬直时间
double timeToReduce = _hardnessTimes[_queue[0]];
// 如果复活时间更快,应该先流逝复活时间
if (_respawnCountdown.Count != 0)
{
double timeToRespawn = _respawnCountdown.Values.Min();
if (timeToRespawn < timeToReduce)
{
timeToReduce = Calculation.Round2Digits(timeToRespawn);
}
}
TotalTime = Calculation.Round2Digits(TotalTime + timeToReduce);
WriteLine("时间流逝:" + timeToReduce);
// 减少复活倒计时
foreach (Character character in _respawnCountdown.Keys)
{
_respawnCountdown[character] = Calculation.Round2Digits(_respawnCountdown[character] - timeToReduce);
if (_respawnCountdown[character] <= 0)
{
double hardnessTime = 5;
character.Respawn(_original[character.Guid]);
WriteLine($"[ {character} ] 已复活!获得 {hardnessTime} 硬直时间。");
AddCharacter(character, hardnessTime, false);
LastRound.Respawns.Add(character);
_respawnCountdown.Remove(character);
if (!_respawnTimes.TryAdd(character, 1))
{
_respawnTimes[character] += 1;
}
}
}
foreach (Character character in _queue)
{
// 减少所有角色的硬直时间
_hardnessTimes[character] = Calculation.Round2Digits(_hardnessTimes[character] - timeToReduce);
// 统计
_stats[character].LiveRound += 1;
_stats[character].LiveTime = Calculation.Round2Digits(_stats[character].LiveTime + timeToReduce);
_stats[character].DamagePerRound = Calculation.Round2Digits(_stats[character].TotalDamage / _stats[character].LiveRound);
_stats[character].DamagePerTurn = Calculation.Round2Digits(_stats[character].TotalDamage / _stats[character].ActionTurn);
_stats[character].DamagePerSecond = Calculation.Round2Digits(_stats[character].TotalDamage / _stats[character].LiveTime);
// 回血回蓝
double recoveryHP = character.HR * timeToReduce;
double recoveryMP = character.MR * timeToReduce;
double needHP = character.MaxHP - character.HP;
double needMP = character.MaxMP - character.MP;
double reallyReHP = needHP >= recoveryHP ? recoveryHP : needHP;
double reallyReMP = needMP >= recoveryMP ? recoveryMP : needMP;
if (reallyReHP > 0 && reallyReMP > 0)
{
character.HP += reallyReHP;
character.MP += reallyReMP;
WriteLine($"角色 {character.NickName} 回血:{recoveryHP:0.##} / 回蓝:{recoveryMP:0.##}");
}
else
{
if (reallyReHP > 0)
{
character.HP += reallyReHP;
WriteLine($"角色 {character.NickName} 回血:{recoveryHP:0.##}");
}
if (reallyReMP > 0)
{
character.MP += reallyReMP;
WriteLine($"角色 {character.NickName} 回蓝:{recoveryMP:0.##}");
}
}
// 减少所有技能的冷却时间
foreach (Skill skill in character.Skills)
{
skill.CurrentCD -= timeToReduce;
if (skill.CurrentCD <= 0)
{
skill.CurrentCD = 0;
skill.Enable = true;
}
}
// 移除到时间的特效
List effects = character.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
if (effect.Level == 0)
{
character.Effects.Remove(effect);
continue;
}
effect.OnTimeElapsed(character, timeToReduce);
// 自身被动不会考虑
if (effect.EffectType == EffectType.None && effect.Skill.SkillType == SkillType.Passive)
{
continue;
}
if (effect.Durative)
{
effect.RemainDuration -= timeToReduce;
if (effect.RemainDuration <= 0)
{
effect.RemainDuration = 0;
character.Effects.Remove(effect);
effect.OnEffectLost(character);
}
}
}
}
WriteLine("\r\n");
return timeToReduce;
}
///
/// 对敌人造成伤害
///
///
///
///
///
///
///
///
public void DamageToEnemy(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage = false, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal)
{
// 如果敌人在结算伤害之前就已经死亡,将不会继续下去
if (enemy.HP <= 0)
{
return;
}
if (!LastRound.IsCritical.TryAdd(enemy, damageResult == DamageResult.Critical) && damageResult == DamageResult.Critical)
{
LastRound.IsCritical[enemy] = true;
}
bool isEvaded = damageResult == DamageResult.Evaded;
Dictionary totalDamageBonus = [];
List effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
double damageBonus = effect.AlterActualDamageAfterCalculation(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, damageResult, ref isEvaded, totalDamageBonus);
totalDamageBonus[effect] = damageBonus;
if (isEvaded)
{
damageResult = DamageResult.Evaded;
}
}
damage += totalDamageBonus.Sum(kv => kv.Value);
// 闪避了就没伤害了
if (!isEvaded)
{
if (damage < 0) damage = 0;
if (isMagicDamage)
{
string dmgType = CharacterSet.GetMagicDamageName(magicType);
WriteLine("[ " + enemy + $" ] 受到了 {damage:0.##} 点{dmgType}!");
}
else WriteLine("[ " + enemy + $" ] 受到了 {damage:0.##} 点物理伤害!");
enemy.HP -= damage;
// 统计伤害
CalculateCharacterDamageStatistics(actor, enemy, damage, isMagicDamage);
// 计算助攻
_assistDamage[actor][enemy] += damage;
// 造成伤害和受伤都可以获得能量
double ep = GetEP(damage, 0.03, 30);
effects = [.. actor.Effects];
foreach (Effect effect in effects)
{
effect.AlterEPAfterDamage(actor, ref ep);
}
actor.EP += ep;
ep = GetEP(damage, 0.015, 15);
effects = enemy.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.AlterEPAfterGetDamage(enemy, ref ep);
}
enemy.EP += ep;
}
effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.AfterDamageCalculation(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, damageResult);
}
if (enemy.HP <= 0 && !_eliminated.Contains(enemy) && !_respawnCountdown.ContainsKey(enemy))
{
LastRound.HasKill = true;
_roundDeaths.Add(enemy);
DeathCalculation(actor, enemy);
}
}
///
/// 治疗一个目标
///
///
///
///
///
public void HealToTarget(Character actor, Character target, double heal, bool canRespawn = false)
{
if (target.HP == target.MaxHP)
{
return;
}
bool isDead = target.HP <= 0;
if (heal < 0) heal = 0;
if (target.HP > 0 || (isDead && canRespawn))
{
target.HP += heal;
if (!LastRound.Heals.TryAdd(target, heal))
{
LastRound.Heals[target] += heal;
}
}
if (isDead && canRespawn)
{
if (target != actor)
{
WriteLine($"[ {target} ] 被 [ {actor} ] 复苏了,并回复了 {heal:0.##} 点生命值!!");
}
else
{
WriteLine($"[ {target} ] 复苏了,并回复了 {heal:0.##} 点生命值!!");
}
}
else
{
WriteLine($"[ {target} ] 回复了 {heal:0.##} 点生命值!");
}
}
///
/// 获取EP
///
/// 参数1
/// 参数2
/// 最大获取量
public static double GetEP(double a, double b, double max)
{
return Math.Min((a + Random.Shared.Next(30)) * b, max);
}
///
/// 计算物理伤害
///
///
///
///
///
///
///
public DamageResult CalculatePhysicalDamage(Character actor, Character enemy, bool isNormalAttack, double expectedDamage, out double finalDamage)
{
bool isMagic = false;
MagicType magicType = MagicType.None;
List effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.AlterDamageTypeBeforeCalculation(actor, enemy, ref isNormalAttack, ref isMagic, ref magicType);
}
if (isMagic)
{
return CalculateMagicalDamage(actor, enemy, isNormalAttack, magicType, expectedDamage, out finalDamage);
}
Dictionary totalDamageBonus = [];
effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, false, MagicType.None, totalDamageBonus);
totalDamageBonus[effect] = damageBonus;
}
expectedDamage += totalDamageBonus.Sum(kv => kv.Value);
double dice = Random.Shared.NextDouble();
double throwingBonus = 0;
bool checkEvade = true;
bool checkCritical = true;
if (isNormalAttack)
{
effects = actor.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
checkEvade = effect.BeforeEvadeCheck(actor, ref throwingBonus);
}
if (checkEvade)
{
// 闪避判定
if (dice < (enemy.EvadeRate + throwingBonus))
{
finalDamage = 0;
List characters = [actor, enemy];
bool isAlterEvaded = false;
effects = characters.SelectMany(c => c.Effects.Where(e => e.Level > 0)).ToList();
foreach (Effect effect in effects)
{
if (effect.OnEvadedTriggered(actor, enemy, dice))
{
isAlterEvaded = true;
}
}
if (!isAlterEvaded)
{
WriteLine("此物理攻击被完美闪避了!");
return DamageResult.Evaded;
}
}
}
}
// 物理穿透后的护甲
double penetratedDEF = (1 - actor.PhysicalPenetration) * enemy.DEF;
// 物理伤害减免
double physicalDamageReduction = penetratedDEF / (penetratedDEF + General.GameplayEquilibriumConstant.DEFReductionFactor);
// 最终的物理伤害
finalDamage = expectedDamage * (1 - Calculation.PercentageCheck(physicalDamageReduction + enemy.ExPDR));
// 暴击判定
effects = actor.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
checkCritical = effect.BeforeCriticalCheck(actor, ref throwingBonus);
}
if (checkCritical)
{
dice = Random.Shared.NextDouble();
if (dice < (actor.CritRate + throwingBonus))
{
finalDamage *= actor.CritDMG; // 暴击伤害倍率加成
WriteLine("暴击生效!!");
effects = actor.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.OnCriticalDamageTriggered(actor, dice);
}
return DamageResult.Critical;
}
}
// 是否有效伤害
return DamageResult.Normal;
}
///
/// 计算魔法伤害
///
///
///
///
///
///
///
///
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();
foreach (Effect effect in effects)
{
effect.AlterDamageTypeBeforeCalculation(actor, enemy, ref isNormalAttack, ref isMagic, ref magicType);
}
if (!isMagic)
{
return CalculatePhysicalDamage(actor, enemy, isNormalAttack, expectedDamage, out finalDamage);
}
Dictionary totalDamageBonus = [];
effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
double damageBonus = effect.AlterExpectedDamageBeforeCalculation(actor, enemy, expectedDamage, isNormalAttack, true, magicType, totalDamageBonus);
totalDamageBonus[effect] = damageBonus;
}
expectedDamage += totalDamageBonus.Sum(kv => kv.Value);
double dice = Random.Shared.NextDouble();
double throwingBonus = 0;
bool checkEvade = true;
bool checkCritical = true;
if (isNormalAttack)
{
effects = actor.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
checkEvade = effect.BeforeEvadeCheck(actor, ref throwingBonus);
}
if (checkEvade)
{
// 闪避判定
if (dice < (enemy.EvadeRate + throwingBonus))
{
finalDamage = 0;
List characters = [actor, enemy];
bool isAlterEvaded = false;
effects = characters.SelectMany(c => c.Effects.Where(e => e.Level > 0)).ToList();
foreach (Effect effect in effects)
{
if (effect.OnEvadedTriggered(actor, enemy, dice))
{
isAlterEvaded = true;
}
}
if (!isAlterEvaded)
{
WriteLine("此魔法攻击被完美闪避了!");
return DamageResult.Evaded;
}
}
}
}
double MDF = magicType switch
{
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
};
// 魔法穿透后的魔法抗性
MDF = (1 - actor.MagicalPenetration) * MDF;
// 最终的魔法伤害
finalDamage = expectedDamage * (1 - MDF);
// 暴击判定
effects = actor.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
checkCritical = effect.BeforeCriticalCheck(actor, ref throwingBonus);
}
if (checkCritical)
{
dice = Random.Shared.NextDouble();
if (dice < (actor.CritRate + throwingBonus))
{
finalDamage *= actor.CritDMG; // 暴击伤害倍率加成
WriteLine("暴击生效!!");
effects = actor.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect effect in effects)
{
effect.OnCriticalDamageTriggered(actor, dice);
}
return DamageResult.Critical;
}
}
// 是否有效伤害
return DamageResult.Normal;
}
public void ProcessCharacterDeath(Character character)
{
foreach (Character enemy in _roundDeaths)
{
// 给所有角色的特效广播角色死亡结算
List effects = _queue.SelectMany(c => c.Effects.Where(e => e.Level > 0)).ToList();
foreach (Effect effect in effects)
{
effect.AfterDeathCalculation(enemy, character, _continuousKilling, _earnedMoney);
}
// 将死者移出队列
_queue.Remove(enemy);
if (_isTeamMode)
{
Team? killTeam = GetTeam(character);
Team? deathTeam = GetTeam(enemy);
if (MaxRespawnTimes != 0)
{
string[] teamActive = Teams.OrderByDescending(kv => kv.Value.Score).Select(kv => {
int activeCount = kv.Value.GetActiveCharacters(this).Count;
if (kv.Value == killTeam)
{
activeCount += 1;
}
return kv.Key + ":" + kv.Value.Score + "(剩余存活人数:" + activeCount + ")";
}).ToArray();
WriteLine($"\r\n=== 当前死亡竞赛比分 ===\r\n{string.Join("\r\n", teamActive)}");
}
if (deathTeam != null)
{
List remain = deathTeam.GetActiveCharacters(this);
int remainCount = remain.Count;
if (remainCount == 0)
{
// 团灭了
_eliminatedTeams.Add(deathTeam);
_teams.Remove(deathTeam.Name);
}
else if (MaxRespawnTimes == 0)
{
WriteLine($"[ {deathTeam} ] 剩余成员:[ {string.Join(" ] / [ ", remain)} ]({remainCount} 人)");
}
}
if (killTeam != null)
{
List actives = killTeam.GetActiveCharacters(this);
actives.Add(character);
int remainCount = actives.Count;
if (remainCount > 0 && MaxRespawnTimes == 0)
{
WriteLine($"[ {killTeam} ] 剩余成员:[ {string.Join(" ] / [ ", actives)} ]({remainCount} 人)");
}
if (!_teams.Keys.Where(str => str != killTeam.Name).Any())
{
// 没有其他的团队了,游戏结束
EndGameInfo(killTeam);
return;
}
if (MaxScoreToWin > 0 && killTeam.Score >= MaxScoreToWin)
{
List combinedTeams = [.. _eliminatedTeams, .. _teams.Values];
combinedTeams.Remove(killTeam);
_eliminatedTeams.Clear();
_eliminatedTeams.AddRange(combinedTeams.OrderByDescending(t => t.Score));
EndGameInfo(killTeam);
return;
}
}
}
else
{
if (!_queue.Where(c => c != character).Any())
{
// 没有其他的角色了,游戏结束
EndGameInfo(character);
}
}
}
}
///
/// 死亡结算
///
///
///
public void DeathCalculation(Character killer, Character death)
{
if (!_continuousKilling.TryAdd(killer, 1)) _continuousKilling[killer] += 1;
if (!_maxContinuousKilling.TryAdd(killer, 1) && _continuousKilling[killer] > _maxContinuousKilling[killer])
{
_maxContinuousKilling[killer] = _continuousKilling[killer];
}
_stats[killer].Kills += 1;
_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();
double totalDamagePercentage = _assistDamage.Keys.Where(assists.Contains).Select(c => _assistDamage[c].GetPercentage(death)).Sum();
int totalMoney = Math.Min(Convert.ToInt32(money * totalDamagePercentage), 425); // 防止刷伤害设置金钱上限
// 按伤害比分配金钱 只有造成10%伤害以上才能参与
foreach (Character assist in assists)
{
int cmoney = Convert.ToInt32(_assistDamage[assist].GetPercentage(death) / totalDamagePercentage * totalMoney);
if (assist != killer)
{
if (!_earnedMoney.TryAdd(assist, cmoney)) _earnedMoney[assist] += cmoney;
_stats[assist].Assists += 1;
}
else
{
money = cmoney;
}
}
// 终结击杀的奖励仍然是全额的
if (_continuousKilling.TryGetValue(death, out int coefficient) && coefficient > 1)
{
money += (coefficient + 1) * Random.Shared.Next(50, 100);
string termination = CharacterSet.GetContinuousKilling(coefficient);
string msg = $"[ {killer} ] 终结了 [ {death} ]{(termination != "" ? " 的" + termination : "")},获得 {money} {General.GameplayEquilibriumConstant.InGameCurrency}!";
LastRound.DeathContinuousKilling.Add(msg);
if (assists.Length > 1)
{
msg += "助攻:[ " + string.Join(" ] / [ ", assists.Where(c => c != killer)) + " ]";
}
WriteLine(msg);
}
else
{
string msg = $"[ {killer} ] 杀死了 [ {death} ],获得 {money} {General.GameplayEquilibriumConstant.InGameCurrency}!";
LastRound.DeathContinuousKilling.Add(msg);
if (assists.Length > 1)
{
msg += "助攻:[ " + string.Join(" ] / [ ", assists.Where(c => c != killer)) + " ]";
}
WriteLine(msg);
}
if (FirstKiller is null)
{
FirstKiller = killer;
_stats[killer].FirstKills += 1;
_stats[death].FirstDeaths += 1;
money += 200;
WriteLine($"[ {killer} ] 拿下了第一滴血!额外奖励 200 {General.GameplayEquilibriumConstant.InGameCurrency}!!");
}
int kills = _continuousKilling[killer];
string continuousKilling = CharacterSet.GetContinuousKilling(kills);
string actorContinuousKilling = "";
if (kills == 2 || kills == 3)
{
actorContinuousKilling = "[ " + killer + " ] 完成了一次" + continuousKilling + "!";
}
else if (kills == 4)
{
actorContinuousKilling = "[ " + killer + " ] 正在" + continuousKilling + "!";
}
else if (kills > 4 && kills < 10)
{
actorContinuousKilling = "[ " + killer + " ] 已经" + continuousKilling + "!";
}
else if (kills >= 10)
{
actorContinuousKilling = "[ " + killer + " ] 已经" + continuousKilling + "!拜托谁去杀了他吧!!!";
}
if (actorContinuousKilling != "")
{
LastRound.ActorContinuousKilling.Add(actorContinuousKilling);
WriteLine(actorContinuousKilling);
}
if (!_earnedMoney.TryAdd(killer, money)) _earnedMoney[killer] += money;
if (_isTeamMode)
{
Team? team = GetTeam(killer);
if (team != null)
{
team.Score++;
}
}
// 清除对死者的助攻数据
List ads = [.. _assistDamage.Values.Where(ad => ad.Character != death)];
foreach (AssistDetail ad in ads)
{
ad[death] = 0;
}
_continuousKilling.Remove(death);
if (MaxRespawnTimes == 0)
{
_eliminated.Add(death);
}
else if (_respawnTimes.TryGetValue(death, out int times) && MaxRespawnTimes != -1 && times > MaxRespawnTimes)
{
WriteLine($"[ {death} ] 已达到复活次数上限,将不能再复活!!");
_eliminated.Add(death);
}
else
{
// 进入复活倒计时
double respawnTime = Calculation.Round2Digits(Math.Min(90, death.Level * 0.15 + times * 2.77 + coefficient * Random.Shared.Next(1, 3)));
_respawnCountdown.TryAdd(death, respawnTime);
LastRound.RespawnCountdowns.TryAdd(death, respawnTime);
WriteLine($"[ {death} ] 进入复活倒计时:{respawnTime:0.##} 时间!");
}
// 移除死者的施法
_castingSkills.Remove(death);
_castingSuperSkills.Remove(death);
// 因丢失目标而中断施法
List castingSkills = [.. _castingSkills.Keys];
foreach (Character caster in castingSkills)
{
SkillTarget st = _castingSkills[caster];
if (st.Targets.Remove(death) && st.Targets.Count == 0)
{
_castingSkills.Remove(caster);
if (caster.CharacterState == CharacterState.Casting)
{
caster.CharacterState = CharacterState.Actionable;
}
WriteLine($"[ {caster} ] 终止了 [ {st.Skill.Name} ] 的施法" + (_hardnessTimes[caster] > 3 ? ",并获得了 3 硬直时间的补偿。" : "。"));
if (_hardnessTimes[caster] > 3)
{
_hardnessTimes[caster] = 3;
}
}
}
}
///
/// 游戏结束信息
///
public void EndGameInfo(Character winner)
{
WriteLine("[ " + winner + " ] 是胜利者。");
_queue.Remove(winner);
_eliminated.Add(winner);
int top = 1;
WriteLine("");
WriteLine("=== 排名 ===");
for (int i = _eliminated.Count - 1; i >= 0; i--)
{
Character ec = _eliminated[i];
CharacterStatistics statistics = CharacterStatistics[ec];
string topCharacter = ec.ToString() +
(statistics.FirstKills > 0 ? " [ 第一滴血 ]" : "") +
(_maxContinuousKilling.TryGetValue(ec, out int kills) && kills > 1 ? $" [ {CharacterSet.GetContinuousKilling(kills)} ]" : "") +
(_earnedMoney.TryGetValue(ec, out int earned) ? $" [ 已赚取 {earned} {General.GameplayEquilibriumConstant.InGameCurrency} ]" : "");
if (top == 1)
{
WriteLine("冠军:" + topCharacter);
_stats[ec].Wins += 1;
_stats[ec].Top3s += 1;
}
else if (top == 2)
{
WriteLine("亚军:" + topCharacter);
_stats[ec].Loses += 1;
_stats[ec].Top3s += 1;
}
else if (top == 3)
{
WriteLine("季军:" + topCharacter);
_stats[ec].Loses += 1;
_stats[ec].Top3s += 1;
}
else
{
WriteLine($"第 {top} 名:" + topCharacter);
_stats[ec].Loses += 1;
}
_stats[ec].Plays += 1;
_stats[ec].TotalEarnedMoney += earned;
_stats[ec].LastRank = top;
top++;
}
WriteLine("");
_isGameEnd = true;
}
///
/// 游戏结束信息 [ 团队版 ]
///
public void EndGameInfo(Team winner)
{
WriteLine("[ " + winner + " ] 是胜利者。");
int top = 1;
WriteLine("");
WriteLine("=== 排名 ===");
WriteLine("");
_eliminatedTeams.Add(winner);
_teams.Remove(winner.Name);
for (int i = _eliminatedTeams.Count - 1; i >= 0; i--)
{
Team team = _eliminatedTeams[i];
string topTeam = "";
if (top == 1)
{
topTeam = "冠军";
}
if (top == 2)
{
topTeam = "亚军";
}
if (top == 3)
{
topTeam = "季军";
}
if (top > 3)
{
topTeam = $"第 {top} 名";
}
topTeam = $"☆--- {topTeam}团队:" + team.Name + " ---☆" + $"(得分:{team.Score})\r\n";
foreach (Character ec in team.Members)
{
CharacterStatistics statistics = CharacterStatistics[ec];
string respawning = "";
if (ec.HP <= 0)
{
respawning = "[ " + (_respawnCountdown.TryGetValue(ec, out double time) && time > 0 ? $"{time:0.##} 时间后复活" : "阵亡") + " ] ";
}
string topCharacter = respawning + ec.ToString() +
(statistics.FirstKills > 0 ? " [ 第一滴血 ]" : "") +
(_maxContinuousKilling.TryGetValue(ec, out int kills) && kills > 1 ? $" [ {CharacterSet.GetContinuousKilling(kills)} ]" : "") +
(_earnedMoney.TryGetValue(ec, out int earned) ? $" [ 已赚取 {earned} {General.GameplayEquilibriumConstant.InGameCurrency} ]" : "") +
$"({statistics.Kills} / {statistics.Assists}{(MaxRespawnTimes != 0 ? " / " + statistics.Deaths : "")})";
topTeam += topCharacter + "\r\n";
if (top == 1)
{
_stats[ec].Wins += 1;
_stats[ec].Top3s += 1;
}
else if (top == 2)
{
_stats[ec].Loses += 1;
_stats[ec].Top3s += 1;
}
else if (top == 3)
{
_stats[ec].Loses += 1;
_stats[ec].Top3s += 1;
}
else
{
_stats[ec].Loses += 1;
}
_stats[ec].Plays += 1;
_stats[ec].TotalEarnedMoney += earned;
_stats[ec].LastRank = top;
}
WriteLine(topTeam);
top++;
}
WriteLine("");
_isGameEnd = true;
}
///
/// 检查是否可以释放技能
///
///
///
///
///
public bool CheckCanCast(Character caster, Skill skill, out double cost)
{
if (skill.SkillType == SkillType.Magic)
{
cost = skill.RealMPCost;
if (cost > 0 && cost <= caster.MP)
{
return true;
}
else
{
WriteLine("[ " + caster + $" ] 魔法不足!");
}
}
else
{
cost = skill.RealEPCost;
if (cost > 0 && cost <= caster.EP)
{
return true;
}
else
{
WriteLine("[ " + caster + $" ] 能量不足!");
}
}
return false;
}
///
/// 是否在回合外释放爆发技插队
///
/// 当前正在行动的角色
///
public void WillPreCastSuperSkill(Character character)
{
// 选取在顺序表一半之后的角色
foreach (Character other in _queue.Where(c => c != character && c.CharacterState == CharacterState.Actionable && _queue.IndexOf(c) >= _queue.Count / 2).ToList())
{
// 有 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();
if (skills.Count > 0)
{
Skill skill = skills[Random.Shared.Next(skills.Count)];
_castingSuperSkills.Add(other, skill);
other.CharacterState = CharacterState.PreCastSuperSkill;
_queue.Remove(other);
_cutCount.Remove(character);
AddCharacter(other, 0, false);
WriteLine("[ " + other + " ] 预释放了爆发技!!");
foreach (Character c in _hardnessTimes.Keys)
{
if (_hardnessTimes[c] != 0)
{
_hardnessTimes[c] = Calculation.Round2Digits(_hardnessTimes[c] + 0.01);
}
}
skill.OnSkillCasting(this, other, []);
}
}
}
}
///
/// 打断施法
///
///
///
public void InterruptCasting(Character caster, Character interrupter)
{
Skill? skill = null;
if (_castingSkills.TryGetValue(caster, out SkillTarget target))
{
skill = target.Skill;
_castingSkills.Remove(caster);
}
else if (_castingSuperSkills.TryGetValue(caster, out skill))
{
_castingSuperSkills.Remove(caster);
}
if (skill != null)
{
WriteLine($"[ {caster} ] 的施法被 [ {interrupter} ] 打断了!!");
List effects = skill.Effects.Where(e => e.Level > 0).ToList();
foreach (Effect e in effects)
{
e.OnSkillCastInterrupted(caster, skill, interrupter);
}
}
}
///
/// 通过概率计算角色要干嘛
///
///
///
///
///
public static CharacterActionType GetActionType(double pUseItem, double pCastSkill, double pNormalAttack)
{
if (pUseItem == 0 && pCastSkill == 0 && pNormalAttack == 0)
{
return CharacterActionType.None;
}
double total = pUseItem + pCastSkill + pNormalAttack;
// 浮点数比较时处理误差
if (Math.Abs(total - 1) > 1e-6)
{
pUseItem /= total;
pCastSkill /= total;
pNormalAttack /= total;
}
double rand = Random.Shared.NextDouble();
// 按概率进行检查
if (rand < pUseItem)
{
return CharacterActionType.UseItem;
}
if (rand < pUseItem + pCastSkill)
{
return CharacterActionType.PreCastSkill;
}
if (rand < pUseItem + pCastSkill + pNormalAttack)
{
return CharacterActionType.NormalAttack;
}
return CharacterActionType.None;
}
///
/// 计算角色的数据
///
public void CalculateCharacterDamageStatistics(Character character, Character characterTaken, double damage, bool isMagic)
{
if (_stats.TryGetValue(character, out CharacterStatistics? stats) && stats != null)
{
if (isMagic)
{
stats.TotalMagicDamage = Calculation.Round2Digits(stats.TotalMagicDamage + damage);
}
else
{
stats.TotalPhysicalDamage = Calculation.Round2Digits(stats.TotalPhysicalDamage + damage);
}
stats.TotalDamage = Calculation.Round2Digits(stats.TotalDamage + damage);
}
if (_stats.TryGetValue(characterTaken, out CharacterStatistics? statsTaken) && statsTaken != null)
{
if (isMagic)
{
statsTaken.TotalTakenMagicDamage = Calculation.Round2Digits(statsTaken.TotalTakenMagicDamage + damage);
}
else
{
statsTaken.TotalTakenPhysicalDamage = Calculation.Round2Digits(statsTaken.TotalTakenPhysicalDamage + damage);
}
statsTaken.TotalTakenDamage = Calculation.Round2Digits(statsTaken.TotalTakenDamage + damage);
}
if (LastRound.Damages.TryGetValue(characterTaken, out double damageTotal))
{
LastRound.Damages[characterTaken] = damageTotal + damage;
}
else
{
LastRound.Damages[characterTaken] = damage;
}
}
///
/// 装备物品
///
///
///
public void Equip(Character character, Item item)
{
if (character.Equip(item))
{
EquipSlotType type = item.EquipSlotType;
WriteLine($"[ {character} ] 装备了 [ {item.Name} ]。" + (type != EquipSlotType.None ? $"({ItemSet.GetEquipSlotTypeName(type)} 栏位)" : ""));
}
}
///
/// 装备物品到指定栏位
///
///
///
///
public void Equip(Character character, EquipSlotType type, Item item)
{
if (character.Equip(item, type))
{
WriteLine($"[ {character} ] 装备了 [ {item.Name} ]。({ItemSet.GetEquipSlotTypeName(type)} 栏位)");
}
}
///
/// 取消装备
///
///
///
public void UnEquip(Character character, EquipSlotType type)
{
Item? item = character.UnEquip(type);
if (item != null)
{
WriteLine($"[ {character} ] 取消装备了 [ {item.Name} ]。({ItemSet.GetEquipSlotTypeName(type)} 栏位)");
}
}
///
/// 选取技能目标
///
///
///
///
///
///
///
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);
if (targets.Count == 0)
{
cancel = true;
}
return targets;
}
///
/// 选取普通攻击目标
///
///
///
///
///
///
///
public virtual List SelectTargets(Character character, NormalAttack attack, List enemys, List teammates, out bool cancel)
{
cancel = false;
if (enemys.Count > 0)
{
List targets = [enemys[Random.Shared.Next(enemys.Count)]];
return targets;
}
return [];
}
}
}