示例#1
0
        private void UseAct(IActor actor, ActTargetInfo target, ITacticalAct act, ISectorMap map)
        {
            bool isInDistance;

            if ((act.Stats.Targets & TacticalActTargets.Self) > 0 && actor == target)
            {
                isInDistance = true;
            }
            else
            {
                isInDistance = IsInDistance(actor, target.TargetNode, act, map);
            }

            if (!isInDistance)
            {
                // Это может произойти, если цель, в процессе применения действия
                // успела выйти из радиуса применения.
                // TODO Лучше сделать, чтобы этот метод возвращал объект с результатом выполнения действия.
                // А внешний код пусть либо считает исход допустимым, либо выбрасывает исключения типа UsageOutOfDistanceException
                return;
            }

            var targetNode = target.TargetNode;

            var targetIsOnLine = map.TargetIsOnLine(
                actor.Node,
                targetNode);

            if (targetIsOnLine)
            {
                actor.UseAct(targetNode, act);

                var tacticalActRoll = GetActEfficient(act);

                var actHandler = _actUsageHandlerSelector.GetHandler(target.TargetObject);
                actHandler.ProcessActUsage(actor, target.TargetObject, tacticalActRoll);

                UseActResources(actor, act);
            }
            else
            {
                // Ситация, когда цель за стеной может произойти по следующим причинам:
                // 1. В момент начала применения действия цель была доступна. К моменту выполнения дейтвия цель скрылась.
                // В этом случае изымаем патроны и начинаем КД по действию, так как фактически ресурсы на него потрачены. Но на цель не воздействуем.
                // 2. Ошибка во внешнем коде, когда не провели предварительную проверку. Это проверяется сравнением ячейки в которую целились
                // на момент начала действия и текущую ячейку цели.

                if (target.TargetNode == target.TargetObject.Node)
                {
                    throw new UsageThroughtWallException();
                }

                UseActResources(actor, act);
            }
        }
示例#2
0
        public void UseOn(IActor actor, ActTargetInfo target, UsedTacticalActs usedActs, ISector sector)
        {
            if (actor is null)
            {
                throw new ArgumentNullException(nameof(actor));
            }

            if (target is null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            if (usedActs is null)
            {
                throw new ArgumentNullException(nameof(usedActs));
            }

            if (sector is null)
            {
                throw new ArgumentNullException(nameof(sector));
            }

            Debug.Assert(SectorHasCurrentActor(sector, actor), "Current actor must be in sector");
            Debug.Assert(SectorHasAttackTarget(sector, target.TargetObject), "Target must be in sector");

            foreach (var act in usedActs.Primary)
            {
                if (!act.Stats.Targets.HasFlag(TacticalActTargets.Self) && actor == target)
                {
                    throw new ArgumentException("Актёр не может атаковать сам себя", nameof(target));
                }

                UseAct(actor, target, act, sector.Map);
            }

            // Использование дополнительных действий.
            // Используются с некоторой вероятностью.
            foreach (var act in usedActs.Secondary)
            {
                var useSuccessRoll = GetUseSuccessRoll();
                var useFactRoll    = GetUseFactRoll();

                if (useFactRoll < useSuccessRoll)
                {
                    continue;
                }

                UseAct(actor, target, act, sector.Map);
            }
        }