/// <summary>
        /// Usually the current JPS implementation creates too many jump points (many of them are aligned in one line).
        /// This function gives three first „natural” jump points (two or three), which means they don't form a single line.
        /// </summary>
        public IList <Vector2Int> GetNaturalJumpPoints(IList <Vector2Int> jumpPoints)
        {
            if (jumpPoints.Count <= 2)
            {
                return(jumpPoints);
            }

            var result = new List <Vector2Int> {
                jumpPoints[0]
            };

            Vector2Int currentDirectionNormalized = Vector2IntUtilities.Normalized(jumpPoints[1] - jumpPoints[0]);

            for (int i = 2; i < jumpPoints.Count; i++)             // we should start checking from current == third and previous == second
            {
                Vector2Int previousPointToCheck = jumpPoints[i - 1];
                Vector2Int currentPointToCheck  = jumpPoints[i];
                Vector2Int currentDirection     = Vector2IntUtilities.Normalized(currentPointToCheck - previousPointToCheck);

                if (currentDirection != currentDirectionNormalized)                 // change of direction implicates that the last jump point was natural
                {
                    result.Add(previousPointToCheck);
                    currentDirectionNormalized = currentDirection;
                }
            }

            result.Add(jumpPoints.Last());
            return(result);
        }
示例#2
0
 public void Pawel()
 {
     foreach (var direction in Vector2IntUtilities.Neighbours8(Vector2Int.zero))
     {
         Console.WriteLine(direction + ", " + ZRotationForLookAt2D(direction.x, direction.y));
     }
 }
示例#3
0
        public void DwaDalej()
        {
            var position = new Vector2Int(3, 10);

            foreach (var vector2Int in Vector2IntUtilities.Neighbours8(Vector2Int.zero)
                     .Select(v => new Vector2Int(v.x * 2, v.y * 2))
                     .Select(v => position + v))
            {
                Console.WriteLine(vector2Int);
            }
        }
示例#4
0
        public void Cofanie()
        {
            var        actorPosition      = new Vector2Int(10, 10);
            var        toEnemy            = new Vector2Int(-1, -1);
            Vector2Int directionFromEnemy = Vector2IntUtilities.Normalized(toEnemy) * -1;
            IEnumerable <Vector2Int> positionsToStepBack = Vector2IntUtilities.GetCone(directionFromEnemy)
                                                           .Select(coneVector => actorPosition + coneVector - directionFromEnemy);

            foreach (var vector2Int in positionsToStepBack)
            {
                Console.WriteLine(vector2Int);
            }
        }
        public static BoundsInt GetFurthestRoomToStairs(Dungeon currentDungeon)
        {
            var roomsSortedByDistanceToStairs = currentDungeon.Rooms.ToList();

            roomsSortedByDistanceToStairs.Sort(
                (first, second) => Vector2IntUtilities.WalkDistance(currentDungeon.StairsLocation, first.min.ToVector2Int())
                .CompareTo(
                    Vector2IntUtilities.WalkDistance(currentDungeon.StairsLocation, second.min.ToVector2Int()))
                );
            BoundsInt furthestRoomToStairs = roomsSortedByDistanceToStairs.Last();

            return(furthestRoomToStairs);
        }
示例#6
0
        private int GetEmptyPositionsAround(ActorData actorData)
        {
            int emptyPositions  = 8;
            var positionsAround = Vector2IntUtilities.Neighbours8(actorData.LogicalPosition);

            foreach (Vector2Int position in positionsAround)
            {
                if (!_gridInfoProvider.IsWalkable(position) || _entityDetector.DetectActors(position).Any())
                {
                    --emptyPositions;
                }
            }
            return(emptyPositions);
        }
        /// <summary>
        /// Returns normalized vectors that point from a tile to the tile that can be considered to be "behind" it.
        /// </summary>
        internal IEnumerable <Vector2Int> GetBehindnessVectors(Vector2Int currentPosition, Vector2Int centerOfSquareToPostProcess)
        {
            Vector2Int direction  = currentPosition - centerOfSquareToPostProcess;
            var        snappedToX = Vector2IntUtilities.SnapToXAxisNormalized(direction);
            var        snappedToY = Vector2IntUtilities.SnapToYAxisNormalized(direction);

            if (snappedToX != Vector2Int.zero)
            {
                yield return(snappedToX);
            }
            if (snappedToY != Vector2Int.zero)
            {
                yield return(snappedToY);
            }
        }
示例#8
0
        private Vector2Int GetPositionToPlaceActor(Vector2Int position)
        {
            List <Vector2Int> candidates = Vector2IntUtilities.Neighbours8(position);
            var candidatesFurther        = Vector2IntUtilities.Neighbours8(Vector2Int.zero)
                                           .Select(v => new Vector2Int(v.x * 2, v.y * 2))
                                           .Select(v => position + v);

            candidates.AddRange(candidatesFurther);
            foreach (Vector2Int neighbour in candidates)
            {
                if (_gridInfoProvider.IsWalkable(neighbour) && !_entityDetector.DetectActors(neighbour).Any())
                {
                    return(neighbour);
                }
            }
            return(position);
        }
