コード例 #1
0
ファイル: EntitySpawner.cs プロジェクト: azsdaja/7drl-2018
        public ActorBehaviour SpawnActor(ActorType actorType, Vector2Int position, bool isBoss = false)
        {
            ActorBehaviour instantiatedActor = _actorBehaviourFactory.Create();

            instantiatedActor.name = actorType.ToString();
            ActorData actorData = instantiatedActor.ActorData;

            actorData.ActorType = actorType;
            actorData.IsBoss    = isBoss;

            ActorDefinition actorDefinition = _gameConfig.ActorConfig.GetDefinition(actorType);

            instantiatedActor.GetComponent <SpriteRenderer>().sprite = actorDefinition.Sprite;
            actorData.WeaponWeld      = _rng.Choice(actorDefinition.WeaponPool);
            actorData.SwordsFromSkill = actorDefinition.SwordsFromSkill;
            actorData.VisionRayLength = actorDefinition.VisionRayLength;
            actorData.EnergyGain      = actorDefinition.EnergyGain;
            actorData.Team            = actorDefinition.Team;
            actorData.MaxHealth       = actorDefinition.MaxHealth;
            actorData.Health          = actorDefinition.MaxHealth;
            actorData.Accuracy        = actorDefinition.Accuracy;
            actorData.XpGiven         = actorDefinition.XpGiven;
            actorData.Level           = actorDefinition.InitialLevel;
            actorData.Traits          = actorDefinition.InitialTraits.ToArray().ToList();
            actorData.AiTraits        = actorDefinition.AiTraits.ToArray().ToList();

            Vector2Int freePosition = GetPositionToPlaceActor(position);

            actorData.LogicalPosition = freePosition;
            instantiatedActor.RefreshWorldPosition();
            _gameContext.Actors.Add(instantiatedActor);
            instantiatedActor.gameObject.SetActive(true);
            return(instantiatedActor);
        }
コード例 #2
0
ファイル: GameEntity.cs プロジェクト: azsdaja/7drl-2018
        public virtual void Show()
        {
            _spriteRenderer.enabled = true;

            for (int i = 0; i < transform.childCount; i++)
            {
                if (transform.GetChild(i).name == "ControlArrows")
                {
                    continue;
                }
                transform.GetChild(i).gameObject.SetActive(true);
            }
            if (this is ActorBehaviour)
            {
                _swordsIndicator.InitializeActiveSwords((this as ActorBehaviour).ActorData.Swords);

                var   actorData = ((ActorBehaviour)this).ActorData;
                float chance    = actorData.ActorType == ActorType.LastMonster ? 1.0f : 0.6f;
                if (actorData.Team == Team.Neutral && _rng.Check(chance))
                {
                    string text = "";
                    if (actorData.ActorType == ActorType.Dog)
                    {
                        text = _rng.Choice(new[] { "Woof!", "Whrrrr!", "Woof! Woof!" });
                    }
                    else if (actorData.ActorType == ActorType.LastMonster)
                    {
                        text = _rng.Choice(new[] { "BACK TO YOUR WARD!!!" });
                    }
                    else if (actorData.ActorType == ActorType.BruisedRat)
                    {
                        text = _rng.Choice(new[] { "Give me your guts!", "Squeak! Squeak!", "Ghhhrrr!" });
                    }
                    else
                    {
                        text = _rng.Choice(new[]
                        {
                            "You?!", "The prisoner is loose!", "Back to your ward!", "Squeak!", "He's there!", "", "", "En garde!", "Have at you!",
                            "Comrades, help me!", "Aah!"
                        });
                    }
                    _textEffectPresenter.ShowTextEffect(EntityData.LogicalPosition, text, text == "BACK TO YOUR WARD!!!" ? Color.magenta : Color.white, text == "BACK TO YOUR WARD!!!");
                }
            }
        }
