@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); UUID exileId = CardUtil.getExileZoneId( game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (permanent != null) { return controller.moveCardToExileWithInfo( permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); } else { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { return controller.moveCardToExileWithInfo( card, exileId, sourceObject.getIdName(), source.getSourceId(), game, game.getState().getZone(card.getId()), true); } } } return false; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { Choice choice = new ChoiceImpl(true); choice.setMessage("Choose a creature type:"); choice.setChoices(CardRepository.instance.getCreatureTypes()); while (!controller.choose(Outcome.BoostCreature, choice, game)) { if (!controller.canRespond()) { return false; } } Cards revealedCards = new CardsImpl(); while (controller.getLibrary().size() > 0) { Card card = controller.getLibrary().removeFromTop(game); if (card.getCardType().contains(CardType.CREATURE) && card.getSubtype().contains(choice.getChoice())) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); break; } revealedCards.add(card); } controller.revealCards(sourceObject.getIdName(), revealedCards, game); controller.moveCards(revealedCards, Zone.LIBRARY, source, game); controller.shuffleLibrary(source, game); return true; } return false; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && controller != null) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard( new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard")); if (controller.chooseTarget(outcome, target, source, game)) { UUID exileId = CardUtil.getExileZoneId( game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { controller.moveCardToExileWithInfo( card, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true); } } return true; } return false; }
@Override public boolean pay( Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); MageObject sourceObject = ability.getSourceObject(game); if (controller != null && sourceObject != null) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { UUID exileId = CardUtil.getExileZoneId( game, ability.getSourceId(), ability.getSourceObjectZoneChangeCounter()); for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { return false; } paid |= controller.moveCardToExileWithInfo( permanent, exileId, sourceObject.getIdName() + " championed permanents", sourceId, game, Zone.BATTLEFIELD, true); } } } return paid; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { controller.shuffleLibrary(source, game); if (controller.getLibrary().size() > 0) { Card card = controller.getLibrary().removeFromTop(game); if (card != null) { controller.moveCardToExileWithInfo( card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); ContinuousEffect effect = new MindsDesireCastFromExileEffect(); effect.setTargetPointer(new FixedTarget(card.getId())); game.addEffect(effect, source); } } return true; } return false; }
@Override public boolean apply(Game game, Ability source) { Cards cardsToCast = new CardsImpl(); Player targetOpponent = game.getPlayer(targetPointer.getFirst(game, source)); MageObject sourceObject = source.getSourceObject(game); if (targetOpponent != null && sourceObject != null) { List<Card> allCards = targetOpponent.getLibrary().getTopCards(game, 7); Cards cards = new CardsImpl(Zone.LIBRARY, allCards); targetOpponent.revealCards( sourceObject.getIdName() + " - " + targetOpponent.getName() + "'s top library cards", cards, game); for (Card card : allCards) { if (filter.match(card, game)) { cardsToCast.add(card); } } // cast an instant or sorcery for free if (cardsToCast.size() > 0) { int numberOfSpells = 1; if (SpellMasteryCondition.getInstance().apply(game, source)) { numberOfSpells++; } Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { TargetCard target = new TargetCard(Zone.LIBRARY, filter); // zone should be ignored here target.setNotTarget(true); while (numberOfSpells > 0 && cardsToCast.size() > 0 && controller.chooseUse( outcome, "Cast an instant or sorcery card from among them for free?", source, game) && controller.choose(outcome, cardsToCast, target, game)) { Card card = cardsToCast.get(target.getFirstTarget(), game); if (card != null) { controller.cast(card.getSpellAbility(), game, true); numberOfSpells--; cardsToCast.remove(card); allCards.remove(card); } if (!controller.isInGame()) { return false; } target.clearChosen(); } } targetOpponent.moveCards(allCards, Zone.LIBRARY, Zone.GRAVEYARD, source, game); } return true; } return false; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { if (controller.getLibrary().size() > 0) { Card card = controller.getLibrary().getFromTop(game); if (card == null) { return false; } controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); if (card.getCardType().contains(CardType.CREATURE)) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); boolean found = false; for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { if (CardUtil.shareSubtypes(card, permanent, game)) { found = true; break; } } if (found) { game.informPlayers( sourceObject.getLogName() + ": Found a creature that shares a creature type with the revealed card."); if (controller.chooseUse(Outcome.Benefit, "Cast the card?", source, game)) { controller.cast(card.getSpellAbility(), game, true); } else { game.informPlayers( sourceObject.getLogName() + ": " + controller.getLogName() + " canceled casting the card."); controller.getLibrary().putOnBottom(card, game); } } else { game.informPlayers( sourceObject.getLogName() + ": No creature that shares a creature type with the revealed card."); controller.getLibrary().putOnBottom(card, game); } } else { game.informPlayers( sourceObject.getLogName() + ": Put " + card.getLogName() + " on the bottom."); controller.getLibrary().putOnBottom(card, game); } return true; } } return false; }
@Override public boolean apply(Game game, Ability source) { UUID exileId = source.getSourceId(); Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && exileId != null && targetPermanent != null && controller != null) { if (targetPermanent.getName().isEmpty()) { // face down creature controller.moveCardToExileWithInfo( targetPermanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); } else { String name = targetPermanent.getName(); for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { if (permanent != null && permanent.getName().equals(name)) { controller.moveCardToExileWithInfo( permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); } } } return true; } return false; }
@Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { Card card = game.getCard(event.getTargetId()); if (card != null) { Cards cards = new CardsImpl(card); controller.revealCards(sourceObject.getIdName(), cards, game); controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; } } return false; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { if (controller.chooseUse(Outcome.Benefit, choiceText, source, game)) { Set<Card> sideboard = controller.getSideboard().getCards(filter, game); List<Card> exile = game.getExile().getAllCards(game); Cards filteredCards = new CardsImpl(); Card card = null; for (Card sideboardCard : sideboard) { filteredCards.add(sideboardCard.getId()); } for (Card exileCard : exile) { if (exileCard.getOwnerId().equals(source.getControllerId()) && exileCard.hasSubtype("Eldrazi")) { filteredCards.add(exileCard); } } if (filteredCards.isEmpty()) { game.informPlayer( controller, "You have no " + filter.getMessage() + " outside the game (your sideboard) or in exile."); } else { TargetCard target = new TargetCard(Zone.OUTSIDE, filter); target.setNotTarget(true); if (controller.choose(outcome, filteredCards, target, game)) { card = controller.getSideboard().get(target.getFirstTarget(), game); if (card == null) { card = game.getCard(target.getFirstTarget()); } } } if (card != null) { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); } } return true; } return false; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { int flipsWon = 0; boolean controllerStopped = false; while (controller.flipCoin(game)) { ++flipsWon; if (!controller.chooseUse( outcome, new StringBuilder("You won ") .append(flipsWon) .append(flipsWon == 1 ? " flip." : " flips.") .append(" Flip another coin?") .toString(), source, game)) { controllerStopped = true; break; } } if (controllerStopped) { Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (creature != null) { creature.damage(3, source.getSourceId(), game, false, true); } if (flipsWon > 1) { new DamagePlayersEffect(6, TargetController.OPPONENT).apply(game, source); } if (flipsWon > 2) { controller.drawCards(9, game); new UntapAllLandsControllerEffect().apply(game, source); } } else { game.informPlayers(sourceObject.getIdName() + " had no effect"); } return true; } return false; }
@Override public boolean activate(Game game, boolean noMana) { Player controller = game.getPlayer(this.getControllerId()); if (controller == null) { return false; } game.applyEffects(); /* 20130201 - 601.2b * If the spell is modal the player announces the mode choice (see rule 700.2). */ if (!getModes().choose(game, this)) { return false; } if (controller.isTestMode()) { if (!controller.addTargets(this, game)) { return false; } } getSourceObject(game); /* 20130201 - 601.2b * If the player wishes to splice any cards onto the spell (see rule 702.45), he * or she reveals those cards in his or her hand. */ if (this.abilityType.equals(AbilityType.SPELL)) { game.getContinuousEffects().applySpliceEffects(this, game); } // if ability can be cast for no mana, clear the mana costs now, because additional mana costs // must be paid. // For Flashback ability can be set X before, so the X costs have to be restored for the // flashbacked ability if (noMana) { if (this.getManaCostsToPay().getVariableCosts().size() > 0) { int xValue = this.getManaCostsToPay().getX(); this.getManaCostsToPay().clear(); VariableManaCost xCosts = new VariableManaCost(); xCosts.setAmount(xValue); this.getManaCostsToPay().add(xCosts); } else { this.getManaCostsToPay().clear(); } } // 20130201 - 601.2b // If the spell has alternative or additional costs that will be paid as it's being cast such // as buyback, kicker, or convoke costs (see rules 117.8 and 117.9), the player announces his // or her intentions to pay any or all of those costs (see rule 601.2e). // A player can't apply two alternative methods of casting or two alternative costs to a single // spell. if (!activateAlternateOrAdditionalCosts(sourceObject, noMana, controller, game)) { if (getAbilityType().equals(AbilityType.SPELL) && ((SpellAbility) this) .getSpellAbilityType() .equals(SpellAbilityType.FACE_DOWN_CREATURE)) { return false; } } // 20121001 - 601.2b // If the spell has a variable cost that will be paid as it's being cast (such as an {X} in // its mana cost; see rule 107.3), the player announces the value of that variable. VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller); String announceString = handleOtherXCosts(game, controller); // For effects from cards like Void Winnower x costs have to be set if (this.getAbilityType().equals(AbilityType.SPELL) && game.replaceEvent( GameEvent.getEvent( GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()), this)) { return false; } for (Mode mode : this.getModes().getSelectedModes()) { this.getModes().setActiveMode(mode); // 20121001 - 601.2c // 601.2c The player announces his or her choice of an appropriate player, object, or zone for // each target the spell requires. A spell may require some targets only if an alternative or // additional cost (such as a buyback or kicker cost), or a particular mode, was chosen for // it; // otherwise, the spell is cast as though it did not require those targets. If the spell has a // variable number of targets, the player announces how many targets he or she will choose // before // he or she announces those targets. The same target can't be chosen multiple times for any // one // instance of the word "target" on the spell. However, if the spell uses the word "target" in // multiple places, the same object, player, or zone can be chosen once for each instance of // the // word "target" (as long as it fits the targeting criteria). If any effects say that an // object // or player must be chosen as a target, the player chooses targets so that he or she obeys // the // maximum possible number of such effects without violating any rules or effects that say // that // an object or player can't be chosen as a target. The chosen players, objects, and/or zones // each become a target of that spell. (Any abilities that trigger when those players, // objects, // and/or zones become the target of a spell trigger at this point; they'll wait to be put on // the stack until the spell has finished being cast.) if (sourceObject != null && !this.getAbilityType() .equals(AbilityType.TRIGGERED)) { // triggered abilities check this already in // playerImpl.triggerAbility sourceObject.adjustTargets(this, game); } if (mode.getTargets().size() > 0 && mode.getTargets() .chooseTargets( getEffects().get(0).getOutcome(), this.controllerId, this, noMana, game) == false) { if ((variableManaCost != null || announceString != null) && !game.isSimulation()) { game.informPlayer( controller, (sourceObject != null ? sourceObject.getIdName() : "") + ": no valid targets with this value of X"); } return false; // when activation of ability is canceled during target selection } } // end modes // TODO: Handle optionalCosts at the same time as already OptionalAdditionalSourceCosts are // handled. for (Cost cost : optionalCosts) { if (cost instanceof ManaCost) { cost.clearPaid(); if (controller.chooseUse( Outcome.Benefit, "Pay optional cost " + cost.getText() + "?", this, game)) { manaCostsToPay.add((ManaCost) cost); } } } // 20100716 - 601.2e if (sourceObject != null) { sourceObject.adjustCosts(this, game); if (sourceObject instanceof Card) { for (Ability ability : ((Card) sourceObject).getAbilities(game)) { if (ability instanceof AdjustingSourceCosts) { ((AdjustingSourceCosts) ability).adjustCosts(this, game); } } } else { for (Ability ability : sourceObject.getAbilities()) { if (ability instanceof AdjustingSourceCosts) { ((AdjustingSourceCosts) ability).adjustCosts(this, game); } } } } // this is a hack to prevent mana abilities with mana costs from causing endless loops - pay // other costs first if (this instanceof ManaAbility && !costs.pay(this, game, sourceId, controllerId, noMana, null)) { logger.debug("activate mana ability failed - non mana costs"); return false; } // 20101001 - 601.2e if (costModificationActive) { game.getContinuousEffects().costModification(this, game); } else { costModificationActive = true; } UUID activatorId = controllerId; if ((this instanceof ActivatedAbilityImpl) && ((ActivatedAbilityImpl) this).getActivatorId() != null) { activatorId = ((ActivatedAbilityImpl) this).getActivatorId(); } // 20100716 - 601.2f (noMana is not used here, because mana costs were cleared for this ability // before adding additional costs and applying cost modification effects) if (!manaCostsToPay.pay(this, game, sourceId, activatorId, false, null)) { return false; // cancel during mana payment } // 20100716 - 601.2g if (!costs.pay(this, game, sourceId, activatorId, noMana, null)) { logger.debug("activate failed - non mana costs"); return false; } if (!game.isSimulation()) { // inform about x costs now, so canceled announcements are not shown in the log if (announceString != null) { game.informPlayers(announceString); } if (variableManaCost != null) { int xValue = getManaCostsToPay().getX(); game.informPlayers( controller.getLogName() + " announces a value of " + xValue + " for " + variableManaCost.getText()); } } activated = true; // fire if tapped for mana (may only fire now because else costs of ability itself can be payed // with mana of abilities that trigger for that event if (this.getAbilityType().equals(AbilityType.MANA)) { for (Cost cost : costs) { if (cost instanceof TapSourceCost) { Mana mana = null; Effect effect = getEffects().get(0); if (effect instanceof DynamicManaEffect) { mana = ((DynamicManaEffect) effect).getMana(game, this); } else if (effect instanceof BasicManaEffect) { mana = ((BasicManaEffect) effect).getMana(game, this); } if (mana != null && mana.getAny() == 0) { // if mana == null or Any > 0 the event has to be fired in the mana effect // to know which mana was produced ManaEvent event = new ManaEvent( GameEvent.EventType.TAPPED_FOR_MANA, sourceId, sourceId, controllerId, mana); if (!game.replaceEvent(event)) { game.fireEvent(event); } } break; } } } return true; }
@Override public boolean apply(Game game, Ability source) { MageObject sourceObject = source.getSourceObject(game); if (sourceObject == null) { return false; } Map<UUID, Set<Card>> permanentsOwned = new HashMap<>(); Collection<Permanent> permanents = game.getBattlefield().getAllActivePermanents(); for (Permanent permanent : permanents) { Set<Card> set = permanentsOwned.get(permanent.getOwnerId()); if (set == null) { set = new LinkedHashSet<>(); } set.add(permanent); permanentsOwned.put(permanent.getOwnerId(), set); } // shuffle permanents into owner's library Map<UUID, Integer> permanentsCount = new HashMap<>(); for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { Set<Card> set = permanentsOwned.remove(playerId); Integer count = 0; if (set != null) { count = set.size(); player.moveCards(set, Zone.BATTLEFIELD, Zone.LIBRARY, source, game); } if (count > 0) { player.shuffleLibrary(game); } permanentsCount.put(playerId, count); } } game.applyEffects(); // so effects from creatures that were on the battlefield won't trigger // from draw or later put into play Map<UUID, CardsImpl> cardsRevealed = new HashMap<>(); // draw cards and reveal them for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { Integer count = Math.min(permanentsCount.get(player.getId()), player.getLibrary().size()); CardsImpl cards = new CardsImpl(); for (int i = 0; i < count; i++) { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); } } player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ")", cards, game); cardsRevealed.put(player.getId(), cards); } } // put artifacts, creaturs and lands onto the battlefield for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { CardsImpl cards = cardsRevealed.get(player.getId()); for (Card card : cards.getCards(game)) { if (card != null && (card.getCardType().contains(CardType.ARTIFACT) || card.getCardType().contains(CardType.CREATURE) || card.getCardType().contains(CardType.LAND))) { card.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), player.getId()); cards.remove(card); } } } } // put enchantments onto the battlefield for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { CardsImpl cards = cardsRevealed.get(player.getId()); for (Card card : cards.getCards(game)) { if (card != null && card.getCardType().contains(CardType.ENCHANTMENT)) { card.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), player.getId()); cards.remove(card); } } } } // put the rest of the cards on buttom of the library for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { CardsImpl cards = cardsRevealed.get(player.getId()); player.putCardsOnBottomOfLibrary(cards, game, source, false); } } return true; }