示例#9
0
        public override IEnumerable <IActionEffect> Execute()
        {
            float chanceToSucceed = ActorData.Accuracy;
            bool  success         = _rng.Check(chanceToSucceed);

            yield return(new BumpEffect(ActorData, _targetEnemy.LogicalPosition));

            if (success)
            {
                _targetEnemy.Energy -= 1.2f;
                --ActorData.Swords;

                Vector2Int direction = _targetEnemy.LogicalPosition - ActorData.LogicalPosition;

                Assert.IsTrue(Vector2IntUtilities.IsOneStep(direction));

                Vector2Int previousPosition = _targetEnemy.LogicalPosition;
                _targetEnemy.LogicalPosition += direction;
                yield return(new MoveEffect(_targetEnemy, previousPosition, _gridInfoProvider, _entityDetector, _uiConfig));
            }
        }
示例#10
0
        private Vector2Int?GetFarReachablePoint(ActorData actorData)
        {
            var reachableRandomPoints = new List <Vector2Int>();

            for (int i = 0; i < 5; i++)
            {
                Vector2Int wanderVector = new Vector2Int(_rng.Next(-7, 7), _rng.Next(-7, 7));
                Vector2Int candidate    = actorData.LogicalPosition + wanderVector;
                if (_clearWayBetweenTwoPointsDetector.ClearWayExists(actorData.LogicalPosition, candidate))
                {
                    reachableRandomPoints.Add(candidate);
                }
            }
            if (reachableRandomPoints.Any())
            {
                reachableRandomPoints.Sort((first, second) =>
                                           Vector2IntUtilities.WalkDistance(actorData.LogicalPosition, first).CompareTo(Vector2IntUtilities.WalkDistance(actorData.LogicalPosition, second))
                                           );

                return(reachableRandomPoints.First());
            }

            return(null);
        }
示例#11
0
        public override IEnumerable <IActionEffect> Execute()
        {
            Vector2Int previousPosition = ActorData.LogicalPosition;
            Vector2Int newPosition      = previousPosition + Direction;

            if (_gridInfoProvider.IsWalkable(newPosition))
            {
                if (ActorData.ActorType == ActorType.Player && _gameContext.EnvironmentTilemap.HasTile(newPosition.ToVector3Int()))
                {
                    TileBase stairsDownTile = Resources.Load <TileBase>("Tiles/Environment/Stairs_down");
                    if (_gameContext.EnvironmentTilemap.GetTile(newPosition.ToVector3Int()) == stairsDownTile)
                    {
                        _textEffectPresenter.ShowTextEffect(ActorData.LogicalPosition, "Back down? Never!", Color.yellow);
                    }
                }
                if (_gameContext.BasherSteps == 0 && ActorData.ActorType == ActorType.Basher && Vector2IntUtilities.WalkDistance(ActorData.LogicalPosition,
                                                                                                                                 _gameContext.PlayerActor.ActorData.LogicalPosition) <= 5)
                {
                    _gameContext.BasherSteps = 1;
                    _uiConfig.BasherMessage.gameObject.SetActive(true);
                    _uiConfig.BasherMessage.SetMessage("Ha! So you didn't disappoint me! Finally I see you again, my rattish friend! As you might " +
                                                       "have guessed, that was me that sent you the key. I'll be happy to take you away from this scary place. But first " +
                                                       "we have to deal with one thing. You saved my life by attributing to yourself my deeds against the revolutionists. " +
                                                       "But this also made me feel like a lousy coward. My honour has been terribly undermined and I need to clean it. " +
                                                       "I challenge you to a duel! No magic, no eating, just me, you and steel. Prepare!");

                    IEnumerable <ActorData> friendsAndBuddies = _entityDetector.DetectActors(ActorData.LogicalPosition, 15)
                                                                .Where(a => a.ActorType == ActorType.Friend || a.ActorType == ActorType.Buddy);
                    foreach (var friendOrBuddy in friendsAndBuddies)
                    {
                        _deathHandler.HandleDeath(friendOrBuddy);
                    }
                }

                IActionEffect effect = ActionEffectFactory.CreateMoveEffect(ActorData, previousPosition);
                ActorData.LogicalPosition = newPosition;
                if (ActorData.CaughtActor != null)
                {
                    ActorData.CaughtActor.LogicalPosition = newPosition;
                }

                yield return(effect);
            }
            else
            {
                IActionEffect effect = ActionEffectFactory.CreateBumpEffect(ActorData, newPosition);
                yield return(effect);
            }
        }
