CombatComponent.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using FL.Nodes.GameMain;
  2. using UnityEngine;
  3. using XGame.Database;
  4. using XGame.Framework.Components;
  5. namespace FL.Battle.Components
  6. {
  7. public interface ICombatContext
  8. {
  9. IEntity Entity { get; }
  10. ITargetSelector Selector { get; }
  11. Vector3 Position { get; }
  12. StatesComponent States { get; }
  13. BuffsComponent Buffs { get; }
  14. SkillComponent Skill { get; }
  15. /// <summary>
  16. /// 铭文组件
  17. /// 可能为空
  18. /// </summary>
  19. EpigraphicsComponent Epigraphics { get; }
  20. }
  21. public class CombatComponent : Component<ICombatContext>, ICombatCalculation
  22. {
  23. protected override void OnDispose()
  24. {
  25. }
  26. /// <summary>
  27. /// 计算血量
  28. /// 正数表示加血
  29. /// 负数表示扣血
  30. /// </summary>
  31. /// <param name="damage"></param>
  32. /// <returns></returns>
  33. private int CalculateHP(int damage)
  34. {
  35. var remainDamage = Context.Buffs.CalculateShieldAbsorb(damage);
  36. if (remainDamage == 0)
  37. { // 全部被护盾吸收
  38. return damage;
  39. }
  40. // 吸收值
  41. var absorption = damage - remainDamage;
  42. var attrs = Context.Entity.Attr;
  43. var lastHp = attrs.CurrentHp;
  44. var nextHp = lastHp + remainDamage;
  45. if (nextHp > attrs.HpLimit)
  46. {
  47. nextHp = attrs.HpLimit;
  48. }
  49. else if (nextHp < 0)
  50. {
  51. nextHp = 0;
  52. }
  53. attrs.CurrentHp = nextHp;
  54. if (nextHp == 0)
  55. {
  56. Context.States.AddState(EEntityState.Dead);
  57. }
  58. var result = (int)(nextHp - lastHp);
  59. // 返回扣血和护盾吸收的总和
  60. return result + absorption;
  61. }
  62. private void AddSkillBuff(SkillTable skill, ITarget attacker, int damage)
  63. {
  64. if (skill.BuffTie.Length != 2)
  65. return;
  66. var probability = skill.BuffTie[0];
  67. var buffId = skill.BuffTie[1];
  68. if (TryGetTrigger(BuffTableRepo.GetTargetType(buffId), attacker, out var trigger))
  69. {
  70. trigger?.Buffs.TryAddBuff(buffId, probability, 1, null, damage);
  71. }
  72. else
  73. {
  74. Context.Buffs.TryAddBuff(buffId, probability, 1, attacker?.Calculation, damage);
  75. }
  76. }
  77. /// <summary>
  78. /// 根据技能/Buff的目标类型确定触发目标
  79. /// </summary>
  80. /// <param name="targetType"></param>
  81. /// <param name="attacker"></param>
  82. /// <returns></returns>
  83. private ICombatCalculation GetTrigger(ESkillTargetType targetType, ICombatCalculation attacker)
  84. {
  85. if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Attacker))
  86. {
  87. return attacker;
  88. }
  89. if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Player))
  90. {
  91. return Context.Selector.GetPlayer()?.Calculation;
  92. }
  93. return this;
  94. }
  95. private bool TryGetTrigger(ESkillTargetType targetType, ITarget attacker, out ITarget trigger)
  96. {
  97. if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Attacker))
  98. {
  99. trigger = attacker;
  100. return true;
  101. }
  102. if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Player))
  103. {
  104. trigger = Context.Selector.GetPlayer();
  105. return true;
  106. }
  107. trigger = null;
  108. return false;
  109. }
  110. #region 被动技能
  111. //private void TickAttackerPassiveSkill(SkillTable skill, ICombatCalculation target)
  112. //{
  113. // Context.Skill.TryTickPassiveSkills((passiveSkill) =>
  114. // {
  115. // return true;
  116. // });
  117. //}
  118. #endregion
  119. #region 接口实现
  120. void ICombatCalculation.Damage(int damage, long attackerId, SkillTable skill)
  121. {
  122. if (Context.Entity.IsDead)
  123. { // 已经死亡
  124. return;
  125. }
  126. ITarget attacker = null;
  127. if (damage != 0)
  128. { // damage为零时不计算
  129. var damageAdd = 0;
  130. if (attackerId != Context.Entity.EntityId)
  131. { // 攻击者和受击者是同一个目标时不计算加成
  132. attacker = Context.Selector.GetTarget(attackerId);
  133. if (attacker != null && !attacker.IsDead)
  134. {
  135. damageAdd += attacker.Buffs.GetDamageAdd(skill.Element, Context.Entity, Context.Buffs);
  136. }
  137. }
  138. damageAdd += Context.Buffs.GetDamageAdd(skill.Element, Context.Entity, Context.Buffs);
  139. var realDamage = Mathf.CeilToInt(damage * (1 + damageAdd.ToRealFloat()));
  140. damage = CalculateHP(realDamage);
  141. EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, new HpAddDto()
  142. {
  143. entityId = Context.Entity.EntityId,
  144. position = Context.Position,
  145. hpValue = damage,
  146. elementType = skill.Element,
  147. });
  148. //攻击者触发铭文
  149. attacker?.Calculation.TickEpigraph(Context.Entity.EntityId, skill.Element, realDamage);
  150. // 受击目标的buff触发
  151. Context.Buffs.TickBuffOrSkill(damage, skill.Element, attacker?.Calculation);
  152. }
  153. //TODO 攻击者的buff触发
  154. AddSkillBuff(skill, attacker, damage);
  155. //TODO 受击者的被动技能
  156. //TODO 攻击者的被动技能
  157. //if (attacker != null && (attacker.Calculation is CombatComponent atkCalculation))
  158. //{
  159. // atkCalculation.TickAttackerPassiveSkill(skill, this);
  160. //}
  161. }
  162. void ICombatCalculation.Damage(int damage, EElementType elementType)
  163. {
  164. if (Context.Entity.IsDead)
  165. { // 已经死亡
  166. return;
  167. }
  168. damage = CalculateHP(damage);
  169. if (damage == 0)
  170. return;
  171. EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, new HpAddDto()
  172. {
  173. entityId = Context.Entity.EntityId,
  174. position = Context.Position,
  175. hpValue = damage,
  176. elementType = elementType,
  177. });
  178. }
  179. ICombatCalculation ICombatCalculation.GetSkillTrigger(long skillId, ICombatCalculation attacker)
  180. {
  181. return GetTrigger(SkillTableRepo.GetTargetType(skillId), attacker);
  182. }
  183. ICombatCalculation ICombatCalculation.GetBuffTrigger(long buffId, ICombatCalculation attacker)
  184. {
  185. return GetTrigger(BuffTableRepo.GetTargetType(buffId), attacker);
  186. }
  187. void ICombatCalculation.TickSkill(long skillId, long targetId, int probability)
  188. {
  189. // TODO
  190. Context.Skill.TryTickSkill((int)skillId, targetId, probability);
  191. }
  192. void ICombatCalculation.TickBuff(long buffId, int probability, int addLayer, int damage)
  193. {
  194. Context.Buffs.TryAddBuff(buffId, probability, addLayer, null, damage);
  195. }
  196. void ICombatCalculation.TickEpigraph(long targetId, EElementType skillElementType, int damage)
  197. {
  198. Context.Epigraphics?.TryTickIceToPoison(targetId, skillElementType, damage);
  199. }
  200. #endregion
  201. }
  202. }