Пример #1
0
        private static bool TacticalActIsAvailableByConstrains(ICombatAct tacticalAct,
                                                               IPropStore propStore)
        {
            if (tacticalAct.Constrains is null)
            {
                // Если нет никаких ограничений, то действие доступно в любом случае.
                return(true);
            }

            if (tacticalAct.Constrains.PropResourceType is null)
            {
                // Если нет ограничений по ресурсам, то действие доступно.
                return(true);
            }

            // Проверяем наличие ресурсов в нужном количестве.
            // Проверка осуществляется в хранилище, указанном параметром.

            if (propStore is null)
            {
                // Персонажи бе инвентаря не могут применять действия,
                // для которых нужны ресурсы.
                return(false);
            }

            var propResourceType  = tacticalAct.Constrains.PropResourceType;
            var propResourceCount = tacticalAct.Constrains.PropResourceCount.Value;

            if (CheckPropResource(propStore, propResourceType, propResourceCount))
            {
                return(true);
            }

            return(false);
        }
Пример #2
0
        public static string GetActHintText(ICombatAct combatAct)
        {
            var title       = GetActTitle(combatAct);
            var description = GetActDescription(combatAct);

            var usedEquipment  = combatAct.Equipment;
            var equipmentTitle = string.Empty;

            if (usedEquipment is not null)
            {
                equipmentTitle = PropHelper.GetPropTitle(usedEquipment);
            }

            if (!string.IsNullOrWhiteSpace(description))
            {
                if (!string.IsNullOrWhiteSpace(equipmentTitle))
                {
                    return($"{title}\n({equipmentTitle})\n{new string('-', 8)}\n{description}");
                }

                return($"{title}\n{new string('-', 8)}\n{description}");
            }

            if (!string.IsNullOrWhiteSpace(equipmentTitle))
            {
                return($"{title}\n({equipmentTitle})");
            }

            return(title);
        }
Пример #3
0
        /// <summary>
        /// Возвращает показатель поглощения брони цели.
        /// Это величина, на которую будет снижен урон.
        /// </summary>
        /// <param name="targetActor"> Целевой актёр, для которого проверяется поглощение урона. </param>
        /// <param name="usedTacticalAct"> Действие, которое будет использовано для нанесения урона. </param>
        /// <returns> Возвращает показатель поглощения брони цели. </returns>
        private static int GetArmorAbsorbtion(IActor targetActor, ICombatAct usedTacticalAct)
        {
            var actorArmors = targetActor.Person.GetModule <ICombatStatsModule>().DefenceStats.Armors;
            var offence     = usedTacticalAct.Stats.Offence;

            if (offence is null)
            {
                throw new InvalidOperationException();
            }

            var actImpact      = offence.Impact;
            var preferredArmor = actorArmors.FirstOrDefault(x => x.Impact == actImpact);

            if (preferredArmor == null)
            {
                return(0);
            }

            return(preferredArmor.AbsorbtionLevel switch
            {
                PersonRuleLevel.None => 0,
                PersonRuleLevel.Lesser => 1,
                PersonRuleLevel.Normal => 2,
                PersonRuleLevel.Grand => 5,
                PersonRuleLevel.Absolute => 10,
                _ => throw new InvalidOperationException(
                    $"Unknown armor absorbtion level: {preferredArmor.AbsorbtionLevel}.")
            });
Пример #4
0
        private void CountTargetActorAttack(IActor actor, IActor targetActor, ICombatAct tacticalAct)
        {
            if (actor.Person is MonsterPerson)
            {
                // Монстры не могут прокачиваться.
                return;
            }

            if (actor.Person == null)
            {
                // Это может происходить в тестах,
                // если в моках не определили персонажа.
                //TODO Поискать решение, как всегда быть уверенным, что персонаж указан в боевых условиях, и может быть null в тестах.
                //TODO Эта же проверка нужна в CountActorDefeat (учёт убиства актёра).
                return;
            }

            var evolutionData = actor.Person.GetModuleSafe <IEvolutionModule>();

            //TODO Такую же проверку добавить в CountActorDefeat (учёт убиства актёра).
            if (evolutionData is null)
            {
                return;
            }

            var progress = new AttackActorJobProgress(targetActor, tacticalAct);

            _perkResolver.ApplyProgress(progress, evolutionData);
        }
Пример #5
0
        private static void RemovePropResource(IActor actor, ICombatAct act)
        {
            var propResources = from prop in actor.Person.GetModule <IInventoryModule>().CalcActualItems()
                                where prop is Resource
                                where prop.Scheme.Bullet?.Caliber == act.Constrains?.PropResourceType
                                select prop;

            if (propResources.FirstOrDefault() is Resource propResource)
            {
                if (propResource.Count >= act.Constrains?.PropResourceCount)
                {
                    var usedResource = new Resource(propResource.Scheme, act.Constrains.PropResourceCount.Value);
                    actor.Person.GetModule <IInventoryModule>().Remove(usedResource);
                }
                else
                {
                    throw new InvalidOperationException(
                              $"Не хватает ресурса {propResource} для использования действия {act}.");
                }
            }
            else
            {
                throw new InvalidOperationException(
                          $"Не хватает ресурса {act.Constrains?.PropResourceType} для использования действия {act}.");
            }
        }
Пример #6
0
        /// <summary>
        /// Возвращает случайное значение эффективность действия.
        /// </summary>
        /// <param name="act"> Соверщённое действие. </param>
        /// <returns> Возвращает выпавшее значение эффективности. </returns>
        private CombatActRoll GetActEfficient(ICombatAct act)
        {
            var rolledEfficient = _actUsageRandomSource.RollEfficient(act.Efficient);

            var roll = new CombatActRoll(act, rolledEfficient);

            return(roll);
        }
Пример #7
0
        private void UseAct(IActor actor, ActTargetInfo target, ICombatAct 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, map);

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

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

                UseActResources(actor, act);
            }
        }
