/// <summary> /// Производит попытку нанесения урона целевову актёру с учётом обороны и брони. /// </summary> /// <param name="actor"> Актёр, который совершил действие. </param> /// <param name="targetActor"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private void DamageActor(IActor actor, IActor targetActor, TacticalActRoll tacticalActRoll) { var targetIsDeadLast = targetActor.Person.CheckIsDead(); var offence = tacticalActRoll.TacticalAct.Stats.Offence; if (offence is null) { throw new InvalidOperationException(); } var offenceType = offence.Type; var usedDefences = GetCurrentDefences(targetActor, offenceType); var prefferedDefenceItem = HitHelper.CalcPreferredDefense(usedDefences); var successToHitRoll = HitHelper.CalcSuccessToHit(prefferedDefenceItem); var factToHitRoll = _actUsageRandomSource.RollToHit(tacticalActRoll.TacticalAct.ToHit); if (factToHitRoll >= successToHitRoll) { ProcessSuccessfullHit(actor, targetActor, tacticalActRoll, targetIsDeadLast, successToHitRoll, factToHitRoll); } else { ProcessFailedHit(actor, targetActor, prefferedDefenceItem, successToHitRoll, factToHitRoll); } }
private void ProcessSuccessfullHit(IActor actor, IActor targetActor, TacticalActRoll tacticalActRoll, bool targetIsDeadLast, int successToHitRoll, int factToHitRoll) { var damageEfficientCalcResult = CalcEfficient(targetActor, tacticalActRoll); var actEfficient = damageEfficientCalcResult.ResultEfficient; ProcessSuccessfulAttackEvent( actor, targetActor, damageEfficientCalcResult, successToHitRoll, factToHitRoll); if (actEfficient > 0) { targetActor.TakeDamage(actEfficient); CountTargetActorAttack(actor, targetActor, tacticalActRoll.TacticalAct); ProcessDiseaseInfection(actor, targetActor); LogDamagePlayerEvent(actor, targetActor, tacticalActRoll.TacticalAct); ReduceTargetEquipmentDurability(targetActor); if (!targetIsDeadLast && targetActor.Person.CheckIsDead()) { CountTargetActorDefeat(actor, targetActor); } } }
/// <summary> /// Расчитывает эффективность умения с учётом поглощения броней. /// </summary> /// <param name="targetActor"> Целевой актёр. </param> /// <param name="tacticalActRoll"> Результат броска исходной эфективности действия. </param> /// <returns> Возвращает числовое значение эффективности действия. </returns> private DamageEfficientCalc CalcEfficient(IActor targetActor, TacticalActRoll tacticalActRoll) { var damageEfficientCalcResult = new DamageEfficientCalc(); var actApRank = GetActApRank(tacticalActRoll.TacticalAct);; damageEfficientCalcResult.ActApRank = actApRank; var armorRank = GetArmorRank(targetActor, tacticalActRoll.TacticalAct); damageEfficientCalcResult.ArmorRank = armorRank; var actEfficientArmorBlocked = tacticalActRoll.Efficient; var rankDiff = actApRank - armorRank; if (armorRank != null && rankDiff < 10) { var factArmorSaveRoll = RollArmorSave(); damageEfficientCalcResult.FactArmorSaveRoll = factArmorSaveRoll; var successArmorSaveRoll = GetSuccessArmorSave(targetActor, tacticalActRoll.TacticalAct); damageEfficientCalcResult.SuccessArmorSaveRoll = successArmorSaveRoll; if (factArmorSaveRoll >= successArmorSaveRoll) { damageEfficientCalcResult.TargetSuccessfullUsedArmor = true; var armorAbsorbtion = GetArmorAbsorbtion(targetActor, tacticalActRoll.TacticalAct); damageEfficientCalcResult.ArmorAbsorbtion = armorAbsorbtion; actEfficientArmorBlocked = AbsorbActEfficient(actEfficientArmorBlocked, armorAbsorbtion); } } damageEfficientCalcResult.ActEfficientArmorBlocked = actEfficientArmorBlocked; return(damageEfficientCalcResult); }
/// <summary> /// Возвращает случайное значение эффективность действия. /// </summary> /// <param name="act"> Соверщённое действие. </param> /// <returns> Возвращает выпавшее значение эффективности. </returns> private TacticalActRoll GetActEfficient(ITacticalAct act) { var rolledEfficient = _actUsageRandomSource.RollEfficient(act.Efficient); var roll = new TacticalActRoll(act, rolledEfficient); return(roll); }
/// <inheritdoc /> public void ProcessActUsage(IActor actor, IAttackTarget target, TacticalActRoll tacticalActRoll) { if (tacticalActRoll is null) { throw new ArgumentNullException(nameof(tacticalActRoll)); } UseOnStaticObject(target as IStaticObject, tacticalActRoll); }
/// <summary> /// Применяет действие на предмет, на который можно подействовать (сундук/дверь/камень). /// </summary> /// <param name="target"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private static void UseOnStaticObject(IAttackTarget target, TacticalActRoll tacticalActRoll) { if (target is null) { throw new ArgumentNullException(nameof(target)); } target.TakeDamage(tacticalActRoll.Efficient); }
/// <summary> /// Возвращает случайное значение эффективность действия. /// </summary> /// <param name="act"> Соверщённое действие. </param> /// <returns> Возвращает выпавшее значение эффективности. </returns> private TacticalActRoll GetActEfficient(ITacticalAct act) { var minEfficient = act.MinEfficient; var maxEfficient = act.MaxEfficient; var rolledEfficient = _actUsageRandomSource.SelectEfficient(minEfficient, maxEfficient); var roll = new TacticalActRoll(act, rolledEfficient); return(roll); }
/// <summary> /// Применяет действие на актёра. /// </summary> /// <param name="actor"> Актёр, который совершил действие. </param> /// <param name="targetActor"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private void UseOnActor(IActor actor, IActor targetActor, TacticalActRoll tacticalActRoll) { var targetIsDeadLast = targetActor.State.IsDead; targetActor.TakeDamage(tacticalActRoll.Efficient); if (!targetIsDeadLast && targetActor.State.IsDead) { CountTargetActorDefeat(actor, targetActor); } }
/// <summary> /// Наносит урон актёру. /// </summary> /// <param name="actor"> Актёр, который совершил действие. </param> /// <param name="targetActor"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private void DamageActor(IActor actor, IActor targetActor, TacticalActRoll tacticalActRoll) { var targetIsDeadLast = targetActor.Person.Survival.IsDead; var offenceType = tacticalActRoll.TacticalAct.Stats.Offence.Type; var usedDefences = GetCurrentDefences(targetActor, offenceType); var prefferedDefenceItem = HitHelper.CalcPreferredDefense(usedDefences); var successToHitRoll = HitHelper.CalcSuccessToHit(prefferedDefenceItem); var factToHitRoll = _actUsageRandomSource.RollToHit(); if (factToHitRoll >= successToHitRoll) { int actEfficient = CalcEfficient(targetActor, tacticalActRoll); if (actEfficient <= 0) { return; } targetActor.TakeDamage(actEfficient); if (EquipmentDurableService != null && targetActor.Person.EquipmentCarrier != null) { var damagedEquipment = GetDamagedEquipment(targetActor); // может быть null, если нет брони вообще if (damagedEquipment != null) { EquipmentDurableService.UpdateByUse(damagedEquipment, targetActor.Person); } } if (!targetIsDeadLast && targetActor.Person.Survival.IsDead) { CountTargetActorDefeat(actor, targetActor); } } else { if (prefferedDefenceItem != null) { targetActor.ProcessDefence(prefferedDefenceItem, successToHitRoll, factToHitRoll); } } }
/// <summary> /// Применяет действие на актёра. /// </summary> /// <param name="actor"> Актёр, который совершил действие. </param> /// <param name="targetActor"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private void UseOnActor(IActor actor, IActor targetActor, TacticalActRoll tacticalActRoll) { switch (tacticalActRoll.TacticalAct.Stats.Effect) { case TacticalActEffectType.Damage: DamageActor(actor, targetActor, tacticalActRoll); break; case TacticalActEffectType.Heal: HealActor(targetActor, tacticalActRoll); break; default: var effect = tacticalActRoll.TacticalAct.Stats.Effect; var tacticalAct = tacticalActRoll.TacticalAct; throw new ArgumentException($"Не определённый эффект {effect} действия {tacticalAct}."); } }
/// <summary> /// Применяет действие на актёра. /// </summary> /// <param name="actor"> Актёр, который совершил действие. </param> /// <param name="targetActor"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private void UseOnActor(IActor actor, IActor targetActor, TacticalActRoll tacticalActRoll) { switch (tacticalActRoll.TacticalAct.Stats.Effect) { case TacticalActEffectType.Damage: DamageActor(actor, targetActor, tacticalActRoll); break; case TacticalActEffectType.Heal: HealActor(actor, targetActor, tacticalActRoll); break; default: throw new ArgumentException(string.Format("Не определённый эффект {0} действия {1}.", tacticalActRoll.TacticalAct.Stats.Effect, tacticalActRoll.TacticalAct)); } }
/// <inheritdoc /> public void ProcessActUsage(IActor actor, IAttackTarget target, TacticalActRoll tacticalActRoll) { if (actor is null) { throw new ArgumentNullException(nameof(actor)); } if (target is null) { throw new ArgumentNullException(nameof(target)); } if (tacticalActRoll is null) { throw new ArgumentNullException(nameof(tacticalActRoll)); } UseOnActor(actor, target as IActor, tacticalActRoll); }
/// <summary> /// Расчитывает эффективность умения с учётом поглощения броней. /// </summary> /// <param name="targetActor"> Целевой актёр. </param> /// <param name="tacticalActRoll"> Результат броска исходной эфективности действия. </param> /// <returns> Возвращает числовое значение эффективности действия. </returns> private int CalcEfficient(IActor targetActor, TacticalActRoll tacticalActRoll) { var actApRank = GetActApRank(tacticalActRoll.TacticalAct); var armorRank = GetArmorRank(targetActor, tacticalActRoll.TacticalAct); var actEfficientArmorBlocked = tacticalActRoll.Efficient; var rankDiff = actApRank - armorRank; if (armorRank != null && rankDiff < 10) { var factArmorSaveRoll = RollArmorSave(); var successArmorSaveRoll = GetSuccessArmorSave(targetActor, tacticalActRoll.TacticalAct); if (factArmorSaveRoll >= successArmorSaveRoll) { var armorAbsorbtion = GetArmorAbsorbtion(targetActor, tacticalActRoll.TacticalAct); actEfficientArmorBlocked = AbsorbActEfficient(actEfficientArmorBlocked, armorAbsorbtion); } targetActor.ProcessArmor(armorRank.Value, successArmorSaveRoll, factArmorSaveRoll); } return(actEfficientArmorBlocked); }
/// <summary> /// Лечит актёра. /// </summary> /// <param name="actor"> Актёр, который совершил действие. </param> /// <param name="targetActor"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private void HealActor(IActor actor, IActor targetActor, TacticalActRoll tacticalActRoll) { targetActor.Person.Survival?.RestoreStat(SurvivalStatType.Health, tacticalActRoll.Efficient); }
/// <summary> /// Производит попытку нанесения урона целевову актёру с учётом обороны и брони. /// </summary> /// <param name="actor"> Актёр, который совершил действие. </param> /// <param name="targetActor"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private void DamageActor(IActor actor, IActor targetActor, TacticalActRoll tacticalActRoll) { var targetIsDeadLast = targetActor.Person.CheckIsDead(); var offenceType = tacticalActRoll.TacticalAct.Stats.Offence.Type; var usedDefences = GetCurrentDefences(targetActor, offenceType); var prefferedDefenceItem = HitHelper.CalcPreferredDefense(usedDefences); var successToHitRoll = HitHelper.CalcSuccessToHit(prefferedDefenceItem); var factToHitRoll = _actUsageRandomSource.RollToHit(tacticalActRoll.TacticalAct.ToHit); if (factToHitRoll >= successToHitRoll) { var damageEfficientCalcResult = CalcEfficient(targetActor, tacticalActRoll); var actEfficient = damageEfficientCalcResult.ResultEfficient; ProcessSuccessfulAttackEvent( actor, targetActor, damageEfficientCalcResult, successToHitRoll, factToHitRoll); if (actEfficient <= 0) { return; } targetActor.TakeDamage(actEfficient); CountTargetActorAttack(actor, targetActor, tacticalActRoll.TacticalAct); if (EquipmentDurableService != null && targetActor.Person.EquipmentCarrier != null) { var damagedEquipment = GetDamagedEquipment(targetActor); // может быть null, если нет брони вообще if (damagedEquipment != null) { EquipmentDurableService.UpdateByUse(damagedEquipment, targetActor.Person); } } if (!targetIsDeadLast && targetActor.Person.CheckIsDead()) { CountTargetActorDefeat(actor, targetActor); } } else { if (prefferedDefenceItem != null) { // Это промах, потому что целевой актёр увернулся. ProcessAttackDodgeEvent(actor, targetActor, prefferedDefenceItem, successToHitRoll, factToHitRoll); } else { // Это промах чистой воды. ProcessPureMissEvent(actor, targetActor, successToHitRoll, factToHitRoll); } } }
/// <summary> /// Применяет действие на предмет, на который можно подействовать (сундук/дверь). /// </summary> /// <param name="target"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private static void UseOnChest(IAttackTarget target, TacticalActRoll tacticalActRoll) { target.TakeDamage(tacticalActRoll.Efficient); }
/// <summary> /// Лечит актёра. /// </summary> /// <param name="targetActor"> Цель использования действия. </param> /// <param name="tacticalActRoll"> Эффективность действия. </param> private static void HealActor(IActor targetActor, TacticalActRoll tacticalActRoll) { targetActor.Person.GetModuleSafe <ISurvivalModule>() ?.RestoreStat(SurvivalStatType.Health, tacticalActRoll.Efficient); }