@Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (player != null && permanent != null) { String colors; ChoiceColor colorChoice = new ChoiceColor(); colorChoice.setMessage("Choose the first color"); while (!player.choose(Outcome.GainLife, colorChoice, game)) { if (!player.canRespond()) { return false; } } game.getState().setValue(permanent.getId() + "_color1", colorChoice.getColor().toString()); colors = colorChoice.getChoice().toLowerCase() + " and "; colorChoice.getChoices().remove(colorChoice.getChoice()); colorChoice.setMessage("Choose the second color"); while (!player.choose(Outcome.GainLife, colorChoice, game) && player.canRespond()) { game.debugMessage("player canceled choosing type. retrying."); } game.getState().setValue(permanent.getId() + "_color2", colorChoice.getColor().toString()); colors = colors + colorChoice.getChoice().toLowerCase(); game.informPlayers( permanent.getName() + ": " + player.getLogName() + " has chosen " + colors); } return false; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = (Permanent) game.getLastKnownInformation(target, Zone.BATTLEFIELD); if (permanent != null && controller != null) { Player player = game.getPlayer(permanent.getOwnerId()); if (player != null) { FilterCreatureCard filter = new FilterCreatureCard( new StringBuilder("a creature card from ") .append(player.getLogName()) .append("'s graveyard") .toString()); filter.add(new OwnerIdPredicate(player.getId())); Target targetCreature = new TargetCardInGraveyard(filter); if (targetCreature.canChoose(source.getSourceId(), controller.getId(), game) && controller.chooseTarget(outcome, targetCreature, source, game)) { Card card = game.getCard(targetCreature.getFirstTarget()); if (card != null && game.getState().getZone(card.getId()).equals(Zone.GRAVEYARD)) { return card.putOntoBattlefield( game, Zone.GRAVEYARD, source.getSourceId(), player.getId()); } } return true; } } return false; }
@Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { boolean retValue = false; GameEvent preventEvent = new GameEvent( GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), event.getAmount(), false); int damage = event.getAmount(); if (!game.replaceEvent(preventEvent)) { event.setAmount(0); game.fireEvent( GameEvent.getEvent( GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), damage)); retValue = true; } Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { permanent.removeCounters(CounterType.P1P1.createInstance(damage), game); } return retValue; }
@Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player == null) { return false; } Card card = player.getLibrary().getFromTop(game); if (card != null) { Cards cards = new CardsImpl(); cards.add(card); player.lookAtCards("Explorer's Scope", cards, game); if (card.getCardType().contains(CardType.LAND)) { String message = "Put " + card.getName() + " onto the battlefield tapped?"; if (player.chooseUse(Outcome.PutLandInPlay, message, game)) { if (card.putOntoBattlefield( game, Zone.LIBRARY, source.getId(), source.getControllerId())) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { permanent.setTapped(true); } } } } } return true; }
@Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); Permanent targetCreature = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (targetCreature != null && permanent != null) { Permanent blueprintPermanent = game.copyPermanent( Duration.Custom, targetCreature, permanent.getId(), source, new EmptyApplyToPermanent()); blueprintPermanent.addAbility( new EntersBattlefieldAllTriggeredAbility( Zone.BATTLEFIELD, new UnstableShapeshifterEffect(), filterAnotherCreature, false, SetTargetPointer.PERMANENT, ""), game); return true; } return false; }
@Override public Boolean apply(Game game, Permanent permanent) { if (!permanent.getCardType().contains(cardType)) { permanent.getCardType().add(cardType); } return true; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); // If no controller, exit out here and do not vote. if (controller == null) return false; this.vote("feather", "quill", controller, game, source); Permanent permanent = game.getPermanent(source.getSourceId()); // Feathers Votes // If feathers received zero votes or the permanent is no longer on the battlefield, do not // attempt to put P1P1 counter on it. if (voteOneCount > 0 && permanent != null) permanent.addCounters(CounterType.P1P1.createInstance(voteOneCount), game); // Quill Votes // Only let the controller loot the appropriate amount of cards if it was voted for. if (voteTwoCount > 0) { Effect lootCardsEffect = new DrawDiscardControllerEffect(voteTwoCount, voteTwoCount); lootCardsEffect.apply(game, source); } return true; }
@Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { GameEvent preventEvent = new GameEvent( GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), event.getAmount(), false); if (!game.replaceEvent(preventEvent)) { int damage = event.getAmount(); Permanent permanent = game.getPermanent(event.getSourceId()); StringBuilder message = new StringBuilder(); if (permanent != null) { message.append(" from ").append(permanent.getName()); } message.insert(0, "Damage").append(" has been prevented: ").append(damage); event.setAmount(0); game.informPlayers(message.toString()); game.fireEvent( GameEvent.getEvent( GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), damage)); } return false; }
@Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { PreventionEffectData preventionResult = preventDamageAction(event, source, game); if (preventionResult.getPreventedDamage() > 0) { Permanent redirectTo = game.getPermanent(getTargetPointer().getFirst(game, source)); if (redirectTo != null) { game.informPlayers( "Dealing " + preventionResult.getPreventedDamage() + " to " + redirectTo.getLogName() + " instead."); DamageEvent damageEvent = (DamageEvent) event; redirectTo.damage( preventionResult.getPreventedDamage(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects()); } discard(); // (only once) } return false; }
@Override public boolean apply(Game game, Ability source) { if (onCard) { Card card; if (affectedObjectsSet) { card = affectedObjectList.get(0).getCard(game); } else { card = game.getCard(source.getSourceId()); } if (card != null) { // add ability to card only once game.getState().addOtherAbility(card, ability); return true; } } else { Permanent permanent; if (affectedObjectsSet) { permanent = affectedObjectList.get(0).getPermanent(game); } else { permanent = game.getPermanent(source.getSourceId()); } if (permanent != null) { permanent.addAbility(ability, source.getSourceId(), game, false); return true; } } if (duration.equals(Duration.Custom)) { this.discard(); } return true; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller == null) { return false; } int totalPowerSacrificed = 0; List<UUID> perms = new ArrayList<>(); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent( 1, 1, new FilterControlledCreaturePermanent(), true); if (target.canChoose(player.getId(), game)) { while (!target.isChosen() && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); } perms.addAll(target.getTargets()); } } } for (UUID permID : perms) { Permanent permanent = game.getPermanent(permID); if (permanent != null) { int power = permanent.getPower().getValue(); if (permanent.sacrifice(source.getSourceId(), game)) { totalPowerSacrificed += power; } } } new CreateTokenEffect(new ReignOfThePitToken(totalPowerSacrificed)).apply(game, source); return true; }
@Override public boolean apply(Game game, Ability source) { Set<String> targets = new HashSet<>(); for (UUID target : targetPointer.getTargets(game, source)) { Permanent permanent = game.getPermanent(target); if (permanent != null) { permanent.untap(game); targets.add(CardUtil.getCardZoneString("", permanent.getId(), game)); } } if (!targets.isEmpty()) { // save the targets for the watcher in a map with zone change counter (as the card is recast // during combat it's neccessary to save with zone change counter) Map<Integer, Set<String>> targetMap; Object object = game.getState().getValue("targets" + source.getSourceId()); if (object != null && object instanceof Map) { targetMap = (Map<Integer, Set<String>>) object; } else { targetMap = new HashMap<>(); } targetMap.put(game.getCard(source.getSourceId()).getZoneChangeCounter(game), targets); if (object == null) { game.getState().setValue("targets" + source.getSourceId().toString(), targetMap); } } return true; }
private void exileCards(Player player, int count, Ability source, Game game) { int amount = Math.min( count, player.getHand().size() + game.getBattlefield().getAllActivePermanents(player.getId()).size()); while (amount > 0) { Target target = new TargetControlledPermanent(0, 1, filter, true); if (target.canChoose(player.getId(), game) && player.choose(Outcome.Exile, target, source.getSourceId(), game)) { for (UUID targetId : target.getTargets()) { Permanent chosen = game.getPermanent(targetId); if (chosen != null) { chosen.moveToExile(source.getId(), "Descent into Madness", source.getSourceId(), game); amount--; } } } if (amount > 0) { TargetCard targetInHand = new TargetCard(Zone.HAND, filterInHand); if (targetInHand.canChoose(player.getId(), game) && player.choose(Outcome.Exile, player.getHand(), targetInHand, game)) { Card card = player.getHand().get(targetInHand.getFirstTarget(), game); if (card != null) { card.moveToExile(source.getId(), "Descent into Madness", source.getSourceId(), game); amount--; } } } } }
@Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && permanent != null && sourcePermanent != null) { CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, permanent, source.getSourceId()); if (controller.moveCardToExileWithInfo( permanent, source.getSourceId(), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) { // Copy exiled permanent game.addEffect(copyEffect, source); // Create delayed triggered ability AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( new ReturnFromExileEffect(source.getSourceId(), Zone.BATTLEFIELD, false)); delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); delayedAbility.setSourceObject(source.getSourceObject(game), game); game.addDelayedTriggeredAbility(delayedAbility); return true; } } return false; }
@Override public boolean apply(Game game, Ability source) { MageObject mageObject = source.getSourceObject(game); Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null && mageObject == null && new MageObjectReference(permanent, game).refersTo(mageObject, game)) { discard(); return false; } UUID exileId = CardUtil.getExileZoneId( game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exileId != null) { ExileZone exileZone = game.getExile().getExileZone(exileId); if (exileZone == null) { return false; } Card exiledCard = null; for (Card card : exileZone.getCards(game)) { exiledCard = card; break; } if (exiledCard != null) { int value = exiledCard.getManaCost().convertedManaCost(); permanent.getPower().setValue(value); permanent.getToughness().setValue(value); } } return true; }
@Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) { if (((DamagedEvent) event).isCombatDamage()) { Permanent creature = game.getPermanent(event.getSourceId()); if (creature != null && creature.getControllerId().equals(controllerId) && !damagedPlayerIds.contains(event.getTargetId())) { damagedPlayerIds.add(event.getTargetId()); return true; } } } if (event.getType().equals(GameEvent.EventType.END_COMBAT_STEP_POST)) { damagedPlayerIds.clear(); } if (event.getType().equals(GameEvent.EventType.ZONE_CHANGE) && event.getTargetId().equals(getSourceId())) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.getFromZone().equals(Zone.GRAVEYARD)) { damagedPlayerIds.clear(); } } return false; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { MageObject mageObject = source.getSourceObject(game); Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null && mageObject != null && new MageObjectReference(permanent, game).refersTo(mageObject, game)) { if (permanent.sacrifice(source.getSourceId(), game)) { UUID exileId = CardUtil.getExileZoneId( game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exileId != null) { ExileZone exileZone = game.getExile().getExileZone(exileId); Card exiledCard = null; if (exileZone != null) { for (Card card : exileZone.getCards(game)) { exiledCard = card; break; } } if (exiledCard != null) { if (exiledCard.getSpellAbility().canChooseTarget(game)) { controller.cast(exiledCard.getSpellAbility(), game, true); } } } } } return true; } return false; }
@Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), game)) { if (permanent != null) { switch (layer) { case TypeChangingEffects_4: if (loseOther) { permanent.getSubtype().clear(); permanent.getSubtype().addAll(subtypes); } else { for (String subtype : subtypes) { if (!permanent.getSubtype().contains(subtype)) { permanent.getSubtype().add(subtype); } } } break; } } else { if (duration.equals(Duration.Custom)) { discard(); } } } return true; }
@Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); if (player == null) { return false; } if (player.getLife() > 2 && player.chooseUse( Outcome.Neutral, "Pay 2 life? If you don't, return a permanent you control to its owner's hand.", game)) { player.loseLife(2, game); game.informPlayers( player.getName() + " pays 2 life. He will not return a permanent he or she controls."); return true; } else { Target target = new TargetControlledPermanent(); if (target.canChoose(source.getSourceId(), player.getId(), game) && player.chooseTarget(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { game.informPlayers(player.getName() + " returns " + permanent.getName() + " to hand."); return permanent.moveToZone(Zone.HAND, source.getSourceId(), game, false); } } } return false; }
public void assignDamageToBlockers(boolean first, Game game) { if (attackers.size() > 0 && (!first || hasFirstOrDoubleStrike(game))) { if (blockers.isEmpty()) { unblockedDamage(first, game); } else { Permanent attacker = game.getPermanent(attackers.get(0)); if (attacker .getAbilities() .containsKey(DamageAsThoughNotBlockedAbility.getInstance().getId())) { Player player = game.getPlayer(attacker.getControllerId()); if (player.chooseUse( Outcome.Damage, "Do you wish to assign damage for " + attacker.getLogName() + " as though it weren't blocked?", game)) { blocked = false; unblockedDamage(first, game); } } if (blockers.size() == 1) { singleBlockerDamage(first, game); } else { multiBlockerDamage(first, game); } } } }
@Override public void assignDamage( int damage, List<UUID> targets, String singleTargetName, UUID sourceId, Game game) { int remainingDamage = damage; UUID targetId; int amount; while (remainingDamage > 0) { if (targets.size() == 1) { targetId = targets.get(0); amount = remainingDamage; } else { targetId = targets.get(rnd.nextInt(targets.size())); amount = rnd.nextInt(damage + 1); } Permanent permanent = game.getPermanent(targetId); if (permanent != null) { permanent.damage(amount, sourceId, game, true, false); remainingDamage -= amount; } else { Player player = game.getPlayer(targetId); if (player != null) { player.damage(amount, sourceId, game, false, true); remainingDamage -= amount; } } targets.remove(targetId); } }
/** * Damages attacking creatures by a creature that blocked several ones Damages only attackers as * blocker was damage in either {@link #singleBlockerDamage} or {@link #multiBlockerDamage}. * * <p>Handles abilities like "{this} an block any number of creatures.". * * @param first * @param game */ private void multiAttackerDamage(boolean first, Game game) { Permanent blocker = game.getPermanent(blockers.get(0)); if (blocker == null) { return; } Player player = game.getPlayer(blocker.getControllerId()); int damage = getDamageValueFromPermanent(blocker, game); if (canDamage(blocker, first)) { Map<UUID, Integer> assigned = new HashMap<>(); for (UUID attackerId : attackerOrder) { Permanent attacker = game.getPermanent(attackerId); int lethalDamage; if (blocker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId())) { lethalDamage = 1; } else { lethalDamage = attacker.getToughness().getValue() - attacker.getDamage(); } if (lethalDamage >= damage) { assigned.put(attackerId, damage); break; } int damageAssigned = player.getAmount( lethalDamage, damage, "Assign damage to " + attacker.getLogName(), game); assigned.put(attackerId, damageAssigned); damage -= damageAssigned; } for (Map.Entry<UUID, Integer> entry : assigned.entrySet()) { Permanent attacker = game.getPermanent(entry.getKey()); attacker.markDamage(entry.getValue(), blocker.getId(), game, true, true); } } }
@Override public boolean applies(GameEvent event, Ability source, Game game) { boolean isCombat = false; switch (event.getType()) { case DAMAGE_CREATURE: case DAMAGE_PLAYER: case DAMAGE_PLANESWALKER: if (event instanceof DamageCreatureEvent) { isCombat = ((DamageCreatureEvent) event).isCombatDamage(); } else if (event instanceof DamageEvent) { isCombat = ((DamageEvent) event).isCombatDamage(); } if (isCombat) { Permanent equipment = game.getPermanent(source.getSourceId()); if (equipment != null && equipment.getAttachedTo() != null) { UUID attachedTo = equipment.getAttachedTo(); if (event.getSourceId().equals(attachedTo)) { event.setAmount(event.getAmount() * 2); } else if (event.getTargetId().equals(attachedTo)) { event.setAmount(event.getAmount() * 2); } } } } return false; }
/** * There are effects that let creatures assigns combat damage equal to its toughness rather than * its power. So this method takes this into account to get the value of damage a creature will * assign * * @param permanent * @param game * @return */ private int getDamageValueFromPermanent(Permanent permanent, Game game) { if (game.getCombat().useToughnessForDamage()) { return permanent.getToughness().getValue(); } else { return permanent.getPower().getValue(); } }
@java.lang.Override public boolean apply(Game game, Ability source) { Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourceObject != null) { // create cost for sacrificing an artifact Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); // if they can pay the cost, then they must pay if (target.canChoose(source.getSourceId(), controller.getId(), game)) { controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game); Permanent artifactSacrifice = game.getPermanent(target.getFirstTarget()); if (artifactSacrifice != null) { // sacrifice the chosen artifact artifactSacrifice.sacrifice(source.getSourceId(), game); } } else { sourceObject.tap(game); controller.damage(4, source.getSourceId(), game, false, true); } } return true; } return false; }
public static boolean isPowerOrThoughnessGreater( Permanent sourceCreature, Permanent newCreature) { if (newCreature.getPower().getValue() > sourceCreature.getPower().getValue()) { return true; } return newCreature.getToughness().getValue() > sourceCreature.getToughness().getValue(); }
/** * Checks if there are enough {@link Permanent} or {@link Player} that can be chosen. Should only * be used for Ability targets since this checks for protection, shroud etc. * * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source * @param game * @return - true if enough valid {@link Permanent} or {@link Player} exist */ @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { int count = 0; MageObject targetSource = game.getObject(sourceId); for (UUID playerId : game.getPlayer(sourceControllerId).getInRange()) { Player player = game.getPlayer(playerId); if (player != null && player.canBeTargetedBy(targetSource, game) && filter.match(player, game)) { count++; if (count >= this.minNumberOfTargets) { return true; } } } for (Permanent permanent : game.getBattlefield() .getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) { if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { count++; if (count >= this.minNumberOfTargets) { return true; } } } return false; }
@Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent == null) { return false; } if (permanent.isCopy()) { // copies can't transform return true; } if (!permanent.isTransformed()) { // keep original card return true; } Card card = permanent.getSecondCardFace(); if (card == null) { return false; } TransformAbility.transform(permanent, card, game); return true; }
@Test public void testEnteringWithCounters() { addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains", 5); addCard(Constants.Zone.GRAVEYARD, playerA, "Dearly Departed"); addCard(Constants.Zone.BATTLEFIELD, playerA, "Thraben Doomsayer"); activateAbility( 2, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Put a 1/1 white Human creature token onto the battlefield."); setStopAt(2, Constants.PhaseStep.BEGIN_COMBAT); execute(); assertLife(playerA, 20); assertLife(playerB, 20); assertPermanentCount(playerA, "Human", 1); // check that the +1/+1 counter was added to the token Permanent humanToken = getPermanent("Human", playerA.getId()); Assert.assertEquals(2, humanToken.getPower().getValue()); Assert.assertEquals(2, humanToken.getToughness().getValue()); }
@Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { DamageEvent damageEvent = (DamageEvent) event; Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null) { // get name of old target Permanent targetPermanent = game.getPermanent(event.getTargetId()); StringBuilder message = new StringBuilder(); message.append(sourcePermanent.getName()).append(": gets "); message.append(damageEvent.getAmount()).append(" damage redirected from "); if (targetPermanent != null) { message.append(targetPermanent.getName()); } else { Player targetPlayer = game.getPlayer(event.getTargetId()); if (targetPlayer != null) { message.append(targetPlayer.getName()); } else { message.append("unknown"); } } game.informPlayers(message.toString()); // redirect damage this.used = true; sourcePermanent.damage( damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isPreventable(), damageEvent.isCombatDamage(), event.getAppliedEffects()); return true; } return false; }