Пример #8
0
 public CombatActButton(Texture2D texture,
                        Texture2D icon,
                        Texture2D selectedMarkerTexture,
                        CombatActButtonGroup buttonGroup,
                        ICombatAct tacticalAct,
                        Rectangle rect) : base(texture, rect)
 {
     _icon           = icon;
     _selectedMarker = selectedMarkerTexture;
     _buttonGroup    = buttonGroup;
     CombatAct       = tacticalAct;
 }
Пример #9
0
        private static bool WeaponHasTag(string tag, ICombatAct tacticalAct)
        {
            if (tacticalAct.Equipment is null)
            {
                return(false);
            }

            if (tacticalAct.Equipment.Scheme.Tags is null)
            {
                return(false);
            }

            return(tacticalAct.Equipment.Scheme.Tags.Contains(tag));
        }
Пример #10
0
        private static bool IsInDistance(IActor actor, IGraphNode targetNode, ICombatAct act, ISectorMap map)
        {
            var actorNodes = GetActorNodes(actor.PhysicalSize, actor.Node, map);

            foreach (var node in actorNodes)
            {
                var isInDistanceInNode = act.CheckDistance(node, targetNode, map);
                if (isInDistanceInNode)
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #11
0
        public AttackTask(IActor actor,
                          IActorTaskContext context,
                          IAttackTarget target,
                          ICombatAct tacticalAct,
                          ITacticalActUsageService actService) :
            base(actor, context)
        {
            _actService = actService;

            TargetObject = target ?? throw new ArgumentNullException(nameof(target));
            TacticalAct  = tacticalAct ?? throw new ArgumentNullException(nameof(tacticalAct));

            TargetNode = target.Node;

            var combatActDuration = tacticalAct.Stats.Duration.GetValueOrDefault(1);
            var durationBonus     = GetDurationBonus(actor);
            var durationWithBonus =
                (int)Math.Round(GlobeMetrics.OneIterationLength * combatActDuration * durationBonus);

            Cost = durationWithBonus;
        }
Пример #12
0
        public async Task SetUpAsync()
        {
            var actUsageRandomSourceMock = new Mock <ITacticalActUsageRandomSource>();

            actUsageRandomSourceMock.Setup(x => x.RollToHit(It.IsAny <Roll>())).Returns(6);
            actUsageRandomSourceMock.Setup(x => x.RollEfficient(It.IsAny <Roll>())).Returns(1);
            _actUsageRandomSource = actUsageRandomSourceMock.Object;

            var personMock = new Mock <IPerson>();

            _person = personMock.Object;

            var evolutionModuleMock = new Mock <IEvolutionModule>();
            var evolutionModule     = evolutionModuleMock.Object;

            personMock.Setup(x => x.GetModule <IEvolutionModule>(It.IsAny <string>())).Returns(evolutionModule);

            var actScheme = new TestTacticalActStatsSubScheme
            {
                Offence = new TestTacticalActOffenceSubScheme
                {
                    Type   = OffenseType.Tactical,
                    Impact = ImpactType.Kinetic,
                    ApRank = 10
                }
            };

            var actMock = new Mock <ICombatAct>();

            actMock.SetupGet(x => x.Stats).Returns(actScheme);
            _act = actMock.Object;

            var map = await SquareMapFactory.CreateAsync(3).ConfigureAwait(false);

            var sectorMock = new Mock <ISector>();

            sectorMock.SetupGet(x => x.Map).Returns(map);
            _sector = sectorMock.Object;
        }
Пример #13
0
        public static string GetActTitle(ICombatAct combatAct)
        {
            var text = combatAct.Scheme.Name?.En;

            var currentLanguage = Thread.CurrentThread.CurrentUICulture;
            var langName        = currentLanguage.TwoLetterISOLanguageName;

            if (string.Equals(langName, "en", StringComparison.InvariantCultureIgnoreCase))
            {
                text = combatAct.Scheme.Name?.En;
            }
            else if (string.Equals(langName, "ru", StringComparison.InvariantCultureIgnoreCase))
            {
                text = combatAct.Scheme.Name?.Ru;
            }
            else
            {
                Debug.Fail(
                    $"Unknown language {langName} is selected. All available language must be supported in the client.");
            }

            return(text ?? "<Undef>");
        }
Пример #14
0
        /// <summary>
        /// Проверяет, допустимая ли дистанция для совершения действия.
        /// </summary>
        /// <param name="act"> Проверяемое действие. </param>
        /// <param name="currentNode"> Узел, из которого совершается действие. </param>
        /// <param name="targetNode"> Целевой узел. </param>
        /// <returns>Возвращает true, если дистанция допустима.</returns>
        public static bool CheckDistance(this ICombatAct act,
                                         IGraphNode currentNode,
                                         IGraphNode targetNode,
                                         ISectorMap map)
        {
            if (act is null)
            {
                throw new ArgumentNullException(nameof(act));
            }

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

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

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

            var range = act.Stats.Range;

            if (range is null)
            {
                throw new ArgumentNullException(nameof(act.Stats.Range));
            }

            var distance     = map.DistanceBetween(currentNode, targetNode);
            var isInDistance = range.Contains(distance);

            return(isInDistance);
        }
Пример #15
0
        private void UseActResources(IActor actor, ICombatAct act)
        {
            // Изъятие патронов
            if (act.Constrains?.PropResourceType != null)
            {
                RemovePropResource(actor, act);
            }

            if (act.Equipment != null)
            {
                EquipmentDurableService?.UpdateByUse(act.Equipment, actor.Person);
            }

            // Сброс КД, если он есть.
            act.StartCooldownIfItIs();

            // Consume energy.
            // Monster's act has no energy cost.
            if (act.Constrains?.EnergyCost != null)
            {
                actor.Person.GetModule <ISurvivalModule>()
                .DecreaseStat(SurvivalStatType.Energy, act.Constrains.EnergyCost.Value);
            }
        }
Пример #16
0
 public UsedActEventArgs([NotNull] IGraphNode targetNode, [NotNull] ICombatAct tacticalAct)
 {
     TargetNode  = targetNode ?? throw new ArgumentNullException(nameof(targetNode));
     TacticalAct = tacticalAct ?? throw new ArgumentNullException(nameof(tacticalAct));
 }
Пример #17
0
 public PlayerDamagedEvent(ICombatAct tacticalAct, IActor damager)
 {
     TacticalAct = tacticalAct ?? throw new ArgumentNullException(nameof(tacticalAct));
     Damager     = damager ?? throw new ArgumentNullException(nameof(damager));
 }
Пример #18
0
 public AttackActorJobProgress(IActor targetActor, ICombatAct tacticalAct)
 {
     _targetActor = targetActor;
     _tacticalAct = tacticalAct;
 }
Пример #19
0
 /// <summary>
 /// Возвращает ранг пробития действия.
 /// </summary>
 /// <param name="tacticalAct"></param>
 /// <returns></returns>
 private static int GetActApRank(ICombatAct tacticalAct)
 {
     return((tacticalAct.Stats.Offence?.ApRank).GetValueOrDefault());
 }
Пример #20
0
 public CombatActRoll(ICombatAct tacticalAct, int efficient)
 {
     CombatAct = tacticalAct;
     Efficient = efficient;
 }
Пример #21
0
 /// <inheritdoc />
 public void UseAct(IGraphNode targetNode, ICombatAct tacticalAct)
 {
     DoUseAct(targetNode, tacticalAct);
 }
Пример #22
0
        private void DoUseAct(IGraphNode targetNode, ICombatAct tacticalAct)
        {
            var args = new UsedActEventArgs(targetNode, tacticalAct);

            UsedAct?.Invoke(this, args);
        }