private async Task Tap(GestureSample gesture) { // try to get a card under the tap first var selectedCardIndex = handOfCards.GetCardIndexAtPosition(gesture.Position); if (selectedCardIndex != -1) { // SELECT CARD if (CanSelectCardFromSelectedCharacter) { selectedCard = selectedCharacter.CurrentHand.ElementAt(selectedCardIndex); } return; } var worldPoint = camera.ScreenToWorld(gesture.Position); var mapPoint = MapPoint.GetFromScreenPosition(worldPoint); var targetCharacter = data.Characters.SingleOrDefault(character => character.IsAtPoint(mapPoint)); var targetEntity = entities.Drawables.SingleOrDefault(entity => entity.IsAtPoint(mapPoint)); if (selectedCharacter == null) { // SELECT CHARACTER // we don't have a character selected, so select whatever we have under the tap selectedCharacter = targetCharacter; SelectedCharacterChange?.Invoke(selectedCharacter); } else if (selectedCard != null && targetCharacter != null && selectedCard.IsWithinRangeDistance(mapPoint) && mapPoint.IsWithinMap && (lockedInCharacter == selectedCard.OwnerCharacter || lockedInCharacter == null) && targetingPoint == null && IsMyTurn) { // TRYING TO TARGET A CARD targetingPoint = mapPoint; } else if (targetingPoint?.Equals(mapPoint) == true && IsMyTurn) { // ACTUALLY PLAY SELECTED CARD var playStatus = selectedCharacter.PlayCard(selectedCard, targetCharacter, data.RoundNumber); if (!playStatus.PlayCancelled) { if (targetCharacter.GetBaseAbilityScore(AbilityScore.Health) < 1) { data.Characters.Remove(targetCharacter); await CheckForWin(); } AddNewGameLogEntry(new GameLogEntry { SourceCharacterColour = selectedCharacter.Colour, SourceCharacterSide = data.Sides[selectedCharacter.OwnerPlayerId], TargetCharacterColour = targetCharacter.Colour, TargetCharacterSide = data.Sides[targetCharacter.OwnerPlayerId], CardId = selectedCard.Id }); lockedInCharacter = selectedCard.OwnerCharacter; selectedCard = null; targetingPoint = null; } var statusText = GetStatusTextForPlay(playStatus); if (statusText != null) { statusPanel.Show(statusText); } } else if (selectedCard != null) { // DESELECTED CARD // we have a character selected and a card selected but the card isn't in range of the desired target, or there is no target selectedCard = null; targetingPoint = null; } else if (selectedCharacter.IsWithinMoveDistanceOf(mapPoint) && mapPoint.IsWithinMap && mapPoint.IsInAvailableMovement && CanMoveSelectedCharacter && targetEntity == null && movingPoint == null) { // TRYING TO MOVE // we have a character selected, it's my character, it is within move distance of the tap and it has moves remaining movingPoint = mapPoint; } else if (movingPoint?.Equals(mapPoint) == true) { // ACTUALLY MOVING selectedCharacter.Move(mapPoint); lockedInCharacter = selectedCharacter; movingPoint = null; AddNewGameLogEntry(new GameLogEntry { SourceCharacterColour = selectedCharacter.Colour, SourceCharacterSide = data.Sides[selectedCharacter.OwnerPlayerId], MovedTo = mapPoint }); } else { // DESELECT CHARACTER AND CARD // we have a character selected, but didn't tap anything else useful so unselect it selectedCharacter = null; selectedCard = null; movingPoint = null; targetingPoint = null; handOfCards.ClearCardPositions(); } }