示例#12
0
        public virtual void Process()
        {
            bool visibleEnemiesClose = ActorData.ControlledByPlayer &&
                                       _entityDetector.DetectActors(ActorData.LogicalPosition, 3)
                                       .Count(a => a.Team != Team.Beasts && a.Entity.IsVisible) > 0;

            if (visibleEnemiesClose)
            {
                DateTime potentialBlockedUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(150);
                ActorData.BlockedUntil = potentialBlockedUntil > ActorData.BlockedUntil
                                        ? potentialBlockedUntil : ActorData.BlockedUntil;
            }

            IGameEntity     entity         = ActorData.Entity;
            IEntityAnimator entityAnimator = entity.EntityAnimator;

            IEnumerable <ActorData> enemiesNearby = _entityDetector.DetectActors(ActorData.LogicalPosition, 3)
                                                    .Where(e => ActorData.Team != e.Team)
                                                    .Where(e => Vector2IntUtilities.IsOneTwoOrThreeSteps(e.LogicalPosition, ActorData.LogicalPosition));

            // this code orientates the actor to face the closest danger, even if it means stepping backwards
            List <Vector2Int> directionsToOneStepEnemiesNearby = enemiesNearby.Select(e => e.LogicalPosition - ActorData.LogicalPosition)
                                                                 .Where(direction => Vector2IntUtilities.IsOneStep(direction))
                                                                 .ToList();
            List <Vector2Int> directionsToAllEnemiesNearby = enemiesNearby.Select(e => e.LogicalPosition - ActorData.LogicalPosition).ToList();
            List <Vector2Int> directionsToRelevantEnemiesNearby
                = directionsToOneStepEnemiesNearby.Any() ? directionsToOneStepEnemiesNearby : directionsToAllEnemiesNearby;

            bool thereAreSomeEnemiesOnOneSide = directionsToRelevantEnemiesNearby.Any()
                                                &&
                                                (directionsToRelevantEnemiesNearby.All(direction => direction.x < 0) ||
                                                 directionsToRelevantEnemiesNearby.All(direction => direction.x > 0));

            if (thereAreSomeEnemiesOnOneSide)
            {
                _actorAligner.AlignActorToDirection(ActorData.Entity, directionsToRelevantEnemiesNearby.First().x);
            }
            else
            {
                _actorAligner.AlignActorToDirection(ActorData.Entity, ActorData.LogicalPosition.x - PreviousPosition.x);
            }

            if (entity.IsVisible)
            {
                entityAnimator.MoveTo(PreviousPosition, ActorData.LogicalPosition);
            }
            else
            {
                Vector3 animationTargetPosition = _gridInfoProvider.GetCellCenterWorld(ActorData.LogicalPosition);

                // The next line makes this class kind of untestable, because ActorData.Entity is a MonoBehaviour. I believe it must be so,
                // so that we can see and assign the reference to it in the inspector window. If this happens more often in other effects,
                // we could maybe extract some kind of proxy class to keep the Entity, so that we can test with fake proxy.
                entity.Position = animationTargetPosition;
            }

            if (!ActorData.ControlledByPlayer)
            {
                return;
            }

            ItemData itemOnTheGround = _entityDetector.DetectItems(ActorData.LogicalPosition).FirstOrDefault();

            if (itemOnTheGround != null)
            {
                _uiConfig.TooltipPresenter.Present(itemOnTheGround.ItemDefinition, false);
            }
        }
示例#13
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));
        }
示例#14
0
        private void PlaceTilesBasingOnDungeon(BoundsInt gridBounds, Dungeon generator)
        {
            bool stairsGenerated = false;

            foreach (Vector3Int position in gridBounds.allPositionsWithin)
            {
                Vector2Int position2D = position.ToVector2Int();
                GenTile    genTile    = generator.GetCellType(position2D.x, position2D.y);
                switch (genTile)
                {
                case GenTile.DirtFloor:
                {
                    _gameContext.DirtTilemap.SetTile(position, Dirt);
                    if (_rng.Check(0.03f))
                    {
                        _gameContext.EnvironmentTilemap.SetTile(position, _rng.Choice(FloorEnvironmetals));
                    }
                    if (_rng.Check(0.06f))
                    {
                        if (Vector2IntUtilities.Neighbours8(position2D).All(n => generator.GetCellType(n.x, n.y) == GenTile.DirtFloor))
                        {
                            _gameContext.ObjectsTilemap.SetTile(position, _rng.Choice(WallEnvironmetals));
                        }
                    }
                    break;
                }

                case GenTile.Corridor:
                {
                    _gameContext.DirtTilemap.SetTile(position, Dirt);
                    break;
                }

                case GenTile.StoneWall:
                case GenTile.DirtWall:
                {
                    _gameContext.WallsTilemap.SetTile(position, Wall);
                    if (_rng.Check(0.04f))
                    {
                        _gameContext.EnvironmentTilemap.SetTile(position, _rng.Choice(WallAttachmentEnvironmetals));
                    }
                    break;
                }

                case GenTile.Upstairs:
                {
                    _gameContext.DirtTilemap.SetTile(position, Dirt);
                    _gameContext.EnvironmentTilemap.SetTile(position, StairsUp);
                    _gameContext.WallsTilemap.SetTile(position, null);
                    stairsGenerated = true;
                    break;
                }

                case GenTile.Downstairs:
                {
                    _gameContext.DirtTilemap.SetTile(position, Dirt);
                    break;
                }

                case GenTile.Door:
                {
                    _gameContext.DirtTilemap.SetTile(position, Dirt);
                    GenTile tileToRight      = generator.GetCellType(position.x + 1, position.y);
                    bool    isHorizontalDoor = tileToRight == GenTile.Corridor || tileToRight == GenTile.DirtFloor;
                    bool    doorsAreOpen     = _rng.Check(0.3f);
                    if (doorsAreOpen)
                    {
                        _gameContext.EnvironmentTilemap.SetTile(position, isHorizontalDoor ? DoorsHorizontalOpen : DoorsVerticalOpen);
                    }
                    else
                    {
                        _gameContext.WallsTilemap.SetTile(position, isHorizontalDoor ? DoorsHorizontalClosed : DoorsVerticalClosed);
                    }
                    break;
                }

                default:
                {
                    break;
                }
                }
            }
            if (!stairsGenerated)
            {
                BoundsInt  randomRoom = _rng.Choice(generator.Rooms);
                Vector3Int center     = BoundsIntUtilities.Center(randomRoom).ToVector3Int();
                _gameContext.DirtTilemap.SetTile(center, Dirt);
                _gameContext.EnvironmentTilemap.SetTile(center, StairsUp);
                _gameContext.WallsTilemap.SetTile(center, null);
                Debug.Log("Missing stairs in dungeon! Generating in random room on position: " + center);
            }
        }
