Merge pull request 'master' (#40) from External/mage:master into master
All checks were successful
/ build_release (push) Successful in 21m46s

Reviewed-on: #40
This commit is contained in:
Failure 2025-09-18 08:48:02 -07:00
commit 466f6ed385
630 changed files with 15838 additions and 2561 deletions

View file

@ -575,7 +575,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
// Constants // Constants
private static final int DEFAULT_COUNT_LABEL_HEIGHT = 40; // can contain 1 or 2 lines private static final int DEFAULT_COUNT_LABEL_HEIGHT = 40; // can contain 1 or 2 lines
public static final int GRID_PADDING = 20; public static final int GRID_PADDING = 12;
private static final ImageIcon INSERT_ROW_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_row.png")); private static final ImageIcon INSERT_ROW_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_row.png"));
private static final ImageIcon INSERT_COL_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_col.png")); private static final ImageIcon INSERT_COL_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_col.png"));

View file

@ -467,6 +467,7 @@ public class ScryfallImageSupportCards {
// add("MD1"); // Modern Event Deck // add("MD1"); // Modern Event Deck
// add("DD3"); // Duel Decks Anthology // add("DD3"); // Duel Decks Anthology
// add("PZ1"); // Legendary Cube // add("PZ1"); // Legendary Cube
add("PLG20"); // Love Your LGS 2020
add("IKO"); // Ikoria: Lair of Behemoths add("IKO"); // Ikoria: Lair of Behemoths
add("C20"); // Commander 2020 add("C20"); // Commander 2020
add("M21"); // Core Set 2021 add("M21"); // Core Set 2021
@ -516,11 +517,13 @@ public class ScryfallImageSupportCards {
add("NCC"); // New Capenna Commander add("NCC"); // New Capenna Commander
add("SLX"); // Universes Within add("SLX"); // Universes Within
add("CLB"); // Commander Legends: Battle for Baldur's Gate add("CLB"); // Commander Legends: Battle for Baldur's Gate
add("PLG22"); // Love Your LGS 2022
add("2X2"); // Double Masters 2022 add("2X2"); // Double Masters 2022
add("SCH"); // Store Championships add("SCH"); // Store Championships
add("DMU"); // Dominaria United add("DMU"); // Dominaria United
add("DMC"); // Dominaria United Commander add("DMC"); // Dominaria United Commander
add("YDMU"); // Alchemy: Dominaria add("YDMU"); // Alchemy: Dominaria
add("PRCQ"); // Regional Championship Qualifiers 2022
add("40K"); // Warhammer 40,000 Commander add("40K"); // Warhammer 40,000 Commander
add("UNF"); // Unfinity add("UNF"); // Unfinity
add("GN3"); // Game Night: Free-for-All add("GN3"); // Game Night: Free-for-All
@ -548,9 +551,11 @@ public class ScryfallImageSupportCards {
add("30A"); // 30th Anniversary Edition add("30A"); // 30th Anniversary Edition
add("P30A"); // 30th Anniversary Play Promos add("P30A"); // 30th Anniversary Play Promos
add("P30M"); // 30th Anniversary Misc Promos add("P30M"); // 30th Anniversary Misc Promos
add("P30H"); // 30th Anniversary History Promos
add("PEWK"); // Eternal Weekend add("PEWK"); // Eternal Weekend
add("LTR"); // The Lord of the Rings: Tales of Middle-Earth add("LTR"); // The Lord of the Rings: Tales of Middle-Earth
add("LTC"); // Tales of Middle-Earth Commander add("LTC"); // Tales of Middle-Earth Commander
add("PF23"); // MagicFest 2023
add("CMM"); // Commander Masters add("CMM"); // Commander Masters
add("WHO"); // Doctor Who add("WHO"); // Doctor Who
add("WOE"); // Wilds of Eldraine add("WOE"); // Wilds of Eldraine
@ -561,10 +566,13 @@ public class ScryfallImageSupportCards {
add("REX"); // Jurassic World Collection add("REX"); // Jurassic World Collection
add("SPG"); // Special Guests add("SPG"); // Special Guests
add("PW24"); // Wizards Play Network 2024 add("PW24"); // Wizards Play Network 2024
add("PF24"); // MagicFest 2024
add("RVR"); // Ravnica Remastered add("RVR"); // Ravnica Remastered
add("PL24"); // Year of the Dragon 2024
add("PIP"); // Fallout add("PIP"); // Fallout
add("MKM"); // Murders at Karlov Manor add("MKM"); // Murders at Karlov Manor
add("MKC"); // Murders at Karlov Manor Commander add("MKC"); // Murders at Karlov Manor Commander
add("PSS4"); // MKM Standard Showdown
add("CLU"); // Ravnica: Clue Edition add("CLU"); // Ravnica: Clue Edition
add("OTJ"); // Outlaws of Thunder Junction add("OTJ"); // Outlaws of Thunder Junction
add("OTC"); // Outlaws of Thunder Junction Commander add("OTC"); // Outlaws of Thunder Junction Commander
@ -576,6 +584,7 @@ public class ScryfallImageSupportCards {
add("ACR"); // Assassin's Creed add("ACR"); // Assassin's Creed
add("BLB"); // Bloomburrow add("BLB"); // Bloomburrow
add("BLC"); // Bloomburrow Commander add("BLC"); // Bloomburrow Commander
add("PLG24"); // Love Your LGS 2024
add("PCBB"); // Cowboy Bebop add("PCBB"); // Cowboy Bebop
add("MB2"); // Mystery Booster 2 add("MB2"); // Mystery Booster 2
add("DSK"); // Duskmourn: House of Horror add("DSK"); // Duskmourn: House of Horror
@ -587,6 +596,7 @@ public class ScryfallImageSupportCards {
add("PSPL"); // Spotlight Series add("PSPL"); // Spotlight Series
add("INR"); // Innistrad Remastered add("INR"); // Innistrad Remastered
add("PF25"); // MagicFest 2025 add("PF25"); // MagicFest 2025
add("PL25"); // Year of the Snake 2025
add("DFT"); // Aetherdrift add("DFT"); // Aetherdrift
add("DRC"); // Aetherdrift Commander add("DRC"); // Aetherdrift Commander
add("PLG25"); // Love Your LGS 2025 add("PLG25"); // Love Your LGS 2025

View file

@ -2818,6 +2818,14 @@ public class ScryfallImageSupportTokens {
put("EOC/Shapeshifter", "https://api.scryfall.com/cards/teoc/2/en?format=image"); put("EOC/Shapeshifter", "https://api.scryfall.com/cards/teoc/2/en?format=image");
put("EOC/Thopter", "https://api.scryfall.com/cards/teoc/16/en?format=image"); put("EOC/Thopter", "https://api.scryfall.com/cards/teoc/16/en?format=image");
// SPM
put("SPM/Food", "https://api.scryfall.com/cards/tspm/5?format=image");
put("SPM/Human", "https://api.scryfall.com/cards/tspm/4?format=image");
put("SPM/Illusion", "https://api.scryfall.com/cards/tspm/2?format=image");
put("SPM/Robot", "https://api.scryfall.com/cards/tspm/6?format=image");
put("SPM/Spider", "https://api.scryfall.com/cards/tspm/3?format=image");
put("SPM/Treasure", "https://api.scryfall.com/cards/tspm/7?format=image");
// JVC // JVC
put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image"); put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image");
@ -2931,6 +2939,12 @@ public class ScryfallImageSupportTokens {
// PL23 // PL23
put("PL23/Food", "https://api.scryfall.com/cards/pl23/2?format=image"); put("PL23/Food", "https://api.scryfall.com/cards/pl23/2?format=image");
// PL24
put("PL24/Dragon", "https://api.scryfall.com/cards/pl24/3?format=image");
// PL25
put("PL25/Snake", "https://api.scryfall.com/cards/pl25/2?format=image");
// generate supported sets // generate supported sets
supportedSets.clear(); supportedSets.clear();
for (String cardName : this.keySet()) { for (String cardName : this.keySet()) {

View file

@ -0,0 +1,66 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.permanent.TokenPredicate;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AgentVenom extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another nontoken creature you control");
static {
filter.add(AnotherPredicate.instance);
filter.add(TokenPredicate.FALSE);
}
public AgentVenom(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SYMBIOTE);
this.subtype.add(SubType.SOLDIER);
this.subtype.add(SubType.HERO);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Flash
this.addAbility(FlashAbility.getInstance());
// Menace
this.addAbility(new MenaceAbility());
// Whenever another nontoken creature you control dies, you draw a card and lose 1 life.
Ability ability = new DiesCreatureTriggeredAbility(
new DrawCardSourceControllerEffect(1, true), false, filter
);
ability.addEffect(new LoseLifeSourceControllerEffect(1).setText("and lose 1 life"));
this.addAbility(ability);
}
private AgentVenom(final AgentVenom card) {
super(card);
}
@Override
public AgentVenom copy() {
return new AgentVenom(this);
}
}

View file

@ -27,9 +27,9 @@ public final class AlabornZealot extends CardImpl {
// When Alaborn Zealot blocks a creature, destroy that creature and Alaborn Zealot. // When Alaborn Zealot blocks a creature, destroy that creature and Alaborn Zealot.
TriggeredAbility ability = new BlocksCreatureTriggeredAbility( TriggeredAbility ability = new BlocksCreatureTriggeredAbility(
new DestroyTargetEffect().setText("destroy that creature") new DestroyTargetEffect().setText("destroy both")
); );
ability.addEffect(new DestroySourceEffect().setText("and {this}")); ability.addEffect(new DestroySourceEffect().setText(" creatures"));
ability.setTriggerPhrase("When {this} blocks a creature, "); ability.setTriggerPhrase("When {this} blocks a creature, ");
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -0,0 +1,101 @@
package mage.cards.a;
import mage.MageIdentifier;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class AlienSymbiosis extends CardImpl {
public AlienSymbiosis(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
this.addAbility(new EnchantAbility(auraTarget));
// Enchanted creature gets +1/+1, has menace, and is a Symbiote in addition to its other types.
Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1));
ability.addEffect(new GainAbilityAttachedEffect(new MenaceAbility(), null).concatBy(","));
ability.addEffect(new AddCardSubtypeAttachedEffect(SubType.SYMBIOTE, AttachmentType.AURA).concatBy(",").setText("and is a Symbiote in addition to its other types"));
this.addAbility(ability);
// You may cast this card from your graveyard by discarding a card in addition to paying its other costs.
this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, new AlienSymbiosisGraveyardEffect()));
}
private AlienSymbiosis(final AlienSymbiosis card) {
super(card);
}
@Override
public AlienSymbiosis copy() {
return new AlienSymbiosis(this);
}
}
class AlienSymbiosisGraveyardEffect extends AsThoughEffectImpl {
AlienSymbiosisGraveyardEffect() {
super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfGame, Outcome.PutCreatureInPlay);
this.staticText = "You may cast this card from your graveyard by discarding a card in addition to paying its other costs.";
}
private AlienSymbiosisGraveyardEffect(final AlienSymbiosisGraveyardEffect effect) {
super(effect);
}
@Override
public AlienSymbiosisGraveyardEffect copy() {
return new AlienSymbiosisGraveyardEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (!objectId.equals(source.getSourceId()) || !source.isControlledBy(affectedControllerId)
|| game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) {
return false;
}
Player controller = game.getPlayer(affectedControllerId);
if (controller != null) {
Costs<Cost> costs = new CostsImpl<>();
costs.add(new DiscardCardCost());
controller.setCastSourceIdWithAlternateMana(objectId, new ManaCostsImpl<>("{1}{B}"), costs,
MageIdentifier.AlienSymbiosisAlternateCast);
return true;
}
return false;
}
}

View file

@ -117,7 +117,7 @@ class AltairIbnLaAhadTokenEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Set<Card> cards = game Set<Card> cards = game
.getExile() .getExile()
.getAllCards(game, source.getControllerId()) .getCardsOwned(game, source.getControllerId())
.stream() .stream()
.filter(card -> card.getCounters(game).containsKey(CounterType.MEMORY)) .filter(card -> card.getCounters(game).containsKey(CounterType.MEMORY))
.filter(card -> card.isCreature(game)) .filter(card -> card.isCreature(game))

View file

@ -0,0 +1,47 @@
package mage.cards.a;
import mage.abilities.Mode;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.StaticFilters;
import mage.target.TargetPermanent;
import mage.target.TargetSpell;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class AmazingAcrobatics extends CardImpl {
public AmazingAcrobatics(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}");
// Choose one or both --
this.getSpellAbility().getModes().setMinModes(1);
this.getSpellAbility().getModes().setMaxModes(2);
// * Counter target spell.
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addTarget(new TargetSpell());
// * Tap one or two target creatures.
Mode mode = new Mode(new TapTargetEffect());
mode.addTarget(new TargetPermanent(1, 2, StaticFilters.FILTER_PERMANENT_CREATURES));
this.getSpellAbility().getModes().addMode(mode);
}
private AmazingAcrobatics(final AmazingAcrobatics card) {
super(card);
}
@Override
public AmazingAcrobatics copy() {
return new AmazingAcrobatics(this);
}
}

View file

@ -14,7 +14,6 @@ import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.game.permanent.token.custom.CreatureToken; import mage.game.permanent.token.custom.CreatureToken;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID; import java.util.UUID;
@ -42,7 +41,11 @@ public final class AmbushCommander extends CardImpl {
ContinuousEffect effect = new BecomesCreatureAllEffect( ContinuousEffect effect = new BecomesCreatureAllEffect(
new CreatureToken(1, 1, "1/1 green Elf creatures").withColor("G").withSubType(SubType.ELF), new CreatureToken(1, 1, "1/1 green Elf creatures").withColor("G").withSubType(SubType.ELF),
"lands", filter2, Duration.WhileOnBattlefield, true); "lands", filter2, Duration.WhileOnBattlefield, true);
effect.getDependencyTypes().add(DependencyType.BecomeForest); effect.addDependedToType(DependencyType.BecomeForest);
effect.addDependedToType(DependencyType.BecomeIsland);
effect.addDependedToType(DependencyType.BecomeMountain);
effect.addDependedToType(DependencyType.BecomePlains);
effect.addDependedToType(DependencyType.BecomeSwamp);
this.addAbility(new SimpleStaticAbility(effect)); this.addAbility(new SimpleStaticAbility(effect));
// {1}{G}, Sacrifice an Elf: Target creature gets +3/+3 until end of turn. // {1}{G}, Sacrifice an Elf: Target creature gets +3/+3 until end of turn.

View file

@ -114,7 +114,7 @@ class AngelOfDestinyLoseEffect extends OneShotEffect {
return false; return false;
} }
Set<UUID> playerSet = watcher.getPlayers(new MageObjectReference( Set<UUID> playerSet = watcher.getPlayers(new MageObjectReference(
source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game source.getSourceId(), source.getStackMomentSourceZCC(), game
)); ));
if (playerSet == null) { if (playerSet == null) {
return false; return false;

View file

@ -28,7 +28,7 @@ import mage.target.common.TargetControlledPermanent;
*/ */
public final class AngelicFavor extends CardImpl { public final class AngelicFavor extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("If you control a Plains"); private static final FilterPermanent filter = new FilterPermanent("you control a Plains");
static { static {
filter.add(SubType.PLAINS.getPredicate()); filter.add(SubType.PLAINS.getPredicate());

View file

@ -0,0 +1,70 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.ChooseCardTypeEffect;
import mage.abilities.effects.common.LookAtTargetPlayerHandEffect;
import mage.abilities.effects.common.cost.SpellsCostIncreasingAllEffect;
import mage.abilities.keyword.WebSlingingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ChosenCardTypePredicate;
import mage.target.common.TargetOpponent;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
* @author Jmlundeen
*/
public final class ArachnePsionicWeaver extends CardImpl {
private static final FilterCard filter = new FilterCard("spells of the chosen type");
static {
filter.add(ChosenCardTypePredicate.TRUE);
}
public ArachnePsionicWeaver(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SPIDER);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.HERO);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Web-slinging {W}
this.addAbility(new WebSlingingAbility(this, "{W}"));
// As Arachne enters, look at target opponent's hand, then choose a noncreature card type.
List<CardType> types = Arrays.stream(CardType.values()).filter(cardType -> cardType != CardType.CREATURE)
.collect(Collectors.toList());
Ability ability = new AsEntersBattlefieldAbility(new LookAtTargetPlayerHandEffect());
ability.addEffect(new ChooseCardTypeEffect(Outcome.Benefit, types)
.setText("choose a noncreature card type")
.concatBy(", then"));
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
// Spells of the chosen type cost {1} more to cast.
this.addAbility(new SimpleStaticAbility(new SpellsCostIncreasingAllEffect(1, filter, TargetController.ANY)));
}
private ArachnePsionicWeaver(final ArachnePsionicWeaver card) {
super(card);
}
@Override
public ArachnePsionicWeaver copy() {
return new ArachnePsionicWeaver(this);
}
}

View file

@ -0,0 +1,63 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.permanent.ModifiedPredicate;
import mage.target.common.TargetAttackingCreature;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AranaHeartOfTheSpider extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("modified creature you control");
static {
filter.add(ModifiedPredicate.instance);
}
public AranaHeartOfTheSpider(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SPIDER);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.HERO);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Whenever you attack, put a +1/+1 counter on target attacking creature.
Ability ability = new AttacksWithCreaturesTriggeredAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance()), 1
);
ability.addTarget(new TargetAttackingCreature());
this.addAbility(ability);
// Whenever a modified creature you control deals combat damage to a player, exile the top card of your library. You may play that card this turn.
this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(
new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn),
filter, false, SetTargetPointer.NONE, true
));
}
private AranaHeartOfTheSpider(final AranaHeartOfTheSpider card) {
super(card);
}
@Override
public AranaHeartOfTheSpider copy() {
return new AranaHeartOfTheSpider(this);
}
}

