@Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (player != null) { Choice typeChoice = new ChoiceImpl(true); typeChoice.setMessage("Choose a creature type:"); typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); while (!player.choose(outcome, typeChoice, game)) { if (!player.canRespond()) { return false; } } if (typeChoice.getChoice() != null) { game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); } FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); filterCreaturePermanent.add(new SubtypePredicate(typeChoice.getChoice())); for (Permanent creature : game.getBattlefield() .getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { creature.untap(game); } return true; } return false; }
@Override public boolean hasSourceObjectAbility(Game game, MageObject source, GameEvent event) { MageObject object = source; // for singleton abilities like Flying we can't rely on abilities' source because it's only once // in continuous effects // so will use the sourceId of the object itself that came as a parameter if it is not null if (object == null) { object = game.getPermanentEntering(getSourceId()); if (object == null) { object = game.getObject(getSourceId()); } } if (object != null) { if (object instanceof Permanent) { if (!((Permanent) object).getAbilities(game).contains(this)) { return false; } return ((Permanent) object).isPhasedIn(); } else if (!object.getAbilities().contains(this)) { // check if it's an ability that is temporary gained to a card Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId()); if (otherAbilities == null || !otherAbilities.contains(this)) { return false; } } } return true; }
@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 (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) { 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, MageObject mageObject) { if (!mageObject.getCardType().contains(cardType)) { mageObject.getCardType().add(cardType); } return true; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getObject(source.getSourceId()); if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceImpl(true); typeChoice.setMessage("Choose creature type"); typeChoice.setChoices(CardRepository.instance.getCreatureTypes()); while (!controller.choose(outcome, typeChoice, game)) { if (!controller.canRespond()) { return false; } } if (!game.isSimulation()) { game.informPlayers( mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); } Cards cardsToLibrary = new CardsImpl(); FilterCreatureCard filter = new FilterCreatureCard(); filter.add(new SubtypePredicate(typeChoice.getChoice())); cardsToLibrary.addAll( controller .getGraveyard() .getCards(filter, source.getSourceId(), source.getControllerId(), game)); controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); controller.shuffleLibrary(game); return true; } return false; }
@Override public boolean apply(Game game, Ability source) { Player player = getPayingPlayer(game, source); MageObject mageObject = game.getObject(source.getSourceId()); if (player != null && mageObject != null) { String message; if (chooseUseText == null) { message = new StringBuilder(getCostText()) .append(" and ") .append(executingEffect.getText(source.getModes().getMode())) .append("?") .toString(); } else { message = chooseUseText; } message = CardUtil.replaceSourceName(message, mageObject.getName()); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffect.getOutcome(), message, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { executingEffect.setTargetPointer(this.targetPointer); if (executingEffect instanceof OneShotEffect) { if (!(executingEffect instanceof PostResolveEffect)) { return executingEffect.apply(game, source); } } else { game.addEffect((ContinuousEffect) executingEffect, source); } } } 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) { 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) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); MageObject mageObject = game.getObject(source.getSourceId()); if (player != null && mageObject != null) { String message = userMessage; if (message == null) { message = getCostText() + " to prevent " + executingEffect.getText(source.getModes().getMode()) + "?"; } message = CardUtil.replaceSourceName(message, mageObject.getLogName()); cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffect.getOutcome(), message, source, game)) { cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } if (!cost.isPaid()) { executingEffect.setTargetPointer(this.targetPointer); return executingEffect.apply(game, source); } return true; } return false; }
@Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); if (object != null && object.hasSubtype("Myr")) { return true; } return false; }
@Override public boolean apply(MageObject input, Game game) { if (input.getAbilities().contains(ChangelingAbility.getInstance())) { return true; } return input.getSubtype().contains(subtype); }
@Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(source.getSourceId()); if (mageObject != null) { return "You can't cast a card with that name (" + mageObject.getLogName() + " in play)."; } return null; }
@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 String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null) { return "This spell can't be countered by spells or abilities (" + sourceObject.getName() + ")."; } return null; }
@Override public boolean apply(Game game, Ability source, UUID manaProducer, Cost costToPay) { if (super.apply(game, source)) { MageObject object = game.getObject(source.getSourceId()); if (object.hasSubtype("Dragon", game) && object.getCardType().contains(CardType.CREATURE)) { return true; } } return false; }
@Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); if (object != null) { for (Ability ability : object.getAbilities()) { if (ability instanceof DevoidAbility) { return true; } } } return false; }
@Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.CAST_SPELL && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { MageObject object = game.getObject(event.getSourceId()); if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString()))) { return true; } } return false; }
private boolean checkAbilityStillExists( Ability ability, ContinuousEffect effect, GameEvent event, Game game) { switch (effect .getDuration()) { // effects with fixed duration don't need an object with the source // ability (e.g. a silence cast with isochronic Scepter has no more a card // object case EndOfCombat: case EndOfGame: case EndOfStep: case EndOfTurn: case OneUse: case Custom: // custom duration means the effect ends itself if needed return true; } if (ability.getSourceId() == null) { // commander replacement effect return true; } MageObject object; if (event.getType().equals(EventType.ZONE_CHANGE) && ((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD) && event.getTargetId().equals(ability.getSourceId())) { object = ((ZoneChangeEvent) event).getTarget(); } else { object = game.getObject(ability.getSourceId()); } if (object == null) { return false; } boolean exists = true; if (!object.getAbilities().contains(ability)) { exists = false; if (object instanceof PermanentCard) { PermanentCard permanent = (PermanentCard) object; if (permanent.canTransform() && event.getType() == GameEvent.EventType.TRANSFORMED) { exists = permanent.getCard().getAbilities().contains(ability); } } } else { if (object instanceof PermanentCard) { PermanentCard permanent = (PermanentCard) object; if (permanent.isFaceDown(game) && !ability.getWorksFaceDown()) { return false; } } else if (object instanceof Spell) { Spell spell = (Spell) object; if (spell.isFaceDown(game) && !ability.getWorksFaceDown()) { return false; } } } return exists; }
@Override public boolean applies(GameEvent event, Ability source, Game game) { if ((event.getType() == GameEvent.EventType.CAST_SPELL) && event.getPlayerId() == source.getControllerId()) { MageObject spellObject = game.getObject(event.getSourceId()); if (spellObject != null && spellObject.getCardType().contains(CardType.CREATURE) && spellObject.getCardType().contains(CardType.ARTIFACT)) { return true; } } return false; }
@Override public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.MANA_PAYED) { MageObject object = game.getObject(event.getSourceId()); // TODO: Replace identification by name by better method that also works if ability is copied // from other land with other name if (object != null && object.getName().equals("Boseiju, Who Shelters All") && event.getFlag()) { spells.add(event.getTargetId()); } } }
@Override public boolean resolve(Game game) { boolean result = true; // 20100716 - 117.12 if (checkIfClause(game)) { for (Effect effect : getEffects()) { if (effect instanceof OneShotEffect) { boolean effectResult = effect.apply(game, this); result &= effectResult; if (logger.isDebugEnabled()) { if (!this.getAbilityType().equals(AbilityType.MANA)) { if (!effectResult) { if (this.getSourceId() != null) { MageObject mageObject = game.getObject(this.getSourceId()); if (mageObject != null) { logger.debug("AbilityImpl.resolve: object: " + mageObject.getName()); } } logger.debug( "AbilityImpl.resolve: effect returned false -" + effect.getText(this.getModes().getMode())); } } } } else { game.addEffect((ContinuousEffect) effect, this); } /** * All restrained trigger events are fired now. To restrain the events is mainly neccessary * because of the movement of multiple object at once. If the event is fired directly as one * object moved, other objects are not already in the correct zone to check for their * effects. (e.g. Valakut, the Molten Pinnacle) */ game.getState().handleSimultaneousEvent(game); game.resetShortLivingLKI(); /** * game.applyEffects() has to be done at least for every effect that moves cards/permanent * between zones, or changes control of objects so Static effects work as intened if * dependant from the moved objects zone it is in Otherwise for example were static * abilities with replacement effects deactivated too late Example: {@link * org.mage.test.cards.replacement.DryadMilitantTest#testDiesByDestroy testDiesByDestroy} */ if (effect.applyEffectsAfter()) { game.applyEffects(); game.getState().getTriggers().checkStateTriggers(game); } } } return result; }
@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; }
private String getKey(TriggeredAbility ability, MageObject target) { String key = ability.getId() + "_"; if (target != null) { key += target.getId(); } return key; }
/** * @param game * @param source * @return */ @Override public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { if (!this.hasSourceObjectAbility(game, source, event)) { return false; } if (zone.equals(Zone.COMMAND)) { if (this.getSourceId() == null) { // commander effects return true; } MageObject object = game.getObject(this.getSourceId()); // emblem are always actual if (object != null && object instanceof Emblem) { return true; } } UUID parameterSourceId; // for singleton abilities like Flying we can't rely on abilities' source because it's only once // in continuous effects // so will use the sourceId of the object itself that came as a parameter if it is not null if (this instanceof MageSingleton && source != null) { parameterSourceId = source.getId(); } else { parameterSourceId = getSourceId(); } // check agains shortLKI for effects that move multiple object at the same time (e.g. destroy // all) if (game.getShortLivingLKI(getSourceId(), getZone())) { return true; } // check against current state Zone test = game.getState().getZone(parameterSourceId); return test != null && zone.match(test); }
@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; }
/** * Adds a by sourceId gained triggered ability * * @param ability - the gained ability * @param sourceId - the source that assigned the ability * @param attachedTo - the object that gained the ability */ public void add(TriggeredAbility ability, UUID sourceId, MageObject attachedTo) { this.add(ability, attachedTo); List<UUID> uuidList = new LinkedList<UUID>(); uuidList.add(sourceId); // if the object that gained the ability moves zone, also then the triggered ability must be // removed uuidList.add(attachedTo.getId()); sources.put(getKey(ability, attachedTo), uuidList); }
@Override public String getGameLogMessage(Game game) { if (game.isSimulation()) { return ""; } MageObject object = game.getObject(this.sourceId); if (object == null) { // e.g. sacrificed token logger.warn("Could get no object: " + this.toString()); } return new StringBuilder(" activates: ") .append( object != null ? this.formatRule(getModes().getText(), object.getLogName()) : getModes().getText()) .append(" from ") .append(getMessageText(game)) .toString(); }
@Override public boolean apply(Game game, Ability source) { Card sourceCard = game.getCard(source.getSourceId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceCard != null) { Player player = game.getPlayer(sourceCard.getOwnerId()); if (player != null) { Zone fromZone = game.getState().getZone(sourceCard.getId()); Cards cards = new CardsImpl(); cards.add(sourceCard); player.revealCards(sourceObject.getLogName(), cards, game); player.moveCardToLibraryWithInfo( sourceCard, source.getSourceId(), game, fromZone, true, true); player.shuffleLibrary(game); return true; } } return false; }