/// <summary> /// Handle moving the current selection to the foundation pile. /// </summary> private void HandleMoveToFoundationPile() { // If we double click on a card, try to put it on the foundation pile. if (DoubleClickHelper.HasDoubleClicked(MouseButton.Left) && foundationPiles.Any(pile => TryMoveCard(pile, true))) { CurrentSelection = null; } }
/// <summary> /// Attempts to move a card onto the <paramref name="pile"/>. /// </summary> /// <param name="pile">The <see cref="CardPile"/> to move the current selection to.</param> /// <param name="ignoreMousePosition">Ignores whether the mouse is over the <paramref name="pile"/>.</param> private bool TryMoveCard(CardPile pile, bool ignoreMousePosition) { if (CurrentSelection == null || !pile.Contains(Input.MousePosition) && !ignoreMousePosition) { return(false); } // If we are trying to move a card from the tableau pile to // another pile, we need to make sure that it is the top card // that we are trying to move. if (CurrentSelection.CardPile is TableauPile && CurrentSelection.Card != CurrentSelection.CardPile.Peek()) { return(false); } if (!pile.CanPush(CurrentSelection.Card)) { return(false); } // If we can move the card onto the pile, move it and clear the selection Card card = CurrentSelection.CardPile.Pop(); LerpInformation <Vector2> animationLerp = new LerpInformation <Vector2>(card.Rectangle.GetValueOrDefault().Position, pile.GetCardRectangle(card).Position, 0.15f, Vector2.Lerp); CardMovementAnimation cardMovementAnimation = new CardMovementAnimation(card, animationLerp, pile); cardMovementAnimations.Add(cardMovementAnimation); CurrentSelection = null; if (pile is FoundationPile) { foundationPileAddSoundEffect.Play(); } return(true); }
/// <summary> /// Handle card movement among tableau piles. /// </summary> private bool HandleTableuPileCardMovement() { // If we are moving from tableau pile to tableau pile, treat all movements as // moving a portion onto another tableau pile; otherwise, move the top card of the // selected pile to the tableau pile. if (CurrentSelection?.CardPile is TableauPile selectedTableauPile) { if (selectedTableauPile.SelectedPortion == null) { // If our selection portion is null despite the fact that // this tableau pile is selected, something has gone terribly // wrong so we should log this occurence. Logger.LogFunctionEntry(string.Empty, "NULL portion in selected tableau pile!", LoggerVerbosity.Warning); return(false); } int maximumPortionLength = freeCells.Count(freeCell => freeCell.Empty) + 1; foreach (TableauPile tableauPile in tableauPiles) { if (!tableauPile.Contains(Input.MousePosition) || tableauPile == selectedTableauPile) { continue; } // If we have more cards than we can move, take the most that we can. int transferAmount = Math.Min(selectedTableauPile.SelectedPortion.Count, maximumPortionLength); bool canTransfer = false; // Check whether a part of the portion pile can be moved // For example, suppose that the portion consisted of 4 and 3 and // the user tried to move the pile onto a pile with a top card of 4. // The intended result is that only the 3 is moved. for (int i = selectedTableauPile.Count - transferAmount; i < selectedTableauPile.Count; i++) { if (!tableauPile.CanPush(selectedTableauPile[i])) { continue; } // Recalculate the transfer amount (subtract by the amount of times we traversed down the pile). transferAmount = selectedTableauPile.Count - i; canTransfer = true; break; } if (!canTransfer) { return(false); } // A temporary "stack" buffer to store the cards as we pop them from the tableau pile Card[] buffer = new Card[transferAmount]; for (int i = 0; i < transferAmount; i++) { buffer[i] = selectedTableauPile.Pop(); } // Push the cards onto the new tableau pile. for (int i = transferAmount - 1; i >= 0; i--) { tableauPile.Push(buffer[i]); } CurrentSelection = null; return(true); } } else { return(tableauPiles.Any(TryMoveCard)); } return(false); }
/// <summary> /// Handle the card selection input. /// </summary> private void HandleCardSelection() { if (!Input.GetMouseButtonDown(MouseButton.Left)) { return; } // A card is a "middle tableau" if it is not the top card. bool isMiddleTableauCardSelected = false; bool isMiddleTableauPortionSelected = false; TableauPile selectedTableauPile = null; if (CurrentSelection?.CardPile is TableauPile) { selectedTableauPile = (TableauPile)CurrentSelection.CardPile; isMiddleTableauCardSelected = CurrentSelection.Card != CurrentSelection.CardPile.Peek(); isMiddleTableauPortionSelected = selectedTableauPile.SelectedPortion.Contains(CurrentSelection.Card) && !selectedTableauPile.SelectedPortion.Contains(selectedTableauPile.Peek()); } // Check if we clicked on a card in a tableau pile foreach (TableauPile tableauPile in tableauPiles) { Card card = tableauPile.GetCardFromPoint(Input.MousePosition); // If the card is null, we didn't click on this tableau pile. if (card == null) { continue; } bool selectedPortionCard = false; if (selectedTableauPile != null) { selectedPortionCard = selectedTableauPile.SelectedPortion.Contains(card); } // If we have a "middle tableau" card selected and we clicked on it again, let's deselect it. // OR if our "middle" tableau card is in a portion and we select another card in that portion // (i.e. we treat portions in the middle of a tableau pile as one card in terms of selection). if (isMiddleTableauCardSelected && card == CurrentSelection.Card || isMiddleTableauPortionSelected && selectedPortionCard) { CurrentSelection = null; return; } // If we were previously selecting a tableau pile, cache it so we can update it. TableauPile oldTableauPile = null; if (CurrentSelection?.CardPile is TableauPile pile) { oldTableauPile = pile; } // Store our previous selection state so we can play the correct sound effect. CardSelectionInformation previousSelection = CurrentSelection; CurrentSelection = new CardSelectionInformation(card, tableauPile); oldTableauPile?.UpdateSelection(tableauPile == oldTableauPile); tableauPile.UpdateSelection(true); // Play the primary sound effect if we selected the top card AND if this is our first card selection if (tableauPile.Peek() == card && previousSelection == null) { cardSelectPrimarySoundEffect.Play(); } else { cardSelectSecondarySoundEffect.Play(); } return; } // Check if we clicked on a free cell foreach (FreeCell freeCell in freeCells) { if (!freeCell.Contains(Input.MousePosition)) { continue; } // Store our previous selection state so we can play the correct sound effect. CardSelectionInformation previousSelection = CurrentSelection; // If we have selected a non-top card in a tableau pile, clicking on an empty free cell shouldn't change the selection. if (isMiddleTableauCardSelected && freeCell.Empty) { return; } if (freeCell.Empty) { return; } CurrentSelection = new CardSelectionInformation(freeCell.Value, freeCell); // Play if this is our first card selection if (previousSelection == null) { cardSelectPrimarySoundEffect.Play(); } else { cardSelectSecondarySoundEffect.Play(); } return; } // If we have selected a non-top card in a tableau pile, clicking on a foundation pile shouldn't change the selection. bool isSelectingFoundationPile = foundationPiles.Any(foundationPile => foundationPile.Contains(Input.MousePosition)); if (isSelectingFoundationPile && isMiddleTableauCardSelected) { return; } // At this point, we are just clicking on an empty space. CurrentSelection = null; selectedTableauPile?.UpdateSelection(false); }