View file

@ -95,7 +95,7 @@ enum OpponentSearchesLibCondition implements Condition {
@Override @Override
public String toString() { public String toString() {
return "If an opponent searched their library this turn"; return "an opponent searched their library this turn";
} }
} }

View file

@ -5,7 +5,7 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.GainsChoiceOfAbilitiesEffect; import mage.abilities.effects.common.GainsChoiceOfAbilitiesEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.HasteAbility;
@ -13,6 +13,7 @@ import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType; import mage.constants.SubType;
import java.util.UUID; import java.util.UUID;
@ -30,7 +31,7 @@ public final class ArgivianAvenger extends CardImpl {
this.toughness = new MageInt(5); this.toughness = new MageInt(5);
// {1}: Until end of turn, Argivian Avenger gets -1/-1 and gains your choice of flying, vigilance, deathtouch, or haste. // {1}: Until end of turn, Argivian Avenger gets -1/-1 and gains your choice of flying, vigilance, deathtouch, or haste.
Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(-1, -1) Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(-1, -1, Duration.EndOfTurn)
.setText("Until end of turn, {this} gets -1/-1"), new GenericManaCost(1)); .setText("Until end of turn, {this} gets -1/-1"), new GenericManaCost(1));
ability.addEffect(new GainsChoiceOfAbilitiesEffect(GainsChoiceOfAbilitiesEffect.TargetType.Source, "", false, ability.addEffect(new GainsChoiceOfAbilitiesEffect(GainsChoiceOfAbilitiesEffect.TargetType.Source, "", false,
FlyingAbility.getInstance(), VigilanceAbility.getInstance(), DeathtouchAbility.getInstance(), HasteAbility.getInstance()) FlyingAbility.getInstance(), VigilanceAbility.getInstance(), DeathtouchAbility.getInstance(), HasteAbility.getInstance())

View file

@ -52,6 +52,6 @@ enum ArrowVolleyTrapCondition implements Condition {
@Override @Override
public String toString() { public String toString() {
return "If four or more creatures are attacking"; return "four or more creatures are attacking";
} }
} }

View file

@ -64,6 +64,7 @@ class AshayaSoulOfTheWildEffect extends ContinuousEffectImpl {
staticText = "Nontoken creatures you control are Forest lands in addition to their other types"; staticText = "Nontoken creatures you control are Forest lands in addition to their other types";
this.dependendToTypes.add(DependencyType.BecomeCreature); this.dependendToTypes.add(DependencyType.BecomeCreature);
this.dependencyTypes.add(DependencyType.BecomeForest); this.dependencyTypes.add(DependencyType.BecomeForest);
this.dependencyTypes.add(DependencyType.BecomeNonbasicLand);
} }
private AshayaSoulOfTheWildEffect(final AshayaSoulOfTheWildEffect effect) { private AshayaSoulOfTheWildEffect(final AshayaSoulOfTheWildEffect effect) {

View file

@ -11,6 +11,7 @@ import mage.constants.*;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.token.AshiokNightmareMuseToken; import mage.game.permanent.token.AshiokNightmareMuseToken;
@ -20,8 +21,6 @@ import mage.target.common.TargetNonlandPermanent;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.filter.predicate.card.OwnerIdPredicate;
/** /**
* @author TheElk801 * @author TheElk801
@ -96,6 +95,10 @@ class AshiokNightmareMuseBounceEffect extends OneShotEffect {
class AshiokNightmareMuseCastEffect extends OneShotEffect { class AshiokNightmareMuseCastEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard("face-up cards your opponents own from exile"); private static final FilterCard filter = new FilterCard("face-up cards your opponents own from exile");
static {
filter.add(TargetController.OPPONENT.getOwnerPredicate());
filter.add(Predicates.not(FaceDownPredicate.instance));
}
AshiokNightmareMuseCastEffect() { AshiokNightmareMuseCastEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
@ -117,11 +120,10 @@ class AshiokNightmareMuseCastEffect extends OneShotEffect {
if (controller == null) { if (controller == null) {
return false; return false;
} }
// card is owned by an opponent and is face up
filter.add(Predicates.not(new OwnerIdPredicate(controller.getId())));
filter.add(Predicates.not(FaceDownPredicate.instance));
CardUtil.castMultipleWithAttributeForFree( CardUtil.castMultipleWithAttributeForFree(
controller, source, game, new CardsImpl(game.getExile().getCards(filter, game)), controller, source, game, new CardsImpl(
game.getExile().getCardsInRange(filter, controller.getId(), source, game)
),
StaticFilters.FILTER_CARD, 3 StaticFilters.FILTER_CARD, 3
); );
return true; return true;

View file

@ -90,7 +90,7 @@ class AshioksErasureExileEffect extends OneShotEffect {
|| spell == null) { || spell == null) {
return false; return false;
} }
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
return controller.moveCardsToExile(spell, source, game, true, exileId, sourceObject.getIdName()); return controller.moveCardsToExile(spell, source, game, true, exileId, sourceObject.getIdName());
} }
} }
@ -126,7 +126,7 @@ class AshioksErasureReplacementEffect extends ContinuousRuleModifyingEffectImpl
|| card == null) { || card == null) {
return false; return false;
} }
UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
ExileZone exile = game.getExile().getExileZone(exileZone); ExileZone exile = game.getExile().getExileZone(exileZone);
if (exile == null) { if (exile == null) {

View file

@ -3,7 +3,7 @@ package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
@ -12,19 +12,25 @@ import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.game.Game; import mage.filter.FilterPermanent;
import mage.game.permanent.Permanent; import mage.filter.predicate.permanent.AttachedToAttachedPredicate;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
* @author spjspj * @author spjspj
*/ */
public final class AuramancersGuise extends CardImpl { public final class AuramancersGuise extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("Aura attached to it");
static {
filter.add(SubType.AURA.getPredicate());
filter.add(AttachedToAttachedPredicate.instance);
}
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter, 2);
public AuramancersGuise(UUID ownerId, CardSetInfo setInfo) { public AuramancersGuise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}");
@ -39,7 +45,7 @@ public final class AuramancersGuise extends CardImpl {
// Enchanted creature gets +2/+2 for each Aura attached to it and has vigilance. // Enchanted creature gets +2/+2 for each Aura attached to it and has vigilance.
Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(
AuramancersGuiseValue.instance, AuramancersGuiseValue.instance, Duration.WhileOnBattlefield xValue, xValue, Duration.WhileOnBattlefield
)); ));
ability.addEffect(new GainAbilityAttachedEffect( ability.addEffect(new GainAbilityAttachedEffect(
VigilanceAbility.getInstance(), AttachmentType.AURA VigilanceAbility.getInstance(), AttachmentType.AURA
@ -57,40 +63,3 @@ public final class AuramancersGuise extends CardImpl {
} }
} }
enum AuramancersGuiseValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Permanent permanent = Optional
.ofNullable(sourceAbility.getSourcePermanentIfItStillExists(game))
.map(Permanent::getAttachedTo)
.map(game::getPermanent)
.orElse(null);
return permanent != null
? 2 * permanent
.getAttachments()
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.filter(p -> p.hasSubtype(SubType.AURA, game))
.mapToInt(x -> 1)
.sum()
: 0;
}
@Override
public AuramancersGuiseValue copy() {
return this;
}
@Override
public String getMessage() {
return "for each Aura attached to it";
}
@Override
public String toString() {
return "2";
}
}

View file

