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); }
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!!!"); } } }
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); } }
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; } }
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)); }
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); }
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); } }
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); }
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; } }
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); } } } }
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)); }