private boolean canFaceDownBeShownTo(final PlayerView viewer) { if (!isFaceDown()) { return true; } if (viewer.hasKeyword("CanSeeOpponentsFaceDownCards")) { return true; } // special viewing permissions for viewer if (mayPlayerLook(viewer)) { return true; } // if viewer is controlled by another player, also check if face can be shown to that player final PlayerView mindSlaveMaster = viewer.getMindSlaveMaster(); if (mindSlaveMaster != null && canFaceDownBeShownTo(mindSlaveMaster)) { return true; } if (isInZone(EnumSet.of(ZoneType.Battlefield, ZoneType.Stack, ZoneType.Sideboard)) && getController().equals(viewer)) { return true; } if (getController().isOpponentOf(viewer) && getCurrentState().getOpponentMayLook()) { return true; } return false; }
@Override protected void drawOnContainer(Graphics g) { // draw target arrows immediately above stack for active item only if (activeItem != null) { Vector2 arrowOrigin = new Vector2( activeItem.getLeft() + VStack.CARD_WIDTH * FCardPanel.TARGET_ORIGIN_FACTOR_X + VStack.PADDING + VStack.BORDER_THICKNESS, activeItem.getTop() + VStack.CARD_HEIGHT * FCardPanel.TARGET_ORIGIN_FACTOR_Y + VStack.PADDING + VStack.BORDER_THICKNESS); PlayerView activator = activeStackInstance.getActivatingPlayer(); arrowOrigin = arrowOrigin.add(screenPos.x, screenPos.y); StackItemView instance = activeStackInstance; while (instance != null) { for (CardView c : instance.getTargetCards()) { TargetingOverlay.drawArrow(g, arrowOrigin, c, activator.isOpponentOf(c.getController())); } for (PlayerView p : instance.getTargetPlayers()) { TargetingOverlay.drawArrow(g, arrowOrigin, p, activator.isOpponentOf(p)); } instance = instance.getSubInstance(); } } }
private boolean canBeShownTo(final PlayerView viewer) { if (viewer == null) { return false; } ZoneType zone = getZone(); if (zone == null) { return true; } // cards outside any zone are visible to all final PlayerView controller = getController(); switch (zone) { case Ante: case Command: case Exile: case Battlefield: case Graveyard: case Flashback: case Stack: // cards in these zones are visible to all return true; case Hand: if (controller.hasKeyword("Play with your hand revealed.")) { return true; } // $FALL-THROUGH$ case Sideboard: // face-up cards in these zones are hidden to opponents unless they specify otherwise if (controller.isOpponentOf(viewer) && !getCurrentState().getOpponentMayLook()) { break; } return true; case Library: case PlanarDeck: // cards in these zones are hidden to all unless they specify otherwise if (viewer != null && viewer.equals(controller) && getCurrentState().getYouMayLook()) { return true; } if (controller.isOpponentOf(viewer) && getCurrentState().getOpponentMayLook()) { return true; } break; case SchemeDeck: // true for now, to actually see the Scheme cards (can't see deck anyway) return true; } // special viewing permissions for viewer if (mayPlayerLook(viewer)) { return true; } // if viewer is controlled by another player, also check if card can be shown to that player PlayerView mindSlaveMaster = controller.getMindSlaveMaster(); if (mindSlaveMaster != null && mindSlaveMaster == viewer) { return canBeShownTo(controller); } return false; }
public void showRewards() { view.getBtnRestart().setVisible(false); final QuestController qc = FModel.getQuest(); // After the first game, reset the card shop pool to be able to buy back anted cards if (lastGame.getNumPlayedGamesInMatch() == 0) { qc.getCards().clearShopList(); qc.getCards().getShopList(); } final LobbyPlayer questLobbyPlayer = GamePlayerUtil.getQuestPlayer(); PlayerView player = null; for (final PlayerView p : lastGame.getPlayers()) { if (p.isLobbyPlayer(questLobbyPlayer)) { player = p; } } final PlayerView questPlayer = player; final boolean matchIsNotOver = !lastGame.isMatchOver(); if (matchIsNotOver) { view.getBtnQuit().setText("Quit (-15 Credits)"); } else { view.getBtnContinue().setVisible(false); if (wonMatch) { view.getBtnQuit().setText("Great!"); } else { view.getBtnQuit().setText("OK"); } } // give controller a chance to run remaining logic on a separate thread view.showRewards( new Runnable() { @Override public void run() { if (isAnte) { // Won/lost cards should already be calculated (even in a draw) final GameOutcome.AnteResult anteResult = lastGame.getAnteResult(questPlayer); if (anteResult != null) { if (anteResult.wonCards != null) { qc.getCards().addAllCards(anteResult.wonCards); } if (anteResult.lostCards != null) { qc.getCards().loseCards(anteResult.lostCards); } anteReport(anteResult.wonCards, anteResult.lostCards); } } if (matchIsNotOver) { return; } // skip remaining logic if match isn't over yet // TODO: We don't have a enum for difficulty? final int difficulty = qData.getAchievements().getDifficulty(); final int wins = qData.getAchievements().getWin(); // Win case if (wonMatch) { // Standard event reward credits awardEventCredits(); // Challenge reward credits if (qEvent instanceof QuestEventChallenge) { awardChallengeWin(); } else { awardSpecialReward("Special bonus reward"); // If any // Random rare for winning against a very hard deck if (qEvent.getDifficulty() == QuestEventDifficulty.EXPERT) { awardRandomRare("You've won a random rare for winning against a very hard deck."); } } awardWinStreakBonus(); // Random rare given at 50% chance (65% with luck upgrade) if (getLuckyCoinResult()) { awardRandomRare("You've won a random rare."); } // Award jackpot every 80 games won (currently 10 rares) if ((wins > 0) && (((wins + 1) % 80) == 0)) { awardJackpot(); } } // Lose case else { penalizeLoss(); } // Grant booster on a win, or on a loss in easy mode if (wonMatch || difficulty == 0) { final int outcome = wonMatch ? wins : qData.getAchievements().getLost(); final int winsPerBooster = FModel.getQuestPreferences() .getPrefInt( DifficultyPrefs.WINS_BOOSTER, qData.getAchievements().getDifficulty()); if (winsPerBooster > 0 && (outcome + 1) % winsPerBooster == 0) { awardBooster(); } } } }); }
void updateTargetPlayers(SpellAbilityStackInstance si) { set( TrackableProperty.TargetPlayers, PlayerView.getCollection(si.getTargetChoices().getTargetPlayers())); }
void updateActivatingPlayer(SpellAbilityStackInstance si) { set(TrackableProperty.ActivatingPlayer, PlayerView.get(si.getActivatingPlayer())); }
@Override public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); final Player player = sa.getActivatingPlayer(); final Game game = player.getGame(); Player chooser = player; int numToDig = AbilityUtils.calculateAmount(host, sa.getParam("DigNum"), sa); final ZoneType srcZone = sa.hasParam("SourceZone") ? ZoneType.smartValueOf(sa.getParam("SourceZone")) : ZoneType.Library; final ZoneType destZone1 = sa.hasParam("DestinationZone") ? ZoneType.smartValueOf(sa.getParam("DestinationZone")) : ZoneType.Hand; final ZoneType destZone2 = sa.hasParam("DestinationZone2") ? ZoneType.smartValueOf(sa.getParam("DestinationZone2")) : ZoneType.Library; int libraryPosition = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : -1; int destZone1ChangeNum = 1; final boolean mitosis = sa.hasParam("Mitosis"); String changeValid = sa.hasParam("ChangeValid") ? sa.getParam("ChangeValid") : ""; // andOrValid is for cards with "creature card and/or a land card" String andOrValid = sa.hasParam("AndOrValid") ? sa.getParam("AndOrValid") : ""; final boolean anyNumber = sa.hasParam("AnyNumber"); final int libraryPosition2 = sa.hasParam("LibraryPosition2") ? Integer.parseInt(sa.getParam("LibraryPosition2")) : -1; final boolean optional = sa.hasParam("Optional"); final boolean noMove = sa.hasParam("NoMove"); final boolean skipReorder = sa.hasParam("SkipReorder"); // A hack for cards like Explorer's Scope that need to ensure that a card is revealed to the // player activating the ability final boolean forceRevealToController = sa.hasParam("ForceRevealToController"); // These parameters are used to indicate that a dialog box must be show to the player asking if // the player wants to proceed // with an optional ability, otherwise the optional ability is skipped. final boolean mayBeSkipped = sa.hasParam("PromptToSkipOptionalAbility"); final String optionalAbilityPrompt = sa.hasParam("OptionalAbilityPrompt") ? sa.getParam("OptionalAbilityPrompt") : ""; boolean changeAll = false; boolean allButOne = false; final List<String> keywords = new ArrayList<String>(); if (sa.hasParam("Keywords")) { keywords.addAll(Arrays.asList(sa.getParam("Keywords").split(" & "))); } if (sa.hasParam("ChangeNum")) { if (sa.getParam("ChangeNum").equalsIgnoreCase("All")) { changeAll = true; } else if (sa.getParam("ChangeNum").equalsIgnoreCase("AllButOne")) { allButOne = true; } else { destZone1ChangeNum = AbilityUtils.calculateAmount(host, sa.getParam("ChangeNum"), sa); } } final TargetRestrictions tgt = sa.getTargetRestrictions(); final List<Player> tgtPlayers = getTargetPlayers(sa); if (sa.hasParam("Choser")) { final List<Player> choosers = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Choser"), sa); if (!choosers.isEmpty()) { chooser = choosers.get(0); } } for (final Player p : tgtPlayers) { if (tgt != null && !p.canBeTargetedBy(sa)) { continue; } final CardCollection top = new CardCollection(); final CardCollection rest = new CardCollection(); final PlayerZone sourceZone = p.getZone(srcZone); numToDig = Math.min(numToDig, sourceZone.size()); for (int i = 0; i < numToDig; i++) { top.add(sourceZone.get(i)); } if (!top.isEmpty()) { DelayedReveal delayedReveal = null; boolean hasRevealed = true; if (sa.hasParam("Reveal")) { game.getAction().reveal(top, p, false); } else if (sa.hasParam("RevealOptional")) { String question = "Reveal: " + Lang.joinHomogenous(top) + "?"; hasRevealed = p.getController().confirmAction(sa, null, question); if (hasRevealed) { game.getAction().reveal(top, p); } } else if (sa.hasParam("RevealValid")) { final String revealValid = sa.getParam("RevealValid"); final CardCollection toReveal = CardLists.getValidCards(top, revealValid, host.getController(), host); if (!toReveal.isEmpty()) { game.getAction().reveal(toReveal, host.getController()); if (sa.hasParam("RememberRevealed")) { for (final Card one : toReveal) { host.addRemembered(one); } } } // Singletons.getModel().getGameAction().revealToCopmuter(top.toArray()); // - for when it exists } else if (!sa.hasParam("NoLooking")) { // show the user the revealed cards delayedReveal = new DelayedReveal(top, srcZone, PlayerView.get(p)); if (noMove) { // Let the activating player see the cards even if they're not moved game.getAction().revealTo(top, player); } } if (sa.hasParam("RememberRevealed") && !sa.hasParam("RevealValid") && hasRevealed) { for (final Card one : top) { host.addRemembered(one); } } if (!noMove) { CardCollection movedCards; CardCollection andOrCards; for (final Card c : top) { rest.add(c); } CardCollection valid; if (mitosis) { valid = sharesNameWithCardOnBattlefield(game, top); andOrCards = new CardCollection(); } else if (!changeValid.isEmpty()) { if (changeValid.contains("ChosenType")) { changeValid = changeValid.replace("ChosenType", host.getChosenType()); } valid = CardLists.getValidCards(top, changeValid.split(","), host.getController(), host); if (!andOrValid.equals("")) { andOrCards = CardLists.getValidCards(top, andOrValid.split(","), host.getController(), host); andOrCards.removeAll((Collection<?>) valid); valid.addAll(andOrCards); } else { andOrCards = new CardCollection(); } } else { valid = top; andOrCards = new CardCollection(); } if (forceRevealToController) { // Force revealing the card to the player activating the ability (e.g. Explorer's Scope) game.getAction().revealTo(top, player); } // Optional abilities that use a dialog box to prompt the user to skip the ability (e.g. // Explorer's Scope, Quest for Ula's Temple) if (optional && mayBeSkipped && !valid.isEmpty()) { String prompt = !optionalAbilityPrompt.isEmpty() ? optionalAbilityPrompt : "Would you like to proceed with the optional ability for " + sa.getHostCard() + "?\n\n(" + sa.getDescription() + ")"; if (!p.getController() .confirmAction(sa, null, prompt.replace("CARDNAME", sa.getHostCard().getName()))) { return; } } if (changeAll) { movedCards = new CardCollection(valid); } else if (sa.hasParam("RandomChange")) { int numChanging = Math.min(destZone1ChangeNum, valid.size()); movedCards = CardLists.getRandomSubList(valid, numChanging); } else if (allButOne) { movedCards = new CardCollection(valid); String prompt; if (destZone2.equals(ZoneType.Library) && libraryPosition2 == 0) { prompt = "Choose a card to leave on top of {player's} library"; } else { prompt = "Choose a card to leave in {player's} " + destZone2.name(); } Card chosen = chooser .getController() .chooseSingleEntityForEffect(valid, delayedReveal, sa, prompt, false, p); movedCards.remove(chosen); if (sa.hasParam("RandomOrder")) { CardLists.shuffle(movedCards); } } else { int j = 0; String prompt; if (sa.hasParam("PrimaryPrompt")) { prompt = sa.getParam("PrimaryPrompt"); } else { prompt = "Choose a card to put into " + destZone1.name(); if (destZone1.equals(ZoneType.Library)) { if (libraryPosition == -1) { prompt = "Choose a card to put on the bottom of {player's} library"; } else if (libraryPosition == 0) { prompt = "Choose a card to put on top of {player's} library"; } } } movedCards = new CardCollection(); while (j < destZone1ChangeNum || (anyNumber && j < numToDig)) { // let user get choice Card chosen = null; if (!valid.isEmpty()) { chosen = chooser .getController() .chooseSingleEntityForEffect( valid, delayedReveal, sa, prompt, anyNumber || optional, p); } else { chooser.getController().notifyOfValue(sa, null, "No valid cards"); } if (chosen == null) { break; } movedCards.add(chosen); valid.remove(chosen); if (!andOrValid.equals("")) { andOrCards.remove(chosen); if (!chosen.isValid(andOrValid.split(","), host.getController(), host)) { valid = new CardCollection(andOrCards); } else if (!chosen.isValid(changeValid.split(","), host.getController(), host)) { valid.removeAll((Collection<?>) andOrCards); } } j++; } if (!changeValid.isEmpty()) { game.getAction() .reveal( movedCards, chooser, true, chooser + " picked " + (movedCards.size() == 1 ? "this card" : "these cards") + " from "); } } if (sa.hasParam("ForgetOtherRemembered")) { host.clearRemembered(); } Collections.reverse(movedCards); for (Card c : movedCards) { final PlayerZone zone = c.getOwner().getZone(destZone1); if (zone.is(ZoneType.Library) || zone.is(ZoneType.PlanarDeck) || zone.is(ZoneType.SchemeDeck)) { if (libraryPosition == -1 || libraryPosition > zone.size()) { libraryPosition = zone.size(); } c = game.getAction().moveTo(zone, c, libraryPosition); } else { c = game.getAction().moveTo(zone, c); if (destZone1.equals(ZoneType.Battlefield)) { for (final String kw : keywords) { c.addExtrinsicKeyword(kw); } if (sa.hasParam("Tapped")) { c.setTapped(true); } } } if (sa.hasParam("ExileFaceDown")) { c.setState(CardStateName.FaceDown, true); } if (sa.hasParam("Imprint")) { host.addImprintedCard(c); } if (sa.hasParam("ForgetOtherRemembered")) { host.clearRemembered(); } if (sa.hasParam("RememberChanged")) { host.addRemembered(c); } rest.remove(c); } // now, move the rest to destZone2 if (destZone2 == ZoneType.Library || destZone2 == ZoneType.PlanarDeck || destZone2 == ZoneType.SchemeDeck) { CardCollection afterOrder = rest; if (sa.hasParam("RestRandomOrder")) { CardLists.shuffle(afterOrder); } else if (!skipReorder && rest.size() > 1) { afterOrder = (CardCollection) chooser.getController().orderMoveToZoneList(rest, destZone2); } if (libraryPosition2 != -1) { // Closest to top Collections.reverse(afterOrder); } for (final Card c : afterOrder) { if (destZone2 == ZoneType.Library) { game.getAction().moveToLibrary(c, libraryPosition2); } else { game.getAction().moveToVariantDeck(c, destZone2, libraryPosition2); } } } else { // just move them randomly for (int i = 0; i < rest.size(); i++) { Card c = rest.get(i); final PlayerZone toZone = c.getOwner().getZone(destZone2); c = game.getAction().moveTo(toZone, c); if (destZone2.equals(ZoneType.Battlefield) && !keywords.isEmpty()) { for (final String kw : keywords) { c.addExtrinsicKeyword(kw); } } } } } } } }
void updateChosenPlayer(Card c) { set(TrackableProperty.ChosenPlayer, PlayerView.get(c.getChosenPlayer())); }
void updateController(Card c) { set(TrackableProperty.Controller, PlayerView.get(c.getController())); }
void updateOwner(Card c) { set(TrackableProperty.Owner, PlayerView.get(c.getOwner())); }