@ -73,7 +73,7 @@ class AuratouchedMageEffect extends OneShotEffect {
Card aura = game.getCard(target.getFirstTarget()); Card aura = game.getCard(target.getFirstTarget());
Permanent auratouchedMage = source.getSourcePermanentIfItStillExists(game); Permanent auratouchedMage = source.getSourcePermanentIfItStillExists(game);
if (aura != null && auratouchedMage != null if (aura != null && auratouchedMage != null
&& game.getState().getZoneChangeCounter(source.getSourceId()) == source.getSourceObjectZoneChangeCounter()) { && game.getState().getZoneChangeCounter(source.getSourceId()) == source.getStackMomentSourceZCC()) {
game.getState().setValue("attachTo:" + aura.getId(), auratouchedMage); game.getState().setValue("attachTo:" + aura.getId(), auratouchedMage);
if (controller.moveCards(aura, Zone.BATTLEFIELD, source, game)) { if (controller.moveCards(aura, Zone.BATTLEFIELD, source, game)) {
auratouchedMage.addAttachment(aura.getId(), source, game); auratouchedMage.addAttachment(aura.getId(), source, game);

View file

@ -111,7 +111,7 @@ class BagOfHoldingReturnCardsEffect extends OneShotEffect {
return false; return false;
} }
ExileZone exileZone = game.getExile().getExileZone( ExileZone exileZone = game.getExile().getExileZone(
CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()) CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC())
); );
if (exileZone == null) { if (exileZone == null) {
return true; return true;

View file

@ -0,0 +1,55 @@
package mage.cards.b;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.token.FoodAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class BagelAndSchmear extends CardImpl {
public BagelAndSchmear(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
this.subtype.add(SubType.FOOD);
// Share -- {W}, {T}, Sacrifice this artifact: Put a +1/+1 counter on up to one target creature. Draw a card. Activate only as a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{W}")
);
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
ability.addEffect(new DrawCardSourceControllerEffect(1));
ability.addTarget(new TargetCreaturePermanent(0, 1));
this.addAbility(ability.withFlavorWord("Share"));
// Nosh -- {2}, {T}, Sacrifice this artifact: You gain 3 life and draw a card.
ability = new FoodAbility();
ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and"));
this.addAbility(ability.withFlavorWord("Nosh"));
}
private BagelAndSchmear(final BagelAndSchmear card) {
super(card);
}
@Override
public BagelAndSchmear copy() {
return new BagelAndSchmear(this);
}
}
// where's the lox?

View file

@ -68,6 +68,6 @@ enum BalothCageTrapCondition implements Condition {
@Override @Override
public String toString() { public String toString() {
return "If an opponent had an artifact enter the battlefield under their control this turn"; return "an opponent had an artifact enter the battlefield under their control this turn";
} }
} }

View file

@ -36,7 +36,7 @@ public final class BalthierAndFran extends CardImpl {
= new FilterCreaturePermanent(SubType.VEHICLE, "a Vehicle crewed by {this} this turn"); = new FilterCreaturePermanent(SubType.VEHICLE, "a Vehicle crewed by {this} this turn");
static { static {
filter.add(BalthierAndFranPredicate.instance); filter2.add(BalthierAndFranPredicate.instance);
} }
public BalthierAndFran(UUID ownerId, CardSetInfo setInfo) { public BalthierAndFran(UUID ownerId, CardSetInfo setInfo) {

View file

@ -1,17 +1,13 @@
package mage.cards.b; package mage.cards.b;
import mage.abilities.Ability; import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.other.AnotherTargetPredicate; import mage.filter.predicate.other.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
@ -27,19 +23,19 @@ public final class BandTogether extends CardImpl {
static { static {
filter.add(new AnotherTargetPredicate(1)); filter.add(new AnotherTargetPredicate(1));
filter2.add(new AnotherTargetPredicate(2)); filter2.add(new AnotherTargetPredicate(3));
} }
public BandTogether(UUID ownerId, CardSetInfo setInfo) { public BandTogether(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}");
// Up to two target creatures you control each deal damage equal to their power to another target creature. // Up to two target creatures you control each deal damage equal to their power to another target creature.
this.getSpellAbility().addEffect(new BandTogetherEffect()); this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(true));
Target target = new TargetPermanent(0, 2, filter, false); Target target = new TargetPermanent(0, 2, filter, false);
target.setTargetTag(1); target.setTargetTag(1);
this.getSpellAbility().addTarget(target); this.getSpellAbility().addTarget(target);
target = new TargetPermanent(1, 1, filter2, false); target = new TargetPermanent(1, 1, filter2, false);
target.setTargetTag(2); target.setTargetTag(3);
this.getSpellAbility().addTarget(target); this.getSpellAbility().addTarget(target);
} }
@ -52,48 +48,3 @@ public final class BandTogether extends CardImpl {
return new BandTogether(this); return new BandTogether(this);
} }
} }
class BandTogetherEffect extends OneShotEffect {
BandTogetherEffect() {
super(Outcome.Benefit);
this.staticText = "Up to two target creatures you control each deal damage equal to their power to another target creature.";
}
private BandTogetherEffect(final BandTogetherEffect effect) {
super(effect);
}
@Override
public BandTogetherEffect copy() {
return new BandTogetherEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (source.getTargets().size() < 2) {
return false;
}
Target damageTarget = source.getTargets().get(0);
Target destTarget = source.getTargets().get(1);
if (damageTarget.getTargets().isEmpty() || destTarget.getTargets().isEmpty()) {
return false;
}
Permanent permanentDamage1 = damageTarget.getTargets().isEmpty() ? null : game.getPermanent(damageTarget.getTargets().get(0));
Permanent permanentDamage2 = damageTarget.getTargets().size() < 2 ? null : game.getPermanent(damageTarget.getTargets().get(1));
Permanent permanentDest = game.getPermanent(destTarget.getTargets().get(0));
if (permanentDest == null) {
return false;
}
if (permanentDamage1 != null) {
permanentDest.damage(permanentDamage1.getPower().getValue(), permanentDamage1.getId(), source, game, false, true);
}
if (permanentDamage2 != null) {
permanentDest.damage(permanentDamage2.getPower().getValue(), permanentDamage2.getId(), source, game, false, true);
}
return true;
}
}

View file

@ -121,11 +121,11 @@ class BeamsplitterMageTriggeredAbility extends TriggeredAbilityImpl {
private boolean checkNotSource(Permanent permanent, Game game) { private boolean checkNotSource(Permanent permanent, Game game) {
// workaround for zcc not being set before first intervening if check // workaround for zcc not being set before first intervening if check
if (this.getSourceObjectZoneChangeCounter() == 0) { if (this.getStackMomentSourceZCC() == 0) {
return !permanent.getId().equals(this.getSourceId()); return !permanent.getId().equals(this.getSourceId());
} }
return !permanent.getId().equals(this.getSourceId()) return !permanent.getId().equals(this.getSourceId())
|| permanent.getZoneChangeCounter(game) != this.getSourceObjectZoneChangeCounter(); || permanent.getZoneChangeCounter(game) != this.getStackMomentSourceZCC();
} }
@Override @Override

View file

@ -0,0 +1,91 @@
package mage.cards.b;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.FilterCard;
import mage.filter.common.FilterPermanentCard;
import mage.game.Game;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class BeholdTheSinisterSix extends CardImpl {
public BeholdTheSinisterSix(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{B}");
// Return up to six target creature cards with different names from your graveyard to the battlefield.
this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect());
this.getSpellAbility().addTarget(new BeholdTheSinisterSixTarget());
}
private BeholdTheSinisterSix(final BeholdTheSinisterSix card) {
super(card);
}
@Override
public BeholdTheSinisterSix copy() {
return new BeholdTheSinisterSix(this);
}
}
class BeholdTheSinisterSixTarget extends TargetCardInYourGraveyard {
private static final FilterCard filter = new FilterPermanentCard("creature cards with different names");
BeholdTheSinisterSixTarget() {
super(0, 6, filter, false);
}
private BeholdTheSinisterSixTarget(final BeholdTheSinisterSixTarget target) {
super(target);
}
@Override
public BeholdTheSinisterSixTarget copy() {
return new BeholdTheSinisterSixTarget(this);
}
@Override
public boolean canTarget(UUID playerId, UUID id, Ability ability, Game game) {
if (!super.canTarget(playerId, id, ability, game)) {
return false;
}
Set<String> names = this.getTargets()
.stream()
.map(game::getCard)
.map(MageObject::getName)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Card card = game.getCard(id);
return card != null && !names.contains(card.getName());
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
Set<String> names = this.getTargets()
.stream()
.map(game::getCard)
.map(MageObject::getName)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
possibleTargets.removeIf(uuid -> {
Card card = game.getCard(uuid);
return card != null && names.contains(card.getName());
});
return possibleTargets;
}
}

View file

@ -0,0 +1,60 @@
package mage.cards.b;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAttachToTarget;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.permanent.ModifiedPredicate;
import java.util.UUID;
/**
* @author Jmlundeen
*/
public final class BiorganicCarapace extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("each modified creature you control");
static {
filter.add(ModifiedPredicate.instance);
}
public BiorganicCarapace(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}{U}");
this.subtype.add(SubType.EQUIPMENT);
// When this Equipment enters, attach it to target creature you control.
this.addAbility(new EntersBattlefieldAttachToTarget());
// Equipped creature gets +2/+2 and has "Whenever this creature deals combat damage to a player, draw a card for each modified creature you control."
Ability gainedAbility = new DealsCombatDamageTriggeredAbility(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(filter)), false);
Ability equipAbility = new SimpleStaticAbility(new BoostEquippedEffect(2, 2));
equipAbility.addEffect(new GainAbilityAttachedEffect(gainedAbility, null)
.concatBy("and"));
this.addAbility(equipAbility);
// Equip {2}
this.addAbility(new EquipAbility(2));
}
private BiorganicCarapace(final BiorganicCarapace card) {
super(card);
}
@Override
public BiorganicCarapace copy() {
return new BiorganicCarapace(this);
}
}

View file

