using FL.Nodes.GameMain;
using UnityEngine;
using XGame.Database;
using XGame.Framework.Components;
namespace FL.Battle.Components
{
public interface ICombatContext
{
IEntity Entity { get; }
ITargetSelector Selector { get; }
Vector3 Position { get; }
StatesComponent States { get; }
BuffsComponent Buffs { get; }
SkillComponent Skill { get; }
///
/// 铭文组件
/// 可能为空
///
EpigraphicsComponent Epigraphics { get; }
}
public class CombatComponent : Component, ICombatCalculation
{
protected override void OnDispose()
{
}
///
/// 计算血量
/// 正数表示加血
/// 负数表示扣血
///
///
///
private int CalculateHP(int damage)
{
var remainDamage = Context.Buffs.CalculateShieldAbsorb(damage);
if (remainDamage == 0)
{ // 全部被护盾吸收
return damage;
}
// 吸收值
var absorption = damage - remainDamage;
var attrs = Context.Entity.Attr;
var lastHp = attrs.CurrentHp;
var nextHp = lastHp + remainDamage;
if (nextHp > attrs.HpLimit)
{
nextHp = attrs.HpLimit;
}
else if (nextHp < 0)
{
nextHp = 0;
}
attrs.CurrentHp = nextHp;
if (nextHp == 0)
{
Context.States.AddState(EEntityState.Dead);
}
var result = (int)(nextHp - lastHp);
// 返回扣血和护盾吸收的总和
return result + absorption;
}
private void AddSkillBuff(SkillTable skill, ITarget attacker, int damage)
{
if (skill.BuffTie.Length != 2)
return;
var probability = skill.BuffTie[0];
var buffId = skill.BuffTie[1];
if (TryGetTrigger(BuffTableRepo.GetTargetType(buffId), attacker, out var trigger))
{
trigger?.Buffs.TryAddBuff(buffId, probability, 1, null, damage);
}
else
{
Context.Buffs.TryAddBuff(buffId, probability, 1, attacker?.Calculation, damage);
}
}
///
/// 根据技能/Buff的目标类型确定触发目标
///
///
///
///
private ICombatCalculation GetTrigger(ESkillTargetType targetType, ICombatCalculation attacker)
{
if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Attacker))
{
return attacker;
}
if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Player))
{
return Context.Selector.GetPlayer()?.Calculation;
}
return this;
}
private bool TryGetTrigger(ESkillTargetType targetType, ITarget attacker, out ITarget trigger)
{
if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Attacker))
{
trigger = attacker;
return true;
}
if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Player))
{
trigger = Context.Selector.GetPlayer();
return true;
}
trigger = null;
return false;
}
#region 被动技能
//private void TickAttackerPassiveSkill(SkillTable skill, ICombatCalculation target)
//{
// Context.Skill.TryTickPassiveSkills((passiveSkill) =>
// {
// return true;
// });
//}
#endregion
#region 接口实现
void ICombatCalculation.Damage(int damage, long attackerId, SkillTable skill)
{
if (Context.Entity.IsDead)
{ // 已经死亡
return;
}
ITarget attacker = null;
if (damage != 0)
{ // damage为零时不计算
var damageAdd = 0;
if (attackerId != Context.Entity.EntityId)
{ // 攻击者和受击者是同一个目标时不计算加成
attacker = Context.Selector.GetTarget(attackerId);
if (attacker != null && !attacker.IsDead)
{
damageAdd += attacker.Buffs.GetDamageAdd(skill.Element, Context.Entity, Context.Buffs);
}
}
damageAdd += Context.Buffs.GetDamageAdd(skill.Element, Context.Entity, Context.Buffs);
var realDamage = Mathf.CeilToInt(damage * (1 + damageAdd.ToRealFloat()));
damage = CalculateHP(realDamage);
EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, new HpAddDto()
{
entityId = Context.Entity.EntityId,
position = Context.Position,
hpValue = damage,
elementType = skill.Element,
});
//攻击者触发铭文
attacker?.Calculation.TickEpigraph(Context.Entity.EntityId, skill.Element, realDamage);
// 受击目标的buff触发
Context.Buffs.TickBuffOrSkill(damage, skill.Element, attacker?.Calculation);
}
//TODO 攻击者的buff触发
AddSkillBuff(skill, attacker, damage);
//TODO 受击者的被动技能
//TODO 攻击者的被动技能
//if (attacker != null && (attacker.Calculation is CombatComponent atkCalculation))
//{
// atkCalculation.TickAttackerPassiveSkill(skill, this);
//}
}
void ICombatCalculation.Damage(int damage, EElementType elementType)
{
if (Context.Entity.IsDead)
{ // 已经死亡
return;
}
damage = CalculateHP(damage);
if (damage == 0)
return;
EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, new HpAddDto()
{
entityId = Context.Entity.EntityId,
position = Context.Position,
hpValue = damage,
elementType = elementType,
});
}
ICombatCalculation ICombatCalculation.GetSkillTrigger(long skillId, ICombatCalculation attacker)
{
return GetTrigger(SkillTableRepo.GetTargetType(skillId), attacker);
}
ICombatCalculation ICombatCalculation.GetBuffTrigger(long buffId, ICombatCalculation attacker)
{
return GetTrigger(BuffTableRepo.GetTargetType(buffId), attacker);
}
void ICombatCalculation.TickSkill(long skillId, long targetId, int probability)
{
// TODO
Context.Skill.TryTickSkill((int)skillId, targetId, probability);
}
void ICombatCalculation.TickBuff(long buffId, int probability, int addLayer, int damage)
{
Context.Buffs.TryAddBuff(buffId, probability, addLayer, null, damage);
}
void ICombatCalculation.TickEpigraph(long targetId, EElementType skillElementType, int damage)
{
Context.Epigraphics?.TryTickIceToPoison(targetId, skillElementType, damage);
}
#endregion
}
}