示例#15
0
        private void GenerateActorsInDungeon(Dungeon currentDungeon, DungeonConfig dungeonConfig, bool isFirstDungeon)
        {
            BoundsInt playerRoom = new BoundsInt();

            if (isFirstDungeon)
            {
                BoundsInt furthestRoomToStairs = FurthestRoomToStairsResolver.GetFurthestRoomToStairs(currentDungeon);

                playerRoom = furthestRoomToStairs;

                BoundsInt  roomToSpawnPlayerIn = playerRoom;
                Vector2Int playerPosition      = BoundsIntUtilities.Center(roomToSpawnPlayerIn);
                Vector2Int breadPosition       = Vector2Int.zero;
                var        neighboursRebourse  = Vector2IntUtilities.Neighbours8(playerPosition).ToList();
                neighboursRebourse.Reverse();
                foreach (var neighbour in neighboursRebourse)
                {
                    if (_gridInfoProvider.IsWalkable(neighbour) && neighbour != playerPosition)
                    {
                        _entitySpawner.SpawnItem(BreadItem, neighbour);
                        breadPosition = neighbour;
                        break;
                    }
                }
                foreach (var neighbour in neighboursRebourse)
                {
                    if (neighbour != breadPosition && _gridInfoProvider.IsWalkable(neighbour))
                    {
                        _entitySpawner.SpawnItem(KeyItem, neighbour);
                        break;
                    }
                }
                BoundsInt aroundPlayerRoom = new BoundsInt(playerRoom.position - new Vector3Int(1, 1, 0),
                                                           playerRoom.size + new Vector3Int(2, 2, 0));
                foreach (Vector3Int positionInPlayerRoom in aroundPlayerRoom.allPositionsWithin)
                {
                    if (_gameContext.WallsTilemap.GetTile(positionInPlayerRoom) == DoorsVerticalClosed ||
                        _gameContext.EnvironmentTilemap.GetTile(positionInPlayerRoom) == DoorsVerticalOpen)
                    {
                        _gameContext.WallsTilemap.SetTile(positionInPlayerRoom, HeavyDoorsVerticalClosed);
                        _gameContext.EnvironmentTilemap.SetTile(positionInPlayerRoom, null);
                    }
                    if (_gameContext.WallsTilemap.GetTile(positionInPlayerRoom) == DoorsHorizontalClosed ||
                        _gameContext.EnvironmentTilemap.GetTile(positionInPlayerRoom) == DoorsHorizontalOpen)
                    {
                        _gameContext.WallsTilemap.SetTile(positionInPlayerRoom, HeavyDoorsHorizontalClosed);
                        _gameContext.EnvironmentTilemap.SetTile(positionInPlayerRoom, null);
                    }
                }
                var playerActorBehaviour = _entitySpawner.SpawnActor(ActorType.Player, playerPosition);

                playerActorBehaviour.ActorData.ControlledByPlayer = true;
                _gameContext.PlayerActor = playerActorBehaviour;
                _gameConfig.FollowPlayerCamera.Follow    = playerActorBehaviour.transform;
                _uiConfig.Arrows.transform.parent        = playerActorBehaviour.transform;
                _uiConfig.Arrows.transform.localPosition = new Vector3(0, -0.1f, 0);
            }

            foreach (BoundsInt room in currentDungeon.Rooms.Skip(isFirstDungeon ? 1 :0))
            {
                if (room == playerRoom)
                {
                    continue;
                }
                float populationValue  = _rng.NextFloat();
                int   populationInRoom = Mathf.RoundToInt(dungeonConfig.ChanceToRoomPopulation.Evaluate(populationValue));
                for (int i = 0; i < populationInRoom; i++)
                {
                    ActorDefinition[] actorTypesAvailable = dungeonConfig.EnemiesToSpawn;
                    ActorType         actorTypeChosen     = _rng.Choice(actorTypesAvailable).ActorType;
                    Vector2Int        centralPosition     = BoundsIntUtilities.Center(room);
                    _entitySpawner.SpawnActor(actorTypeChosen, centralPosition);
                }
            }

            _entitySpawner.SpawnActor(dungeonConfig.BossToSpawn.ActorType, currentDungeon.StairsLocation, true);
        }