@ -88,7 +88,7 @@ class BiotransferenceEffect extends ContinuousEffectImpl {
} }
} }
// in Exile // in Exile
for (Card card : game.getState().getExile().getAllCards(game, source.getControllerId())) { for (Card card : game.getState().getExile().getCardsOwned(game, source.getControllerId())) {
if (card.isCreature(game) && !card.isArtifact(game)) { if (card.isCreature(game) && !card.isArtifact(game)) {
card.addCardType(game, CardType.ARTIFACT); card.addCardType(game, CardType.ARTIFACT);
} }

View file

@ -18,13 +18,11 @@ import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.game.ExileZone; import mage.game.ExileZone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.util.CardUtil; import mage.util.CardUtil;
import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE; import static mage.filter.StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE;
@ -87,7 +85,7 @@ class BishopOfBindingExileEffect extends OneShotEffect {
// the target creature won't be exiled. // the target creature won't be exiled.
if (permanent != null) { if (permanent != null) {
new ExileTargetEffect( new ExileTargetEffect(
CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), permanent.getIdName() CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC()), permanent.getIdName()
).apply(game, source); ).apply(game, source);
game.addDelayedTriggeredAbility(new OnLeaveReturnExiledAbility(), source); game.addDelayedTriggeredAbility(new OnLeaveReturnExiledAbility(), source);
return true; return true;
@ -101,7 +99,7 @@ enum BishopOfBindingValue implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, sourceAbility.getSourceId(), sourceAbility.getSourceObjectZoneChangeCounter())); ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, sourceAbility.getSourceId(), sourceAbility.getStackMomentSourceZCC()));
if (exileZone != null) { if (exileZone != null) {
Card exiledCard = exileZone.getRandom(game); Card exiledCard = exileZone.getRandom(game);
if (exiledCard != null) { if (exiledCard != null) {

View file

@ -0,0 +1,91 @@
package mage.cards.b;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileFaceDownYouMayPlayAsLongAsExiledTargetEffect;
import mage.cards.*;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetOpponent;
import mage.target.targetpointer.FixedTargets;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
* @author Jmlundeen
*/
public final class BlackCatCunningThief extends CardImpl {
public BlackCatCunningThief(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ROGUE);
this.subtype.add(SubType.VILLAIN);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// When Black Cat enters, look at the top nine cards of target opponent's library, exile two of them face down, then put the rest on the bottom of their library in a random order. You may play the exiled cards for as long as they remain exiled. Mana of any type can be spent to cast spells this way.
Ability ability = new EntersBattlefieldTriggeredAbility(new BlackCatCunningThiefEffect());
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
private BlackCatCunningThief(final BlackCatCunningThief card) {
super(card);
}
@Override
public BlackCatCunningThief copy() {
return new BlackCatCunningThief(this);
}
}
class BlackCatCunningThiefEffect extends OneShotEffect {
BlackCatCunningThiefEffect() {
super(Outcome.Benefit);
this.staticText = "look at the top nine cards of target opponent's library, exile two of them face down, then put the rest on the bottom of their library in a random order. You may play the exiled cards for as long as they remain exiled. Mana of any type can be spent to cast spells this way";
}
private BlackCatCunningThiefEffect(final BlackCatCunningThiefEffect effect) {
super(effect);
}
@Override
public BlackCatCunningThiefEffect copy() {
return new BlackCatCunningThiefEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
MageObject sourceObject = source.getSourceObject(game);
if (controller == null || opponent == null || sourceObject == null) {
return false;
}
Cards topCards = new CardsImpl();
topCards.addAllCards(opponent.getLibrary().getTopCards(game, 9));
TargetCard target = new TargetCard(2, 2, Zone.LIBRARY, new FilterCard("card to exile"));
controller.choose(outcome, topCards, target, source, game);
Cards exiledCards = new CardsImpl(target.getTargets().stream()
.map(game::getCard)
.collect(Collectors.toList()));
new ExileFaceDownYouMayPlayAsLongAsExiledTargetEffect(false, CastManaAdjustment.AS_THOUGH_ANY_MANA_TYPE)
.setTargetPointer(new FixedTargets(exiledCards, game))
.apply(game, source);
topCards.retainZone(Zone.LIBRARY, game);
// then put the rest on the bottom of that library in a random order
controller.putCardsOnBottomOfLibrary(topCards, game, source, false);
return true;
}
}

View file

@ -28,7 +28,7 @@ public final class BlasphemousEdict extends CardImpl {
// You may pay {B} rather than pay this spell's mana cost if there are thirteen or more creatures on the battlefield. // You may pay {B} rather than pay this spell's mana cost if there are thirteen or more creatures on the battlefield.
Ability ability = new AlternativeCostSourceAbility(new ManaCostsImpl<>("{B}"), new PermanentsOnTheBattlefieldCondition( Ability ability = new AlternativeCostSourceAbility(new ManaCostsImpl<>("{B}"), new PermanentsOnTheBattlefieldCondition(
new FilterCreaturePermanent("If there are thirteen or more creatures on the battlefield"), new FilterCreaturePermanent("there are thirteen or more creatures on the battlefield"),
ComparisonType.OR_GREATER, ComparisonType.OR_GREATER,
13, 13,
false false

View file

@ -59,7 +59,7 @@ enum BlazingEffigyCount implements DynamicValue {
if (watcher == null) { if (watcher == null) {
return 3; return 3;
} }
int effigyDamage = watcher.damageDoneTo(sourceAbility.getSourceId(), sourceAbility.getSourceObjectZoneChangeCounter() - 1, game); int effigyDamage = watcher.damageDoneTo(sourceAbility.getSourceId(), sourceAbility.getStackMomentSourceZCC() - 1, game);
return CardUtil.overflowInc(3, effigyDamage); return CardUtil.overflowInc(3, effigyDamage);
} }

View file

@ -1,4 +1,3 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID; import java.util.UUID;
@ -34,7 +33,9 @@ public final class Blight extends CardImpl {
this.addAbility(ability); this.addAbility(ability);
// When enchanted land becomes tapped, destroy it. // When enchanted land becomes tapped, destroy it.
this.addAbility(new BecomesTappedAttachedTriggeredAbility(new DestroyAttachedToEffect("it"), "enchanted land")); this.addAbility(new BecomesTappedAttachedTriggeredAbility(
new DestroyAttachedToEffect("it"), "enchanted land"
).setTriggerPhrase("When enchanted land becomes tapped, "));
} }
private Blight(final Blight card) { private Blight(final Blight card) {

View file

@ -74,11 +74,11 @@ class BogardanPhoenixEffect extends OneShotEffect {
if (permanent == null if (permanent == null
|| controller == null || controller == null
|| permanent.getZoneChangeCounter(game) + 1 || permanent.getZoneChangeCounter(game) + 1
!= source.getSourceObjectZoneChangeCounter()) { != source.getStackMomentSourceZCC()) {
return false; return false;
} }
Card card = game.getCard(permanent.getId()); Card card = game.getCard(permanent.getId());
if (card == null || card.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter()) { if (card == null || card.getZoneChangeCounter(game) != source.getStackMomentSourceZCC()) {
return false; return false;
} }
if (permanent.getCounters(game).containsKey(CounterType.DEATH)) { if (permanent.getCounters(game).containsKey(CounterType.DEATH)) {

View file

@ -1,8 +1,8 @@
package mage.cards.b; package mage.cards.b;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility;
import mage.abilities.effects.common.CopySourceSpellEffect; import mage.abilities.effects.common.CopySourceSpellEffect;
@ -13,20 +13,25 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.AttachmentType; import mage.constants.AttachmentType;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.game.Game; import mage.filter.FilterPermanent;
import mage.game.permanent.Permanent; import mage.filter.predicate.permanent.AttachedToAttachedPredicate;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Stream;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class BrassKnuckles extends CardImpl { public final class BrassKnuckles extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("Equipment attached to it");
static {
filter.add(SubType.EQUIPMENT.getPredicate());
filter.add(AttachedToAttachedPredicate.instance);
}
private static final Condition twoEquipmentAttachedToAttached = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.OR_GREATER, 2);
public BrassKnuckles(UUID ownerId, CardSetInfo setInfo) { public BrassKnuckles(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
@ -40,7 +45,7 @@ public final class BrassKnuckles extends CardImpl {
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilityAttachedEffect( new GainAbilityAttachedEffect(
DoubleStrikeAbility.getInstance(), AttachmentType.EQUIPMENT DoubleStrikeAbility.getInstance(), AttachmentType.EQUIPMENT
), BrassKnucklesCondition.instance, "equipped creature has double strike " + ), twoEquipmentAttachedToAttached, "equipped creature has double strike " +
"as long as two or more Equipment are attached to it" "as long as two or more Equipment are attached to it"
))); )));
@ -57,23 +62,3 @@ public final class BrassKnuckles extends CardImpl {
return new BrassKnuckles(this); return new BrassKnuckles(this);
} }
} }
enum BrassKnucklesCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
return Optional
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.map(Permanent::getAttachedTo)
.map(game::getPermanent)
.map(Permanent::getAttachments)
.map(Collection::stream)
.map(stream -> stream.map(game::getPermanent))
.map(stream -> stream.filter(Objects::nonNull))
.map(stream -> stream.filter(p -> p.hasSubtype(SubType.EQUIPMENT, game)))
.map(Stream::count)
.map(x -> x >= 2)
.orElse(false);
}
}

View file

@ -9,6 +9,7 @@ import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
@ -28,7 +29,7 @@ public final class CallToTheGrave extends CardImpl {
} }
private static final Condition condition = new PermanentsOnTheBattlefieldCondition( private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
new FilterCreaturePermanent("no creatures are on the battlefield"), false new FilterCreaturePermanent("no creatures are on the battlefield"), ComparisonType.EQUAL_TO, 0, false
); );
public CallToTheGrave(UUID ownerId, CardSetInfo setInfo) { public CallToTheGrave(UUID ownerId, CardSetInfo setInfo) {

View file

@ -40,7 +40,7 @@ public final class CallousBloodmage extends CardImpl {
ability.addMode(mode); ability.addMode(mode);
// Exile target player's graveyard. // Exile target player's graveyard.
mode = new Mode(new ExileGraveyardAllTargetPlayerEffect().setText("exile target player's graveyard")); mode = new Mode(new ExileGraveyardAllTargetPlayerEffect());
mode.addTarget(new TargetPlayer()); mode.addTarget(new TargetPlayer());
ability.addMode(mode); ability.addMode(mode);
this.addAbility(ability); this.addAbility(ability);

View file

@ -65,7 +65,7 @@ enum CandlekeepInspirationValue implements DynamicValue {
.getCards(game) .getCards(game)
.stream(), .stream(),
game.getExile() game.getExile()
.getAllCards(game, sourceAbility.getControllerId()) .getCardsOwned(game, sourceAbility.getControllerId())
.stream() .stream()
) )
.filter(Objects::nonNull) .filter(Objects::nonNull)

View file

@ -0,0 +1,116 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksEachCombatStaticAbility;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.MayhemAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class CarnageCrimsonChaos extends CardImpl {
private static final FilterCard filter = new FilterCard("creature card with mana value 3 or less");
static {
filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3));
}
public CarnageCrimsonChaos(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SYMBIOTE);
this.subtype.add(SubType.VILLAIN);
this.power = new MageInt(4);
this.toughness = new MageInt(3);
// Trample
this.addAbility(TrampleAbility.getInstance());
// When Carnage enters, return target creature card with mana value 3 or less from your graveyard to the battlefield. It gains "This creature attacks each combat if able" and "When this creature deals combat damage to a player, sacrifice it."
Ability ability = new EntersBattlefieldTriggeredAbility(new CarnageCrimsonChaosReturnEffect());
ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability);
// Mayhem {B}{R}
this.addAbility(new MayhemAbility(this, "{B}{R}"));
}
private CarnageCrimsonChaos(final CarnageCrimsonChaos card) {
super(card);
}
@Override
public CarnageCrimsonChaos copy() {
return new CarnageCrimsonChaos(this);
}
}
class CarnageCrimsonChaosReturnEffect extends OneShotEffect {
CarnageCrimsonChaosReturnEffect() {
super(Outcome.PutCreatureInPlay);
this.staticText = "return target creature card with mana value 3 or less from your graveyard to the battlefield. It gains \"This creature attacks each combat if able\" and \"When this creature deals combat damage to a player, sacrifice it.\"";
}
protected CarnageCrimsonChaosReturnEffect(final CarnageCrimsonChaosReturnEffect effect) {
super(effect);
}
@Override
public CarnageCrimsonChaosReturnEffect copy() {
return new CarnageCrimsonChaosReturnEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Card card = game.getCard(source.getFirstTarget());
if (card == null) {
return false;
}
controller.moveCards(card, Zone.BATTLEFIELD, source, game);
Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game);
if (permanent == null) {
return false;
}
Ability attacksEachTurnAbility = new AttacksEachCombatStaticAbility();
Ability damageTriggerAbility = new DealsCombatDamageToAPlayerTriggeredAbility(new SacrificeSourceEffect());
ContinuousEffect effectOne = new GainAbilityTargetEffect(attacksEachTurnAbility, Duration.WhileOnBattlefield);
effectOne.setTargetPointer(new FixedTarget(permanent, game));
ContinuousEffect effectTwo = new GainAbilityTargetEffect(damageTriggerAbility, Duration.WhileOnBattlefield);
effectTwo.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effectOne, source);
game.addEffect(effectTwo, source);
return true;
}
}

View file

