private Vector2Int GetPositionToPlaceItem(Vector2Int position) { if (_entityDetector.DetectItems(position).Any()) { 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.DetectItems(neighbour).Any()) { position = neighbour; break; } } } return(position); }
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); } } } }
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); } }
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); }