示例#16
0
        public IGameAction GetAction(ActorData actorData)
        {
            if (_inputHolder.PlayerInput == PlayerInput.None)
            {
                return(null);
            }

            if (_inputHolder.PlayerInput != PlayerInput.UseCurrentItem && _inputHolder.PlayerInput != PlayerInput.DropCurrentItem)
            {
                _uiConfig.ItemHolder.DeselectItem();
                _uiConfig.TooltipPresenter.Panel.gameObject.SetActive(false);
                _uiConfig.TooltipCurrentWeaponPresenter.gameObject.SetActive(false);
                _uiConfig.TooltipCurrentWeaponPresenter.GetComponent <CurrentWeaponTooltip>().LabelWearingUpper.gameObject.SetActive(false);
                var quitButton = GameObject.FindGameObjectWithTag("button_quit");
                if (quitButton != null)
                {
                    quitButton.SetActive(false);
                }
            }
            if (_uiConfig.WalkAbilityButton.GetComponentInChildren <Text>() != null)
            {
                _uiConfig.WalkAbilityButton.GetComponentInChildren <Text>().gameObject.SetActive(false);
            }
            if (_uiConfig.DaringBlowAbilityButton.GetComponentInChildren <Text>() != null)
            {
                _uiConfig.DaringBlowAbilityButton.GetComponentInChildren <Text>().gameObject.SetActive(false);
            }
            if (_uiConfig.PushAbilityButton.GetComponentInChildren <Text>() != null)
            {
                _uiConfig.PushAbilityButton.GetComponentInChildren <Text>().gameObject.SetActive(false);
            }

            IGameAction gameActionToReturn;

            if (_inputHolder.PlayerInput == PlayerInput.PickUp)
            {
                IList <ItemData> items            = _entityDetector.DetectItems(actorData.LogicalPosition).ToList();
                bool             allSlotsOccupied = _uiConfig.ItemHolder.Items.All(i => i != null);
                if (!items.Any() || allSlotsOccupied)
                {
                    return(null);
                }
                ItemData itemToPickUp = items.First();
                _inputHolder.PlayerInput = PlayerInput.None;
                return(_actionFactory.CreatePickUpAction(actorData, itemToPickUp));
            }

            if (_inputHolder.PlayerInput == PlayerInput.Drop)
            {
                ItemData firstItem = actorData.Items.FirstOrDefault();
                if (firstItem == null)
                {
                    return(null);
                }
                _inputHolder.PlayerInput = PlayerInput.None;
                return(_actionFactory.CreateDropAction(actorData, firstItem));
            }
            if (_inputHolder.PlayerInput == PlayerInput.Catch)
            {
                ActorData caughtActor = _entityDetector.DetectActors(actorData.LogicalPosition, 1).FirstOrDefault();
                if (caughtActor == null)
                {
                    return(null);
                }
                _inputHolder.PlayerInput = PlayerInput.None;
                return(_actionFactory.CreateCatchAction(actorData, caughtActor));
            }
            if (_inputHolder.PlayerInput == PlayerInput.Release)
            {
                if (actorData.CaughtActor == null)
                {
                    return(null);
                }
                _inputHolder.PlayerInput = PlayerInput.None;
                return(_actionFactory.CreateReleaseAction(actorData));
            }
            if (_inputHolder.PlayerInput == PlayerInput.Pass)
            {
                _inputHolder.PlayerInput = PlayerInput.None;
                return(_actionFactory.CreatePassAction(actorData));
            }
            if (_inputHolder.PlayerInput == PlayerInput.Eat)
            {
                _inputHolder.PlayerInput = PlayerInput.None;
                ItemData foodAtFeet = _entityDetector.DetectItems(actorData.LogicalPosition).FirstOrDefault(i => i.ItemType == ItemType.DeadBody);
                if (foodAtFeet == null)
                {
                    return(null);
                }
                return(_actionFactory.CreateEatAction(actorData, foodAtFeet));
            }
            if (_inputHolder.PlayerInput == PlayerInput.UseCurrentItem)
            {
                _inputHolder.PlayerInput = PlayerInput.None;
                ItemDefinition item;
                item = _uiConfig.ItemHolder.CurrentItem();
                if (item == null)
                {
                    ItemData itemAtFeet = _entityDetector.DetectItems(actorData.LogicalPosition).FirstOrDefault();
                    if (itemAtFeet != null)
                    {
                        item = itemAtFeet.ItemDefinition;
                        return(_actionFactory.CreateUseItemAction(actorData, item, false));
                    }
                    return(null);
                }
                return(_actionFactory.CreateUseItemAction(actorData, item, true));
            }
            if (_inputHolder.PlayerInput == PlayerInput.DropCurrentItem)
            {
                _inputHolder.PlayerInput = PlayerInput.None;
                ItemDefinition item = _uiConfig.ItemHolder.CurrentItem();
                if (item == null)
                {
                    return(null);
                }

                return(_actionFactory.CreateDropItemAction(actorData, item));
            }
            if (_inputHolder.PlayerInput == PlayerInput.Ascend)
            {
                TileBase stairsDown = Resources.Load <TileBase>("Tiles/Environment/Stairs_down");

                _inputHolder.PlayerInput = PlayerInput.None;
                Vector2Int playerPosition     = _gameContext.PlayerActor.ActorData.LogicalPosition;
                TileBase   envTileBelowPlayer = _gameContext.EnvironmentTilemap.GetTile(playerPosition.ToVector3Int());
                if (envTileBelowPlayer != null && envTileBelowPlayer != stairsDown)
                {
                    return(_actionFactory.CreateAscendAction(actorData));
                }
                return(null);
            }
            Vector2Int actionVector   = GetActionVector(_inputHolder.PlayerInput);
            Vector2Int targetPosition = actionVector + actorData.LogicalPosition;

            if (_inputHolder.PlayerInputModifier == PlayerInputModifier.Move)
            {
                _inputHolder.PlayerInputModifier = PlayerInputModifier.None;
                _inputHolder.PlayerInput         = PlayerInput.None;
                _arrowsVisibilityManager.Hide();

                IEnumerable <ActorData> actorsAtTarget = _entityDetector.DetectActors(targetPosition);
                if (actorsAtTarget.Any())
                {
                    return(null);
                }
                gameActionToReturn = _actionFactory.CreateMoveAction(actorData, actionVector);
                return(gameActionToReturn);
            }
            bool isAggressiveAttack = false;

            if (_inputHolder.PlayerInputModifier == PlayerInputModifier.DaringBlow)
            {
                isAggressiveAttack = true;
                _inputHolder.PlayerInputModifier = PlayerInputModifier.None;
                _inputHolder.PlayerInput         = PlayerInput.None;
                _weaponColorizer.Decolorize((actorData.Entity as ActorBehaviour).WeaponAnimator);
            }

            IList <Vector2Int> targetPositionsCone = Vector2IntUtilities.GetCone(actionVector)
                                                     .Select(zeroBasedPosition => actorData.LogicalPosition + zeroBasedPosition)
                                                     .ToList();
            IList <ActorData> actorsCloseToCone = _entityDetector.DetectActors(targetPosition, 2).ToList();

            ActorData targetActor;
            ActorData actorAtTargetPosition = actorsCloseToCone.FirstOrDefault(a => a.LogicalPosition == targetPosition);

            if (actorAtTargetPosition != null && actorAtTargetPosition.Team == actorData.Team)
            {
                _inputHolder.PlayerInput = PlayerInput.None;
                gameActionToReturn       = _actionFactory.CreateDisplaceAction(actorData, actorAtTargetPosition);
                return(gameActionToReturn);
            }

            bool isPushing = _inputHolder.PlayerInputModifier == PlayerInputModifier.Push;

            _arrowsVisibilityManager.Hide();
            _inputHolder.PlayerInputModifier = PlayerInputModifier.None;
            if ((actorAtTargetPosition != null || isPushing) || actorData.WeaponWeld.WeaponDefinition.AllowsFarCombat == false)
            {
                targetActor = actorAtTargetPosition;
            }
            else
            {
                targetActor = actorsCloseToCone
                              .FirstOrDefault(potentialTarget => potentialTarget.Team != actorData.Team &&
                                              targetPositionsCone.Contains(potentialTarget.LogicalPosition) &&
                                              _clearWayBetweenTwoPointsDetector.ClearWayExists(actorData.LogicalPosition, potentialTarget.LogicalPosition));
            }

            if (targetActor != null)            // hit!
            {
                gameActionToReturn = isPushing
                                        ? _actionFactory.CreatePushAction(actorData, targetActor)
                                        : _actionFactory.CreateAttackAction(actorData, targetActor, isAggressiveAttack);
            }
            else
            {
                TileBase wallTileAtTarget = _gameContext.WallsTilemap.GetTile(targetPosition.ToVector3Int());
                if (wallTileAtTarget != null)
                {
                    _heavyDoorsHClosedTile = Resources.Load <Tile>("Tiles/Environment/doors_HEAVY_0");
                    _heavyDoorsVClosedTile = Resources.Load <Tile>("Tiles/Environment/doors_HEAVY_2");
                    if ((wallTileAtTarget == _heavyDoorsHClosedTile || wallTileAtTarget == _heavyDoorsVClosedTile) &&
                        _uiConfig.ItemHolder.Items.Where(i => i != null).All(i => i.Name != "Key") &&
                        _gameContext.PlayerActor.ActorData.WeaponWeld.Name != "Key")
                    {
                        // bump
                        gameActionToReturn = _actionFactory.CreateMoveAction(actorData, actionVector);
                        _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, "Umph! Locked!", Color.yellow);
                    }
                    else
                    {
                        var doorsHClosedTile = Resources.Load <Tile>("Tiles/Environment/doors_H_closed");
                        var doorsVClosedTile = Resources.Load <Tile>("Tiles/Environment/doors_V_closed");

                        if (wallTileAtTarget == doorsHClosedTile || wallTileAtTarget == doorsVClosedTile)
                        {
                            bool isHorizontal = wallTileAtTarget == doorsHClosedTile;
                            gameActionToReturn = _actionFactory.CreateOpenDoorAction(actorData, targetPosition, isHorizontal);
                        }
                        else if (wallTileAtTarget == _heavyDoorsHClosedTile || wallTileAtTarget == _heavyDoorsVClosedTile)
                        {
                            bool isHorizontal = wallTileAtTarget == _heavyDoorsHClosedTile;
                            gameActionToReturn = _actionFactory.CreateOpenDoorAction(actorData, targetPosition, isHorizontal, true);
                        }
                        else
                        {
                            gameActionToReturn = _actionFactory.CreateMoveAction(actorData, actionVector);
                        }
                    }
                }
                else
                {
                    gameActionToReturn = _actionFactory.CreateMoveAction(actorData, actionVector);
                }
            }
            _inputHolder.PlayerInput = PlayerInput.None;
            return(gameActionToReturn);
        }
