using System.Text;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Entity
{
///
/// 与 不同,构造技能时,建议继承此类再构造
///
public class Skill : BaseEntity, ISkill, IActiveEnable
{
///
/// 唯一标识符 [ 只有物品技能需要赋值,用于表示与其关联的物品: ]
/// 其他情况请保持此属性为
///
public override Guid Guid { get; set; } = Guid.Empty;
///
/// 此技能所属的角色
///
public Character? Character { get; set; } = null;
///
/// 技能描述
///
public virtual string Description { get; set; } = "";
///
/// 技能的通用描述
///
public virtual string GeneralDescription { get; set; } = "";
///
/// 驱散性和被驱散性的描述
///
public virtual string DispelDescription { get; set; } = "";
///
/// 释放技能时的口号
///
public virtual string Slogan { get; set; } = "";
///
/// 技能等级,等于 0 时可以称之为尚未学习
///
public int Level
{
get
{
return Math.Max(0, _Level);
}
set
{
int max = SkillSet.GetSkillMaxLevel(SkillType, GameplayEquilibriumConstant);
_Level = Math.Min(Math.Max(0, value), max);
OnLevelUp();
}
}
///
/// 技能类型 [ 此项为最高优先级 ]
///
[InitRequired]
public SkillType SkillType { get; set; } = SkillType.Passive;
///
/// 是否是主动技能 [ 此项为高优先级 ]
///
public bool IsActive => SkillType != SkillType.Passive;
///
/// 是否可用 [ 此项为高优先级 ]
///
public bool Enable { get; set; } = true;
///
/// 效果持续生效中 [ 此项为高优先级 ] [ 此项设置为true后不允许再次释放,防止重复释放 ]
///
public bool IsInEffect { get; set; } = false;
///
/// 是否是爆发技 [ 此项为高优先级 ]
///
public bool IsSuperSkill => SkillType == SkillType.SuperSkill;
///
/// 是否属于魔法 [ 必须为 true ],反之为战技
///
public bool IsMagic => SkillType == SkillType.Magic;
///
/// 是否无视施法距离(全图施法),魔法默认为 true,战技默认为 false
///
public bool CastAnyWhere { get; set; } = false;
///
/// 施法距离 [ 单位:格 ]
///
[InitOptional]
public int CastRange { get; set; } = 5;
///
/// 可选取自身
///
public virtual bool CanSelectSelf { get; set; } = false;
///
/// 可选取敌对角色
///
public virtual bool CanSelectEnemy { get; set; } = true;
///
/// 可选取友方角色
///
public virtual bool CanSelectTeammate { get; set; } = false;
///
/// 选取所有敌对角色,优先级大于
///
public virtual bool SelectAllEnemies { get; set; } = false;
///
/// 选取所有友方角色,优先级大于 ,默认包含自身
///
public virtual bool SelectAllTeammates { get; set; } = false;
///
/// 可选取的作用目标数量
///
public virtual int CanSelectTargetCount { get; set; } = 1;
///
/// 可选取的作用范围 [ 单位:格 ]
///
public virtual int CanSelectTargetRange { get; set; } = 0;
///
/// 选取角色的条件
///
public List> SelectTargetPredicates { get; } = [];
///
/// 实际魔法消耗 [ 魔法 ]
///
public double RealMPCost => Math.Max(0, MPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * GameplayEquilibriumConstant.INTtoCastMPReduce)));
///
/// 魔法消耗 [ 魔法 ]
///
[InitOptional]
public virtual double MPCost { get; set; } = 0;
///
/// 吟唱时间 [ 魔法 ]
///
[InitOptional]
public virtual double CastTime { get; set; } = 0;
///
/// 实际吟唱时间 [ 魔法 ]
///
public double RealCastTime => Math.Max(0, CastTime * (1 - Calculation.PercentageCheck(Character?.AccelerationCoefficient ?? 0)));
///
/// 实际能量消耗 [ 战技 ]
///
public double RealEPCost => CostAllEP ? Math.Max(MinCostEP, Character?.EP ?? MinCostEP) : (IsSuperSkill ? EPCost : Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * GameplayEquilibriumConstant.INTtoCastEPReduce))));
///
/// 能量消耗 [ 战技 ]
///
[InitOptional]
public virtual double EPCost { get; set; } = 0;
///
/// 消耗所有能量 [ 战技 ]
///
public virtual bool CostAllEP { get; set; } = false;
///
/// 消耗所有能量的最小能量限制 [ 战技 ] 默认值:100
///
public virtual double MinCostEP { get; set; } = 100;
///
/// 上一次释放此技能消耗的魔法 [ 魔法 ]
///
public double LastCostMP { get; set; } = 0;
///
/// 上一次释放此技能消耗的能量 [ 战技 ]
///
public double LastCostEP { get; set; } = 0;
///
/// 实际冷却时间
///
public double RealCD => Math.Max(0, CD * (1 - (Character?.CDR ?? 0)));
///
/// 冷却时间
///
[InitRequired]
public virtual double CD { get; set; } = 0;
///
/// 剩余冷却时间 [ 建议配合 属性使用 ]
///
public double CurrentCD { get; set; } = 0;
///
/// 硬直时间
///
[InitRequired]
public virtual double HardnessTime { get; set; } = 0;
///
/// 额外硬直时间 [ 技能和物品相关 ]
///
public double ExHardnessTime { get; set; } = 0;
///
/// 额外硬直时间% [ 技能和物品相关 ]
///
public double ExHardnessTime2 { get; set; } = 0;
///
/// 实际硬直时间
///
public double RealHardnessTime => Math.Max(0, (HardnessTime + ExHardnessTime) * (1 + ExHardnessTime2) * (1 - Calculation.PercentageCheck(Character?.ActionCoefficient ?? 0)));
///
/// 效果列表
///
public HashSet Effects { get; } = [];
///
/// 用于动态扩展技能的参数
///
public Dictionary Values { get; } = [];
///
/// 游戏中的行动顺序表实例,在技能效果被触发时,此实例会获得赋值,使用时需要判断其是否存在
///
public IGamingQueue? GamingQueue { get; set; } = null;
///
/// 技能是否属于某个物品
///
public Item? Item { get; set; } = null;
///
/// 继承此类实现时,调用基类的构造函数
///
///
///
protected Skill(SkillType type, Character? character = null)
{
SkillType = type;
CastAnyWhere = SkillType == SkillType.Magic;
Character = character;
}
///
/// 用于构造 JSON
///
internal Skill() { }
///
/// 设置一些属性给从工厂构造出来的 对象
///
///
public void SetPropertyToItemModuleNew(Skill newbyFactory)
{
newbyFactory.GamingQueue = GamingQueue;
newbyFactory.Enable = Enable;
newbyFactory.IsInEffect = IsInEffect;
newbyFactory.CurrentCD = CurrentCD;
}
///
/// 触发技能升级
///
public void OnLevelUp()
{
if (!IsActive && Level > 0)
{
foreach (Effect e in AddPassiveEffectToCharacter())
{
e.GamingQueue = GamingQueue;
if (Character != null && !Character.Effects.Contains(e))
{
Character.Effects.Add(e);
e.OnEffectGained(Character);
}
}
}
if (Level > 0 && Character != null)
{
Effect[] effects = [.. Character.Effects.Where(e => e.IsInEffect)];
foreach (Effect e in effects)
{
e.OnSkillLevelUp(Character, Level);
}
}
}
///
/// 当获得技能时
///
///
public void OnSkillGained(IGamingQueue queue)
{
GamingQueue = queue;
OnLevelUp();
}
///
/// 在技能持有者的回合开始前
///
///
///
///
///
///
public virtual void OnTurnStart(Character character, List enemys, List teammates, List skills, List- items)
{
}
///
/// 获取可选择的目标列表
///
///
///
///
///
public virtual List GetSelectableTargets(Character caster, List enemys, List teammates)
{
List selectable = [];
if (CanSelectSelf)
{
selectable.Add(caster);
}
ImmuneType checkType = ImmuneType.Skilled | ImmuneType.All;
if (IsMagic)
{
checkType |= ImmuneType.Magical;
}
foreach (Character character in enemys)
{
IEnumerable effects = character.Effects.Where(e => e.IsInEffect);
if (CanSelectEnemy && ((character.ImmuneType & checkType) == ImmuneType.None ||
effects.Any(e => e.IgnoreImmune == ImmuneType.All || e.IgnoreImmune == ImmuneType.Skilled || (IsMagic && e.IgnoreImmune == ImmuneType.Magical))))
{
selectable.Add(character);
}
}
foreach (Character character in teammates)
{
IEnumerable effects = character.Effects.Where(e => e.IsInEffect);
if (CanSelectTeammate && ((character.ImmuneType & checkType) == ImmuneType.None ||
effects.Any(e => e.IgnoreImmune == ImmuneType.All || e.IgnoreImmune == ImmuneType.Skilled || (IsMagic && e.IgnoreImmune == ImmuneType.Magical))))
{
selectable.Add(character);
}
}
// 其他条件
selectable = [.. selectable.Where(c => SelectTargetPredicates.All(f => f(c)))];
return selectable;
}
///
/// 选取技能目标
///
///
///
///
///
public virtual List SelectTargets(Character caster, List enemys, List teammates)
{
List tobeSelected = GetSelectableTargets(caster, enemys, teammates);
List targets = [];
if (SelectAllTeammates || SelectAllEnemies)
{
if (SelectAllTeammates)
{
targets.AddRange(tobeSelected.Where(c => c == caster || teammates.Contains(c)));
}
if (SelectAllEnemies)
{
targets.AddRange(tobeSelected.Where(enemys.Contains));
}
}
else if (tobeSelected.Count <= CanSelectTargetCount)
{
targets.AddRange(tobeSelected);
}
else
{
targets.AddRange(tobeSelected.OrderBy(x => Random.Shared.Next()).Take(CanSelectTargetCount));
}
return [.. targets.Distinct()];
}
///
/// 技能开始吟唱时 [ 吟唱魔法、释放战技和爆发技、预释放爆发技均可触发 ]
///
///
///
///
public void OnSkillCasting(IGamingQueue queue, Character caster, List targets)
{
GamingQueue = queue;
foreach (Effect e in Effects)
{
e.GamingQueue = GamingQueue;
e.OnSkillCasting(caster, targets);
}
}
///
/// 技能效果触发前
///
public void BeforeSkillCasted()
{
LastCostMP = RealMPCost;
LastCostEP = RealEPCost;
}
///
/// 触发技能效果 [ 局内版 ]
///
///
///
///
public void OnSkillCasted(IGamingQueue queue, Character caster, List targets)
{
GamingQueue = queue;
foreach (Effect e in Effects)
{
e.GamingQueue = GamingQueue;
e.OnSkillCasted(caster, targets, Values);
}
}
///
/// 对目标触发技能效果
///
///
///
public void OnSkillCasted(User user, List targets)
{
foreach (Effect e in Effects)
{
e.OnSkillCasted(user, targets, Values);
}
}
///
/// 检查角色是否在 AI 控制状态
///
///
///
public bool IsCharacterInAIControlling(Character character)
{
return GamingQueue?.IsCharacterInAIControlling(character) ?? false;
}
///
/// 被动技能,需要重写此方法,返回被动特效给角色 [ 此方法会在技能学习时触发 ]
///
///
public virtual IEnumerable AddPassiveEffectToCharacter()
{
return [];
}
///
/// 返回技能的详细说明
///
///
///
///
///
public string GetInfo(bool showOriginal = false, bool showCD = true, bool showHardness = true)
{
StringBuilder builder = new();
string type = IsSuperSkill ? "【爆发技】" : (IsMagic ? "【魔法】" : (IsActive ? "【主动】" : "【被动】"));
string level = Level > 0 ? " - 等级 " + Level : " - 尚未学习";
builder.AppendLine(type + Name + level);
builder.AppendLine("技能描述:" + (Level == 0 && GeneralDescription.Trim() != "" ? GeneralDescription : Description));
if (CurrentCD > 0)
{
builder.AppendLine($"正在冷却:剩余 {CurrentCD:0.##} {GameplayEquilibriumConstant.InGameTime}");
}
if (!Enable)
{
builder.AppendLine("技能当前不可用");
}
if (IsInEffect)
{
builder.AppendLine("效果结束前不可用");
}
if (DispelDescription != "")
{
builder.AppendLine($"{DispelDescription}");
}
if (IsActive && (Item?.IsInGameItem ?? true))
{
if (SkillType == SkillType.Item)
{
if (RealMPCost > 0)
{
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}{(showOriginal && RealMPCost != MPCost ? $"(原始值:{MPCost:0.##})" : "")}");
}
if (RealEPCost > 0)
{
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost:0.##})" : "")}");
}
}
else
{
if (IsSuperSkill)
{
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost:0.##})" : "")}");
}
else
{
if (IsMagic)
{
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}{(showOriginal && RealMPCost != MPCost ? $"(原始值:{MPCost:0.##})" : "")}");
builder.AppendLine($"吟唱时间:{RealCastTime:0.##}{(showOriginal && RealCastTime != CastTime ? $"(原始值:{CastTime:0.##})" : "")}");
}
else
{
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost:0.##})" : "")}");
}
}
}
if (showCD && CD > 0)
{
builder.AppendLine($"冷却时间:{RealCD:0.##}{(showOriginal && RealCD != CD ? $"(原始值:{CD:0.##})" : "")}");
}
if (showHardness && HardnessTime > 0)
{
builder.AppendLine($"硬直时间:{RealHardnessTime:0.##}{(showOriginal && RealHardnessTime != HardnessTime ? $"(原始值:{HardnessTime:0.##})" : "")}");
}
}
return builder.ToString();
}
///
/// 返回技能的详细说明
///
///
public override string ToString() => GetInfo(true);
///
/// 返回技能的详细说明,有选项
///
///
///
///
///
public string ToString(bool showOriginal, bool showCD, bool showHardness)
{
return GetInfo(showOriginal, showCD, showHardness);
}
///
/// 判断两个技能是否相同 检查Id.Name
///
///
///
public override bool Equals(IBaseEntity? other)
{
return other is Skill c && c.Id + "." + c.Name == Id + "." + Name;
}
///
/// 复制一个技能
///
///
public Skill Copy(bool copyProperty = true, IEnumerable? skillsDefined = null)
{
Dictionary args = new()
{
{ "values", Values }
};
Skill? skillDefined = null;
if (skillsDefined != null && skillsDefined.FirstOrDefault(i => i.GetIdName() == GetIdName()) is Skill temp)
{
skillDefined = temp;
}
if (skillDefined != null)
{
args["values"] = skillDefined.Values;
}
Skill skill = Factory.OpenFactory.GetInstance(Id, Name, args);
skillDefined ??= this;
if (copyProperty) SetPropertyToItemModuleNew(skill);
skill.Id = skillDefined.Id;
skill.Name = skillDefined.Name;
skill.Description = skillDefined.Description;
skill.GeneralDescription = skillDefined.GeneralDescription;
skill.DispelDescription = skillDefined.DispelDescription;
skill.SkillType = skillDefined.SkillType;
skill.MPCost = skillDefined.MPCost;
skill.CastTime = skillDefined.CastTime;
skill.EPCost = skillDefined.EPCost;
skill.CD = skillDefined.CD;
skill.HardnessTime = skillDefined.HardnessTime;
skill.GamingQueue = skillDefined.GamingQueue;
if (skill is OpenSkill)
{
foreach (Effect e in skillDefined.Effects)
{
// 特效没法动态扩展,必须使用编程钩子实现,因此动态扩展的技能需要使用代码定义的特效
Effect neweffect = e.Copy(skill, true);
if (skill.GamingQueue != null)
{
neweffect.GamingQueue = skill.GamingQueue;
}
skill.Effects.Add(neweffect);
}
}
return skill;
}
///
/// 等级
///
private int _Level = 0;
}
}