コード例 #3
0
 private void SpreadInitialSeeds()
 {
     for (var i = 0; i < _initialSeeds; i++)
     {
         Position position = _rng.NextPosition(Values.XSize, Values.YSize);
         Plant    plant    = _rng.Choice(_config.PlantDefinitions);
         SetPlant(position.x, position.y, plant);
     }
 }
コード例 #4
0
ファイル: EntityGenerator.cs プロジェクト: bmjoy/Osnowa
        public void GenerateActorFromRecipeeAndAddToContext(IContext <GameEntity> context,
                                                            IEntityRecipee entityRecipee, Position position, out GameEntity entity, bool controlledByPlayer = false)
        {
            entity = context.CreateEntity();

            entity.AddRecipee(entityRecipee.Id);

            List <IEntityRecipee> allApplyingRecipees = GetAllRecipeesWithBaseFirst(entityRecipee);

            foreach (IEntityRecipee applyingRecipee in allApplyingRecipees)
            {
                if (applyingRecipee.NewComponents.Any(c => c == null))
                {
                    _logger.Warning($"Null component in {applyingRecipee.Name} recipee");
                }
            }
            List <IComponentRecipee> allComponentRecipees = allApplyingRecipees.SelectMany(r => r.NewComponents).ToList();

            foreach (IComponentRecipee recipee in allComponentRecipees)
            {
                recipee.ApplyToEntity(entity, _rng);
            }
            if (entity.hasPosition)
            {
                entity.ReplacePosition(position);
            }

            List <Skill> allSkills = allApplyingRecipees.SelectMany(r => r.NewSkills).ToList();

            if (allSkills.Count > 0)
            {
                entity.AddSkills(allSkills);
            }

            List <Sprite> spritePool = allApplyingRecipees.LastOrDefault(r => r.Sprites != null && r.Sprites.Count > 0).Sprites;

            if (spritePool != null)
            {
                var sprite = _rng.Choice(spritePool);
                entity.ReplaceLooks(sprite);
            }

            if (controlledByPlayer)
            {
                _context.ReplacePlayerEntity(entity.id.Id);
            }

            // duplicated from GameInitializer:
            entity.isFinishedTurn = true;
            if (_context.playerEntity.Id == entity.id.Id)
            {
                entity.isPlayerControlled = true;
            }
        }
コード例 #5
0
        private void GenerateActorsAndItemsOutside()
        {
            var bound = new BoundsInt(new Vector3Int(-2, -53, 0), new Vector3Int(19, 18, 1));

            for (int i = 0; i < 10; i++)
            {
                Vector2Int randomPosition = _rng.NextPosition(bound);
                if (_gridInfoProvider.IsWalkable(randomPosition))
                {
                    var actor = _rng.Choice(new[]
                    {
                        ActorType.Rogue,
                        ActorType.BruisedRat,
                        ActorType.BruisedRat,
                        ActorType.Rat,
                        ActorType.Rat,
                        ActorType.RatChiefBetter,
                        ActorType.RatChief,
                        ActorType.Dog,
                        ActorType.RatVeteran,
                    });
                    _entitySpawner.SpawnActor(actor, randomPosition);
                }
            }
            ItemDefinition recoverTailDefinition = Resources.Load <ItemDefinition>("PotionOfRecoverTail");

            _entitySpawner.SpawnItem(recoverTailDefinition, new Vector2Int(-3, -83));
            _entitySpawner.SpawnActor(ActorType.LastMonster, new Vector2Int(-2, -83));
            _entitySpawner.SpawnActor(ActorType.Basher, new Vector2Int(11, -64));
            _entitySpawner.SpawnActor(ActorType.RatChief, new Vector2Int(3, -87));
        }