示例#17
0
        //and here's the one generating the whole map
        public bool CreateDungeon(Vector3Int gridBoundsMin, int inx, int iny, int inobj)
        {
            _offset       = gridBoundsMin;
            this._objects = inobj < 1 ? 10 : inobj;

            // adjust the size of the map, if it's smaller or bigger than the limits
            if (inx < 3)
            {
                this._xsize = 3;
            }
            else if (inx > xmax)
            {
                this._xsize = xmax;
            }
            else
            {
                this._xsize = inx;
            }

            if (iny < 3)
            {
                this._ysize = 3;
            }
            else if (iny > ymax)
            {
                this._ysize = ymax;
            }
            else
            {
                this._ysize = iny;
            }

            Console.WriteLine(MsgXSize + this._xsize);
            Console.WriteLine(MsgYSize + this._ysize);
            Console.WriteLine(MsgMaxObjects + this._objects);

            // redefine the map var, so it's adjusted to our new map size
            this._dungeonMap = new GenTile[this._xsize * this._ysize];

            // start with making the "standard stuff" on the map
            this.Initialize();

            /*******************************************************************************
            *  And now the code of the random-map-generation-algorithm begins!
            *******************************************************************************/

            // start with making a room in the middle, which we can start building upon
            this.MakeRoom(this._xsize / 2, this._ysize / 2, _roomSizeMaxX, _roomSizeMaxY, RandomDirection());             // getrand saken f????r att slumpa fram riktning p?? rummet

            // keep count of the number of "objects" we've made
            int currentFeatures = 1;             // +1 for the first room we just made

            // then we sart the main loop
            for (int countingTries = 0; countingTries < 1000; countingTries++)
            {
                // check if we've reached our quota
                if (currentFeatures == this._objects)
                {
                    break;
                }

                // start with a random wall
                int       newx      = 0;
                int       xmod      = 0;
                int       newy      = 0;
                int       ymod      = 0;
                Direction?validTile = null;

                // 1000 chances to find a suitable object (room or corridor)..
                for (int testing = 0; testing < 1000; testing++)
                {
                    newx = this.GetRand(1, this._xsize - 1);
                    newy = this.GetRand(1, this._ysize - 1);

                    if (GetCellTypeNoOffset(newx, newy) == GenTile.DirtWall || GetCellTypeNoOffset(newx, newy) == GenTile.Corridor)
                    {
                        var surroundings = this.GetSurroundings(new Vector2Int(newx, newy));

                        // check if we can reach the place
                        var canReach =
                            surroundings.FirstOrDefault(s => s.Item2.Item2 == GenTile.Corridor || s.Item2.Item2 == GenTile.DirtFloor);
                        if (canReach == null)
                        {
                            continue;
                        }
                        validTile = canReach.Item2.Item1;
                        switch (canReach.Item2.Item1)
                        {
                        case Direction.North:
                            xmod = 0;
                            ymod = -1;
                            break;

                        case Direction.East:
                            xmod = 1;
                            ymod = 0;
                            break;

                        case Direction.South:
                            xmod = 0;
                            ymod = 1;
                            break;

                        case Direction.West:
                            xmod = -1;
                            ymod = 0;
                            break;

                        default:
                            throw new InvalidOperationException();
                        }


                        // check that we haven't got another door nearby, so we won't get alot of openings besides
                        // each other

                        if (GetCellTypeNoOffset(newx, newy + 1) == GenTile.Door)                         // north
                        {
                            validTile = null;
                        }

                        else if (GetCellTypeNoOffset(newx - 1, newy) == GenTile.Door)                         // east
                        {
                            validTile = null;
                        }
                        else if (GetCellTypeNoOffset(newx, newy - 1) == GenTile.Door)                         // south
                        {
                            validTile = null;
                        }
                        else if (GetCellTypeNoOffset(newx + 1, newy) == GenTile.Door)                         // west
                        {
                            validTile = null;
                        }


                        // if we can, jump out of the loop and continue with the rest
                        if (validTile.HasValue)
                        {
                            break;
                        }
                    }
                }

                if (validTile.HasValue)
                {
                    // choose what to build now at our newly found place, and at what direction
                    int feature = this.GetRand(0, 100);
                    if (feature <= ChanceRoom)
                    {                     // a new room
                        if (this.MakeRoom(newx + xmod, newy + ymod, 8, 6, validTile.Value))
                        {
                            currentFeatures++;                             // add to our quota

                            // then we mark the wall opening with a door
                            this.SetCell(newx, newy, GenTile.Door);

                            // clean up infront of the door so we can reach it
                            this.SetCell(newx + xmod, newy + ymod, GenTile.DirtFloor);
                        }
                    }
                    else if (feature >= ChanceRoom)
                    {                     // new corridor
                        if (this.MakeCorridor(newx + xmod, newy + ymod, 6, validTile.Value))
                        {
                            // same thing here, add to the quota and a door
                            currentFeatures++;

                            this.SetCell(newx, newy, GenTile.Door);
                        }
                    }
                }
            }

            /*******************************************************************************
            *  All done with the building, let's finish this one off
            *******************************************************************************/
            AddSprinkles();

            // all done with the map generation, tell the user about it and finish
            Console.WriteLine(MsgNumObjects + currentFeatures);

            for (int y = 0; y < this._ysize; y++)
            {
                for (int x = 0; x < this._xsize; x++)
                {
                    if (GetCellTypeNoOffset(x, y) == GenTile.Corridor)
                    {
                        List <Vector2Int> neighbours = Vector2IntUtilities.Neighbours8(new Vector2Int(x, y));
                        foreach (Vector2Int neighbour in neighbours)
                        {
                            GenTile neighbourCell = GetCellTypeNoOffset(neighbour.x, neighbour.y);
                            if (neighbourCell == GenTile.Unused)
                            {
                                SetCell(neighbour.x, neighbour.y, GenTile.StoneWall);
                            }
                        }
                    }
                }
            }

            return(true);
        }
