private void UseAct(IActor actor, IAttackTarget target, ITacticalAct act)
        {
            bool isInDistance;

            if ((act.Stats.Targets & TacticalActTargets.Self) > 0 && actor == target)
            {
                isInDistance = true;
            }
            else
            {
                var currentCubePos = ((HexNode)actor.Node).CubeCoords;
                var targetCubePos  = ((HexNode)target.Node).CubeCoords;

                isInDistance = act.CheckDistance(currentCubePos, targetCubePos);
            }

            if (!isInDistance)
            {
                throw new InvalidOperationException("Попытка атаковать цель, находящуюся за пределами атаки.");
            }

            var targetNode = target.Node;

            var targetIsOnLine = _sectorManager.CurrentSector.Map.TargetIsOnLine(
                actor.Node,
                targetNode);

            if (!targetIsOnLine)
            {
                throw new InvalidOperationException("Задачу на атаку нельзя выполнить сквозь стены.");
            }


            actor.UseAct(target, act);

            var tacticalActRoll = GetActEfficient(act);

            // Изъятие патронов
            if (act.Constrains?.PropResourceType != null)
            {
                RemovePropResource(actor, act);
            }

            if (target is IActor targetActor)
            {
                UseOnActor(actor, targetActor, tacticalActRoll);
            }
            else
            {
                UseOnChest(target, tacticalActRoll);
            }

            if (act.Equipment != null)
            {
                EquipmentDurableService?.UpdateByUse(act.Equipment, actor.Person);
            }
        }
Exemplo n.º 2
0
        private void ReduceTargetEquipmentDurability(IActor targetActor)
        {
            if (EquipmentDurableService is null || targetActor.Person.GetModuleSafe <IEquipmentModule>() is null)
            {
                return;
            }

            var damagedEquipment = GetDamagedEquipment(targetActor);

            // может быть null, если нет брони вообще
            if (damagedEquipment is null)
            {
                return;
            }

            EquipmentDurableService.UpdateByUse(damagedEquipment, targetActor.Person);
        }
        /// <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);
                }
            }
        }