コード例 #6
0
ファイル: WeaponAnimator.cs プロジェクト: azsdaja/7drl-2018
    public void SwingTo(Vector2Int targetPosition, bool isAggressiveAttack)
    {
        if (!gameObject.activeInHierarchy)
        {
            gameObject.SetActive(true);
        }
        _initialPosition    = transform.position;
        _isAggressiveAttack = isAggressiveAttack;
        _mySwingTarget      = _gridInfoProvider.GetCellCenterWorld(targetPosition);
        _animator.enabled   = false;
        Vector3 directionToTarget = _mySwingTarget - _initialPosition;

        _deviationCurveForX        = _rng.Choice(_weaponAnimationData.DeviationCurves);
        _deviationCurveForY        = _rng.Choice(_weaponAnimationData.DeviationCurves);
        _deviationCurveForRotation = _rng.Choice(_weaponAnimationData.DeviationCurvesForRotation);
        _deviationImportanceForX   = _rng.NextFloat();
        _deviationImportanceForY   = _rng.NextFloat();

        var angle = ZRotationForLookAt2DConsidering45OffsetOfWeapon(Math.Abs(directionToTarget.x), directionToTarget.y);

        _mySwingTargetRotation = Quaternion.AngleAxis(angle, Vector3.forward);
    }
コード例 #7
0
        private NavigationData FindNavigationDataToGoodPosition(GameEntity entity, IFloodArea targetFlood, int preferredDistance)
        {
            IList <Position> availablePositions = GetPositionsOnFloodWithGivenDistance(targetFlood, preferredDistance).ToList();

            int attemptsLimit = 5;
            int attempts      = 0;

            while (true)
            {
                ++attempts;
                if (attempts > attemptsLimit)
                {
                    Debug.Log("Failed after " + attempts + " attempts.");
                    return(null);
                }
                Position[] candidates = { _rng.Choice(availablePositions), _rng.Choice(availablePositions), _rng.Choice(availablePositions) };
                var        navigationsToCandidates = new List <NavigationData>(candidates.Length);

                foreach (Position candidatePosition in candidates)
                {
                    NavigationData navigation = _navigator.GetNavigationData(entity.position.Position, candidatePosition);
                    navigationsToCandidates.Add(navigation);
                }

                List <NavigationData> validCandidates = navigationsToCandidates.Where(c => c != null).ToList();
                if (!validCandidates.Any())
                {
                    return(null);
                }

                validCandidates.Sort((first, second) =>
                                     PositionUtilities.WalkDistance(entity.position.Position, first.Destination)
                                     .CompareTo(PositionUtilities.WalkDistance(entity.position.Position, second.Destination)));
                NavigationData closestValidCandidate = validCandidates.First();
                return(closestValidCandidate);
            }
        }
コード例 #8
0
        private Position BuildHouse(Area area)
        {
            bool ValidForBeingDoor(Position position)
            => position.y == area.Bounds.yMin && position.x > area.Bounds.xMin && position.x < area.Bounds.xMax - 1;

            Position doorPosition = RepeatedActionExecutor.Execute(() =>
            {
                var position = _rng.Choice(area.Perimeter);
                return(ValidForBeingDoor(position), position);
            });

            foreach (Position position in area.Perimeter)
            {
                if (position != doorPosition)
                {
                    Construct(position, House, _tileset.Wall);
                }
                else
                {
                    Construct(position, -1f, null);
                }
            }

            OsnowaBaseTile roofBaseTile = _tileset.Roof;

            foreach (Position housePosition in area.Positions)
            {
                Construct(housePosition, -1f, roofBaseTile);
                if (housePosition != doorPosition)
                {
                    _grid.SetWalkability(housePosition, 0f);
                    _walkability.Set(housePosition, 0f);
                }
            }

            BoundsInt boundsForRoofAdditions = area.Bounds;

            ++boundsForRoofAdditions.xMin;
            ++boundsForRoofAdditions.yMin;
            --boundsForRoofAdditions.xMax;
            --boundsForRoofAdditions.yMax;

            return(doorPosition);
        }