示例#18
0
        public void Heartbeat(ActorData actorData)
        {
            ++actorData.RoundsCount;

            BoundsInt lastLevelBounds       = new BoundsInt(-18, -103, 0, 49, 72, 1);
            BoundsInt almostLastLevelBounds = new BoundsInt(-16, -101, 0, 45, 68, 1);

            if (actorData.ActorType == ActorType.Player && _gameContext.CurrentDungeonIndex >= _gameContext.Dungeons.Count &&
                !almostLastLevelBounds.Contains(actorData.LogicalPosition.ToVector3Int()))
            {
                _textEffectPresenter.ShowTextEffect(actorData.LogicalPosition, "Almost free!", Color.yellow);
            }

            if (actorData.ActorType == ActorType.Player && _gameContext.CurrentDungeonIndex >= _gameContext.Dungeons.Count &&
                !lastLevelBounds.Contains(actorData.LogicalPosition.ToVector3Int()))
            {
                var finisher = _uiConfig.GameFinisher;
                finisher.gameObject.SetActive(true);
                finisher.Initialize(actorData);
            }

            //if (actorData.Health < actorData.MaxHealth)
            //	++actorData.Health;

            IEnumerable <ActorData> enemiesNearby = _entityDetector.DetectActors(actorData.LogicalPosition, 2)
                                                    .Where(a => a.Team != actorData.Team);

            if (enemiesNearby.Any(a => Vector2IntUtilities.IsOneStep(a.LogicalPosition, actorData.LogicalPosition)))
            {
                actorData.IsInCloseCombat = true;
            }
            else
            {
                actorData.IsInCloseCombat = false;
            }

            actorData.HasLittleSpace = _playerSpaceResolver.ResolveIfPlayerHasLittleSpace(actorData);

            int maxSwords = _maxSwordCalculator.Calculate(actorData);

            actorData.MaxSwords = maxSwords;
            if (actorData.Swords > maxSwords)
            {
                actorData.Swords = maxSwords;
            }

            if (actorData.Swords < maxSwords)
            {
                if (actorData.WeaponWeld.WeaponDefinition.RecoveryTime == RecoveryTime.ThreePerSeven)
                {
                    int roundNumber = actorData.RoundsCount % 21;
                    if (new[] { 0, 3, 5, 8, 10, 13, 15, 18, 20 }.Contains(roundNumber))
                    {
                        ++actorData.Swords;
                    }
                }
                else if (actorData.WeaponWeld.WeaponDefinition.RecoveryTime == RecoveryTime.OnePerTwo &&
                         actorData.RoundsCount % 2 == 0)
                {
                    ++actorData.Swords;
                }
                else if (actorData.WeaponWeld.WeaponDefinition.RecoveryTime == RecoveryTime.ThreePerFive)
                {
                    int roundNumber = actorData.RoundsCount % 15;
                    if (new[] { 0, 2, 5, 7, 10, 12 }.Contains(roundNumber))
                    {
                        ++actorData.Swords;
                    }
                }
            }

            if (actorData.Entity.transform.GetComponentInChildren <SwordsIndicator>() == null /*inactive*/)
            {
            }
            else
            {
                actorData.Entity.transform.GetComponentInChildren <SwordsIndicator>().UpdateActiveSwords(actorData.Swords);
                // kind of ugly workaround, but seems to help
            }

            if (actorData.ControlledByPlayer)
            {
                if (actorData.Xp >= _gameConfig.XpForLevels[actorData.Level + 1])
                {
                    ++actorData.Level;
                    _uiConfig.AdvanceManager.gameObject.SetActive(true);
                    GameObject.Find("PlayerLevelIndicator").GetComponent <Text>().text = "Player level: " + actorData.Level;
                }
            }
        }