BuffsComponent.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. using FL.Battle.Buffs;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using XGame;
  5. using XGame.Database;
  6. using XGame.Framework;
  7. using XGame.Framework.Components;
  8. using XGame.Framework.Map;
  9. using XGame.Framework.Time;
  10. namespace FL.Battle.Components
  11. {
  12. public interface IBuffsContext
  13. {
  14. public IEntity Entity { get; }
  15. public ITimeModule Time { get; }
  16. public IMapAssetModule Asset { get; }
  17. Vector3 Position { get; }
  18. Transform OwnerTr { get; }
  19. ICombatCalculation Calculation { get; }
  20. StatesComponent States { get; }
  21. MoveComponent Move { get; }
  22. }
  23. /// <summary>
  24. /// buff的逻辑控制脚本
  25. /// </summary>
  26. public partial class BuffsComponent : Component<IBuffsContext>, IBuffListener
  27. {
  28. private Dictionary<long, Buff> _buffsMap = new Dictionary<long, Buff>();
  29. protected override void OnEnable(object intent)
  30. {
  31. TotalShieldVal = 0;
  32. }
  33. protected override void OnDisable()
  34. {
  35. Clear();
  36. }
  37. protected override void OnDispose()
  38. {
  39. Clear();
  40. }
  41. public bool IsDirty { get; set; }
  42. public int BuffCount => _buffsMap.Count;
  43. /// <summary>
  44. /// 护盾buff是否有变化
  45. /// </summary>
  46. public bool IsShieldDirty { get; set; }
  47. /// <summary>
  48. /// 所有护盾吸收值
  49. /// </summary>
  50. public long TotalShieldVal { get; private set; }
  51. public void GetBuffs(ref List<IBuff> buffs)
  52. {
  53. if (buffs == null)
  54. {
  55. buffs = new List<IBuff>();
  56. }
  57. else
  58. {
  59. buffs.Clear();
  60. }
  61. foreach (var buff in _buffsMap.Values)
  62. {
  63. if (!buff.IsShowIcon)
  64. continue;
  65. buffs.Add(buff);
  66. }
  67. }
  68. public bool GetElementBuffs(ref List<IBuff> buffs)
  69. {
  70. if (buffs == null)
  71. {
  72. buffs = new List<IBuff>();
  73. }
  74. var lastCount = buffs.Count;
  75. foreach (var buff in _buffsMap.Values)
  76. {
  77. if (buff is ElementAddDebuff element && element.IsReachLayer3())
  78. {
  79. buffs.Add(buff);
  80. }
  81. }
  82. return buffs.Count > lastCount;
  83. }
  84. ///// <summary>
  85. ///// 获取最近的可触发效果的元素buff
  86. ///// </summary>
  87. ///// <returns></returns>
  88. //public IBuff GetPreTickElementBuff()
  89. //{
  90. // Buff result = null;
  91. // foreach (var buff in _buffsMap.Values)
  92. // {
  93. // if (buff.ElementType == EElementType.None)
  94. // continue;
  95. // if (buff.Layers == buff.LayerLimit)
  96. // {
  97. // result = buff;
  98. // break;
  99. // }
  100. // if (result == null || (float)buff.Layers / buff.LayerLimit > (float)result.Layers / result.LayerLimit)
  101. // {
  102. // result = buff;
  103. // }
  104. // }
  105. // return result;
  106. //}
  107. public bool IsContains(EBuffType buffType)
  108. {
  109. foreach (var buff in _buffsMap.Values)
  110. {
  111. if (buff.BuffType == buffType)
  112. return true;
  113. }
  114. return false;
  115. }
  116. public int GetLayers(long buffId)
  117. {
  118. if (_buffsMap.TryGetValue(buffId, out var buff))
  119. {
  120. return buff.Layers;
  121. }
  122. return 0;
  123. }
  124. //void IUpdate.Update(int millisecond)
  125. //{
  126. // _updateBuffs.AddRange(_buffsMap.Values);
  127. // foreach (var buff in _updateBuffs)
  128. // {
  129. // if (buff.Update(millisecond))
  130. // {
  131. // _buffsMap.Remove(buff.TableId);
  132. // }
  133. // }
  134. // _updateBuffs.Clear();
  135. //}
  136. /// <summary>
  137. /// 护盾吸收
  138. /// </summary>
  139. /// <param name="damage"></param>
  140. /// <returns>护盾吸收后剩余的伤害值 负数</returns>
  141. public int CalculateShieldAbsorb(int damage)
  142. {
  143. if (damage >= 0)
  144. return damage;
  145. var tempBuffs = ListPool.Acquire<Buff>();
  146. tempBuffs.AddRange(_buffsMap.Values);
  147. foreach (var buff in tempBuffs)
  148. { // 遍历中buff的数量可能会增减
  149. if (buff is ShieldBuff shieldBuff)
  150. {
  151. damage = shieldBuff.Reduce(damage);
  152. if (damage == 0)
  153. break; // 剩余伤害为零,全部吸收了
  154. }
  155. }
  156. ListPool.Recycle(tempBuffs);
  157. return damage;
  158. }
  159. /// <summary>
  160. /// 获取技能伤害Buff加成
  161. /// </summary>
  162. /// <param name="skill"></param>
  163. /// <param name="target"></param>
  164. /// <returns></returns>
  165. public int GetDamageAdd(EElementType elementType, IEntity target, BuffsComponent targetBuffs)
  166. {
  167. var result = 0;
  168. foreach (var buff in _buffsMap.Values)
  169. {
  170. var buffType = buff.BuffType;
  171. if (buffType is EBuffType.DizzAdd)
  172. {
  173. if (target.IsState(EEntityState.Dizzy))
  174. {
  175. result += buff.Table.BuffTypeNum[0];
  176. }
  177. }
  178. else if (buffType is EBuffType.FreezeAdd)
  179. {
  180. if (target.IsState(EEntityState.Freeze))
  181. {
  182. result += buff.Table.BuffTypeNum[0];
  183. }
  184. }
  185. else if (buffType is EBuffType.DotAdd)
  186. {
  187. if (targetBuffs.IsContains(EBuffType.Dot))
  188. {
  189. result += buff.Table.BuffTypeNum[0];
  190. }
  191. }
  192. else if (elementType == EElementType.None)
  193. { // 非元素技能
  194. continue;
  195. }
  196. else if (buffType != EBuffType.ElementAddIce || target.EntityId != Context.Entity.EntityId ||
  197. ((buff as ElementAddDebuff)?.IsReachLayer5(elementType) ?? false))
  198. { // 目标有冻伤
  199. continue;
  200. }
  201. else
  202. {// 目标有冻伤 且 本次攻击没有达到5层元素易伤条件
  203. result += buff.Table.BuffTypeNum[1];
  204. }
  205. }
  206. return result;
  207. }
  208. /// <summary>
  209. /// 检测受击目标的buff触发
  210. /// </summary>
  211. /// <param name="damage"></param>
  212. /// <param name="elementType"></param>
  213. /// <param name="attacker"></param>
  214. public void TickBuffOrSkill(int damage, EElementType elementType, ICombatCalculation attacker)
  215. {
  216. if (elementType == EElementType.None)
  217. return; // TODO 目前只有元素技能会触发buff
  218. var tempBuffs = ListPool.Acquire<Buff>();
  219. tempBuffs.AddRange(_buffsMap.Values);
  220. foreach (var buff in tempBuffs)
  221. { // 遍历中buff的数量可能会增减
  222. if (buff is ElementAddDebuff elementAddDebuff)
  223. {
  224. elementAddDebuff.TryTickBuff(damage, elementType, attacker);
  225. }
  226. }
  227. ListPool.Recycle(tempBuffs);
  228. }
  229. public void TryAddBuff(long buffId, int probability, int addLayer = 1, ICombatCalculation attacker = null, int damage = 0)
  230. {
  231. if (Context.Entity.IsDead)
  232. return;
  233. if (MathUtils.Random(probability) == false)
  234. {
  235. return;
  236. }
  237. var buff = AddBuff(buffId, addLayer);
  238. if (attacker != null && buff is ElementAddDebuff elementAddDebuff)
  239. { // 受击者buff触发攻击者的Buff或者技能
  240. if (elementAddDebuff.TryTickLayer3(attacker))
  241. {
  242. EventSingle.Instance.Notify(EventDefine.GameMainMapAddBuff, new BuffEventDto()
  243. {
  244. ownerId = Context.Entity.EntityId,
  245. buffTableId = buff.TableId,
  246. });
  247. }
  248. }
  249. else if (buff is DotDebuff dotDebuff)
  250. {
  251. dotDebuff.TryTickLayer5();
  252. }
  253. else if (damage != 0 && buff is ShieldBuff shieldBuff)
  254. {
  255. shieldBuff.Add(damage);
  256. }
  257. else if (buff.BuffType == EBuffType.Attribute)
  258. {
  259. AddAttributeBuff(buff);
  260. }
  261. }
  262. private Buff AddBuff(long buffId, int addLayer)
  263. {
  264. IsDirty = true;
  265. if (_buffsMap.TryGetValue(buffId, out var buff))
  266. {
  267. buff.Layers += addLayer;
  268. }
  269. else
  270. {
  271. var buffTable = BuffTableRepo.Get(buffId);
  272. buff = GenBuff((EBuffType)buffTable.BuffType);
  273. buff.Init(buffTable, UIDDefine.New(), Context, this);
  274. if (addLayer > 1)
  275. {
  276. buff.Layers = addLayer;
  277. }
  278. _buffsMap.Add(buff.TableId, buff);
  279. if (TryToEntityState(buff.BuffType, out var entityState))
  280. {
  281. Context.States.AddState(entityState);
  282. }
  283. }
  284. //Log.Debug($"AddBuff EntityId:{Context.Entity.EntityId} BuffId:{buffId} Overlay:{buff.Layers}");
  285. return buff;
  286. }
  287. private void RemoveBuff(int buffId)
  288. {
  289. if (_buffsMap.TryGetValue(buffId, out var buff))
  290. {
  291. _buffsMap.Remove(buffId);
  292. if (TryToEntityState(buff.BuffType, out var entityState))
  293. { // TODO 需要判断剩余的buff是否有相同类型的状态
  294. Context.States.RemoveState(entityState);
  295. }
  296. else if (buff is ElementAddDebuff)
  297. {
  298. EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveBuff, new BuffEventDto()
  299. {
  300. ownerId = Context.Entity.EntityId,
  301. buffTableId = buffId,
  302. });
  303. }
  304. else if (buff is ShieldBuff shieldBuff)
  305. {
  306. // 减去剩余的护盾值
  307. (this as IBuffListener).OnShieldChanged(-shieldBuff.Absorption);
  308. }
  309. else if (buff.BuffType == EBuffType.Attribute)
  310. {
  311. RemoveAttributeBuff(buff);
  312. }
  313. ObjectPool.Recycle(buff);
  314. IsDirty = true;
  315. }
  316. }
  317. private Buff GenBuff(EBuffType buffType)
  318. {
  319. return buffType switch
  320. {
  321. EBuffType.Dot => ObjectPool.Acquire<DotDebuff>(),
  322. EBuffType.Shield => ObjectPool.Acquire<ShieldBuff>(),
  323. EBuffType.ElementAddFire or EBuffType.ElementAddThunder or EBuffType.ElementAddIce
  324. or EBuffType.ElementAddPoison or EBuffType.ElementAddWind => ObjectPool.Acquire<ElementAddDebuff>(),
  325. _ => ObjectPool.Acquire<Buff>(),
  326. };
  327. }
  328. /// <summary>
  329. /// EBuffType => EEntityState
  330. /// </summary>
  331. /// <param name="buffType"></param>
  332. /// <param name="entityState"></param>
  333. /// <returns></returns>
  334. private bool TryToEntityState(EBuffType buffType, out EEntityState entityState)
  335. {
  336. switch (buffType)
  337. {
  338. case EBuffType.Dizzy:
  339. entityState = EEntityState.Dizzy;
  340. return true;
  341. case EBuffType.Freeze:
  342. entityState = EEntityState.Freeze;
  343. return true;
  344. case EBuffType.Paralysis:
  345. entityState = EEntityState.Palsy;
  346. return true;
  347. default:
  348. entityState = EEntityState.Idle;
  349. return false;
  350. }
  351. }
  352. private void Clear()
  353. {
  354. foreach (var buff in _buffsMap.Values)
  355. {
  356. RemoveAttributeValue(buff);
  357. ObjectPool.Recycle(buff);
  358. }
  359. _buffsMap.Clear();
  360. TotalShieldVal = 0;
  361. ClearAttributes();
  362. }
  363. #region IBuffListener 实现
  364. void IBuffListener.OnShieldChanged(long val)
  365. {
  366. TotalShieldVal += val;
  367. if (TotalShieldVal < 0)
  368. {
  369. Log.Error($"护盾剩余值计算错误.OnShieldChanged total: {TotalShieldVal} value:{val}");
  370. TotalShieldVal = 0;
  371. }
  372. IsShieldDirty = true;
  373. }
  374. void IBuffListener.OnCompleted(int buffId)
  375. {
  376. RemoveBuff(buffId);
  377. //Log.Debug($"RemoveBuff EntityId:{Context.Entity.EntityId} BuffId:{buffId}");
  378. }
  379. #endregion
  380. }
  381. }