コード例 #9
0
ファイル: DeathHandler.cs プロジェクト: azsdaja/7drl-2018
        public void HandleDeath(ActorData actorData)
        {
            ItemDefinition weaponToSpawn = actorData.WeaponWeld;

            _entityRemover.CleanSceneAndGameContextAfterDeath(actorData);
            //_entitySpawner.SpawnItem(_gameConfig.ItemConfig.Definitions.FirstOrDefault(i => i.ItemType == ItemType.PotionOfFriend), actorData.LogicalPosition);
            if (actorData.ActorType == ActorType.Basher)
            {
                _gameContext.BasherDead = true;
            }
            if (actorData.IsBoss && _gameContext.CurrentDungeonIndex == 0)
            {
                _entitySpawner.SpawnItem(_gameConfig.ItemConfig.Definitions.First(i => i.ItemType == ItemType.PotionOfBuddy), actorData.LogicalPosition);
            }
            else if (actorData.ActorType != ActorType.Buddy && actorData.ActorType != ActorType.Friend && _rng.Check(0.42f))
            {
                ItemDefinition[] itemPool = actorData.XpGiven < 15
                                        ? _gameConfig.ItemConfig.ItemPoolWeak
                                        : actorData.XpGiven < 26 ? _gameConfig.ItemConfig.ItemPoolMedium : _gameConfig.ItemConfig.ItemPoolStrong;
                ItemDefinition item = _rng.Choice(itemPool);

                _entitySpawner.SpawnItem(item, actorData.LogicalPosition);
            }

            if (!weaponToSpawn.WeaponDefinition.IsBodyPart && actorData.ActorType != ActorType.Buddy && actorData.ActorType != ActorType.Friend)
            {
                _entitySpawner.SpawnItem(weaponToSpawn, actorData.LogicalPosition);
            }

            if (actorData.ControlledByPlayer)
            {
                _uiConfig.RestartButton.gameObject.SetActive(true);
                var postMortem = "You died at level " + actorData.Level + " after surviving " + actorData.RoundsCount +
                                 " rounds. \r\nIf you have trouble playing, check out \"Combat help\" to the right. Restart?";
                _uiConfig.RestartButton.transform.GetComponentInChildren <Text>().text = postMortem;
            }
        }
