using FL.Battle.Buffs;
using System.Collections.Generic;
using UnityEngine;
using XGame;
using XGame.Database;
using XGame.Framework;
using XGame.Framework.Components;
using XGame.Framework.Map;
using XGame.Framework.Time;
namespace FL.Battle.Components
{
public interface IBuffsContext
{
public IEntity Entity { get; }
public ITimeModule Time { get; }
public IMapAssetModule Asset { get; }
Vector3 Position { get; }
Transform OwnerTr { get; }
ICombatCalculation Calculation { get; }
StatesComponent States { get; }
MoveComponent Move { get; }
}
///
/// buff的逻辑控制脚本
///
public partial class BuffsComponent : Component, IBuffListener
{
private Dictionary _buffsMap = new Dictionary();
protected override void OnEnable(object intent)
{
TotalShieldVal = 0;
}
protected override void OnDisable()
{
Clear();
}
protected override void OnDispose()
{
Clear();
}
public bool IsDirty { get; set; }
public int BuffCount => _buffsMap.Count;
///
/// 护盾buff是否有变化
///
public bool IsShieldDirty { get; set; }
///
/// 所有护盾吸收值
///
public long TotalShieldVal { get; private set; }
public List GetBuffs()
{
var buffs = ListPool.Acquire();
foreach (var buff in _buffsMap.Values)
{
if (!buff.IsShowIcon)
continue;
buffs.Add(buff);
}
return buffs;
}
public bool GetElementBuffs(ref List buffs)
{
if (buffs == null)
{
buffs = new List();
}
var lastCount = buffs.Count;
foreach (var buff in _buffsMap.Values)
{
if (buff is ElementAddDebuff element && element.IsReachLayer3())
{
buffs.Add(buff);
}
}
return buffs.Count > lastCount;
}
/////
///// 获取最近的可触发效果的元素buff
/////
/////
//public IBuff GetPreTickElementBuff()
//{
// Buff result = null;
// foreach (var buff in _buffsMap.Values)
// {
// if (buff.ElementType == EElementType.None)
// continue;
// if (buff.Layers == buff.LayerLimit)
// {
// result = buff;
// break;
// }
// if (result == null || (float)buff.Layers / buff.LayerLimit > (float)result.Layers / result.LayerLimit)
// {
// result = buff;
// }
// }
// return result;
//}
public bool IsContains(EBuffType buffType)
{
foreach (var buff in _buffsMap.Values)
{
if (buff.BuffType == buffType)
return true;
}
return false;
}
public int GetLayers(long buffId)
{
if (_buffsMap.TryGetValue(buffId, out var buff))
{
return buff.Layers;
}
return 0;
}
//void IUpdate.Update(int millisecond)
//{
// _updateBuffs.AddRange(_buffsMap.Values);
// foreach (var buff in _updateBuffs)
// {
// if (buff.Update(millisecond))
// {
// _buffsMap.Remove(buff.TableId);
// }
// }
// _updateBuffs.Clear();
//}
///
/// 护盾吸收
///
///
/// 护盾吸收后剩余的伤害值 负数
public int CalculateShieldAbsorb(int damage)
{
if (damage >= 0)
return damage;
var tempBuffs = ListPool.Acquire();
tempBuffs.AddRange(_buffsMap.Values);
foreach (var buff in tempBuffs)
{ // 遍历中buff的数量可能会增减
if (buff is ShieldBuff shieldBuff)
{
damage = shieldBuff.Reduce(damage);
if (damage == 0)
break; // 剩余伤害为零,全部吸收了
}
}
ListPool.Recycle(tempBuffs);
return damage;
}
///
/// 获取技能伤害Buff加成
///
///
///
///
public int GetDamageAdd(EElementType elementType, IEntity target, BuffsComponent targetBuffs)
{
var result = 0;
foreach (var buff in _buffsMap.Values)
{
var buffType = buff.BuffType;
if (buffType is EBuffType.DizzAdd)
{
if (target.IsState(EEntityState.Dizzy))
{
result += buff.Table.BuffTypeNum[0];
}
}
else if (buffType is EBuffType.FreezeAdd)
{
if (target.IsState(EEntityState.Freeze))
{
result += buff.Table.BuffTypeNum[0];
}
}
else if (buffType is EBuffType.DotAdd)
{
if (targetBuffs.IsContains(EBuffType.Dot))
{
result += buff.Table.BuffTypeNum[0];
}
}
else if (elementType == EElementType.None)
{ // 非元素技能
continue;
}
else if (buffType != EBuffType.ElementAddIce || target.EntityId != Context.Entity.EntityId ||
((buff as ElementAddDebuff)?.IsReachLayer5(elementType) ?? false))
{ // 目标有冻伤
continue;
}
else
{// 目标有冻伤 且 本次攻击没有达到5层元素易伤条件
result += buff.Table.BuffTypeNum[1];
}
}
return result;
}
///
/// 检测受击目标的buff触发
///
///
///
///
public void TickBuffOrSkill(int damage, EElementType elementType, ICombatCalculation attacker)
{
if (elementType == EElementType.None)
return; // TODO 目前只有元素技能会触发buff
var tempBuffs = ListPool.Acquire();
tempBuffs.AddRange(_buffsMap.Values);
foreach (var buff in tempBuffs)
{ // 遍历中buff的数量可能会增减
if (buff is ElementAddDebuff elementAddDebuff)
{
elementAddDebuff.TryTickBuff(damage, elementType, attacker);
}
}
ListPool.Recycle(tempBuffs);
}
public void TryAddBuff(long buffId, int probability, int addLayer = 1, ICombatCalculation attacker = null, int damage = 0)
{
if (Context.Entity.IsDead)
return;
if (MathUtils.RandomTick(probability) == false)
{
return;
}
var buff = AddBuff(buffId, addLayer);
if (attacker != null && buff is ElementAddDebuff elementAddDebuff)
{ // 受击者buff触发攻击者的Buff或者技能
if (elementAddDebuff.TryTickLayer3(attacker))
{
EventSingle.Instance.Notify(EventDefine.GameMainMapAddBuff, new BuffEventDto()
{
ownerId = Context.Entity.EntityId,
buffTableId = buff.TableId,
});
}
}
else if (buff is DotDebuff dotDebuff)
{
dotDebuff.TryTickLayer5();
}
else if (damage != 0 && buff is ShieldBuff shieldBuff)
{
shieldBuff.Add(damage);
}
else if (buff.BuffType == EBuffType.Attribute)
{
AddAttributeBuff(buff);
}
}
private Buff AddBuff(long buffId, int addLayer)
{
IsDirty = true;
if (_buffsMap.TryGetValue(buffId, out var buff))
{
buff.Layers += addLayer;
}
else
{
var buffTable = BuffTableRepo.Get(buffId);
buff = GenBuff((EBuffType)buffTable.BuffType);
buff.Init(buffTable, UIDDefine.New(), Context, this);
if (addLayer > 1)
{
buff.Layers = addLayer;
}
_buffsMap.Add(buff.TableId, buff);
if (TryToEntityState(buff.BuffType, out var entityState))
{
Context.States.AddState(entityState);
}
}
//Log.Debug($"AddBuff EntityId:{Context.Entity.EntityId} BuffId:{buffId} Overlay:{buff.Layers}");
return buff;
}
private void RemoveBuff(int buffId)
{
if (_buffsMap.TryGetValue(buffId, out var buff))
{
_buffsMap.Remove(buffId);
if (TryToEntityState(buff.BuffType, out var entityState))
{ // TODO 需要判断剩余的buff是否有相同类型的状态
Context.States.RemoveState(entityState);
}
else if (buff is ElementAddDebuff)
{
EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveBuff, new BuffEventDto()
{
ownerId = Context.Entity.EntityId,
buffTableId = buffId,
});
}
else if (buff is ShieldBuff shieldBuff)
{
// 减去剩余的护盾值
(this as IBuffListener).OnShieldChanged(-shieldBuff.Absorption);
}
else if (buff.BuffType == EBuffType.Attribute)
{
RemoveAttributeBuff(buff);
}
ObjectPool.Recycle(buff);
IsDirty = true;
}
}
private Buff GenBuff(EBuffType buffType)
{
return buffType switch
{
EBuffType.Dot => ObjectPool.Acquire(),
EBuffType.Shield => ObjectPool.Acquire(),
EBuffType.ElementAddFire or EBuffType.ElementAddThunder or EBuffType.ElementAddIce
or EBuffType.ElementAddPoison or EBuffType.ElementAddWind => ObjectPool.Acquire(),
_ => ObjectPool.Acquire(),
};
}
///
/// EBuffType => EEntityState
///
///
///
///
private bool TryToEntityState(EBuffType buffType, out EEntityState entityState)
{
switch (buffType)
{
case EBuffType.Dizzy:
entityState = EEntityState.Dizzy;
return true;
case EBuffType.Freeze:
entityState = EEntityState.Freeze;
return true;
case EBuffType.Paralysis:
entityState = EEntityState.Palsy;
return true;
default:
entityState = EEntityState.Idle;
return false;
}
}
private void Clear()
{
foreach (var buff in _buffsMap.Values)
{
RemoveAttributeValue(buff);
ObjectPool.Recycle(buff);
}
_buffsMap.Clear();
TotalShieldVal = 0;
ClearAttributes();
}
#region IBuffListener 实现
void IBuffListener.OnShieldChanged(long val)
{
TotalShieldVal += val;
if (TotalShieldVal < 0)
{
Log.Error($"护盾剩余值计算错误.OnShieldChanged total: {TotalShieldVal} value:{val}");
TotalShieldVal = 0;
}
IsShieldDirty = true;
}
void IBuffListener.OnCompleted(int buffId)
{
RemoveBuff(buffId);
//Log.Debug($"RemoveBuff EntityId:{Context.Entity.EntityId} BuffId:{buffId}");
}
#endregion
}
}