@ -63,6 +63,8 @@ class CelestialDawnToPlainsEffect extends ContinuousEffectImpl {
CelestialDawnToPlainsEffect() { CelestialDawnToPlainsEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment); super(Duration.WhileOnBattlefield, Outcome.Detriment);
this.staticText = "Lands you control are Plains"; this.staticText = "Lands you control are Plains";
this.dependendToTypes.add(DependencyType.BecomeNonbasicLand);
this.dependencyTypes.add(DependencyType.BecomePlains);
} }
private CelestialDawnToPlainsEffect(final CelestialDawnToPlainsEffect effect) { private CelestialDawnToPlainsEffect(final CelestialDawnToPlainsEffect effect) {
@ -126,7 +128,7 @@ class CelestialDawnToWhiteEffect extends ContinuousEffectImpl {
} }
} }
// Exile // Exile
for (Card card : game.getExile().getAllCards(game)) { for (Card card : game.getExile().getCardsInRange(game, controller.getId())) {
if (card.isOwnedBy(controller.getId())) { if (card.isOwnedBy(controller.getId())) {
setColor(card.getColor(game), game); setColor(card.getColor(game), game);
} }

View file

@ -86,7 +86,7 @@ class CemeteryGatekeeperEffect extends OneShotEffect {
controller.choose(outcome, target, source, game); controller.choose(outcome, target, source, game);
Card card = game.getCard(target.getFirstTarget()); Card card = game.getCard(target.getFirstTarget());
if (card != null) { if (card != null) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
String exileName = sourceObject == null ? null : sourceObject.getIdName(); String exileName = sourceObject == null ? null : sourceObject.getIdName();
return controller.moveCardsToExile(card, source, game, true, exileId, exileName); return controller.moveCardsToExile(card, source, game, true, exileId, exileName);

View file

@ -92,7 +92,7 @@ class CemeteryIlluminatorExileEffect extends OneShotEffect {
controller.choose(outcome, target, source, game); controller.choose(outcome, target, source, game);
Card card = game.getCard(target.getFirstTarget()); Card card = game.getCard(target.getFirstTarget());
if (card != null) { if (card != null) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
String exileName = sourceObject == null ? null : sourceObject.getIdName(); String exileName = sourceObject == null ? null : sourceObject.getIdName();
return controller.moveCardsToExile(card, source, game, true, exileId, exileName); return controller.moveCardsToExile(card, source, game, true, exileId, exileName);

View file

@ -87,7 +87,7 @@ class CemeteryProtectorEffect extends OneShotEffect {
controller.choose(outcome, target, source, game); controller.choose(outcome, target, source, game);
Card card = game.getCard(target.getFirstTarget()); Card card = game.getCard(target.getFirstTarget());
if (card != null) { if (card != null) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
String exileName = sourceObject == null ? null : sourceObject.getIdName(); String exileName = sourceObject == null ? null : sourceObject.getIdName();
return controller.moveCardsToExile(card, source, game, true, exileId, exileName); return controller.moveCardsToExile(card, source, game, true, exileId, exileName);

View file

@ -79,7 +79,7 @@ class CemeteryProwlerExileEffect extends OneShotEffect {
controller.choose(outcome, target, source, game); controller.choose(outcome, target, source, game);
Card card = game.getCard(target.getFirstTarget()); Card card = game.getCard(target.getFirstTarget());
if (card != null) { if (card != null) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
String exileName = sourceObject == null ? null : sourceObject.getIdName(); String exileName = sourceObject == null ? null : sourceObject.getIdName();
return controller.moveCardsToExile(card, source, game, true, exileId, exileName); return controller.moveCardsToExile(card, source, game, true, exileId, exileName);

View file

@ -141,14 +141,14 @@ class ChainerNightmareAdeptWatcher extends Watcher {
return false; return false;
} }
MageObjectReference mor = new MageObjectReference( MageObjectReference mor = new MageObjectReference(
source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game source.getSourceId(), source.getStackMomentSourceZCC(), game
); );
return morMap.computeIfAbsent(mor, m -> new HashMap<>()).getOrDefault(playerId, 0) > 0; return morMap.computeIfAbsent(mor, m -> new HashMap<>()).getOrDefault(playerId, 0) > 0;
} }
void addPlayable(Ability source, Game game) { void addPlayable(Ability source, Game game) {
MageObjectReference mor = new MageObjectReference( MageObjectReference mor = new MageObjectReference(
source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game source.getSourceId(), source.getStackMomentSourceZCC(), game
); );
morMap.computeIfAbsent(mor, m -> new HashMap<>()) morMap.computeIfAbsent(mor, m -> new HashMap<>())
.compute(source.getControllerId(), CardUtil::setOrIncrementValue); .compute(source.getControllerId(), CardUtil::setOrIncrementValue);

View file

@ -0,0 +1,65 @@
package mage.cards.c;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.effects.common.CopyPermanentEffect;
import mage.abilities.keyword.MayhemAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.util.functions.CopyApplier;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ChameleonMasterOfDisguise extends CardImpl {
private static final CopyApplier applier = new CopyApplier() {
@Override
public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) {
blueprint.setName("Chameleon, Master of Disguise");
return true;
}
@Override
public String getText() {
return ", except his name is Chameleon, Master of Disguise";
}
};
public ChameleonMasterOfDisguise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SHAPESHIFTER);
this.subtype.add(SubType.VILLAIN);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// You may have Chameleon enter as a copy of a creature you control, except his name is Chameleon, Master of Disguise.
this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect(
StaticFilters.FILTER_CONTROLLED_CREATURE, applier
), true));
// Mayhem {2}{U}
this.addAbility(new MayhemAbility(this, "{2}{U}"));
}
private ChameleonMasterOfDisguise(final ChameleonMasterOfDisguise card) {
super(card);
}
@Override
public ChameleonMasterOfDisguise copy() {
return new ChameleonMasterOfDisguise(this);
}
}

View file

@ -97,7 +97,7 @@ class ChandraDressedToKillExile1Effect extends OneShotEffect {
if (card == null) { if (card == null) {
return false; return false;
} }
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
String exileName = sourceObject == null ? null : sourceObject.getIdName(); String exileName = sourceObject == null ? null : sourceObject.getIdName();
controller.moveCardsToExile(card, source, game, true, exileId, exileName); controller.moveCardsToExile(card, source, game, true, exileId, exileName);
@ -135,7 +135,7 @@ class ChandraDressedToKillExile5Effect extends OneShotEffect {
if (cards.isEmpty()) { if (cards.isEmpty()) {
return false; return false;
} }
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
String exileName = sourceObject == null ? null : sourceObject.getIdName(); String exileName = sourceObject == null ? null : sourceObject.getIdName();
controller.moveCardsToExile(cards, source, game, true, exileId, exileName); controller.moveCardsToExile(cards, source, game, true, exileId, exileName);

View file

@ -0,0 +1,100 @@
package mage.cards.c;
import mage.MageInt;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.PutCountersSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class CheeringCrowd extends CardImpl {
public CheeringCrowd(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R/G}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CITIZEN);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// At the beginning of each player's first main phase, that player may put a +1/+1 counter on this creature. If they do, they add {C} for each counter on it.
this.addAbility(new BeginningOfFirstMainTriggeredAbility(TargetController.EACH_PLAYER, new CheeringCrowdDoIfPaidEffect(), false));
}
private CheeringCrowd(final CheeringCrowd card) {
super(card);
}
@Override
public CheeringCrowd copy() {
return new CheeringCrowd(this);
}
}
class CheeringCrowdDoIfPaidEffect extends DoIfCostPaid {
CheeringCrowdDoIfPaidEffect() {
super(new CheeringCrowdEffect(), new PutCountersSourceCost(CounterType.P1P1.createInstance()),
"Put a +1/+1 counter on Cheering Crowd and add {C} for each counter on it?", true);
staticText = "that player may put a +1/+1 counter on this creature. If they do, they add {C} for each counter on it";
}
private CheeringCrowdDoIfPaidEffect(final CheeringCrowdDoIfPaidEffect effect) {
super(effect);
}
@Override
public CheeringCrowdDoIfPaidEffect copy() {
return new CheeringCrowdDoIfPaidEffect(this);
}
@Override
protected Player getPayingPlayer(Game game, Ability source) {
return game.getPlayer(getTargetPointer().getFirst(game, source));
}
}
class CheeringCrowdEffect extends OneShotEffect {
public CheeringCrowdEffect() {
super(Outcome.PutManaInPool);
staticText = "they add {C} for each counter on it";
}
protected CheeringCrowdEffect(final CheeringCrowdEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
Permanent permanent = source.getSourcePermanentOrLKI(game);
if (player == null || permanent == null) {
return false;
}
int counterCounter = permanent.getCounters(game).getCount(CounterType.P1P1);
player.getManaPool().addMana(Mana.ColorlessMana(counterCounter), game, source);
return true;
}
@Override
public CheeringCrowdEffect copy() {
return new CheeringCrowdEffect(this);
}
}

View file

@ -164,7 +164,7 @@ class ChissGoriaForgeTyrantAffinityEffect extends ContinuousEffectImpl {
return false; return false;
} }
for (Card card : game.getExile().getAllCardsByRange(game, source.getControllerId())) { for (Card card : game.getExile().getCardsInRange(game, source.getControllerId())) {
if (morSet.contains(new MageObjectReference(card, game)) && card.isArtifact(game)) { if (morSet.contains(new MageObjectReference(card, game)) && card.isArtifact(game)) {
game.getState().addOtherAbility(card, new AffinityForArtifactsAbility()); game.getState().addOtherAbility(card, new AffinityForArtifactsAbility());
} }

View file

@ -41,7 +41,7 @@ public final class ChoArrimLegate extends CardImpl {
this.addAbility(ProtectionAbility.from(ObjectColor.BLACK)); this.addAbility(ProtectionAbility.from(ObjectColor.BLACK));
// If an opponent controls a Swamp and you control a Plains, you may cast this spell without paying its mana cost. // If an opponent controls a Swamp and you control a Plains, you may cast this spell without paying its mana cost.
Condition condition = new CompoundCondition("If an opponent controls a Swamp and you control a Plains", Condition condition = new CompoundCondition("an opponent controls a Swamp and you control a Plains",
new OpponentControlsPermanentCondition(filterSwamp), new OpponentControlsPermanentCondition(filterSwamp),
new PermanentsOnTheBattlefieldCondition(filterPlains)); new PermanentsOnTheBattlefieldCondition(filterPlains));
this.addAbility(new AlternativeCostSourceAbility(null, condition)); this.addAbility(new AlternativeCostSourceAbility(null, condition));

View file

@ -3,13 +3,14 @@ package mage.cards.c;
import java.util.UUID; import java.util.UUID;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.DependencyType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
/** /**
@ -21,7 +22,10 @@ public final class ChromaticLantern extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
// Lands you control have "{T}: Add one mana of any color." // Lands you control have "{T}: Add one mana of any color."
this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(new AnyColorManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS, false))); ContinuousEffect effect = new GainAbilityControlledEffect(new AnyColorManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS, false);
effect.getDependedToTypes().add(DependencyType.BecomeNonbasicLand);
this.addAbility(new SimpleStaticAbility(effect));
// {T}: Add one mana of any color. // {T}: Add one mana of any color.
this.addAbility(new AnyColorManaAbility()); this.addAbility(new AnyColorManaAbility());

View file

@ -0,0 +1,42 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.game.permanent.token.FoodToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CityPigeon extends CardImpl {
public CityPigeon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}");
this.subtype.add(SubType.BIRD);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Flying
this.addAbility(FlyingAbility.getInstance());
// When this creature leaves the battlefield, create a Food token.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken())));
}
private CityPigeon(final CityPigeon card) {
super(card);
}
@Override
public CityPigeon copy() {
return new CityPigeon(this);
}
}

View file

@ -66,7 +66,7 @@ class ClockworkBeetleEffect extends OneShotEffect {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) { if (permanent != null) {
Effect effect = new RemoveCounterTargetEffect(CounterType.P1P1.createInstance()); Effect effect = new RemoveCounterTargetEffect(CounterType.P1P1.createInstance());
effect.setTargetPointer(new FixedTarget(source.getSourceId(), source.getSourceObjectZoneChangeCounter())); effect.setTargetPointer(new FixedTarget(source.getSourceId(), source.getStackMomentSourceZCC()));
game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(effect), source); game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(effect), source);
return true; return true;
} }

View file

@ -60,7 +60,7 @@ enum CobraTrapCondition implements Condition {
@Override @Override
public String toString() { public String toString() {
return "If a noncreature permanent under your control was destroyed this turn by a spell or ability an opponent controlled"; return "a noncreature permanent under your control was destroyed this turn by a spell or ability an opponent controlled";
} }
} }

View file

@ -1,15 +1,11 @@
package mage.cards.c; package mage.cards.c;
import mage.abilities.Ability; import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterTeamCreaturePermanent; import mage.filter.common.FilterTeamCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
@ -26,9 +22,9 @@ public final class ComboAttack extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}");
// Two target creatures your team controls each deal damage equal to their power to target creature. // Two target creatures your team controls each deal damage equal to their power to target creature.
this.getSpellAbility().addEffect(new ComboAttackEffect()); this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(true));
this.getSpellAbility().addTarget(new TargetPermanent(2, filter)); this.getSpellAbility().addTarget(new TargetPermanent(2, filter).setTargetTag(1));
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(3));
} }
private ComboAttack(final ComboAttack card) { private ComboAttack(final ComboAttack card) {
@ -40,41 +36,3 @@ public final class ComboAttack extends CardImpl {
return new ComboAttack(this); return new ComboAttack(this);
} }
} }
class ComboAttackEffect extends OneShotEffect {
ComboAttackEffect() {
super(Outcome.Benefit);
this.staticText = "Two target creatures your team controls each deal damage equal to their power to target creature";
}
private ComboAttackEffect(final ComboAttackEffect effect) {
super(effect);
}
@Override
public ComboAttackEffect copy() {
return new ComboAttackEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (source.getTargets().size() < 2) {
return false;
}
Permanent permanent3 = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (permanent3 == null) {
return false;
}
// You cant cast Combo Attack without targeting two creatures your team controls.
// If one of those creatures is an illegal target as Combo Attack resolves,
// the other will still deal damage equal to its power. (2018-06-08)
for (UUID id : source.getTargets().get(0).getTargets()) {
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
permanent3.damage(permanent.getPower().getValue(), permanent.getId(), source, game);
}
}
return true;
}
}

View file

@ -0,0 +1,40 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.game.permanent.token.TreasureToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CommonCrook extends CardImpl {
public CommonCrook(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ROGUE);
this.subtype.add(SubType.VILLAIN);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// When this creature dies, create a Treasure token.
this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new TreasureToken())));
}
private CommonCrook(final CommonCrook card) {
super(card);
}
@Override
public CommonCrook copy() {
return new CommonCrook(this);
}
}

View file

@ -1,8 +1,7 @@
package mage.cards.c; package mage.cards.c;
import mage.abilities.Ability; import mage.abilities.common.delayed.CastNextSpellDelayedTriggeredAbility;
import mage.abilities.common.delayed.CopyNextSpellDelayedTriggeredAbility; import mage.abilities.effects.common.CopyTargetStackObjectEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect;
import mage.abilities.keyword.ConvokeAbility; import mage.abilities.keyword.ConvokeAbility;
@ -10,11 +9,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.stack.Spell;
import java.util.UUID; import java.util.UUID;
@ -40,10 +36,9 @@ public final class CompleteTheCircuit extends CardImpl {
// When you next cast an instant or sorcery spell this turn, copy that spell twice. You may choose new targets for the copies. // When you next cast an instant or sorcery spell this turn, copy that spell twice. You may choose new targets for the copies.
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(
new CopyNextSpellDelayedTriggeredAbility( new CastNextSpellDelayedTriggeredAbility(
StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, new CopyTargetStackObjectEffect(false, true, true, 2, null),
new CompleteTheCircuitEffect(), "When you next cast an instant or sorcery spell " + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, true
"this turn, copy that spell twice. You may choose new targets for the copies."
) )
).concatBy("<br>")); ).concatBy("<br>"));
} }
@ -57,29 +52,3 @@ public final class CompleteTheCircuit extends CardImpl {
return new CompleteTheCircuit(this); return new CompleteTheCircuit(this);
} }
} }
class CompleteTheCircuitEffect extends OneShotEffect {
CompleteTheCircuitEffect() {
super(Outcome.Benefit);
}
private CompleteTheCircuitEffect(final CompleteTheCircuitEffect effect) {
super(effect);
}
@Override
public CompleteTheCircuitEffect copy() {
return new CompleteTheCircuitEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = (Spell) getValue("spellCast");
if (spell != null) {
spell.createCopyOnStack(game, source, source.getControllerId(), true, 2);
return true;
}
return false;
}
}

View file

@ -6,11 +6,10 @@ import mage.abilities.keyword.ReplicateAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.FilterSpell;
import mage.filter.FilterStackObject; import mage.filter.FilterStackObject;
import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicate;
import mage.filter.predicate.mageobject.ColorlessPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell;
import mage.game.stack.StackObject; import mage.game.stack.StackObject;
import mage.target.TargetStackObject; import mage.target.TargetStackObject;
@ -31,7 +30,6 @@ public final class ConsignToMemory extends CardImpl {
public ConsignToMemory(UUID ownerId, CardSetInfo setInfo) { public ConsignToMemory(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
// Replicate {1} // Replicate {1}
this.addAbility(new ReplicateAbility("{1}")); this.addAbility(new ReplicateAbility("{1}"));
@ -53,18 +51,11 @@ public final class ConsignToMemory extends CardImpl {
enum ConsignToMemoryPredicate implements Predicate<StackObject> { enum ConsignToMemoryPredicate implements Predicate<StackObject> {
instance; instance;
private static final FilterSpell filterSpell = new FilterSpell("colorless spell");
static {
filterSpell.add(ColorlessPredicate.instance);
}
@Override @Override
public boolean apply(StackObject input, Game game) { public boolean apply(StackObject input, Game game) {
if (input instanceof Ability) { if (input instanceof Spell) {
Ability ability = (Ability) input; return input.getColor(game).isColorless();
return ability.getAbilityType().isTriggeredAbility();
} }
return filterSpell.match(input, game); return input instanceof Ability && ((Ability) input).isTriggeredAbility();
} }
} }

View file

@ -92,14 +92,14 @@ public final class Conspiracy extends CardImpl {
} }
} }
// in Exile // in Exile
for (Card card : game.getState().getExile().getAllCards(game)) { for (Card card : game.getState().getExile().getCardsOwned(game, controller.getId())) {
if (card.isOwnedBy(controller.getId()) && card.isCreature(game)) { if (card.isCreature(game)) {
setCreatureSubtype(card, subType, game); setCreatureSubtype(card, subType, game);
} }
} }
// in Library (e.g. for Mystical Teachings) // in Library (e.g. for Mystical Teachings)
for (Card card : controller.getLibrary().getCards(game)) { for (Card card : controller.getLibrary().getCards(game)) {
if (card.isOwnedBy(controller.getId()) && card.isCreature(game)) { if (card.isCreature(game)) {
setCreatureSubtype(card, subType, game); setCreatureSubtype(card, subType, game);
} }
} }

View file

@ -54,6 +54,12 @@ public final class Conversion extends CardImpl {
ConversionEffect() { ConversionEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment); super(Duration.WhileOnBattlefield, Outcome.Detriment);
this.staticText = "All Mountains are Plains"; this.staticText = "All Mountains are Plains";
this.dependendToTypes.add(DependencyType.BecomeForest);
this.dependendToTypes.add(DependencyType.BecomeIsland);
this.dependendToTypes.add(DependencyType.BecomeMountain);
this.dependendToTypes.add(DependencyType.BecomePlains);
this.dependendToTypes.add(DependencyType.BecomeSwamp);
this.dependencyTypes.add(DependencyType.BecomePlains);
} }
private ConversionEffect(final ConversionEffect effect) { private ConversionEffect(final ConversionEffect effect) {

View file

@ -1,21 +1,15 @@
package mage.cards.c; package mage.cards.c;
import mage.abilities.Ability; import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetOpponentsCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.List;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* @author TheElk801 * @author TheElk801
@ -26,11 +20,12 @@ public final class CoordinatedClobbering extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}");
// Tap one or two target untapped creatures you control. They each deal damage equal to their power to target creature an opponent controls. // Tap one or two target untapped creatures you control. They each deal damage equal to their power to target creature an opponent controls.
this.getSpellAbility().addEffect(new CoordinatedClobberingEffect()); this.getSpellAbility().addEffect(new TapTargetEffect());
this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(false));
this.getSpellAbility().addTarget(new TargetPermanent( this.getSpellAbility().addTarget(new TargetPermanent(
1, 2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES 1, 2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES
)); ).setTargetTag(1));
this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent().setTargetTag(3));
} }
private CoordinatedClobbering(final CoordinatedClobbering card) { private CoordinatedClobbering(final CoordinatedClobbering card) {
@ -42,48 +37,4 @@ public final class CoordinatedClobbering extends CardImpl {
return new CoordinatedClobbering(this); return new CoordinatedClobbering(this);
} }
} }
class CoordinatedClobberingEffect extends OneShotEffect {
CoordinatedClobberingEffect() {
super(Outcome.Benefit);
staticText = "tap one or two target untapped creatures you control. " +
"They each deal damage equal to their power to target creature an opponent controls";
}
private CoordinatedClobberingEffect(final CoordinatedClobberingEffect effect) {
super(effect);
}
@Override
public CoordinatedClobberingEffect copy() {
return new CoordinatedClobberingEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
List<Permanent> permanents = this
.getTargetPointer()
.getTargets(game, source)
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (permanents.isEmpty()) {
return false;
}
for (Permanent permanent : permanents) {
permanent.tap(source, game);
}
Permanent targetPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (targetPermanent == null) {
return true;
}
game.processAction();
for (Permanent permanent : permanents) {
targetPermanent.damage(permanent.getPower().getValue(), permanent.getId(), source, game);
}
return true;
}
}
// flame on! // flame on!

View file

@ -79,7 +79,7 @@ class CorrosiveOozeEffect extends OneShotEffect {
if (watcher == null) { if (watcher == null) {
return false; return false;
} }
MageObjectReference sourceMor = new MageObjectReference(source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game); MageObjectReference sourceMor = new MageObjectReference(source.getSourceId(), source.getStackMomentSourceZCC(), game);
List<Permanent> equipments = watcher.getEquipmentsToDestroy(sourceMor) List<Permanent> equipments = watcher.getEquipmentsToDestroy(sourceMor)
.stream() .stream()
.map(mor -> mor.getPermanent(game)) .map(mor -> mor.getPermanent(game))

View file

@ -0,0 +1,77 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.*;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CosmicSpiderMan extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent(SubType.SPIDER, "Spiders");
public CosmicSpiderMan(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SPIDER);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.HERO);
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// Flying
this.addAbility(FlyingAbility.getInstance());
// First strike
this.addAbility(FirstStrikeAbility.getInstance());
// Trample
this.addAbility(TrampleAbility.getInstance());
// Lifelink
this.addAbility(LifelinkAbility.getInstance());
// Haste
this.addAbility(HasteAbility.getInstance());
// At the beginning of combat on your turn, other Spiders you control gain flying, first strike, trample, lifelink, and haste until end of turn.
Ability ability = new BeginningOfCombatTriggeredAbility(new GainAbilityControlledEffect(
FlyingAbility.getInstance(), Duration.EndOfTurn, filter, true
).setText("other Spiders you control gain flying"));
ability.addEffect(new GainAbilityControlledEffect(
FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filter, true
).setText(", first strike"));
ability.addEffect(new GainAbilityControlledEffect(
TrampleAbility.getInstance(), Duration.EndOfTurn, filter, true
).setText(", trample"));
ability.addEffect(new GainAbilityControlledEffect(
LifelinkAbility.getInstance(), Duration.EndOfTurn, filter, true
).setText(", lifelink"));
ability.addEffect(new GainAbilityControlledEffect(
HasteAbility.getInstance(), Duration.EndOfTurn, filter, true
).setText(", and haste until end of turn"));
this.addAbility(ability);
}
private CosmicSpiderMan(final CosmicSpiderMan card) {
super(card);
}
@Override
public CosmicSpiderMan copy() {
return new CosmicSpiderMan(this);
}
}

View file

@ -56,7 +56,7 @@ enum CosmogoyfValue implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
return game.getState().getExile().getAllCards(game, sourceAbility.getControllerId()).size(); return game.getState().getExile().getCardsOwned(game, sourceAbility.getControllerId()).size();
} }
@Override @Override

View file

@ -0,0 +1,62 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.MoveCountersFromSourceToTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.permanent.ModifiedPredicate;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CostumeCloset extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a modified creature you control");
static {
filter.add(ModifiedPredicate.instance);
}
public CostumeCloset(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}");
// This artifact enters with two +1/+1 counters on it.
this.addAbility(new EntersBattlefieldAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)),
"with two +1/+1 counters on it"
));
// {T}: Move a +1/+1 counter from this artifact onto target creature you control. Activate only as a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(
new MoveCountersFromSourceToTargetEffect(), new TapSourceCost()
);
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
// Whenever a modified creature you control leaves the battlefield, put a +1/+1 counter on this artifact.
this.addAbility(new LeavesBattlefieldAllTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter
));
}
private CostumeCloset(final CostumeCloset card) {
super(card);
}
@Override
public CostumeCloset copy() {
return new CostumeCloset(this);
}
}

View file

@ -131,7 +131,7 @@ class CustodyBattleUnlessPaysEffect extends OneShotEffect {
return true; return true;
} }
} }
if (source.getSourceObjectZoneChangeCounter() == game.getState().getZoneChangeCounter(source.getSourceId()) if (source.getStackMomentSourceZCC() == game.getState().getZoneChangeCounter(source.getSourceId())
&& game.getState().getZone(source.getSourceId()) == Zone.BATTLEFIELD) { && game.getState().getZone(source.getSourceId()) == Zone.BATTLEFIELD) {
ContinuousEffect effect = new GiveControlEffect(); ContinuousEffect effect = new GiveControlEffect();
effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game));

View file

@ -147,7 +147,7 @@ class CyclopeanTombEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObjectReference mor = new MageObjectReference(source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game); MageObjectReference mor = new MageObjectReference(source.getSourceId(), source.getStackMomentSourceZCC(), game);
CyclopeanTombCounterWatcher watcher = game.getState().getWatcher(CyclopeanTombCounterWatcher.class); CyclopeanTombCounterWatcher watcher = game.getState().getWatcher(CyclopeanTombCounterWatcher.class);
if (controller != null && watcher != null) { if (controller != null && watcher != null) {

View file

@ -0,0 +1,52 @@
package mage.cards.d;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.MenaceAbility;
import mage.abilities.mana.AnyColorManaAbility;
import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.StaticFilters;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class DailyBugleBuilding extends CardImpl {
public DailyBugleBuilding(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
// {1}, {T}: Add one mana of any color.
Ability ability = new AnyColorManaAbility(new GenericManaCost(1));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
// Smear Campaign -- {1}, {T}: Target legendary creature gains menace until end of turn. Activate only as a sorcery.
ability = new ActivateAsSorceryActivatedAbility(
new GainAbilityTargetEffect(new MenaceAbility(false)), new GenericManaCost(1)
);
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_LEGENDARY));
this.addAbility(ability.withFlavorWord("Smear Campaign"));
}
private DailyBugleBuilding(final DailyBugleBuilding card) {
super(card);
}
@Override
public DailyBugleBuilding copy() {
return new DailyBugleBuilding(this);
}
}

View file

@ -0,0 +1,62 @@
package mage.cards.d;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.target.TargetPermanent;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class DamageControlCrew extends CardImpl {
private static final FilterCard filter = new FilterCard("card with mana value 4 or greater from your graveyard");
static {
filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3));
}
public DamageControlCrew(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CITIZEN);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// When this creature enters, choose one --
// * Repair -- Return target card with mana value 4 or greater from your graveyard to your hand.
Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect());
ability.addTarget(new TargetCardInYourGraveyard(filter));
ability.withFirstModeFlavorWord("Repair");
// * Impound -- Exile target artifact or enchantment.
ability.addMode(new Mode(new ExileTargetEffect())
.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT))
.withFlavorWord("Impound"));
this.addAbility(ability);
}
private DamageControlCrew(final DamageControlCrew card) {
super(card);
}
@Override
public DamageControlCrew copy() {
return new DamageControlCrew(this);
}
}

View file

@ -78,7 +78,7 @@ public class DampingEngine extends CardImpl {
return "dampingEngine_" return "dampingEngine_"
+ playerId + "_" + playerId + "_"
+ source.getSourceId() + "_" + source.getSourceId() + "_"
+ source.getSourceObjectZoneChangeCounter() + "_" + source.getStackMomentSourceZCC() + "_"
+ game.getTurnNum(); + game.getTurnNum();
} }

View file

@ -1,4 +1,3 @@
package mage.cards.d; package mage.cards.d;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
@ -13,7 +12,6 @@ import mage.constants.Duration;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID; import java.util.UUID;
@ -23,7 +21,7 @@ import java.util.UUID;
public final class DarkTriumph extends CardImpl { public final class DarkTriumph extends CardImpl {
private static final Condition condition = new PermanentsOnTheBattlefieldCondition( private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
new FilterPermanent(SubType.SWAMP, "If you control a Swamp") new FilterPermanent(SubType.SWAMP, "you control a Swamp")
); );
public DarkTriumph(UUID ownerId, CardSetInfo setInfo) { public DarkTriumph(UUID ownerId, CardSetInfo setInfo) {

View file

@ -78,7 +78,7 @@ class DayOfTheDragonsEntersEffect extends OneShotEffect {
Set<Card> toExile = new HashSet<>(); Set<Card> toExile = new HashSet<>();
toExile.addAll(game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)); toExile.addAll(game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game));
if (!toExile.isEmpty()) { if (!toExile.isEmpty()) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
controller.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName()); controller.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName());
DragonToken2 token = new DragonToken2(); DragonToken2 token = new DragonToken2();
token.putOntoBattlefield(toExile.size(), game, source, source.getControllerId()); token.putOntoBattlefield(toExile.size(), game, source, source.getControllerId());
@ -110,7 +110,7 @@ class DayOfTheDragonsLeavesEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
if (controller != null) { if (controller != null) {
int zoneChangeCounter = source.getSourceObjectZoneChangeCounter(); int zoneChangeCounter = source.getStackMomentSourceZCC();
if (zoneChangeCounter > 0 && !(sourceObject instanceof PermanentToken)) { if (zoneChangeCounter > 0 && !(sourceObject instanceof PermanentToken)) {
zoneChangeCounter--; zoneChangeCounter--;
} }

View file

@ -101,7 +101,7 @@ class DayOfTheMoonEffect extends OneShotEffect {
} }
private static List<String> getOrSetValue(Game game, Ability source) { private static List<String> getOrSetValue(Game game, Ability source) {
String key = "DayOfTheMoon_" + source.getControllerId() + '_' + source.getSourceObjectZoneChangeCounter(); String key = "DayOfTheMoon_" + source.getControllerId() + '_' + source.getStackMomentSourceZCC();
List<String> list = (List<String>) game.getState().getValue(key); List<String> list = (List<String>) game.getState().getValue(key);
if (list != null) { if (list != null) {
return list; return list;

View file

@ -40,7 +40,7 @@ public final class DeepwoodLegate extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// If an opponent controls a Forest and you control a Swamp, you may cast this spell without paying its mana cost. // If an opponent controls a Forest and you control a Swamp, you may cast this spell without paying its mana cost.
Condition condition = new CompoundCondition("If an opponent controls a Forest and you control a Swamp", Condition condition = new CompoundCondition("an opponent controls a Forest and you control a Swamp",
new OpponentControlsPermanentCondition(filterForest), new OpponentControlsPermanentCondition(filterForest),
new PermanentsOnTheBattlefieldCondition(filterSwamp)); new PermanentsOnTheBattlefieldCondition(filterSwamp));
this.addAbility(new AlternativeCostSourceAbility(null, condition)); this.addAbility(new AlternativeCostSourceAbility(null, condition));

View file

@ -161,7 +161,7 @@ class TargetControlledSource extends TargetSource {
possibleTargets.add(card.getId()); possibleTargets.add(card.getId());
} }
// 108.4a If anything asks for the controller of a card that doesn't have one (because it's not a permanent or spell), use its owner instead. // 108.4a If anything asks for the controller of a card that doesn't have one (because it's not a permanent or spell), use its owner instead.
for (Card card : game.getExile().getAllCards(game)) { for (Card card : game.getExile().getCardsInRange(game, sourceControllerId)) {
if (Objects.equals(card.getOwnerId(), sourceControllerId)) { if (Objects.equals(card.getOwnerId(), sourceControllerId)) {
possibleTargets.add(card.getId()); possibleTargets.add(card.getId());
} }

View file

@ -74,7 +74,7 @@ class DetentionSphereEntersEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC());
Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source); MageObject sourceObject = game.getObject(source);

View file

@ -35,13 +35,12 @@ public final class DiscipleOfPerdition extends CardImpl {
// When Disciple of Perdition dies, choose one. If you have exactly 13 life, you may choose both. // When Disciple of Perdition dies, choose one. If you have exactly 13 life, you may choose both.
// * You draw a card and you lose 1 life. // * You draw a card and you lose 1 life.
Ability ability = new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1, true), false); Ability ability = new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1, true), false);
ability.getModes().setChooseText("choose one. If you have exactly 13 life, you may choose both."); ability.getModes().setChooseText("choose one. If you have exactly 13 life, you may choose both instead.");
ability.getModes().setMoreCondition(2, new LifeCompareCondition(TargetController.YOU, ComparisonType.EQUAL_TO, 13)); ability.getModes().setMoreCondition(2, new LifeCompareCondition(TargetController.YOU, ComparisonType.EQUAL_TO, 13));
ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and"));
// * Exile target opponent's graveyard. That player loses 1 life. // * Exile target opponent's graveyard. That player loses 1 life.
ability.addMode(new Mode(new ExileGraveyardAllTargetPlayerEffect() ability.addMode(new Mode(new ExileGraveyardAllTargetPlayerEffect())
.setText("Exile target opponent's graveyard"))
.addEffect(new LoseLifeTargetEffect(1).setText("that player loses 1 life")) .addEffect(new LoseLifeTargetEffect(1).setText("that player loses 1 life"))
.addTarget(new TargetOpponent())); .addTarget(new TargetOpponent()));
this.addAbility(ability); this.addAbility(ability);

View file

@ -0,0 +1,57 @@
package mage.cards.d;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class DocOcksTentacles extends CardImpl {
private static final FilterPermanent filter
= new FilterControlledCreaturePermanent("a creature you control with mana value 5 or greater");
static {
filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 4));
}
public DocOcksTentacles(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
this.subtype.add(SubType.EQUIPMENT);
// Whenever a creature you control with mana value 5 or greater enters, you may attach this Equipment to it.
this.addAbility(new EntersBattlefieldAllTriggeredAbility(
new AttachEffect(Outcome.BoostCreature, "attach {this} to it"), filter, true
));
// Equipped creature gets +4/+4.
this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(4, 4)));
// Equip {5}
this.addAbility(new EquipAbility(5));
}
private DocOcksTentacles(final DocOcksTentacles card) {
super(card);
}
@Override
public DocOcksTentacles copy() {
return new DocOcksTentacles(this);
}
}

View file

@ -79,7 +79,7 @@ class DragonKamisEggEffect extends OneShotEffect {
} }
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();
game.getExile() game.getExile()
.getAllCards(game, player.getId()) .getCardsOwned(game, player.getId())
.stream() .stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(card -> card.getCounters(game).containsKey(CounterType.HATCHLING)) .filter(card -> card.getCounters(game).containsKey(CounterType.HATCHLING))

View file

@ -19,7 +19,6 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
/** /**
@ -74,7 +73,7 @@ class DragonWhelpEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
ActivationInfo activationInfo = ActivationInfo.getInstance(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); ActivationInfo activationInfo = ActivationInfo.getInstance(game, source.getSourceId(), source.getStackMomentSourceZCC());
activationInfo.addActivation(game); activationInfo.addActivation(game);
if (activationInfo.getActivationCounter() >= 4) { if (activationInfo.getActivationCounter() >= 4) {
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect()); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect());

View file

@ -18,8 +18,8 @@ import mage.filter.common.FilterControlledPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetCreatureOrPlaneswalker; import mage.target.common.TargetCreatureOrPlaneswalker;
/** /**
@ -54,11 +54,10 @@ class DragonsFireCost extends CostImpl {
public enum DragonZone { public enum DragonZone {
HAND, HAND,
BATTLEFIELD, BATTLEFIELD
NONE
} }
private DragonZone dragonZone = DragonZone.NONE; private DragonZone dragonZone = null;
private UUID selectedCardId = null; private UUID selectedCardId = null;
private static final FilterCard handFilter = new FilterCard("Dragon card from your hand"); private static final FilterCard handFilter = new FilterCard("Dragon card from your hand");
@ -90,14 +89,13 @@ class DragonsFireCost extends CostImpl {
@Override @Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
this.getTargets().clear(); dragonZone = null;
dragonZone = DragonZone.NONE;
selectedCardId = null; selectedCardId = null;
Player controller = game.getPlayer(controllerId); Player controller = game.getPlayer(controllerId);
if (controller != null) { if (controller != null) {
boolean dragonInHand = false; boolean dragonInHand = false;
boolean dragonOnBattlefield = false; boolean dragonOnBattlefield = false;
DragonZone chosenZone = DragonZone.NONE; DragonZone chosenZone = null;
for (UUID cardId : controller.getHand()) { for (UUID cardId : controller.getHand()) {
Card card = game.getCard(cardId); Card card = game.getCard(cardId);
if (card != null && card.hasSubtype(SubType.DRAGON, game)) { if (card != null && card.hasSubtype(SubType.DRAGON, game)) {
@ -132,23 +130,25 @@ class DragonsFireCost extends CostImpl {
} }
switch (chosenZone) { switch (chosenZone) {
case HAND: case HAND:
this.getTargets().add(new TargetCardInHand(handFilter)); TargetCardInHand handTarget = new TargetCardInHand(handFilter);
if (this.getTargets().choose(Outcome.Benefit, controllerId, source.getSourceId(), source, game)) { handTarget.withNotTarget(true);
Card card = game.getCard(this.getTargets().getFirstTarget()); if (controller.choose(Outcome.Benefit, handTarget, source, game)) {
Card card = game.getCard(handTarget.getFirstTarget());
if (card != null) { if (card != null) {
dragonZone = DragonZone.HAND; dragonZone = DragonZone.HAND;
selectedCardId = this.getTargets().getFirstTarget(); selectedCardId = handTarget.getFirstTarget();
controller.revealCards(source, new CardsImpl(card), game); controller.revealCards(source, new CardsImpl(card), game);
} }
} }
break; break;
case BATTLEFIELD: case BATTLEFIELD:
this.getTargets().add(new TargetControlledPermanent(battlefieldFilter)); TargetPermanent battlefieldTarget = new TargetPermanent(battlefieldFilter);
if (this.getTargets().choose(Outcome.Benefit, controllerId, source.getSourceId(), source, game)) { battlefieldTarget.withNotTarget(true);
Permanent permanent = game.getPermanent(this.getTargets().getFirstTarget()); if (controller.choose(Outcome.Benefit, battlefieldTarget, source, game)) {
Permanent permanent = game.getPermanent(battlefieldTarget.getFirstTarget());
if (permanent != null) { if (permanent != null) {
dragonZone = DragonZone.BATTLEFIELD; dragonZone = DragonZone.BATTLEFIELD;
selectedCardId = this.getTargets().getFirstTarget(); selectedCardId = battlefieldTarget.getFirstTarget();
game.informPlayers(controller.getLogName() + " chooses " + permanent.getLogName()); game.informPlayers(controller.getLogName() + " chooses " + permanent.getLogName());
} }
} }
@ -190,7 +190,7 @@ class DragonsFireEffect extends OneShotEffect {
if (targetedPermanent == null) { if (targetedPermanent == null) {
return false; return false;
} }
DragonsFireCost.DragonZone dragonZone = DragonsFireCost.DragonZone.NONE; DragonsFireCost.DragonZone dragonZone = null;
UUID selectedCardId = null; UUID selectedCardId = null;
int damage = 3; int damage = 3;
for (Cost cost : source.getCosts()) { for (Cost cost : source.getCosts()) {
@ -201,21 +201,23 @@ class DragonsFireEffect extends OneShotEffect {
break; break;
} }
} }
switch (dragonZone) { if (dragonZone != null) {
case HAND: switch (dragonZone) {
Card card = game.getCard(selectedCardId); case HAND:
if (card != null) { Card card = game.getCard(selectedCardId);
damage = card.getPower().getValue(); if (card != null) {
} damage = card.getPower().getValue();
break; }
case BATTLEFIELD: break;
Permanent dragon = game.getPermanentOrLKIBattlefield(selectedCardId); case BATTLEFIELD:
if (dragon != null) { Permanent dragon = game.getPermanentOrLKIBattlefield(selectedCardId);
damage = dragon.getPower().getValue(); if (dragon != null) {
} damage = dragon.getPower().getValue();
break; }
break;
}
} }
targetedPermanent.damage(damage, source.getSourceId(), source, game); targetedPermanent.damage(damage, source.getSourceId(), source, game);
return true; return true;
} }
} }

View file

@ -92,7 +92,7 @@ class DralnusPetEffect extends OneShotEffect {
SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY);
if (spellAbility != null if (spellAbility != null
&& spellAbility.getSourceId().equals(source.getSourceId()) && spellAbility.getSourceId().equals(source.getSourceId())
&& permanent.getZoneChangeCounter(game) == spellAbility.getSourceObjectZoneChangeCounter()) { && permanent.getZoneChangeCounter(game) == spellAbility.getStackMomentSourceZCC()) {
int cmc = 0; int cmc = 0;
for (Cost cost : spellAbility.getCosts()) { for (Cost cost : spellAbility.getCosts()) {
if (cost instanceof DiscardCardCost && !((DiscardCardCost) cost).getCards().isEmpty()) { if (cost instanceof DiscardCardCost && !((DiscardCardCost) cost).getCards().isEmpty()) {

View file

@ -82,6 +82,6 @@ class DredgingClawTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public String getRule() { public String getRule() {
return "Whenever a creature enters the battlefield from your graveyard, you may attach {this} to it."; return "Whenever a creature enters from your graveyard, you may attach {this} to it.";
} }
} }

View file

@ -5,6 +5,7 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
@ -45,10 +46,12 @@ public final class DuneChanter extends CardImpl {
this.addAbility(new SimpleStaticAbility(new DuneChanterContinuousEffect())); this.addAbility(new SimpleStaticAbility(new DuneChanterContinuousEffect()));
// Lands you control have "{T}: Add one mana of any color." // Lands you control have "{T}: Add one mana of any color."
this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( ContinuousEffect effect = new GainAbilityControlledEffect(
new AnyColorManaAbility(), Duration.WhileOnBattlefield, new AnyColorManaAbility(), Duration.WhileOnBattlefield,
StaticFilters.FILTER_LANDS, false StaticFilters.FILTER_LANDS, false
))); );
effect.getDependedToTypes().add(DependencyType.BecomeNonbasicLand);
this.addAbility(new SimpleStaticAbility(effect));
// {T}: Mill two cards. You gain 1 life for each land card milled this way. // {T}: Mill two cards. You gain 1 life for each land card milled this way.
this.addAbility(new SimpleActivatedAbility(new DuneChanterEffect(), new TapSourceCost())); this.addAbility(new SimpleActivatedAbility(new DuneChanterEffect(), new TapSourceCost()));
@ -76,6 +79,7 @@ class DuneChanterContinuousEffect extends ContinuousEffectImpl {
public DuneChanterContinuousEffect() { public DuneChanterContinuousEffect() {
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
staticText = "Lands you control and land cards you own that aren't on the battlefield are Deserts in addition to their other types"; staticText = "Lands you control and land cards you own that aren't on the battlefield are Deserts in addition to their other types";
dependendToTypes.add(DependencyType.BecomeNonbasicLand);
} }
private DuneChanterContinuousEffect(final DuneChanterContinuousEffect effect) { private DuneChanterContinuousEffect(final DuneChanterContinuousEffect effect) {
@ -111,7 +115,7 @@ class DuneChanterContinuousEffect extends ContinuousEffectImpl {
} }
} }
// in exile // in exile
for (Card card : game.getState().getExile().getAllCards(game, controllerId)) { for (Card card : game.getState().getExile().getCardsOwned(game, controllerId)) {
if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) { if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) {
game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType);
} }
@ -170,5 +174,3 @@ class DuneChanterEffect extends OneShotEffect {
return true; return true;
} }
} }

View file

@ -70,7 +70,7 @@ class DurkwoodTrackerEffect extends OneShotEffect {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null if (permanent == null
|| permanent.getZoneChangeCounter(game) || permanent.getZoneChangeCounter(game)
!= source.getSourceObjectZoneChangeCounter()) { != source.getStackMomentSourceZCC()) {
return false; return false;
} }
Permanent targeted = game.getPermanent(source.getFirstTarget()); Permanent targeted = game.getPermanent(source.getFirstTarget());

View file

@ -83,7 +83,7 @@ class DustOfMomentsEffect extends OneShotEffect {
permanent.addCounters(CounterType.TIME.createInstance(2), source, game); permanent.addCounters(CounterType.TIME.createInstance(2), source, game);
} }
} }
for (Card card : game.getExile().getCards(filter.getCardFilter(), game)) { for (Card card : game.getExile().getCardsInRange(filter.getCardFilter(), source.getControllerId(), source, game)) {
if (remove) { if (remove) {
card.removeCounters(CounterType.TIME.createInstance(2), source, game); card.removeCounters(CounterType.TIME.createInstance(2), source, game);
} else { } else {

View file

@ -0,0 +1,130 @@
package mage.cards.e;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.MenaceAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardSetInfo;
import mage.cards.ModalDoubleFacedCard;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterPermanentCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.Objects;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class EddieBrock extends ModalDoubleFacedCard {
private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 1 or less");
static {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 2));
}
public EddieBrock(UUID ownerId, CardSetInfo setInfo) {
super(
ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.HERO, SubType.VILLAIN}, "{2}{B}",
"Venom, Lethal Protector",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SYMBIOTE, SubType.HERO, SubType.VILLAIN}, "{3}{B}{R}{G}"
);
this.getLeftHalfCard().setPT(5, 5);
this.getRightHalfCard().setPT(5, 5);
// When Eddie Brock enters, return target creature card with mana value 1 or less from your graveyard to the battlefield.
Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect());
ability.addTarget(new TargetCardInYourGraveyard(filter));
this.getLeftHalfCard().addAbility(ability);
// {3}{B}{R}{G}: Transform Eddie Brock. Activate only as a sorcery.
this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(
new TransformSourceEffect(), new ManaCostsImpl<>("{3}{B}{R}{G}")
));
// Venom, Lethal Protector
// Menace
this.getRightHalfCard().addAbility(new MenaceAbility());
// Trample
this.getRightHalfCard().addAbility(TrampleAbility.getInstance());
// Haste
this.getRightHalfCard().addAbility(HasteAbility.getInstance());
// Whenever Venom attacks, you may sacrifice another creature. If you do, draw X cards, then you may put a permanent card with mana value X or less from your hand onto the battlefield, where X is the sacrificed creature's mana value.
this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new VenomLethalProtectorEffect()));
}
private EddieBrock(final EddieBrock card) {
super(card);
}
@Override
public EddieBrock copy() {
return new EddieBrock(this);
}
}
class VenomLethalProtectorEffect extends OneShotEffect {
VenomLethalProtectorEffect() {
super(Outcome.Benefit);
staticText = "you may sacrifice another creature. If you do, draw X cards, " +
"then you may put a permanent card with mana value X or less from your hand onto the battlefield, " +
"where X is the sacrificed creature's mana value";
}
private VenomLethalProtectorEffect(final VenomLethalProtectorEffect effect) {
super(effect);
}
@Override
public VenomLethalProtectorEffect copy() {
return new VenomLethalProtectorEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
SacrificeTargetCost cost = new SacrificeTargetCost(StaticFilters.FILTER_ANOTHER_CREATURE);
if (!cost.canPay(source, source, source.getControllerId(), game)
|| !player.chooseUse(Outcome.Sacrifice, "Sacrifice another creature?", source, game)
|| !cost.pay(source, game, source, source.getControllerId(), true)) {
return false;
}
int amount = cost
.getPermanents()
.stream()
.filter(Objects::nonNull)
.mapToInt(MageObject::getManaValue)
.sum();
player.drawCards(amount, source, game);
game.processAction();
FilterCard filter = new FilterPermanentCard("permanent card with mana value " + amount + " or less");
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, amount + 1));
new PutCardFromHandOntoBattlefieldEffect(filter).apply(game, source);
return true;
}
}

View file

@ -0,0 +1,93 @@
package mage.cards.e;
import mage.MageInt;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.YouDontLoseManaEffect;
import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer;
import mage.util.ManaUtil;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class ElectroAssaultingBattery extends CardImpl {
public ElectroAssaultingBattery(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.VILLAIN);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Flying
this.addAbility(FlyingAbility.getInstance());
// You don't lose unspent red mana as steps and phases end.
this.addAbility(new SimpleStaticAbility(new YouDontLoseManaEffect(ManaType.RED)));
// Whenever you cast an instant or sorcery spell, add {R}.
this.addAbility(new SpellCastControllerTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(Mana.RedMana(1)), false));
// When Electro leaves the battlefield, you may pay x. When you do, he deals X damage to target player.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ElectroAssaultingBatteryEffect()));
}
private ElectroAssaultingBattery(final ElectroAssaultingBattery card) {
super(card);
}
@Override
public ElectroAssaultingBattery copy() {
return new ElectroAssaultingBattery(this);
}
}
class ElectroAssaultingBatteryEffect extends OneShotEffect {
ElectroAssaultingBatteryEffect() {
super(Outcome.Damage);
staticText = "you may pay x. When you do, he deals X damage to target player";
}
private ElectroAssaultingBatteryEffect(final ElectroAssaultingBatteryEffect effect) {
super(effect);
}
@Override
public ElectroAssaultingBatteryEffect copy() {
return new ElectroAssaultingBatteryEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
if (controller.chooseUse(outcome, "Pay x mana to deal x damage to target player?", source, game)) {
TargetPlayer target = new TargetPlayer();
target.chooseTarget(outcome, controller.getId(), source, game);
int amount = ManaUtil.playerPaysXGenericMana(false, "Electro, Assaulting Battery", controller, source, game);
Player targetOpponent = game.getPlayer(target.getFirstTarget());
if (targetOpponent != null) {
targetOpponent.damage(amount, source, game);
}
}
return true;
}
}

View file

@ -58,8 +58,7 @@ public final class ElspethsNightmare extends CardImpl {
// III - Exile target opponent's graveyard. // III - Exile target opponent's graveyard.
sagaAbility.addChapterEffect( sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_III, SagaChapter.CHAPTER_III, this, SagaChapter.CHAPTER_III, SagaChapter.CHAPTER_III,
new ExileGraveyardAllTargetPlayerEffect() new ExileGraveyardAllTargetPlayerEffect(),
.setText("exile target opponent's graveyard"),
new TargetOpponent() new TargetOpponent()
); );
this.addAbility(sagaAbility); this.addAbility(sagaAbility);

View file

@ -82,7 +82,7 @@ class EmberwildeDjinnEffect extends OneShotEffect {
if (player.chooseUse(Outcome.GainControl, "Gain control of " + sourceObject.getLogName() + "?", source, game)) { if (player.chooseUse(Outcome.GainControl, "Gain control of " + sourceObject.getLogName() + "?", source, game)) {
if (cost.pay(source, game, source, player.getId(), false)) { if (cost.pay(source, game, source, player.getId(), false)) {
ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, false, player.getId()); ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, false, player.getId());
effect.setTargetPointer(new FixedTarget(source.getSourceId(), source.getSourceObjectZoneChangeCounter())); effect.setTargetPointer(new FixedTarget(source.getSourceId(), source.getStackMomentSourceZCC()));
game.addEffect(effect, source); game.addEffect(effect, source);
player.resetStoredBookmark(game); player.resetStoredBookmark(game);
} }

View file

@ -45,6 +45,7 @@ class EncroachingMycosynthEffect extends ContinuousEffectImpl {
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
staticText = "Nonland permanents you control are artifacts in addition to their other types. " + staticText = "Nonland permanents you control are artifacts in addition to their other types. " +
"The same is true for permanent spells you control and nonland permanent cards you own that aren't on the battlefield"; "The same is true for permanent spells you control and nonland permanent cards you own that aren't on the battlefield";
this.dependendToTypes.add(DependencyType.BecomeNonbasicLand);
this.dependencyTypes.add(DependencyType.ArtifactAddingRemoving); // March of the Machines this.dependencyTypes.add(DependencyType.ArtifactAddingRemoving); // March of the Machines
} }
@ -79,7 +80,7 @@ class EncroachingMycosynthEffect extends ContinuousEffectImpl {
} }
} }
// in Exile // in Exile
for (Card card : game.getState().getExile().getAllCards(game, source.getControllerId())) { for (Card card : game.getState().getExile().getCardsOwned(game, source.getControllerId())) {
if (card.isPermanent(game) && !card.isLand(game) && !card.isArtifact(game)) { if (card.isPermanent(game) && !card.isLand(game) && !card.isArtifact(game)) {
card.addCardType(game, CardType.ARTIFACT); card.addCardType(game, CardType.ARTIFACT);
} }

View file

@ -119,7 +119,7 @@ class EsperTerraEffect extends OneShotEffect {
.filter(amount -> amount > 0) .filter(amount -> amount > 0)
.ifPresent(amount -> token.addCounters(CounterType.LORE.createInstance(amount), source, game)); .ifPresent(amount -> token.addCounters(CounterType.LORE.createInstance(amount), source, game));
} }
effect.sacrificeTokensCreatedAtNextEndStep(game, source); effect.removeTokensCreatedAt(game, source, false, PhaseStep.END_TURN, TargetController.YOU);
return true; return true;
} }
} }

View file

@ -32,7 +32,7 @@ public final class EternalScourge extends CardImpl {
// When Eternal Scourge becomes the target of a spell or ability an opponent controls, exile Eternal Scourge. // When Eternal Scourge becomes the target of a spell or ability an opponent controls, exile Eternal Scourge.
this.addAbility(new BecomesTargetSourceTriggeredAbility(new ExileSourceEffect(), this.addAbility(new BecomesTargetSourceTriggeredAbility(new ExileSourceEffect(),
StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS)); StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS).withRuleTextReplacement(false));
} }
private EternalScourge(final EternalScourge card) { private EternalScourge(final EternalScourge card) {

View file

@ -96,8 +96,8 @@ class EtrataTheSilencerEffect extends OneShotEffect {
if (card != null) { if (card != null) {
card.addCounters(CounterType.HIT.createInstance(), source.getControllerId(), source, game); card.addCounters(CounterType.HIT.createInstance(), source.getControllerId(), source, game);
} }
int cardsFound = game.getExile().getAllCards(game).stream() int cardsFound = game.getExile().getCardsOwned(game, player.getId())
.filter(c -> c.getOwnerId().equals(player.getId())) .stream()
.filter(c -> c.getCounters(game).getCount(CounterType.HIT) > 0) .filter(c -> c.getCounters(game).getCount(CounterType.HIT) > 0)
.mapToInt(x -> 1) .mapToInt(x -> 1)
.sum(); .sum();

View file

@ -0,0 +1,53 @@
package mage.cards.e;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.keyword.ReachAbility;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class EzekielSimsSpiderTotem extends CardImpl {
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SPIDER);
public EzekielSimsSpiderTotem(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SPIDER);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ADVISOR);
this.power = new MageInt(3);
this.toughness = new MageInt(5);
// Reach
this.addAbility(ReachAbility.getInstance());
// At the beginning of combat on your turn, target Spider you control gets +2/+2 until end of turn.
Ability ability = new BeginningOfCombatTriggeredAbility(new BoostTargetEffect(2, 2));
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
}
private EzekielSimsSpiderTotem(final EzekielSimsSpiderTotem card) {
super(card);
}
@Override
public EzekielSimsSpiderTotem copy() {
return new EzekielSimsSpiderTotem(this);
}
}

View file

@ -77,7 +77,7 @@ class FaerieArtisansEffect extends OneShotEffect {
CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, CardType.ARTIFACT, false); CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, CardType.ARTIFACT, false);
effect.setTargetPointer(new FixedTarget(permanentToCopy, game)); effect.setTargetPointer(new FixedTarget(permanentToCopy, game));
if (effect.apply(game, source)) { if (effect.apply(game, source)) {
String oldTokens = (String) game.getState().getValue(source.getSourceId().toString() + source.getSourceObjectZoneChangeCounter()); String oldTokens = (String) game.getState().getValue(source.getSourceId().toString() + source.getStackMomentSourceZCC());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (Permanent permanent : effect.getAddedPermanents()) { for (Permanent permanent : effect.getAddedPermanents()) {
if (sb.length() > 0) { if (sb.length() > 0) {
@ -85,7 +85,7 @@ class FaerieArtisansEffect extends OneShotEffect {
} }
sb.append(permanent.getId()); sb.append(permanent.getId());
} }
game.getState().setValue(source.getSourceId().toString() + source.getSourceObjectZoneChangeCounter(), sb.toString()); game.getState().setValue(source.getSourceId().toString() + source.getStackMomentSourceZCC(), sb.toString());
if (oldTokens != null) { if (oldTokens != null) {
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();

View file

@ -85,30 +85,26 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller == null) {
Map<UUID, MadnessAbility> usedMadnessAbilities = new HashMap<>(); return false;
// hand
for (Card card : controller.getHand().getCards(filter, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// graveyard
for (Card card : controller.getGraveyard().getCards(filter, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// Exile
for (Card card : game.getExile().getAllCards(game)) {
if (filter.match(card, controller.getId(), source, game)) {
if (card.isOwnedBy(controller.getId())) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
}
}
madnessAbilities.clear();
madnessAbilities.putAll(usedMadnessAbilities);
return true;
} }
Map<UUID, MadnessAbility> usedMadnessAbilities = new HashMap<>();
// hand
for (Card card : controller.getHand().getCards(filter, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// graveyard
for (Card card : controller.getGraveyard().getCards(filter, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// Exile
for (Card card : game.getExile().getCardsOwned(filter, controller.getId(), source, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
madnessAbilities.clear();
madnessAbilities.putAll(usedMadnessAbilities);
return true;
return false;
} }
private void addMadnessToCard(Game game, Card card, Map<UUID, MadnessAbility> usedMadnessAbilities) { private void addMadnessToCard(Game game, Card card, Map<UUID, MadnessAbility> usedMadnessAbilities) {

View file

@ -67,7 +67,7 @@ class FarrelitePriestEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
ActivationInfo activationInfo = ActivationInfo.getInstance(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); ActivationInfo activationInfo = ActivationInfo.getInstance(game, source.getSourceId(), source.getStackMomentSourceZCC());
activationInfo.addActivation(game); activationInfo.addActivation(game);
if (activationInfo.getActivationCounter() == 4) { if (activationInfo.getActivationCounter() == 4) {
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect()); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect());

Some files were not shown because too many files have changed in this diff Show more