コード例 #10
0
ファイル: UseItemAction.cs プロジェクト: azsdaja/7drl-2018
        public override IEnumerable <IActionEffect> Execute()
        {
            if (_fromInventory)
            {
                _uiConfig.ItemHolder.RemoveItem(_uiConfig.ItemHolder.SelectedItemIndex);
            }
            else
            {
                ItemData itemAtFeet = _entityDetector.DetectItems(ActorData.LogicalPosition).First(i => i.ItemType == _item.ItemType);
                _entityRemover.RemoveItem(itemAtFeet);
            }

            bool isAllowed = !
                             (_gameContext.BasherSteps == 1 &&
                              new[]
            {
                ItemType.PotionOfBuddy, ItemType.PotionOfFriend, ItemType.PotionOfHealing,
                ItemType.PotionOfLight, ItemType.Food
            }
                              .Contains(_item.ItemType)
                             );

            if (_item.ItemType == ItemType.PotionOfRecoverTail)
            {
                _textEffectPresenter.ShowTextEffect(ActorData.LogicalPosition, "Squeak! At last!", Color.yellow);
            }
            else
            {
                _textEffectPresenter.ShowTextEffect(ActorData.LogicalPosition, isAllowed ? "Ha!" : "Oh, it doesn't work!", Color.yellow);
            }

            if (_item.ItemType == ItemType.Weapon)
            {
                ItemDefinition previousWeapon = ActorData.WeaponWeld;
                if (_fromInventory)
                {
                    _uiConfig.ItemHolder.AddItem(previousWeapon);
                }
                else
                {
                    if (previousWeapon.Name == "Key")
                    {
                        _entitySpawner.SpawnItem(previousWeapon, ActorData.LogicalPosition);
                    }
                    else
                    {
                        _entitySpawner.SpawnWeapon(previousWeapon.WeaponDefinition, ActorData.LogicalPosition, previousWeapon);
                    }
                }
                Image currentWeaponSprite = _uiConfig.CurrentWeaponHolder.gameObject.transform.Find("Image")
                                            .gameObject.GetComponent <Image>();
                _uiConfig.TooltipCurrentWeaponPresenter.GetComponent <CurrentWeaponTooltip>().LabelWearingUpper.gameObject.SetActive(true);
                _uiConfig.TooltipCurrentWeaponPresenter.Present(_item, true);
                _uiConfig.TooltipPresenter.gameObject.SetActive(false);
                currentWeaponSprite.sprite = _item.Sprite;
                currentWeaponSprite.color  = Color.white;

                ActorData.WeaponWeld = _item;
                Action effectAction = () => ((ActorBehaviour)ActorData.Entity).WeaponAnimator.Awake();
                var    effect       = new LambdaEffect(effectAction);
                yield return(effect);
            }
            else if (_item.ItemType == ItemType.PotionOfRecoverTail)
            {
                Sprite withTailSprite = Resources.Load <Sprite>("Sprites/Characters/player_with_tail");
                ActorData.Entity.SpriteRenderer.sprite = withTailSprite;
                ActorData.HasTail = true;
            }
            else if (isAllowed)
            {
                if (_item.ItemType == ItemType.Food)
                {
                    ActorData.Health += (int)(ActorData.MaxHealth * 0.3f);
                    if (ActorData.Health > ActorData.MaxHealth)
                    {
                        ActorData.Health = ActorData.MaxHealth;
                    }
                }
                else if (_item.ItemType == ItemType.PotionOfHealing)
                {
                    ActorData.Health += (int)(ActorData.MaxHealth * 0.7f);
                    if (ActorData.Health > ActorData.MaxHealth)
                    {
                        ActorData.Health = ActorData.MaxHealth;
                    }
                }
                else if (_item.ItemType == ItemType.PotionOfBuddy)
                {
                    _entitySpawner.SpawnActor(ActorType.Buddy, ActorData.LogicalPosition);
                }
                else if (_item.ItemType == ItemType.PotionOfFriend)
                {
                    _entitySpawner.SpawnActor(ActorType.Friend, ActorData.LogicalPosition);
                }
                else if (_item.ItemType == ItemType.PotionOfLight)
                {
                    IEnumerable <ActorData> actorsAround = _entityDetector.DetectActors(ActorData.LogicalPosition, 4).Where(a => a != ActorData);
                    foreach (var actorData in actorsAround)
                    {
                        actorData.Energy -= (2 + _rng.NextFloat() * 2f);
                        actorData.Swords -= 1;
                        if (actorData.Swords < 0)
                        {
                            actorData.Swords = 0;
                        }
                        string text = "";
                        if (actorData.ActorType != ActorType.Dog)
                        {
                            text = _rng.Choice(new[] { "My eyes!", "I can't see!", "Oh!", "Squeak!" });
                        }
                        else
                        {
                            text = "Squeak!";
                        }
                        _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text);
                    }
                }
            }
        }
コード例 #11
0
        private IGameAction ResolveActionForAggresion(ActorData actorData)
        {
            if (_rng.Check(0.04f))
            {
                if (_gameContext.PlayerActor.ActorData.Health <= 0)
                {
                    if (_rng.Check(0.07f))
                    {
                        string text = _rng.Choice(new[] { "Ha, ha!", "I got him!", "I know my strength!", "Got what he deserved!",
                                                          "Guess what we'll cook for dinner..." });
                        _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text);
                    }
                }
                else if (actorData.ActorType == ActorType.Dog && actorData.Team != Team.Beasts)
                {
                    string text = _rng.Choice(new[] { "Woof", "Wrrrr!" });
                    _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text);
                }
                else if (actorData.ActorType == ActorType.LastMonster)
                {
                    var potential = new[] { "Whshsh!", "Rrrruv!" }.ToList();
                    if (!actorData.Entity.IsVisible)
                    {
                        potential.AddRange(new[] { "[THUD!]", "[THUD!]", "[THUD!]" });
                    }
                    string text = _rng.Choice(potential);
                    _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text, text == "[THUD!]" ? Color.white
                                                : Color.magenta, true);
                }
                else if (actorData.ActorType == ActorType.Friend || actorData.ActorType == ActorType.Buddy)
                {
                    string text = _rng.Choice(new[] { "Ma-uluh, ruv!", "Suku bgeve lir...", "Alir tak rettenekopast!" });
                    _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text, new Color(0.7f, 0.8f, 1f));
                }
                else if (actorData.ActorType != ActorType.Basher && actorData.ActorType != ActorType.LastMonster)
                {
                    string text = _rng.Choice(new[] { "Back to your ward!", "Squeak!", "You're mine!", "Comrades, help me!", "Aah!" });
                    _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, text);
                }
            }

            List <ActorData> enemiesClose = _entityDetector.DetectActors(actorData.LogicalPosition, actorData.VisionRayLength)
                                            .Where(a => a.Team != actorData.Team && a.Entity.IsVisible)
                                            .ToList();

            enemiesClose.Sort((first, second) =>
                              Vector2IntUtilities.WalkDistance(first.LogicalPosition, actorData.LogicalPosition)
                              .CompareTo(Vector2IntUtilities.WalkDistance(second.LogicalPosition, actorData.LogicalPosition))
                              );
            ActorData closestEnemy = enemiesClose.FirstOrDefault();

            if (closestEnemy != null)
            {
                Vector2Int toEnemy = closestEnemy.LogicalPosition - actorData.LogicalPosition;

                // mam nadzieje, ze zadziala
                if (Vector2IntUtilities.WalkDistance(closestEnemy.LogicalPosition, actorData.LogicalPosition) == 2)
                {                 // move towards player if possible and desired
                    bool possible = false;

                    Vector2Int?legalMove        = null;
                    Vector2Int directionToEnemy = Vector2IntUtilities.Normalized(toEnemy);
                    IEnumerable <Vector2Int> candidateMovesToEnemy = Vector2IntUtilities.GetCone(directionToEnemy)
                                                                     .Select(coneVector => coneVector - directionToEnemy)
                                                                     .Where(fixedConeVector => fixedConeVector != actorData.LogicalPosition);

                    IList <Vector2Int> candidateMovesShuffled = _rng.Shuffle(candidateMovesToEnemy);
                    foreach (var cand in candidateMovesShuffled)
                    {
                        if (!_entityDetector.DetectActors(actorData.LogicalPosition + cand).Any() &&
                            _gridInfoProvider.IsWalkable(actorData.LogicalPosition + cand))
                        {
                            legalMove = cand;
                            break;
                        }
                    }
                    if (legalMove.HasValue)
                    {
                        int closeCombatAdvantage = actorData.WeaponWeld.WeaponDefinition.CloseCombatModifier -
                                                   closestEnemy.WeaponWeld.WeaponDefinition.CloseCombatModifier;
                        if (closeCombatAdvantage < 0)
                        {
                            closeCombatAdvantage = 0;
                        }
                        float chanceToMove = .1f + 0.2f * closeCombatAdvantage;
                        if (_rng.Check(chanceToMove))
                        {
                            return(_actionFactory.CreateMoveAction(actorData, legalMove.Value));
                        }
                    }
                }

                if (Vector2IntUtilities.IsOneStep(toEnemy) ||
                    (actorData.WeaponWeld.WeaponDefinition.AllowsFarCombat && Vector2IntUtilities.IsOneOrTwoSteps(toEnemy) &&
                     _clearWayBetweenTwoPointsDetector.ClearWayExists(actorData.LogicalPosition, closestEnemy.LogicalPosition)))
                {
                    IGameAction actionToPerform;

                    bool pushingIsPossible = actorData.AiTraits.Contains(AiTrait.Pusher) && Vector2IntUtilities.IsOneStep(toEnemy) &&
                                             _gridInfoProvider.IsWalkable(closestEnemy.LogicalPosition + toEnemy);
                    bool pushingIsDesired = false;
                    if (pushingIsPossible)
                    {
                        float pushingChanceScore = 0.08f;
                        if (actorData.WeaponWeld.WeaponDefinition.CloseCombatModifier < closestEnemy.WeaponWeld.WeaponDefinition.CloseCombatModifier)
                        {
                            pushingChanceScore += .25f;
                        }
                        if (!_gridInfoProvider.IsWalkable(closestEnemy.LogicalPosition + toEnemy + toEnemy))
                        {
                            pushingChanceScore += .2f;
                        }

                        if (_rng.Check(pushingChanceScore))
                        {
                            pushingIsDesired = true;
                        }
                    }

                    if (pushingIsPossible && pushingIsDesired)
                    {
                        actionToPerform = _actionFactory.CreatePushAction(actorData, closestEnemy);
                    }
                    else
                    {
                        bool isInGoodPosition = Vector2IntUtilities.IsOneStep(toEnemy) && actorData.WeaponWeld.WeaponDefinition.CloseCombatModifier
                                                > closestEnemy.WeaponWeld.WeaponDefinition.CloseCombatModifier;
                        if (Vector2IntUtilities.IsOneOrTwoSteps(toEnemy) && !isInGoodPosition)                        // && actorData.AiTraits.Contains(AiTrait.Careful)))
                        {
                            float chanceToStepBack = 0f;
                            float healthFactor     = (1 - actorData.HealthProgress) * .15f;
                            float swordsFactor     = (closestEnemy.Swords - actorData.Swords) * .15f;
                            chanceToStepBack = healthFactor + swordsFactor;
                            if (_rng.Check(chanceToStepBack))
                            {
                                Vector2Int directionFromEnemy = Vector2IntUtilities.Normalized(toEnemy) * -1;
                                IEnumerable <Vector2Int> positionsToStepBack = Vector2IntUtilities.GetCone(directionFromEnemy)
                                                                               .Select(coneVector => actorData.LogicalPosition + coneVector - directionFromEnemy)
                                                                               .Where(position => position != actorData.LogicalPosition);
                                foreach (var conePosition in positionsToStepBack)
                                {
                                    if (!_gridInfoProvider.IsWalkable(conePosition) ||
                                        _entityDetector.DetectEntities(conePosition).Any())
                                    {
                                        continue;
                                    }
                                    Vector2Int stepBackMoveVector = conePosition - actorData.LogicalPosition;
                                    return(_actionFactory.CreateMoveAction(actorData, stepBackMoveVector));
                                }
                            }
                        }

                        bool isDaringBlow = false;
                        if (actorData.Traits.Contains(Trait.DaringBlow) && actorData.Swords >= 2)
                        {
                            float daringBlowChance = actorData.AiTraits.Contains(AiTrait.Aggressive) ? .5f : .2f;
                            if (actorData.ActorType == ActorType.Basher)
                            {
                                daringBlowChance += .2f;
                            }
                            if (_rng.Check(daringBlowChance))
                            {
                                isDaringBlow = true;
                            }
                        }
                        actionToPerform = _actionFactory.CreateAttackAction(actorData, closestEnemy, isDaringBlow);
                    }
                    if (DateTime.UtcNow < closestEnemy.BlockedUntil)
                    {
                        actorData.StoredAction = actionToPerform;
                        actorData.BlockedUntil = closestEnemy.BlockedUntil;
                        return(null);
                    }
                    return(actionToPerform);
                }
                int        moveX      = toEnemy.x.CompareTo(0);
                int        moveY      = toEnemy.y.CompareTo(0);
                Vector2Int moveVector = new Vector2Int(moveX, moveY);

                Func <Vector2Int, bool> isWalkableAndFree = position =>
                                                            _gridInfoProvider.IsWalkable(position) &&
                                                            !_entityDetector.DetectActors(position).Any();

                if (!isWalkableAndFree(actorData.LogicalPosition + moveVector))
                {
                    Vector2Int?finalMoveVector = null;
                    Vector2Int alternativeMoveVector1;
                    Vector2Int alternativeMoveVector2;

                    // trying to find best alternative vectors to move
                    if (moveVector.x == 0)
                    {
                        alternativeMoveVector1 = new Vector2Int(+1, moveVector.y);
                        alternativeMoveVector2 = new Vector2Int(-1, moveVector.y);
                    }
                    else if (moveVector.y == 0)
                    {
                        alternativeMoveVector1 = new Vector2Int(moveVector.x, -1);
                        alternativeMoveVector2 = new Vector2Int(moveVector.x, +1);
                    }
                    else
                    {
                        alternativeMoveVector1 = new Vector2Int(moveVector.x, 0);
                        alternativeMoveVector2 = new Vector2Int(0, moveVector.y);
                    }

                    if (isWalkableAndFree(actorData.LogicalPosition + alternativeMoveVector1))
                    {
                        finalMoveVector = alternativeMoveVector1;
                    }
                    else if (isWalkableAndFree(actorData.LogicalPosition + alternativeMoveVector2))
                    {
                        finalMoveVector = alternativeMoveVector2;
                    }
                    if (finalMoveVector.HasValue)
                    {
                        return(_actionFactory.CreateMoveAction(actorData, finalMoveVector.Value));
                    }
                    return(_actionFactory.CreatePassAction(actorData));
                }
                return(_actionFactory.CreateMoveAction(actorData, moveVector));
            }
            else if (actorData.Team == Team.Beasts)
            {
                ActorData playerClose = _entityDetector.DetectActors(actorData.LogicalPosition, actorData.VisionRayLength).FirstOrDefault(
                    f => f != actorData && f.ActorType == ActorType.Player);
                if (playerClose != null)
                {
                    Vector2Int toFriend          = playerClose.LogicalPosition - actorData.LogicalPosition;
                    Vector2Int directionToFriend = Vector2IntUtilities.Normalized(toFriend);
                    Vector2Int legalMove         = new Vector2Int();

                    IEnumerable <Vector2Int> candidateMovesToFriend = Vector2IntUtilities.GetCone(directionToFriend)
                                                                      .Select(coneVector => coneVector - directionToFriend)
                                                                      .Where(fixedConeVector => fixedConeVector != actorData.LogicalPosition);

                    IList <Vector2Int> candidateMovesShuffled = _rng.Shuffle(candidateMovesToFriend);
                    foreach (var cand in candidateMovesShuffled)
                    {
                        if (!_entityDetector.DetectActors(actorData.LogicalPosition + cand).Any() &&
                            _gridInfoProvider.IsWalkable(actorData.LogicalPosition + cand))
                        {
                            legalMove = cand;
                            break;
                        }
                    }

                    Vector2Int moveVector = legalMove;
                    if (!_entityDetector.DetectActors(actorData.LogicalPosition + moveVector).Any())
                    {
                        return(_actionFactory.CreateMoveAction(actorData, moveVector));
                    }
                }
                return(_actionFactory.CreatePassAction(actorData));
            }
            if (Vector2IntUtilities.WalkDistance(actorData.LogicalPosition, _gameContext.PlayerActor.ActorData.LogicalPosition) < 15 &&
                _gameContext.PlayerActor.ActorData.Health > 0 && actorData.ActorType != ActorType.Basher)
            {
                Vector2Int?farReachablePoint = GetFarReachablePoint(actorData);
                if (farReachablePoint.HasValue)
                {
                    Vector2Int moveVector = Vector2IntUtilities.Normalized(farReachablePoint.Value - actorData.LogicalPosition);
                    return(_actionFactory.CreateMoveAction(actorData, moveVector));
                }
            }
            return(_actionFactory.CreatePassAction(actorData));
        }