Merge branch 'master' into refactor/multiple-names

This commit is contained in:
theelk801 2024-09-20 12:08:53 -04:00
commit d18bd25d21
190 changed files with 4573 additions and 812 deletions

View file

@ -8,10 +8,12 @@ import mage.client.cards.BigCard;
import mage.client.cards.VirtualCardInfo;
import mage.client.dialog.PreferencesDialog;
import mage.client.game.GamePanel;
import mage.game.command.Dungeon;
import mage.game.command.Plane;
import mage.util.CardUtil;
import mage.util.GameLog;
import mage.view.CardView;
import mage.view.DungeonView;
import mage.view.PlaneView;
import javax.swing.*;
@ -156,7 +158,7 @@ public class MageEditorPane extends JEditorPane {
// show real object by priority (workable card hints and actual info)
CardView cardView = needCard;
// if no game object found then show default card
// if no game object found then show default card/object
if (cardView == null) {
CardInfo card = CardRepository.instance.findCards(cardName).stream().findFirst().orElse(null);
if (card != null) {
@ -172,6 +174,14 @@ public class MageEditorPane extends JEditorPane {
}
}
// dungeon
if (cardView == null) {
Dungeon dungeon = Dungeon.createDungeon(cardName, false);
if (dungeon != null) {
cardView = new CardView(new DungeonView(dungeon));
}
}
// TODO: add other objects like dungeon, emblem, commander
if (cardView != null) {

View file

@ -314,7 +314,7 @@ public class PickChoiceDialog extends MageDialog {
cardInfo.init(item.getHint(), this.bigCard, this.gameId);
} else if (item.getHintType() == ChoiceHintType.CARD_DUNGEON) {
// as card name
CardView cardView = new CardView(new DungeonView(Dungeon.createDungeon(item.getHint())));
CardView cardView = new CardView(new DungeonView(Dungeon.createDungeon(item.getHint(), true)));
cardInfo.init(cardView, this.bigCard, this.gameId);
} else if (item.getHintType() == ChoiceHintType.GAME_OBJECT) {
// as object

View file

@ -27,9 +27,7 @@ import mage.counters.Counter;
import mage.counters.CounterType;
import mage.designations.CitysBlessing;
import mage.designations.Monarch;
import mage.game.Game;
import mage.game.GameException;
import mage.game.GameImpl;
import mage.game.*;
import mage.game.command.Dungeon;
import mage.game.command.Emblem;
import mage.game.command.Plane;
@ -270,8 +268,8 @@ public class TestCardRenderDialog extends MageDialog {
// prepare fake game and players without real match
// it's a workaround with minimum code and data init
this.match = new TestMatch();
this.game = new TestGame(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20, 7);
this.match = new FakeMatch();
this.game = new FakeGame();
Deck deck = new Deck();
Player playerYou = new StubPlayer("player1", RangeOfInfluence.ALL);
playerYou.addDesignation(new CitysBlessing());
@ -977,68 +975,4 @@ public class TestCardRenderDialog extends MageDialog {
private javax.swing.JSpinner spinnerCardIconsAdditionalAmount;
private javax.swing.JSpinner spinnerCardIconsMaxVisible;
// End of variables declaration//GEN-END:variables
}
class TestGame extends GameImpl {
private int numPlayers;
public TestGame(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startHandSize) {
super(attackOption, range, mulligan, 60, startLife, startHandSize);
}
public TestGame(final TestGame game) {
super(game);
this.numPlayers = game.numPlayers;
}
@Override
public MatchType getGameType() {
return new TestGameType();
}
@Override
public int getNumPlayers() {
return numPlayers;
}
@Override
public TestGame copy() {
return new TestGame(this);
}
}
class TestGameType extends MatchType {
public TestGameType() {
this.name = "Test Game Type";
this.maxPlayers = 10;
this.minPlayers = 3;
this.numTeams = 0;
this.useAttackOption = true;
this.useRange = true;
this.sideboardingAllowed = true;
}
protected TestGameType(final TestGameType matchType) {
super(matchType);
}
@Override
public TestGameType copy() {
return new TestGameType(this);
}
}
class TestMatch extends MatchImpl {
public TestMatch() {
super(new MatchOptions("fake match", "fake game type", true, 2));
}
@Override
public void startGame() throws GameException {
throw new IllegalStateException("Can't start fake match");
}
}
}

View file

@ -2,6 +2,7 @@ package mage.client.game;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.cards.BigCard;
import mage.client.chat.ChatPanelBasic;
import mage.client.dialog.MageDialog;
import mage.client.util.audio.AudioManager;
@ -56,9 +57,9 @@ public class FeedbackPanel extends javax.swing.JPanel {
customInitComponents();
}
public void init(UUID gameId) {
public void init(UUID gameId, BigCard bigCard) {
this.gameId = gameId;
helper.init(gameId);
helper.init(gameId, bigCard);
setGUISize();
}

View file

@ -196,11 +196,20 @@ public final class GamePanel extends javax.swing.JPanel {
player.getGraveyard().values().forEach(c -> this.allCardsIndex.put(c.getId(), c));
Optional.ofNullable(player.getTopCard()).ifPresent(c -> this.allCardsIndex.put(c.getId(), c));
// TODO: add support of dungeon, emblem all another non-card objects
// commanders and custom emblems
player.getCommandObjectList()
.stream()
.filter(c -> c instanceof CardView)
.map(c -> (CardView) c)
.forEach(c -> this.allCardsIndex.put(c.getId(), c));
.forEach(object -> {
if (object instanceof CardView) {
// commanders and custom emblems
this.allCardsIndex.put(object.getId(), (CardView) object);
} else if (object instanceof DungeonView) {
// dungeons
this.allCardsIndex.put(object.getId(), new CardView((DungeonView) object));
} else {
// TODO: enable after all view types added here?
//throw new IllegalArgumentException("Unsupported object type: " + object.getName() + " - " + object.getClass().getSimpleName());
}
});
});
}
@ -808,7 +817,7 @@ public final class GamePanel extends javax.swing.JPanel {
this.gamePane = gamePane;
this.playerId = playerId;
MageFrame.addGame(gameId, this);
this.feedbackPanel.init(gameId);
this.feedbackPanel.init(gameId, bigCard);
this.feedbackPanel.clear();
this.abilityPicker.init(gameId, bigCard);
this.btnConcede.setVisible(true);
@ -851,7 +860,7 @@ public final class GamePanel extends javax.swing.JPanel {
this.gamePane = gamePane;
this.playerId = null;
MageFrame.addGame(gameId, this);
this.feedbackPanel.init(gameId);
this.feedbackPanel.init(gameId, bigCard);
this.feedbackPanel.clear();
this.btnConcede.setVisible(false);
@ -886,7 +895,7 @@ public final class GamePanel extends javax.swing.JPanel {
this.gameId = gameId;
this.playerId = null;
MageFrame.addGame(gameId, this);
this.feedbackPanel.init(gameId);
this.feedbackPanel.init(gameId, bigCard);
this.feedbackPanel.clear();
this.btnConcede.setVisible(false);
this.btnSkipToNextTurn.setVisible(false);

View file

@ -1,6 +1,7 @@
package mage.client.game;
import mage.client.SessionHandler;
import mage.client.cards.BigCard;
import mage.client.components.MageTextArea;
import mage.client.constants.Constants;
import mage.client.dialog.PreferencesDialog;
@ -89,8 +90,9 @@ public class HelperPanel extends JPanel {
initComponents();
}
public void init(UUID gameId) {
public void init(UUID gameId, BigCard bigCard) {
this.gameId = gameId;
this.dialogTextArea.setGameData(gameId, bigCard);
}
public void changeGUISize() {

View file

@ -878,7 +878,8 @@ public class CardView extends SimpleCardView {
this.displayName = name;
this.displayFullName = name;
this.rules = new ArrayList<>(emblem.getRules());
// emblem images are always with common (black) symbol
// image - emblem are always with common (black) symbol
this.frameStyle = FrameStyle.M15_NORMAL;
this.expansionSetCode = emblem.getExpansionSetCode();
this.cardNumber = emblem.getCardNumber();
@ -901,12 +902,13 @@ public class CardView extends SimpleCardView {
this.displayName = name;
this.displayFullName = name;
this.rules = new ArrayList<>(dungeon.getRules());
// emblem images are always with common (black) symbol
this.frameStyle = FrameStyle.M15_NORMAL;
// image
this.frameStyle = FrameStyle.M15_NORMAL; // TODO: needs in full art? Test dungeon choose dialog
this.expansionSetCode = dungeon.getExpansionSetCode();
this.cardNumber = "";
this.imageFileName = "";
this.imageNumber = 0;
this.imageFileName = dungeon.getImageFileName();
this.imageNumber = dungeon.getImageNumber();
this.rarity = Rarity.SPECIAL;
this.playableStats = dungeon.playableStats.copy();
@ -923,7 +925,8 @@ public class CardView extends SimpleCardView {
this.displayName = name;
this.displayFullName = name;
this.rules = new ArrayList<>(plane.getRules());
// Display the plane in landscape (similar to Fused cards)
// image - display the plane in landscape (similar to Fused cards)
this.rotate = true;
this.frameStyle = FrameStyle.M15_NORMAL;
this.expansionSetCode = plane.getExpansionSetCode();
@ -947,6 +950,8 @@ public class CardView extends SimpleCardView {
this.displayFullName = name;
this.rules = new ArrayList<>();
this.rules.add(stackAbility.getRule(designation.getName()));
// image
this.frameStyle = FrameStyle.M15_NORMAL;
this.cardNumber = designation.getCardNumber();
this.expansionSetCode = designation.getExpansionSetCode();
@ -954,6 +959,7 @@ public class CardView extends SimpleCardView {
this.imageFileName = "";
this.imageNumber = 0;
this.rarity = Rarity.SPECIAL;
// no playable/chooseable marks for designations
}

View file

@ -32,7 +32,7 @@ public class StackAbilityView extends CardView {
public StackAbilityView(Game game, StackAbility ability, String sourceName, MageObject sourceObject, CardView sourceView) {
this.id = ability.getId();
this.mageObjectType = MageObjectType.ABILITY_STACK;
this.mageObjectType = sourceView.getMageObjectType().isUseTokensRepository() ? MageObjectType.ABILITY_STACK_FROM_TOKEN : MageObjectType.ABILITY_STACK_FROM_CARD;
this.abilityType = ability.getStackAbility().getAbilityType();
this.sourceCard = sourceView;
this.sourceCard.setMageObjectType(mageObjectType);

View file

@ -35,7 +35,7 @@ public final class AbandonHope extends CardImpl {
this.addAbility(ability);
// Look at target opponent's hand and choose X cards from it. That player discards those cards.
this.getSpellAbility().addEffect(new LookTargetHandChooseDiscardEffect(false, GetXValue.instance));
this.getSpellAbility().addEffect(new LookTargetHandChooseDiscardEffect(false, GetXValue.instance, StaticFilters.FILTER_CARD_CARDS));
this.getSpellAbility().addTarget(new TargetOpponent());
this.getSpellAbility().setCostAdjuster(AbandonHopeAdjuster.instance);
}

View file

@ -10,6 +10,7 @@ import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -50,7 +51,9 @@ public final class AcererakTheArchlich extends CardImpl {
"to its owner's hand and venture into the dungeon."
);
ability.addEffect(new VentureIntoTheDungeonEffect());
this.addAbility(ability.addHint(CompletedDungeonCondition.getHint()), new CompletedDungeonWatcher());
ability.addHint(CurrentDungeonHint.instance);
ability.addHint(CompletedDungeonCondition.getHint());
this.addAbility(ability, new CompletedDungeonWatcher());
// Whenever Acererak the Archlich attacks, for each opponent, you create a 2/2 black Zombie creature token unless that player sacrifices a creature.
this.addAbility(new AttacksTriggeredAbility(new AcererakTheArchlichEffect()));

View file

@ -2,16 +2,12 @@
package mage.cards.a;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.SimpleManaAbility;
import mage.abilities.mana.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
/**
*
@ -24,10 +20,10 @@ public final class AdarkarWastes extends CardImpl {
this.addAbility(new ColorlessManaAbility());
Ability whiteManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana(1), new TapSourceCost());
Ability whiteManaAbility = new WhiteManaAbility();
whiteManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(whiteManaAbility);
Ability blueManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlueMana(1), new TapSourceCost());
Ability blueManaAbility = new BlueManaAbility();
blueManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(blueManaAbility);
}

View file

@ -10,6 +10,7 @@ import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.AddCardSubTypeSourceEffect;
import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint;
import mage.constants.*;
@ -45,8 +46,8 @@ public final class Adrestia extends CardImpl {
// Whenever Adrestia attacks, if an Assassin crewed it this turn, draw a card. Adrestia becomes an Assassin in addition to its other types until end of turn.
Ability ability = new ConditionalInterveningIfTriggeredAbility(
new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1), false),
condition, "Whenever Adrestia attacks, if an Assassin crewed it this turn, draw a card. Adrestia becomes an Assassin in addition to its other types until end of turn.");
ability.addEffect(new AdrestiaEffect());
condition, "Whenever {this} attacks, if an Assassin crewed it this turn, draw a card. {this} becomes an Assassin in addition to its other types until end of turn.");
ability.addEffect(new AddCardSubTypeSourceEffect(Duration.EndOfTurn, true, SubType.ASSASSIN));
ability.addHint(AdrestiaCondition.getHint());
this.addAbility(ability, new AdrestiaWatcher());
@ -65,32 +66,6 @@ public final class Adrestia extends CardImpl {
}
}
class AdrestiaEffect extends ContinuousEffectImpl {
public AdrestiaEffect() {
super(Duration.EndOfTurn, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
}
protected AdrestiaEffect(final AdrestiaEffect effect) {
super(effect);
}
@Override
public AdrestiaEffect copy() {
return new AdrestiaEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null) {
return false;
}
permanent.addSubType(game, SubType.ASSASSIN);
return true;
}
}
enum AdrestiaCondition implements Condition {
instance;
private static final Hint hint = new ConditionHint(instance, "an Assassin crewed it this turn");

View file

@ -25,12 +25,12 @@ public final class AkromaAngelOfWrath extends CardImpl {
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// Flying, first strike, vigilance, trample, haste, protection from black and from red
this.addAbility(FlyingAbility.getInstance());
this.addAbility(FirstStrikeAbility.getInstance());
this.addAbility(VigilanceAbility.getInstance());
this.addAbility(TrampleAbility.getInstance());
this.addAbility(HasteAbility.getInstance());
// protection from black and from red
this.addAbility(ProtectionAbility.from(ObjectColor.BLACK, ObjectColor.RED));
}

View file

@ -33,7 +33,7 @@ public final class AkromasWill extends CardImpl {
this.getSpellAbility().getModes().setChooseText(
"Choose one. If you control a commander as you cast this spell, you may choose both instead."
);
this.getSpellAbility().getModes().setMoreCondition(ControlACommanderCondition.instance);
this.getSpellAbility().getModes().setMoreCondition(2, ControlACommanderCondition.instance);
// Creatures you control gain flying, vigilance, and double strike until end of turn.
this.getSpellAbility().addEffect(new GainAbilityControlledEffect(

View file

@ -5,19 +5,14 @@ import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.Condition;
import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AddContinuousEffectToGame;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.choices.Choice;
import mage.choices.ChoiceCardType;
import mage.constants.*;
import mage.filter.common.FilterOwnedCard;
import mage.game.ExileZone;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -26,6 +21,8 @@ import mage.util.CardUtil;
import java.util.*;
import java.util.stream.Collectors;
import mage.abilities.SpellAbility;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
/**
* @author jeffwadsworth
@ -40,11 +37,11 @@ public class ApexObservatory extends CardImpl {
// Apex Observatory enters the battlefield tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// Apex Observatory enters the battlefield tapped. As it enters, choose a card type shared among two exiled cards used to craft it.
// As it enters, choose a card type shared among two exiled cards used to craft it.
this.addAbility(new AsEntersBattlefieldAbility(new ChooseCardTypeEffect()));
// The next spell you cast this turn of the chosen type can be cast without paying its mana cost.
this.addAbility(new SimpleActivatedAbility(new AddContinuousEffectToGame(new ApexObservatoryEffect()), new TapSourceCost()));
this.addAbility(new SimpleActivatedAbility(new ApexObservatoryEffect(), new TapSourceCost()));
}
private ApexObservatory(final ApexObservatory card) {
@ -141,10 +138,10 @@ class ChooseCardTypeEffect extends OneShotEffect {
}
}
class ApexObservatoryEffect extends ContinuousEffectImpl {
class ApexObservatoryEffect extends OneShotEffect {
ApexObservatoryEffect() {
super(Duration.EndOfTurn, Outcome.Benefit);
super(Outcome.Benefit);
staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost.";
}
@ -158,86 +155,85 @@ class ApexObservatoryEffect extends ContinuousEffectImpl {
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
public boolean apply(Game game, Ability source) {
String chosenCardType = (String) game.getState().getValue("ApexObservatoryType_" + source.getSourceId().toString());
if (controller != null
&& chosenCardType != null) {
Card apexObservatory = game.getCard(source.getSourceId());
if (apexObservatory != null) {
Boolean wasItUsed = (Boolean) game.getState().getValue(
apexObservatory.getId().toString());
if (wasItUsed == null) {
ApexObservatoryAlternativeCostAbility alternateCostAbility = new ApexObservatoryAlternativeCostAbility(chosenCardType);
alternateCostAbility.setSourceId(source.getSourceId());
controller.getAlternativeSourceCosts().add(alternateCostAbility);
if (chosenCardType == null) {
return false;
}
game.addEffect(new ApexObservatoryCastWithoutManaEffect(chosenCardType, source.getControllerId()), source);
return true;
}
}
class ApexObservatoryCastWithoutManaEffect extends CostModificationEffectImpl {
private final String chosenCardType;
private final UUID playerId;
private boolean used = false;
ApexObservatoryCastWithoutManaEffect(String chosenCardType, UUID playerId) {
super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.SET_COST);
this.chosenCardType = chosenCardType;
this.playerId = playerId;
staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost";
}
private ApexObservatoryCastWithoutManaEffect(final ApexObservatoryCastWithoutManaEffect effect) {
super(effect);
this.chosenCardType = effect.chosenCardType;
this.playerId = effect.playerId;
this.used = effect.used;
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
// Ask the player if they want to use the effect
Player controller = game.getPlayer(playerId);
if (controller != null) {
MageObject spell = abilityToModify.getSourceObject(game);
if (spell != null && !game.isSimulation()) {
String message = "Cast " + spell.getIdName() + " without paying its mana cost?";
if (controller.chooseUse(Outcome.Benefit, message, source, game)) {
// Set the cost to zero
abilityToModify.getManaCostsToPay().clear();
// Mark as used
used = true;
game.informPlayers(controller.getLogName() + " casts " + spell.getIdName() + " without paying its mana cost.");
return true;
} else {
// Player chose not to use the effect
return false;
}
return true;
}
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return false;
public ApexObservatoryCastWithoutManaEffect copy() {
return new ApexObservatoryCastWithoutManaEffect(this);
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.RulesEffects;
}
}
class ApexObservatoryAlternativeCostAbility extends AlternativeCostSourceAbility {
private boolean wasActivated;
ApexObservatoryAlternativeCostAbility(String chosenCardType) {
super(new SpellMatchesChosenTypeCondition(chosenCardType), null, new FilterOwnedCard(), true, null);
}
private ApexObservatoryAlternativeCostAbility(final ApexObservatoryAlternativeCostAbility ability) {
super(ability);
this.wasActivated = ability.wasActivated;
public boolean isInactive(Ability source, Game game) {
return used || super.isInactive(source, game);
}
@Override
public ApexObservatoryAlternativeCostAbility copy() {
return new ApexObservatoryAlternativeCostAbility(this);
}
@Override
public boolean activateAlternativeCosts(Ability ability, Game game) {
if (!super.activateAlternativeCosts(ability, game)) {
public boolean applies(Ability ability, Ability source, Game game) {
if (used) {
return false;
}
Card apexObservatory = game.getCard(this.getSourceId());
if (apexObservatory != null) {
game.getState().setValue(apexObservatory.getId().toString(), true);
if (!ability.isControlledBy(playerId)) {
return false;
}
return true;
}
}
class SpellMatchesChosenTypeCondition implements Condition {
final private String chosenCardType;
public SpellMatchesChosenTypeCondition(String chosenCardType) {
this.chosenCardType = chosenCardType;
}
@Override
public boolean apply(Game game, Ability source) {
return checkSpell(game.getObject(source), game, chosenCardType);
}
public static boolean checkSpell(MageObject spell, Game game, String chosenCardType) {
if (spell instanceof Card) {
Card card = (Card) spell;
return chosenCardType != null
&& card.getCardType(game).toString().contains(chosenCardType);
if (!(ability instanceof SpellAbility)) {
return false;
}
MageObject object = game.getObject(ability.getSourceId());
if (object != null && object.getCardType(game).stream()
.anyMatch(cardType -> cardType.toString().equals(chosenCardType))) {
return true;
}
return false;
}

View file

@ -2,28 +2,19 @@ package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.*;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.keyword.DisguiseAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
/**
*
@ -31,6 +22,13 @@ import mage.target.targetpointer.FixedTarget;
*/
public final class AvelineDeGrandpre extends CardImpl {
private static final FilterPermanent filter
= new FilterControlledCreaturePermanent("a creature you control with deathtouch");
static {
filter.add(new AbilityPredicate(DeathtouchAbility.class));
}
public AvelineDeGrandpre(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}");
@ -44,7 +42,11 @@ public final class AvelineDeGrandpre extends CardImpl {
this.addAbility(DeathtouchAbility.getInstance());
// Whenever a creature you control with deathtouch deals combat damage to a player, put that many +1/+1 counters on that creature.
this.addAbility(new AvelineDeGrandpreTriggeredAbility());
this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance(), SavedDamageValue.MANY),
filter,
false, SetTargetPointer.PERMANENT, true
));
// Disguise {B}{G}
this.addAbility(new DisguiseAbility(this, new ManaCostsImpl<>("{B}{G}")));
@ -60,52 +62,3 @@ public final class AvelineDeGrandpre extends CardImpl {
return new AvelineDeGrandpre(this);
}
}
class AvelineDeGrandpreTriggeredAbility extends TriggeredAbilityImpl {
private static final FilterPermanent filter
= new FilterControlledCreaturePermanent("a creature you control with deathtouch");
static {
filter.add(new AbilityPredicate(DeathtouchAbility.class));
}
public AvelineDeGrandpreTriggeredAbility() {
// Copied from Necropolis Regent, I don't know why QUEST counters.
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), false);
}
private AvelineDeGrandpreTriggeredAbility(final AvelineDeGrandpreTriggeredAbility ability) {
super(ability);
}
@Override
public AvelineDeGrandpreTriggeredAbility copy() {
return new AvelineDeGrandpreTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (((DamagedPlayerEvent) event).isCombatDamage()) {
Permanent creature = game.getPermanent(event.getSourceId());
if (creature != null && creature.isControlledBy(controllerId) && filter.match(creature, game)) {
this.getEffects().clear();
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(event.getAmount()));
effect.setTargetPointer(new FixedTarget(creature.getId(), game));
this.addEffect(effect);
return true;
}
}
return false;
}
@Override
public String getRule() {
return "Whenever a creature you control with deathtouch deals combat damage to a player, put that many +1/+1 counters on it.";
}
}

View file

@ -4,6 +4,7 @@ import java.util.UUID;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -33,6 +34,7 @@ public final class BarTheGate extends CardImpl {
this.getSpellAbility().addTarget(new TargetSpell(filter));
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addEffect(new VentureIntoTheDungeonEffect());
this.getSpellAbility().addHint(CurrentDungeonHint.instance);
}
private BarTheGate(final BarTheGate card) {

View file

@ -8,6 +8,7 @@ import mage.abilities.condition.common.CompletedDungeonCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -44,7 +45,8 @@ public final class BarrowinOfClanUndurr extends CardImpl {
this.toughness = new MageInt(3);
// When Barrowin of Clan Undurr enters the battlefield, venture into the dungeon.
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
// Whenever Barrowin of Clan Undurr attacks, return up to one creature card with mana value 3 or less from your graveyard to the battlefield if you've completed a dungeon.
Ability ability = new AttacksTriggeredAbility(new ConditionalOneShotEffect(

View file

@ -2,16 +2,12 @@
package mage.cards.b;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.SimpleManaAbility;
import mage.abilities.mana.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
/**
*
@ -26,10 +22,10 @@ public final class BattlefieldForge extends CardImpl {
this.addAbility(new ColorlessManaAbility());
// Tap: Add Red or White. Battlefield Forge deals 1 damage to you.
Ability redManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana(1), new TapSourceCost());
Ability redManaAbility = new RedManaAbility();
redManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(redManaAbility);
Ability whiteManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana(1), new TapSourceCost());
Ability whiteManaAbility = new WhiteManaAbility();
whiteManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(whiteManaAbility);
}

View file

@ -0,0 +1,55 @@
package mage.cards.b;
import mage.abilities.condition.common.DeliriumCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.hint.common.CardTypesInGraveyardHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityWord;
import mage.constants.CardType;
import mage.counters.CounterType;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class BeastieBeatdown extends CardImpl {
public BeastieBeatdown(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}{G}");
// Choose target creature you control and target creature an opponent controls.
this.getSpellAbility().addEffect(new InfoEffect(
"Choose target creature you control and target creature an opponent controls."
));
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent());
// Delirium -- If there are four or more card types among cards in your graveyard, put two +1/+1 counters on the creature you control.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)),
DeliriumCondition.instance, AbilityWord.DELIRIUM.formatWord() + "If there are four or more " +
"card types among cards in your graveyard, put two +1/+1 counters on the creature you control."
).concatBy("<br>"));
this.getSpellAbility().addHint(CardTypesInGraveyardHint.YOU);
// The creature you control deals damage equal to its power to the creature an opponent controls.
this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()
.setText("<br>The creature you control deals damage equal to its power to the creature an opponent controls."));
}
private BeastieBeatdown(final BeastieBeatdown card) {
super(card);
}
@Override
public BeastieBeatdown copy() {
return new BeastieBeatdown(this);
}
}

View file

@ -81,6 +81,6 @@ class BloodSeekerTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever a creature enters the battlefield under an opponent's control, you may have that player lose 1 life.";
return "Whenever a creature an opponent controls enters, you may have that player lose 1 life.";
}
}

View file

@ -0,0 +1,48 @@
package mage.cards.b;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.DoWhenCostPaid;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class BoilerbilgesRipper extends CardImpl {
public BoilerbilgesRipper(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ASSASSIN);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// When Boilerbilges Ripper enters, you may sacrifice another creature or enchantment. When you do, Boilerbilges Ripper deals 2 damage to any target.
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DamageTargetEffect(2), false);
ability.addTarget(new TargetAnyTarget());
this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid(
ability, new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ANOTHER_CREATURE_OR_ENCHANTMENT),
"Sacrifice another creature or enchantment?"
)));
}
private BoilerbilgesRipper(final BoilerbilgesRipper card) {
super(card);
}
@Override
public BoilerbilgesRipper copy() {
return new BoilerbilgesRipper(this);
}
}

View file

@ -11,12 +11,10 @@ import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
@ -41,6 +39,7 @@ public final class BoxingRing extends CardImpl {
= new FilterCreaturePermanent("creature you don't control with the same mana value");
static {
filter.add(TargetController.NOT_YOU.getControllerPredicate());
filter.add(BoxingRingPredicate.instance);
}

View file

@ -1,4 +1,3 @@
package mage.cards.b;
import java.util.ArrayList;
@ -100,24 +99,34 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
List<Permanent> fromBattlefield = new ArrayList<>();
List<Card> fromHandGraveyard = new ArrayList<>();
int countBattlefield = game.getBattlefield().getActivePermanents(filterAura, source.getControllerId(), source, game).size() - sourcePermanent.getAttachments().size();
int countBattlefield = (int) (game.getBattlefield().getActivePermanents(filterAura, source.getControllerId(), source, game).size()
- sourcePermanent.getAttachments().stream().map(game::getPermanent).filter(permanent -> permanent != null
&& permanent.hasSubtype(SubType.AURA, game)).count());
while (controller.canRespond()
&& countBattlefield > 0
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from the battlefield?", source, game)) {
Target targetAura = new TargetPermanent(filterAura);
targetAura.withNotTarget(true);
if (!controller.choose(Outcome.Benefit, targetAura, source, game)) { continue; }
if (!controller.choose(Outcome.Benefit, targetAura, source, game)) {
continue;
}
Permanent aura = game.getPermanent(targetAura.getFirstTarget());
if (aura == null) { continue; }
if (aura == null) {
continue;
}
Target target = aura.getSpellAbility().getTargets().get(0);
if (target == null) { continue; }
if (target == null) {
continue;
}
fromBattlefield.add(aura);
filterAura.add(Predicates.not(new CardIdPredicate(aura.getId())));
countBattlefield = game.getBattlefield().getActivePermanents(filterAura, source.getControllerId(), source, game).size() - sourcePermanent.getAttachments().size();
countBattlefield = (int) (game.getBattlefield().getActivePermanents(filterAura, source.getControllerId(), source, game).size()
- sourcePermanent.getAttachments().stream().map(game::getPermanent).filter(permanent -> permanent != null
&& permanent.hasSubtype(SubType.AURA, game)).count());
}
int countHand = controller.getHand().count(filterAuraCard, game);
@ -125,13 +134,19 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
&& countHand > 0
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", source, game)) {
TargetCard targetAura = new TargetCard(Zone.HAND, filterAuraCard);
if (!controller.choose(Outcome.Benefit, controller.getHand(), targetAura, source, game)) { continue; }
if (!controller.choose(Outcome.Benefit, controller.getHand(), targetAura, source, game)) {
continue;
}
Card aura = game.getCard(targetAura.getFirstTarget());
if (aura == null) { continue; }
if (aura == null) {
continue;
}
Target target = aura.getSpellAbility().getTargets().get(0);
if (target == null) { continue; }
if (target == null) {
continue;
}
fromHandGraveyard.add(aura);
filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId())));
@ -143,13 +158,19 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
&& countGraveyard > 0
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", source, game)) {
TargetCard targetAura = new TargetCard(Zone.GRAVEYARD, filterAuraCard);
if (!controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, source, game)) { continue; }
if (!controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, source, game)) {
continue;
}
Card aura = game.getCard(targetAura.getFirstTarget());
if (aura == null) { continue; }
if (aura == null) {
continue;
}
Target target = aura.getSpellAbility().getTargets().get(0);
if (target == null) { continue; }
if (target == null) {
continue;
}
fromHandGraveyard.add(aura);
filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId())));
@ -168,7 +189,9 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
// Move cards
for (Card aura : fromHandGraveyard) {
if (aura == null) { continue; }
if (aura == null) {
continue;
}
game.getState().setValue("attachTo:" + aura.getId(), sourcePermanent);
controller.moveCards(aura, Zone.BATTLEFIELD, source, game);

View file

@ -2,16 +2,12 @@
package mage.cards.b;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.SimpleManaAbility;
import mage.abilities.mana.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
/**
*
@ -23,10 +19,10 @@ public final class Brushland extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
this.addAbility(new ColorlessManaAbility());
Ability greenManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(1), new TapSourceCost());
Ability greenManaAbility = new GreenManaAbility();
greenManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(greenManaAbility);
Ability whiteManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana(1), new TapSourceCost());
Ability whiteManaAbility = new WhiteManaAbility();
whiteManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(whiteManaAbility);
}

View file

@ -32,7 +32,7 @@ public final class BrutalCathar extends CardImpl {
Ability ability = new TransformsOrEntersTriggeredAbility(
new ExileUntilSourceLeavesEffect()
.setText("exile target creature an opponent controls until this creature leaves the battlefield"), false
).setTriggerPhrase("When this creature enters the battlefield or transforms into {this}, ");
).setTriggerPhrase("When this creature enters or transforms into {this}, ");
ability.addTarget(new TargetOpponentsCreaturePermanent());
this.addAbility(ability);

View file

@ -8,8 +8,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledArtifactPermanent;
import mage.filter.common.FilterControlledPermanent;
import java.util.UUID;
@ -18,7 +18,7 @@ import java.util.UUID;
*/
public final class Caprichrome extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledArtifactPermanent("artifact");
private static final FilterPermanent filter = new FilterControlledArtifactPermanent("artifact");
public Caprichrome(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{W}");

View file

@ -0,0 +1,47 @@
package mage.cards.c;
import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.targetpointer.SecondTargetPointer;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CatharticParting extends CardImpl {
private static final FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment an opponent controls");
static {
filter.add(TargetController.OPPONENT.getControllerPredicate());
}
public CatharticParting(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}");
// The owner of target artifact or enchantment an opponent controls shuffles it into their library. You may shuffle up to four target cards from your graveyard into your library.
this.getSpellAbility().addEffect(new ShuffleIntoLibraryTargetEffect()
.setText("the owner of target artifact or enchantment an opponent controls shuffles it into their library"));
this.getSpellAbility().addTarget(new TargetPermanent(filter));
this.getSpellAbility().addEffect(new ShuffleIntoLibraryTargetEffect(true)
.setTargetPointer(new SecondTargetPointer()));
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 4));
}
private CatharticParting(final CatharticParting card) {
super(card);
}
@Override
public CatharticParting copy() {
return new CatharticParting(this);
}
}

View file

@ -2,16 +2,12 @@
package mage.cards.c;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.SimpleManaAbility;
import mage.abilities.mana.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
/**
*
@ -27,10 +23,10 @@ public final class CavesOfKoilos extends CardImpl {
this.addAbility(new ColorlessManaAbility());
// Tap: Add White or Black. Caves of Koilos deals 1 damage to you.
Ability whiteManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana(1), new TapSourceCost());
Ability whiteManaAbility = new WhiteManaAbility();
whiteManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(whiteManaAbility);
Ability blackManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1), new TapSourceCost());
Ability blackManaAbility = new BlackManaAbility();
blackManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(blackManaAbility);
}

View file

@ -3,6 +3,7 @@ package mage.cards.c;
import mage.MageInt;
import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -23,7 +24,8 @@ public final class ClatteringSkeletons extends CardImpl {
this.toughness = new MageInt(3);
// When Clattering Skeletons dies, venture into the dungeon.
this.addAbility(new DiesSourceTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new DiesSourceTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
}
private ClatteringSkeletons(final ClatteringSkeletons card) {

View file

@ -9,6 +9,7 @@ import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -32,7 +33,8 @@ public final class CloisterGargoyle extends CardImpl {
this.toughness = new MageInt(4);
// When Cloister Gargoyle enters the battlefield, venture into the dungeon.
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
// As long as you've completed a dungeon, Cloister Gargoyle gets +3/+0 and has flying.
Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect(

View file

@ -0,0 +1,87 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfPlayersNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ComeBackWrong extends CardImpl {
public ComeBackWrong(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}");
// Destroy target creature. If a creature card is put into a graveyard this way, return it to the battlefield under your control. Sacrifice it at the beginning of your next end step.
this.getSpellAbility().addEffect(new ComeBackWrongEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
private ComeBackWrong(final ComeBackWrong card) {
super(card);
}
@Override
public ComeBackWrong copy() {
return new ComeBackWrong(this);
}
}
class ComeBackWrongEffect extends OneShotEffect {
ComeBackWrongEffect() {
super(Outcome.Benefit);
staticText = "destroy target creature. If a creature card is put into a graveyard this way, " +
"return it to the battlefield under your control. Sacrifice it at the beginning of your next end step";
}
private ComeBackWrongEffect(final ComeBackWrongEffect effect) {
super(effect);
}
@Override
public ComeBackWrongEffect copy() {
return new ComeBackWrongEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent == null) {
return false;
}
permanent.destroy(source, game);
Card card = permanent.getMainCard();
if (card == null || !card.isCreature(game) || !Zone.GRAVEYARD.match(game.getState().getZone(card.getId()))) {
return true;
}
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
player.moveCards(card, Zone.BATTLEFIELD, source, game);
Permanent creature = game.getPermanent(card.getId());
if (permanent != null) {
game.addDelayedTriggeredAbility(new AtTheBeginOfPlayersNextEndStepDelayedTriggeredAbility(
new SacrificeTargetEffect("sacrifice it")
.setTargetPointer(new FixedTarget(creature, game)),
player.getId()
).setTriggerPhrase("At the beginning of your next end step, "), source);
}
return true;
}
}

View file

@ -99,12 +99,12 @@ class ConduitOfRuinWatcher extends Watcher {
}
}
class FirstCastCreatureSpellPredicate implements ObjectSourcePlayerPredicate<Controllable> {
class FirstCastCreatureSpellPredicate implements ObjectSourcePlayerPredicate<Card> {
@Override
public boolean apply(ObjectSourcePlayer<Controllable> input, Game game) {
if (input.getObject() instanceof Card
&& ((Card) input.getObject()).isCreature(game)) {
public boolean apply(ObjectSourcePlayer<Card> input, Game game) {
if (input.getObject() != null
&& input.getObject().isCreature(game)) {
ConduitOfRuinWatcher watcher = game.getState().getWatcher(ConduitOfRuinWatcher.class);
return watcher != null && watcher.creatureSpellsCastThisTurn(input.getPlayerId()) == 0;
}

View file

@ -0,0 +1,89 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class CoordinatedClobbering extends CardImpl {
public CoordinatedClobbering(UUID ownerId, CardSetInfo setInfo) {
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.
this.getSpellAbility().addEffect(new CoordinatedClobberingEffect());
this.getSpellAbility().addTarget(new TargetPermanent(
1, 2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES
));
this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent());
}
private CoordinatedClobbering(final CoordinatedClobbering card) {
super(card);
}
@Override
public CoordinatedClobbering copy() {
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!

View file

@ -0,0 +1,60 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.common.DealtDamageAttachedTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.discard.LookTargetHandChooseDiscardEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.target.TargetPermanent;
import mage.target.TargetPlayer;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CrackedSkull extends CardImpl {
public CrackedSkull(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{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));
// When Cracked Skull enters, look at target player's hand. You may choose a nonland card from it. That player discards that card.
Ability ability = new EntersBattlefieldTriggeredAbility(
new LookTargetHandChooseDiscardEffect(true, StaticValue.get(1), StaticFilters.FILTER_CARD_NON_LAND)
.setText("look at target player's hand. You may choose a nonland card from it. That player discards that card")
);
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
// When enchanted creature is dealt damage, destroy it.
this.addAbility(new DealtDamageAttachedTriggeredAbility(
Zone.BATTLEFIELD, new DestroyTargetEffect("destroy it"),
false, SetTargetPointer.PERMANENT
).setTriggerPhrase("When enchanted creature is dealt damage, "));
}
private CrackedSkull(final CrackedSkull card) {
super(card);
}
@Override
public CrackedSkull copy() {
return new CrackedSkull(this);
}
}

View file

@ -33,11 +33,11 @@ public final class CursedRecording extends CardImpl {
// Whenever you cast an instant or sorcery spell, put a time counter on Cursed Recording. Then if there are seven or more time counters on it, remove those counters and it deals 20 damage to you.
Ability ability = new SpellCastControllerTriggeredAbility(
new AddCountersSourceEffect(CounterType.TIME.createInstance()),
StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, true
StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false
);
ability.addEffect(new ConditionalOneShotEffect(
new RemoveAllCountersSourceEffect(CounterType.TIME),
condition, "then if there are seven or more time counters on it, " +
condition, "Then if there are seven or more time counters on it, " +
"remove those counters and it deals 20 damage to you"
).addEffect(new DamageControllerEffect(20)));
this.addAbility(ability);

View file

@ -6,6 +6,7 @@ import mage.abilities.common.AttacksAttachedTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.EquipAbility;
import mage.constants.SubType;
import mage.cards.CardImpl;
@ -27,7 +28,8 @@ public final class DelversTorch extends CardImpl {
this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1)));
// Whenever equipped creature attacks, venture into the dungeon.
this.addAbility(new AttacksAttachedTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new AttacksAttachedTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
// Equip {3}
this.addAbility(new EquipAbility(3));

View file

@ -1,24 +1,14 @@
package mage.cards.d;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.DevourEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetSacrifice;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import java.util.UUID;
@ -35,7 +25,11 @@ public final class DevouringHellion extends CardImpl {
this.toughness = new MageInt(2);
// As Devouring Hellion enters the battlefield, you may sacrifice any number of creatures and/or planeswalkers. If you do, it enters with twice that many +1/+1 counters on it.
this.addAbility(new AsEntersBattlefieldAbility(new DevouringHellionEffect()));
this.addAbility(new SimpleStaticAbility(Zone.ALL,
new DevourEffect(2, StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER)
.setText("As {this} enters the battlefield, you may sacrifice any number of creatures and/or planeswalkers."
+ " If you do, it enters with twice that many +1/+1 counters on it")
));
}
private DevouringHellion(final DevouringHellion card) {
@ -47,50 +41,3 @@ public final class DevouringHellion extends CardImpl {
return new DevouringHellion(this);
}
}
class DevouringHellionEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterControlledPermanent("creatures and/or planeswalkers");
static {
filter.add(Predicates.or(
CardType.CREATURE.getPredicate(),
CardType.PLANESWALKER.getPredicate()
));
}
DevouringHellionEffect() {
super(Outcome.Benefit);
staticText = "you may sacrifice any number of creatures and/or planeswalkers. " +
"If you do, it enters with twice that many +1/+1 counters on it.";
}
private DevouringHellionEffect(final DevouringHellionEffect effect) {
super(effect);
}
@Override
public DevouringHellionEffect copy() {
return new DevouringHellionEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Target target = new TargetSacrifice(0, Integer.MAX_VALUE, filter);
if (!player.choose(Outcome.Sacrifice, target, source, game)) {
return false;
}
int xValue = 0;
for (UUID targetId : target.getTargets()) {
Permanent permanent = game.getPermanent(targetId);
if (permanent != null && permanent.sacrifice(source, game)) {
xValue++;
}
}
return new AddCountersSourceEffect(CounterType.P1P1.createInstance(2 * xValue)).apply(game, source);
}
}

View file

@ -36,7 +36,7 @@ public final class DiscipleOfPerdition extends CardImpl {
// * You draw a card and you lose 1 life.
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().setMoreCondition(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"));
// * Exile target opponent's graveyard. That player loses 1 life.

View file

@ -6,6 +6,7 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -27,7 +28,8 @@ public final class DisplacerBeast extends CardImpl {
this.toughness = new MageInt(2);
// When Displacer Beast enters the battlefield, venture into the dungeon.
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
// Displacement {3}{U}: Return Displacer Beast to its owner's hand.
this.addAbility(new SimpleActivatedAbility(

View file

@ -0,0 +1,78 @@
package mage.cards.d;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetSpell;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class DontMakeASound extends CardImpl {
public DontMakeASound(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
// Counter target spell unless its controller pays {2}. If they do, surveil 2.
this.getSpellAbility().addEffect(new DontMakeASoundEffect());
this.getSpellAbility().addTarget(new TargetSpell());
}
private DontMakeASound(final DontMakeASound card) {
super(card);
}
@Override
public DontMakeASound copy() {
return new DontMakeASound(this);
}
}
class DontMakeASoundEffect extends OneShotEffect {
DontMakeASoundEffect() {
super(Outcome.Benefit);
staticText = "counter target spell unless its controller pays {2}. If they do, surveil 2";
}
private DontMakeASoundEffect(final DontMakeASoundEffect effect) {
super(effect);
}
@Override
public DontMakeASoundEffect copy() {
return new DontMakeASoundEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getSpell(getTargetPointer().getFirst(game, source));
if (spell == null) {
return false;
}
Player player = game.getPlayer(spell.getControllerId());
if (player == null) {
return game.getStack().counter(spell.getId(), source, game);
}
Cost cost = new GenericManaCost(2);
if (!cost.canPay(source, source, player.getId(), game)
|| !player.chooseUse(outcome, "Pay {2}?", source, game)
|| !cost.pay(source, game, source, player.getId(), false)) {
return game.getStack().counter(spell.getId(), source, game);
}
Optional.ofNullable(game.getPlayer(source.getControllerId()))
.ifPresent(p -> p.surveil(2, source, game));
return true;
}
}

View file

@ -28,7 +28,7 @@ public final class DrownInDreams extends CardImpl {
this.getSpellAbility().getModes().setChooseText(
"Choose one. If you control a commander as you cast this spell, you may choose both."
);
this.getSpellAbility().getModes().setMoreCondition(ControlACommanderCondition.instance);
this.getSpellAbility().getModes().setMoreCondition(2, ControlACommanderCondition.instance);
// Target player draws X cards.
this.getSpellAbility().addEffect(new DrawCardTargetEffect(GetXValue.instance));

View file

@ -9,6 +9,7 @@ import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.common.TapTargetCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -45,6 +46,7 @@ public final class DungeonDescent extends CardImpl {
Ability ability = new ActivateAsSorceryActivatedAbility(new VentureIntoTheDungeonEffect(), new GenericManaCost(4));
ability.addCost(new TapSourceCost());
ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(filter)));
ability.addHint(CurrentDungeonHint.instance);
this.addAbility(ability);
}

View file

@ -5,6 +5,7 @@ import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -28,6 +29,7 @@ public final class DungeonMap extends CardImpl {
new VentureIntoTheDungeonEffect(), new GenericManaCost(3)
);
ability.addCost(new TapSourceCost());
ability.addHint(CurrentDungeonHint.instance);
this.addAbility(ability);
}

View file

@ -8,6 +8,7 @@ import mage.abilities.condition.common.CompletedDungeonCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -36,7 +37,8 @@ public final class EccentricApprentice extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Eccentric Apprentice enters the battlefield, venture into the dungeon.
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
// At the beginning of combat on your turn, if you've completed a dungeon, up to one target creature becomes a Bird with base power and toughness 1/1 and flying until end of turn.
Ability ability = new ConditionalInterveningIfTriggeredAbility(

View file

@ -5,6 +5,7 @@ import mage.abilities.LoyaltyAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GetEmblemEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.*;
import mage.constants.*;
import mage.filter.StaticFilters;
@ -29,7 +30,8 @@ public final class EllywickTumblestrum extends CardImpl {
this.setStartingLoyalty(4);
// +1: Venture into the dungeon.
this.addAbility(new LoyaltyAbility(new VentureIntoTheDungeonEffect(), 1));
this.addAbility(new LoyaltyAbility(new VentureIntoTheDungeonEffect(), 1)
.addHint(CurrentDungeonHint.instance));
// 2: Look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. If it's legendary, you gain 3 life. Put the rest on the bottom of your library in a random order.
this.addAbility(new LoyaltyAbility(new EllywickTumblestrumEffect(), -2));

View file

@ -93,13 +93,13 @@ public final class ElugeTheShorelessSea extends CardImpl {
}
}
enum ElugeTheShorelessSeaPredicate implements ObjectSourcePlayerPredicate<Controllable> {
enum ElugeTheShorelessSeaPredicate implements ObjectSourcePlayerPredicate<Card> {
instance;
@Override
public boolean apply(ObjectSourcePlayer<Controllable> input, Game game) {
if (input.getObject() instanceof Card &&
((Card) input.getObject()).isInstantOrSorcery(game)) {
public boolean apply(ObjectSourcePlayer<Card> input, Game game) {
if (input.getObject() != null &&
input.getObject().isInstantOrSorcery(game)) {
ElugeTheShorelessSeaWatcher watcher = game.getState().getWatcher(ElugeTheShorelessSeaWatcher.class);
return watcher != null &&
watcher.getInstantOrSorcerySpellsCastThisTurn(input.getPlayerId()) == 0;

View file

@ -2,6 +2,7 @@ package mage.cards.f;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -24,6 +25,7 @@ public final class FatesReversal extends CardImpl {
0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD
));
this.getSpellAbility().addEffect(new VentureIntoTheDungeonEffect().concatBy("."));
this.getSpellAbility().addHint(CurrentDungeonHint.instance);
}
private FatesReversal(final FatesReversal card) {

View file

@ -0,0 +1,99 @@
package mage.cards.f;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.DeliriumCondition;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.common.DamagePlayersEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.hint.common.CardTypesInGraveyardHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.DamagedEvent;
import mage.game.events.GameEvent;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class FearOfBurningAlive extends CardImpl {
public FearOfBurningAlive(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{4}{R}{R}");
this.subtype.add(SubType.NIGHTMARE);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// When Fear of Burning Alive enters, it deals 4 damage to each opponent.
this.addAbility(new EntersBattlefieldTriggeredAbility(
new DamagePlayersEffect(4, TargetController.OPPONENT, "it")
));
// Delirium -- Whenever a source you control deals noncombat damage to an opponent, if there are four or more card types among cards in your graveyard, Fear of Burning Alive deals that amount of damage to target creature that player controls.
this.addAbility(new FearOfBurningAliveTriggeredAbility());
}
private FearOfBurningAlive(final FearOfBurningAlive card) {
super(card);
}
@Override
public FearOfBurningAlive copy() {
return new FearOfBurningAlive(this);
}
}
class FearOfBurningAliveTriggeredAbility extends TriggeredAbilityImpl {
FearOfBurningAliveTriggeredAbility() {
super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MANY)
.setText("{this} deals that amount of damage to target creature that player controls"));
this.setTriggerPhrase("Whenever a source you control deals noncombat damage to an opponent, " +
"if there are four or more card types among cards in your graveyard, ");
this.setAbilityWord(AbilityWord.DELIRIUM);
this.addHint(CardTypesInGraveyardHint.YOU);
}
private FearOfBurningAliveTriggeredAbility(final FearOfBurningAliveTriggeredAbility ability) {
super(ability);
}
@Override
public FearOfBurningAliveTriggeredAbility copy() {
return new FearOfBurningAliveTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (((DamagedEvent) event).isCombatDamage()
|| !isControlledBy(game.getControllerId(event.getSourceId()))
|| !game.getOpponents(getControllerId()).contains(event.getTargetId())) {
return false;
}
this.getEffects().setValue("damage", event.getAmount());
FilterPermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(event.getTargetId()));
this.getTargets().clear();
this.addTarget(new TargetPermanent(filter));
return true;
}
@Override
public boolean checkInterveningIfClause(Game game) {
return DeliriumCondition.instance.apply(game, this);
}
}

View file

@ -14,7 +14,6 @@ import mage.filter.StaticFilters;
import java.util.UUID;
/**
*
* @author Susucr
*/
public final class FeastingHobbit extends CardImpl {

View file

@ -10,6 +10,7 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect;
import mage.abilities.effects.common.combat.CantBlockTargetEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -44,6 +45,7 @@ public final class FiftyFeetOfRope extends CardImpl {
// Rappel Down {4}, {T}: Venture into the dungeon. Activate only as a sorcery.
ability = new ActivateAsSorceryActivatedAbility(new VentureIntoTheDungeonEffect(), new ManaCostsImpl<>("{4}"));
ability.addCost(new TapSourceCost());
ability.addHint(CurrentDungeonHint.instance);
this.addAbility(ability.withFlavorWord("Rappel Down"));
}

View file

@ -8,6 +8,7 @@ import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
@ -36,7 +37,8 @@ public final class FindThePath extends CardImpl {
this.addAbility(ability);
// When Find the Path enters the battlefield, venture into the dungeon.
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
// Enchanted land has "{T}: Add {G}{G}."
this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(

View file

@ -32,8 +32,7 @@ public final class FlameOfAnor extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{R}");
// Choose one. If you control a Wizard as you cast this spell, you may choose two instead.
this.getSpellAbility().getModes().setMoreCondition(condition);
this.getSpellAbility().getModes().setMoreLimit(2);
this.getSpellAbility().getModes().setMoreCondition(2, condition);
this.getSpellAbility().getModes().setChooseText(
"Choose one. If you control a Wizard as you cast this spell, you may choose two instead."
);

View file

@ -6,6 +6,7 @@ import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.FlyingAbility;
import mage.constants.AttachmentType;
import mage.constants.SubType;
@ -43,6 +44,7 @@ public final class Fly extends CardImpl {
new DealsCombatDamageToAPlayerTriggeredAbility(new VentureIntoTheDungeonEffect(), false),
AttachmentType.AURA).setText("and \"Whenever this creature deals combat damage to a player, venture into the dungeon.\"")
);
ability.addHint(CurrentDungeonHint.instance);
this.addAbility(ability);
}

View file

@ -0,0 +1,90 @@
package mage.cards.f;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ChooseColorEffect;
import mage.abilities.effects.keyword.ScryEffect;
import mage.abilities.effects.mana.AddManaChosenColorEffect;
import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.UUID;
/**
* @author Svyatoslav28
*/
public final class ForsakenCrossroads extends CardImpl {
public ForsakenCrossroads(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Forsaken Crossroads enters tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// As Forsaken Crossroads enters, choose a color.
this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral)));
// When Forskaken Crossroads enters, scry 1. If you werent the starting player, you may untap Forsaken Crossroads instead.
this.addAbility(new EntersBattlefieldTriggeredAbility(new ForsakenCrossroadsEffect()));
// {T}: Add one mana of the chosen color.
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaChosenColorEffect(), new TapSourceCost()));
}
private ForsakenCrossroads(final ForsakenCrossroads card) {
super(card);
}
@Override
public ForsakenCrossroads copy() {
return new ForsakenCrossroads(this);
}
}
class ForsakenCrossroadsEffect extends OneShotEffect {
ForsakenCrossroadsEffect() {
super(Outcome.PutCardInPlay);
this.staticText = "scry 1. If you weren't the starting player, you may untap {this} instead.";
}
private ForsakenCrossroadsEffect(final ForsakenCrossroadsEffect effect) {
super(effect);
}
@Override
public ForsakenCrossroadsEffect copy() {
return new ForsakenCrossroadsEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && !controller.getId().equals(game.getStartingPlayerId())) {
if (controller.chooseUse(Outcome.Untap, "Untap {this} instead of scrying 1?", "", "Untap", "Scry 1", source, game)) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
return false;
}
permanent.untap(game);
return true;
}
}
OneShotEffect scryEffect = new ScryEffect(1);
scryEffect.apply(game, source);
return true;
}
}

View file

@ -0,0 +1,50 @@
package mage.cards.f;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.LookAtOpponentFaceDownCreaturesAnyTimeEffect;
import mage.abilities.effects.keyword.SurveilEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.TargetController;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class FoundFootage extends CardImpl {
public FoundFootage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
this.subtype.add(SubType.CLUE);
// You may look at face-down creatures your opponents control any time.
this.addAbility(new SimpleStaticAbility(
new LookAtOpponentFaceDownCreaturesAnyTimeEffect(Duration.WhileOnBattlefield, TargetController.OPPONENT)
));
// {2}, Sacrifice Found Footage: Surveil 2, then draw a card.
Ability ability = new SimpleActivatedAbility(new SurveilEffect(2, false), new GenericManaCost(2));
ability.addCost(new SacrificeSourceCost());
ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy(", then"));
this.addAbility(ability);
}
private FoundFootage(final FoundFootage card) {
super(card);
}
@Override
public FoundFootage copy() {
return new FoundFootage(this);
}
}

View file

@ -0,0 +1,33 @@
package mage.cards.g;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.game.permanent.token.GlimmerToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class Glimmerburst extends CardImpl {
public Glimmerburst(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}");
// Draw two cards. Create a 1/1 white Glimmer enchantment creature token.
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2));
this.getSpellAbility().addEffect(new CreateTokenEffect(new GlimmerToken()));
}
private Glimmerburst(final Glimmerburst card) {
super(card);
}
@Override
public Glimmerburst copy() {
return new Glimmerburst(this);
}
}

View file

@ -0,0 +1,61 @@
package mage.cards.h;
import mage.abilities.Ability;
import mage.abilities.common.ActivateOncePerGameActivatedAbility;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.mana.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.game.permanent.token.custom.CreatureToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class HauntedScreen extends CardImpl {
public HauntedScreen(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {T}: Add {W} or {B}.
this.addAbility(new WhiteManaAbility());
this.addAbility(new BlackManaAbility());
// {T}, Pay 1 life: Add {G}, {U}, or {R}.
Ability ability = new GreenManaAbility();
ability.addCost(new PayLifeCost(1));
this.addAbility(ability);
ability = new BlueManaAbility();
ability.addCost(new PayLifeCost(1));
this.addAbility(ability);
ability = new RedManaAbility();
ability.addCost(new PayLifeCost(1));
this.addAbility(ability);
// {7}: Put seven +1/+1 counters on Haunted Screen. It becomes a 0/0 Spirit creature in addition to its other types. Activate only once.
ability = new ActivateOncePerGameActivatedAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(7)), new GenericManaCost(7)
);
ability.addEffect(new BecomesCreatureSourceEffect(new CreatureToken(
0, 0, "0/0 Spirit creature", SubType.SPIRIT
), CardType.ARTIFACT, Duration.Custom).withKeepCreatureSubtypes(true));
this.addAbility(ability);
}
private HauntedScreen(final HauntedScreen card) {
super(card);
}
@Override
public HauntedScreen copy() {
return new HauntedScreen(this);
}
}

View file

@ -0,0 +1,72 @@
package mage.cards.h;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.effects.common.ConjureCardEffect;
import mage.abilities.effects.common.SeekCardEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
/**
* @author Svyatoslav28
*/
public final class HollowhengeWrangler extends CardImpl {
public HollowhengeWrangler(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}");
this.subtype.add(SubType.ELEMENTAL);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// When Hollowhenge Wrangler enters the battlefield, seek a land card.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SeekCardEffect(StaticFilters.FILTER_CARD_LAND)));
// Discard a land card: Conjure a card named Hollowhenge Beast into your hand.
// You may also activate this ability while Hollowhenge Wrangler is in your graveyard.
Ability ability = new ActivateIfConditionActivatedAbility(
Zone.ALL, new ConjureCardEffect("Hollowhenge Beast"), new DiscardCardCost(StaticFilters.FILTER_CARD_LAND), HollowhengeWranglerCondition.instance
);
this.addAbility(ability);
}
private HollowhengeWrangler(final HollowhengeWrangler card) {
super(card);
}
@Override
public HollowhengeWrangler copy() {
return new HollowhengeWrangler(this);
}
}
enum HollowhengeWranglerCondition implements Condition {
instance;
private static final List<Zone> zones = Arrays.asList(Zone.BATTLEFIELD, Zone.GRAVEYARD);
@Override
public boolean apply(Game game, Ability source) {
return zones.contains(game.getState().getZone(source.getSourceId()));
}
@Override
public String toString() {
return "You may also activate this ability while {this} is in your graveyard";
}
}

View file

@ -8,6 +8,7 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.InspiredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -38,7 +39,8 @@ public final class ImmovableRod extends CardImpl {
this.addAbility(new SkipUntapOptionalAbility());
// Whenever Immovable Rod becomes untapped, venture into the dungeon.
this.addAbility(new InspiredAbility(new VentureIntoTheDungeonEffect(), false, false));
this.addAbility(new InspiredAbility(new VentureIntoTheDungeonEffect(), false, false)
.addHint(CurrentDungeonHint.instance));
// {3}{W}, {T}: For as long as Immovable Rod remains tapped, another target permanent loses all abilities and can't attack or block.
Ability ability = new SimpleActivatedAbility(new ImmovableRodAbilityEffect(), new ManaCostsImpl<>("{3}{W}"));

View file

@ -41,7 +41,7 @@ public final class ImposterMech extends CardImpl {
// You may have Imposter Mech enter the battlefield as a copy of a creature an opponent controls, except its a Vehicle artifact with crew 3 and it loses all other card types.
this.addAbility(new EntersBattlefieldAbility(
new CopyPermanentEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE, applier),
new CopyPermanentEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE, applier), true,
null, "You may have {this} enter the battlefield as a copy of a creature " +
"an opponent controls, except it's a Vehicle artifact with crew 3 and it loses all other card types.", null
));

View file

@ -1,4 +1,3 @@
package mage.cards.i;
import mage.abilities.Ability;
@ -15,9 +14,7 @@ import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.XTargetsCountAdjuster;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.*;
/**
* @author LevelX2
@ -67,37 +64,48 @@ class IndomitableCreativityEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
List<Permanent> destroyedPermanents = new ArrayList<>();
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
Permanent target = game.getPermanent(targetId);
if (target != null) {
if (target.destroy(source, game, false)) {
destroyedPermanents.add(target);
}
}
}
for (Permanent permanent : destroyedPermanents) {
Player controllerOfDestroyedCreature = game.getPlayer(permanent.getControllerId());
if (controllerOfDestroyedCreature != null) {
Library library = controllerOfDestroyedCreature.getLibrary();
if (library.hasCards()) {
Cards cardsToReaveal = new CardsImpl();
for (Card card : library.getCards(game)) {
cardsToReaveal.add(card);
if (card.isCreature(game) || card.isArtifact(game)) {
controllerOfDestroyedCreature.moveCards(card, Zone.EXILED, source, game);
controllerOfDestroyedCreature.moveCards(card, Zone.BATTLEFIELD, source, game);
break;
}
}
controllerOfDestroyedCreature.revealCards(source, " for destroyed " + permanent.getIdName(), cardsToReaveal, game);
controllerOfDestroyedCreature.shuffleLibrary(source, game);
}
}
}
return true;
if (controller == null) {
return false;
}
return false;
List<Permanent> destroyedPermanents = new ArrayList<>();
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
Permanent target = game.getPermanent(targetId);
if (target != null && target.destroy(source, game, false)) {
destroyedPermanents.add(target);
}
}
if (destroyedPermanents.isEmpty()) {
return false;
}
game.processAction();
Map<UUID, Set<Card>> playerToBattlefield = new HashMap<>();
for (Permanent permanent : destroyedPermanents) {
Player controllerOfDestroyedCreature = game.getPlayer(permanent.getControllerId());
if (controllerOfDestroyedCreature != null) {
Library library = controllerOfDestroyedCreature.getLibrary();
if (library.hasCards()) {
playerToBattlefield.computeIfAbsent(controllerOfDestroyedCreature.getId(), x -> new HashSet<>());
Cards cardsToReveal = new CardsImpl();
for (Card card : library.getCards(game)) {
cardsToReveal.add(card);
if (card.isCreature(game) || card.isArtifact(game)) {
controllerOfDestroyedCreature.moveCards(card, Zone.EXILED, source, game);
playerToBattlefield.computeIfAbsent(controllerOfDestroyedCreature.getId(), x -> new HashSet<>()).add(card);
break;
}
}
controllerOfDestroyedCreature.revealCards(source, " for destroyed " + permanent.getIdName(), cardsToReveal, game);
}
}
}
game.processAction();
for (Map.Entry<UUID, Set<Card>> entry: playerToBattlefield.entrySet()) {
Player player = game.getPlayer(entry.getKey());
if (player != null) {
player.moveCards(entry.getValue(), Zone.BATTLEFIELD, source, game);
player.shuffleLibrary(source, game);
}
}
return true;
}
}

View file

@ -2,6 +2,7 @@ package mage.cards.i;
import mage.MageInt;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.PackTacticsAbility;
import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl;
@ -28,7 +29,8 @@ public final class IntrepidOutlander extends CardImpl {
this.addAbility(ReachAbility.getInstance());
// Pack tactics Whenever Intrepid Outlander attacks, if you attacked with creatures with total power 6 or greater this combat, venture into the dungeon.
this.addAbility(new PackTacticsAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new PackTacticsAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
}
private IntrepidOutlander(final IntrepidOutlander card) {

View file

@ -29,7 +29,7 @@ public final class JeskasWill extends CardImpl {
this.getSpellAbility().getModes().setChooseText(
"Choose one. If you control a commander as you cast this spell, you may choose both instead."
);
this.getSpellAbility().getModes().setMoreCondition(ControlACommanderCondition.instance);
this.getSpellAbility().getModes().setMoreCondition(2, ControlACommanderCondition.instance);
// Add {R} for each card in target opponent's hand.
this.getSpellAbility().addEffect(new JeskasWillEffect());

View file

@ -0,0 +1,47 @@
package mage.cards.j;
import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect;
import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class JumpScare extends CardImpl {
public JumpScare(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}");
// Until end of turn, target creature gets +2/+2, gains flying, and becomes a Horror enchantment creature in addition to its other types.
this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)
.setText("until end of turn, target creature gets +2/+2"));
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance())
.setText(", gains flying"));
this.getSpellAbility().addEffect(new AddCardSubTypeTargetEffect(
SubType.HORROR, Duration.EndOfTurn
).setText(", and becomes"));
this.getSpellAbility().addEffect(new AddCardTypeTargetEffect(
Duration.EndOfTurn, CardType.ENCHANTMENT, CardType.CREATURE
).setText(" a Horror enchantment creature in addition to its other types"));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
private JumpScare(final JumpScare card) {
super(card);
}
@Override
public JumpScare copy() {
return new JumpScare(this);
}
}

View file

@ -34,7 +34,7 @@ public final class KamahlsWill extends CardImpl {
this.getSpellAbility().getModes().setChooseText(
"Choose one. If you control a commander as you cast this spell, you may choose both."
);
this.getSpellAbility().getModes().setMoreCondition(ControlACommanderCondition.instance);
this.getSpellAbility().getModes().setMoreCondition(2, ControlACommanderCondition.instance);
// Until end of turn, any number of target lands you control become 1/1 Elemental creatures with vigilance, indestructible, and haste. They're still lands.
this.getSpellAbility().addEffect(new BecomesCreatureTargetEffect(

View file

@ -2,16 +2,12 @@
package mage.cards.k;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.SimpleManaAbility;
import mage.abilities.mana.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
/**
*
@ -24,10 +20,10 @@ public final class KarplusanForest extends CardImpl {
this.addAbility(new ColorlessManaAbility());
Ability redManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana(1), new TapSourceCost());
Ability redManaAbility = new RedManaAbility();
redManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(redManaAbility);
Ability greenManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(1), new TapSourceCost());
Ability greenManaAbility = new GreenManaAbility();
greenManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(greenManaAbility);
}

View file

@ -6,6 +6,7 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.continuous.GainAbilityControllerEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.HexproofAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -35,7 +36,7 @@ public final class KeenEaredSentry extends CardImpl {
this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance())));
// Your opponents can't venture into the dungeon more than once each turn.
this.addAbility(new SimpleStaticAbility(new KeenEaredSentryEffect()), new KeenEaredSentryWatcher());
this.addAbility(new SimpleStaticAbility(new KeenEaredSentryEffect()).addHint(CurrentDungeonHint.instance), new KeenEaredSentryWatcher());
}
private KeenEaredSentry(final KeenEaredSentry card) {

View file

@ -6,6 +6,7 @@ import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -40,6 +41,7 @@ public final class KickInTheDoor extends CardImpl {
.setText("and can't be blocked by Walls this turn")
);
this.getSpellAbility().addEffect(new VentureIntoTheDungeonEffect());
this.getSpellAbility().addHint(CurrentDungeonHint.instance);
}
private KickInTheDoor(final KickInTheDoor card) {

View file

@ -40,7 +40,7 @@ public final class KlauthsWill extends CardImpl {
this.getSpellAbility().getModes().setChooseText(
"Choose one. If you control a commander as you cast this spell, you may choose both."
);
this.getSpellAbility().getModes().setMoreCondition(ControlACommanderCondition.instance);
this.getSpellAbility().getModes().setMoreCondition(2, ControlACommanderCondition.instance);
// Breathe Flame Klauth's Will deals X damage to each creature without flying.
this.getSpellAbility().addEffect(new DamageAllEffect(GetXValue.instance, filter));
@ -76,4 +76,4 @@ enum KlauthsWillAdjuster implements TargetAdjuster {
));
}
}
}
}

View file

@ -1,8 +1,6 @@
package mage.cards.l;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
@ -14,14 +12,16 @@ import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.constants.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* @author grimreap124
*/
@ -31,7 +31,7 @@ public final class LeonardoDaVinci extends CardImpl {
static {
filter.add(SubType.THOPTER.getPredicate());
filter.add(TargetController.YOU.getPlayerPredicate());
filter.add(TargetController.YOU.getControllerPredicate());
}
public LeonardoDaVinci(UUID ownerId, CardSetInfo setInfo) {
@ -112,4 +112,4 @@ class LeonardoDaVinciEffect extends OneShotEffect {
return true;
}
}
}

View file

@ -30,7 +30,7 @@ public final class LetsPlayAGame extends CardImpl {
this.getSpellAbility().getModes().setChooseText(
"choose one. If there are four or more card types among cards in your graveyard, choose one or more instead."
);
this.getSpellAbility().getModes().setMoreCondition(DeliriumCondition.instance);
this.getSpellAbility().getModes().setMoreCondition(3, DeliriumCondition.instance);
this.getSpellAbility().setAbilityWord(AbilityWord.DELIRIUM);
this.getSpellAbility().addHint(CardTypesInGraveyardHint.YOU);

View file

@ -2,16 +2,12 @@
package mage.cards.l;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.SimpleManaAbility;
import mage.abilities.mana.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
/**
*
@ -26,10 +22,10 @@ public final class LlanowarWastes extends CardImpl {
this.addAbility(new ColorlessManaAbility());
// Tap: Add Black or Green. Llanowar Wastes deals 1 damage to you.
Ability blackManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1), new TapSourceCost());
Ability blackManaAbility = new BlackManaAbility();
blackManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(blackManaAbility);
Ability greenManaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(1), new TapSourceCost());
Ability greenManaAbility = new GreenManaAbility();
greenManaAbility.addEffect(new DamageControllerEffect(1));
this.addAbility(greenManaAbility);
}

View file

@ -0,0 +1,87 @@
package mage.cards.m;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class MarvinMurderousMimic extends CardImpl {
public MarvinMurderousMimic(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.TOY);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Marvin, Murderous Mimic has all activated abilities of creatures you control that don't have the same name as this creature.
this.addAbility(new SimpleStaticAbility(new MarvinMurderousMimicEffect()));
}
private MarvinMurderousMimic(final MarvinMurderousMimic card) {
super(card);
}
@Override
public MarvinMurderousMimic copy() {
return new MarvinMurderousMimic(this);
}
}
class MarvinMurderousMimicEffect extends ContinuousEffectImpl {
MarvinMurderousMimicEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = "{this} has all activated abilities of creatures " +
"you control that don't have the same name as this creature";
}
private MarvinMurderousMimicEffect(final MarvinMurderousMimicEffect effect) {
super(effect);
}
@Override
public MarvinMurderousMimicEffect copy() {
return new MarvinMurderousMimicEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
return false;
}
List<Ability> abilities = game
.getBattlefield()
.getActivePermanents(
StaticFilters.FILTER_CONTROLLED_CREATURE,
source.getControllerId(), source, game
)
.stream()
.filter(p -> !CardUtil.haveSameNames(p, permanent))
.map(p -> p.getAbilities(game))
.flatMap(Collection::stream)
.filter(Ability::isActivatedAbility)
.collect(Collectors.toList());
for (Ability ability : abilities) {
permanent.addAbility(ability, source.getSourceId(), game);
}
return true;
}
}

View file

@ -71,13 +71,13 @@ public final class MelekReforgedResearcher extends CardImpl {
}
}
enum MelekReforgedResearcherPredicate implements ObjectSourcePlayerPredicate<Controllable> {
enum MelekReforgedResearcherPredicate implements ObjectSourcePlayerPredicate<Card> {
instance;
@Override
public boolean apply(ObjectSourcePlayer<Controllable> input, Game game) {
if (input.getObject() instanceof Card &&
((Card) input.getObject()).isInstantOrSorcery(game)) {
public boolean apply(ObjectSourcePlayer<Card> input, Game game) {
if (input.getObject() != null &&
input.getObject().isInstantOrSorcery(game)) {
MelekReforgedResearcherWatcher watcher = game.getState().getWatcher(MelekReforgedResearcherWatcher.class);
return watcher != null &&
watcher.getInstantOrSorcerySpellsCastThisTurn(input.getPlayerId()) == 0;

View file

@ -5,6 +5,7 @@ import mage.abilities.common.DealCombatDamageControlledTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesAllEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -44,7 +45,8 @@ public final class MidnightPathlighter extends CardImpl {
)));
// Whenever one or more creatures you control deal combat damage to a player, venture into the dungeon.
this.addAbility(new DealCombatDamageControlledTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new DealCombatDamageControlledTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
}
private MidnightPathlighter(final MidnightPathlighter card) {

View file

@ -5,6 +5,7 @@ import mage.abilities.effects.common.discard.LookTargetHandChooseDiscardEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.StaticFilters;
import mage.target.TargetPlayer;
import java.util.UUID;
@ -18,7 +19,7 @@ public final class MindWarp extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{3}{B}");
// Look at target player's hand and choose X cards from it. That player discards those cards.
this.getSpellAbility().addEffect(new LookTargetHandChooseDiscardEffect(false, GetXValue.instance));
this.getSpellAbility().addEffect(new LookTargetHandChooseDiscardEffect(false, GetXValue.instance, StaticFilters.FILTER_CARD_CARDS));
this.getSpellAbility().addTarget(new TargetPlayer());
}

View file

@ -34,7 +34,7 @@ public final class MoltenCollapse extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{R}");
// Choose one. If you descended this turn, you may choose both instead.
this.getSpellAbility().getModes().setMoreCondition(DescendedThisTurnCondition.instance);
this.getSpellAbility().getModes().setMoreCondition(2, DescendedThisTurnCondition.instance);
this.getSpellAbility().getModes().setChooseText(
"Choose one. If you descended this turn, you may choose both instead."
);

View file

@ -7,6 +7,7 @@ import mage.abilities.condition.common.CompletedDungeonCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -36,7 +37,8 @@ public final class NadaarSelflessPaladin extends CardImpl {
this.addAbility(VigilanceAbility.getInstance());
// Whenever Nadaar, Selfless Paladin enters the battlefield or attacks, venture into the dungeon.
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
// Other creatures you control get +1/+1 as long as you've completed a dungeon.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(

View file

@ -0,0 +1,104 @@
package mage.cards.n;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageInt;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.mana.SimpleManaAbility;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.abilities.mana.conditional.ConditionalSpellManaBuilder;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.abilities.keyword.UndyingAbility;
import mage.abilities.keyword.DoctorsCompanionAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author Cguy7777
*/
public final class NardoleResourcefulCyborg extends CardImpl {
public NardoleResourcefulCyborg(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{U}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SCIENTIST);
this.power = new MageInt(1);
this.toughness = new MageInt(2);
// {T}: Add {U} for each counter on Nardole. Spend this mana only to cast noncreature spells.
this.addAbility(new SimpleManaAbility(new NardoleResourcefulCyborgManaEffect(), new TapSourceCost()));
// Undying
this.addAbility(new UndyingAbility());
// Doctor's companion
this.addAbility(DoctorsCompanionAbility.getInstance());
}
private NardoleResourcefulCyborg(final NardoleResourcefulCyborg card) {
super(card);
}
@Override
public NardoleResourcefulCyborg copy() {
return new NardoleResourcefulCyborg(this);
}
}
class NardoleResourcefulCyborgManaEffect extends ManaEffect {
private final ConditionalManaBuilder manaBuilder
= new ConditionalSpellManaBuilder(StaticFilters.FILTER_SPELLS_NON_CREATURE);
NardoleResourcefulCyborgManaEffect() {
this.staticText = "Add {U} for each counter on {this}. " + manaBuilder.getRule();
}
private NardoleResourcefulCyborgManaEffect(final NardoleResourcefulCyborgManaEffect effect) {
super(effect);
}
@Override
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netMana = new ArrayList<>();
if (game == null) {
return netMana;
}
Permanent permanent = source.getSourcePermanentOrLKI(game);
if (permanent != null) {
netMana.add(manaBuilder.setMana(
Mana.BlueMana(permanent.getCounters(game).getTotalCount()), source, game).build());
}
return netMana;
}
@Override
public Mana produceMana(Game game, Ability source) {
Mana mana = new Mana();
if (game == null) {
return mana;
}
Permanent permanent = source.getSourcePermanentOrLKI(game);
if (permanent == null) {
return mana;
}
return manaBuilder.setMana(
Mana.BlueMana(permanent.getCounters(game).getTotalCount()), source, game).build();
}
@Override
public NardoleResourcefulCyborgManaEffect copy() {
return new NardoleResourcefulCyborgManaEffect(this);
}
}

View file

@ -2,22 +2,17 @@ package mage.cards.n;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
import mage.filter.StaticFilters;
/**
*
@ -36,7 +31,12 @@ public final class NecropolisRegent extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever a creature you control deals combat damage to a player, put that many +1/+1 counters on it.
this.addAbility(new NecropolisRegentTriggeredAbility());
this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance(), SavedDamageValue.MANY)
.setText("put that many +1/+1 counters on it"),
StaticFilters.FILTER_CONTROLLED_A_CREATURE,
false, SetTargetPointer.PERMANENT, true
));
}
private NecropolisRegent(final NecropolisRegent card) {
@ -48,44 +48,3 @@ public final class NecropolisRegent extends CardImpl {
return new NecropolisRegent(this);
}
}
class NecropolisRegentTriggeredAbility extends TriggeredAbilityImpl {
public NecropolisRegentTriggeredAbility() {
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), false);
}
private NecropolisRegentTriggeredAbility(final NecropolisRegentTriggeredAbility ability) {
super(ability);
}
@Override
public NecropolisRegentTriggeredAbility copy() {
return new NecropolisRegentTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (((DamagedPlayerEvent) event).isCombatDamage()) {
Permanent creature = game.getPermanent(event.getSourceId());
if (creature != null && creature.isControlledBy(controllerId)) {
this.getEffects().clear();
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(event.getAmount()));
effect.setTargetPointer(new FixedTarget(creature.getId(), game));
this.addEffect(effect);
return true;
}
}
return false;
}
@Override
public String getRule() {
return "Whenever a creature you control deals combat damage to a player, put that many +1/+1 counters on it.";
}
}

View file

@ -0,0 +1,87 @@
package mage.cards.n;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BecomesBlockedAllTriggeredAbility;
import mage.abilities.common.CantBlockAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class NorinSwiftSurvivalist extends CardImpl {
public NorinSwiftSurvivalist(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.COWARD);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
// Norin, Swift Survivalist can't block.
this.addAbility(new CantBlockAbility());
// Whenever a creature you control becomes blocked, you may exile it. You may play that card from exile this turn.
this.addAbility(new BecomesBlockedAllTriggeredAbility(
new NorinSwiftSurvivalistEffect(), true,
StaticFilters.FILTER_CONTROLLED_A_CREATURE, true
));
}
private NorinSwiftSurvivalist(final NorinSwiftSurvivalist card) {
super(card);
}
@Override
public NorinSwiftSurvivalist copy() {
return new NorinSwiftSurvivalist(this);
}
}
class NorinSwiftSurvivalistEffect extends OneShotEffect {
NorinSwiftSurvivalistEffect() {
super(Outcome.Benefit);
staticText = "exile it. You may play that card from exile this turn";
}
private NorinSwiftSurvivalistEffect(final NorinSwiftSurvivalistEffect effect) {
super(effect);
}
@Override
public NorinSwiftSurvivalistEffect copy() {
return new NorinSwiftSurvivalistEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (player == null || permanent == null) {
return false;
}
Card card = permanent.getMainCard();
player.moveCards(permanent, Zone.EXILED, source, game);
if (card != null) {
CardUtil.makeCardPlayable(
game, source, card, false,
Duration.EndOfTurn, false, player.getId(), null
);
}
return true;
}
}

View file

@ -36,7 +36,7 @@ public final class OverlordOfTheBalemurk extends CardImpl {
this.toughness = new MageInt(5);
// Impending 5--{1}{B}
this.addAbility(new ImpendingAbility("{1}{B}", 5));
this.addAbility(new ImpendingAbility(5, "{1}{B}"));
// Whenever Overlord of the Balemurk enters or attacks, mill four cards, then you may return a non-Avatar creature card or a planeswalker card from your graveyard to your hand.
Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new MillCardsControllerEffect(4));

View file

@ -27,7 +27,7 @@ public final class OverlordOfTheBoilerbilges extends CardImpl {
this.toughness = new MageInt(5);
// Impending 4--{2}{R}{R}
this.addAbility(new ImpendingAbility("{2}{R}{R}"));
this.addAbility(new ImpendingAbility(4, "{2}{R}{R}"));
// Whenever Overlord of the Boilerbilges enters or attacks, it deals 4 damage to any target.
Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DamageTargetEffect(4));

View file

@ -26,7 +26,7 @@ public final class OverlordOfTheFloodpits extends CardImpl {
this.toughness = new MageInt(3);
// Impending 4--{1}{U}{U}
this.addAbility(new ImpendingAbility("{1}{U}{U}"));
this.addAbility(new ImpendingAbility(4, "{1}{U}{U}"));
// Flying
this.addAbility(FlyingAbility.getInstance());

View file

@ -26,7 +26,7 @@ public final class OverlordOfTheHauntwoods extends CardImpl {
this.toughness = new MageInt(5);
// Impending 4--{1}{G}{G}
this.addAbility(new ImpendingAbility("{1}{G}{G}"));
this.addAbility(new ImpendingAbility(4, "{1}{G}{G}"));
// Whenever Overlord of the Hauntwoods enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type.
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(

View file

@ -26,7 +26,7 @@ public final class OverlordOfTheMistmoors extends CardImpl {
this.toughness = new MageInt(6);
// Impending 4--{2}{W}{W}
this.addAbility(new ImpendingAbility("{2}{W}{W}"));
this.addAbility(new ImpendingAbility(4, "{2}{W}{W}"));
// Whenever Overlord of the Mistmoors enters or attacks, create two 2/1 white Insect creature tokens with flying.
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new CreateTokenEffect(new InsectWhiteToken(), 2)));

View file

@ -21,7 +21,7 @@ import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.targetpointer.FixedTargets;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.UUID;
@ -118,7 +118,7 @@ class PartyThrasherEffect extends OneShotEffect {
exileZone.setCleanupOnEndTurn(true);
game.getExile().moveToAnotherZone(card, game, exileZone);
game.addEffect(new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfTurn)
.setTargetPointer(new FixedTargets(cards, game)), source);
.setTargetPointer(new FixedTarget(card, game)), source);
return true;
}

View file

@ -0,0 +1,242 @@
package mage.cards.p;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.LoseAbilityTargetEffect;
import mage.abilities.hint.Hint;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ShadowAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.filter.predicate.other.AnotherTargetPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.stack.StackAbility;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author JayDi85
*/
public final class PhyrexianSplicer extends CardImpl {
static final FilterCreaturePermanent filterLose = new FilterCreaturePermanent("creature with the chosen ability");
private static final FilterCreaturePermanent filterGain = new FilterCreaturePermanent("another target creature");
static {
filterLose.add(Predicates.or(
new AbilityPredicate(FlyingAbility.class),
new AbilityPredicate(FirstStrikeAbility.class),
new AbilityPredicate(TrampleAbility.class),
new AbilityPredicate(ShadowAbility.class)
));
filterLose.add(new AnotherTargetPredicate(1));
filterGain.add(new AnotherTargetPredicate(2));
}
public PhyrexianSplicer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// {2}, {T}, Choose flying, first strike, trample, or shadow: Until end of turn, target creature with the chosen ability loses it and another target creature gains it.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PhyrexianSplicerEffect(), new ManaCostsImpl<>("{2}"));
ability.addCost(new TapSourceCost());
ability.addCost(new PhyrexianSplicerChooseCost());
ability.addTarget(new TargetPermanent(filterLose).withChooseHint("to lose ability").setTargetTag(1));
ability.addTarget(new TargetPermanent(filterGain).withChooseHint("to gain ability").setTargetTag(2));
ability.addHint(PhyrexianSplicerCardHint.instance);
this.addAbility(ability);
}
private PhyrexianSplicer(final PhyrexianSplicer card) {
super(card);
}
@Override
public PhyrexianSplicer copy() {
return new PhyrexianSplicer(this);
}
}
class PhyrexianSplicerEffect extends OneShotEffect {
PhyrexianSplicerEffect() {
super(Outcome.LoseAbility);
this.staticText = "Until end of turn, target creature with the chosen ability loses it and another target creature gains it.";
}
private PhyrexianSplicerEffect(final PhyrexianSplicerEffect effect) {
super(effect);
}
@Override
public PhyrexianSplicerEffect copy() {
return new PhyrexianSplicerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Ability loseAbility = findChosenAbility(source);
if (loseAbility == null) {
return false;
}
// If the target which is having the ability removed does not have that ability during the resolution of this
// effect, then this effect still grants the chosen ability. The reason is that the second target is still
// legal even if the first one is not.
// (2004-10-04)
Permanent targetLose = game.getPermanent(source.getTargets().get(0).getFirstTarget());
Permanent targetGain = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (targetGain == null) {
return false;
}
// lose
if (targetLose != null) {
ContinuousEffect effect = new LoseAbilityTargetEffect(loseAbility, Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(targetLose, game));
game.addEffect(effect, source);
}
// gain
ContinuousEffect effect = new GainAbilityTargetEffect(loseAbility, Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(targetGain, game));
game.addEffect(effect, source);
return true;
}
static Ability findChosenAbility(Ability source) {
return CardUtil
.castStream(source.getCosts().stream(), PhyrexianSplicerChooseCost.class)
.map(PhyrexianSplicerChooseCost::getTargetedAbility)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
}
class PhyrexianSplicerChooseCost extends CostImpl {
private static final Map<String, Ability> allChoices = new LinkedHashMap<>();
static {
allChoices.put("Flying", FlyingAbility.getInstance());
allChoices.put("First Strike", FirstStrikeAbility.getInstance());
allChoices.put("Trample", TrampleAbility.getInstance());
allChoices.put("Shadow", ShadowAbility.getInstance());
}
Ability targetedAbility = null;
public PhyrexianSplicerChooseCost() {
this.text = "Choose flying, first strike, trample, or shadow";
}
private PhyrexianSplicerChooseCost(final PhyrexianSplicerChooseCost cost) {
super(cost);
this.targetedAbility = cost.targetedAbility == null ? null : cost.targetedAbility.copy();
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
this.paid = false;
this.targetedAbility = null;
Permanent losePermanent = game.getPermanent(source.getTargets().get(0).getFirstTarget());
Permanent gainPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
if (losePermanent == null || gainPermanent == null || controller == null) {
return false;
}
// choose ability to lose
Set<String> choices = allChoices.entrySet().stream()
.filter(entry -> losePermanent.hasAbility(entry.getValue(), game))
.map(Map.Entry::getKey)
.collect(Collectors.toCollection(LinkedHashSet::new));
Ability chosenAbility;
if (choices.size() == 1) {
chosenAbility = allChoices.getOrDefault(choices.stream().findFirst().orElse(null), null);
} else {
Choice choice = new ChoiceImpl(true);
choice.setMessage("Choose ability to remove from " + losePermanent.getLogName() + " to " + gainPermanent.getLogName());
choice.setChoices(choices);
controller.choose(Outcome.LoseAbility, choice, game);
chosenAbility = allChoices.getOrDefault(choice.getChoice(), null);
}
if (chosenAbility == null) {
return false;
}
// all fine
this.targetedAbility = chosenAbility;
paid = true;
// additional logs
game.informPlayers(controller.getLogName() + " chosen ability to lose and gain: "
+ CardUtil.getTextWithFirstCharUpperCase(chosenAbility.getRule()));
return true;
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
return true;
}
@Override
public PhyrexianSplicerChooseCost copy() {
return new PhyrexianSplicerChooseCost(this);
}
Ability getTargetedAbility() {
return this.targetedAbility;
}
}
enum PhyrexianSplicerCardHint implements Hint {
instance;
@Override
public String getText(Game game, Ability ability) {
// works on stack only
if (ability instanceof StackAbility) {
Ability loseAbility = PhyrexianSplicerEffect.findChosenAbility(((StackAbility) ability).getStackAbility());
if (loseAbility != null) {
return String.format("Chosen ability to lose and gain: " + CardUtil.getTextWithFirstCharUpperCase(loseAbility.getRule()));
}
}
return "";
}
@Override
public PhyrexianSplicerCardHint copy() {
return this;
}
}

View file

@ -3,6 +3,7 @@ package mage.cards.p;
import mage.MageInt;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -27,7 +28,8 @@ public final class PlanarAlly extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever Planar Ally attacks, venture into the dungeon.
this.addAbility(new AttacksTriggeredAbility(new VentureIntoTheDungeonEffect(), false));
this.addAbility(new AttacksTriggeredAbility(new VentureIntoTheDungeonEffect(), false)
.addHint(CurrentDungeonHint.instance));
}
private PlanarAlly(final PlanarAlly card) {

View file

@ -0,0 +1,98 @@
package mage.cards.p;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.ActivateOncePerGameActivatedAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class PossessedGoat extends CardImpl {
public PossessedGoat(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}");
this.subtype.add(SubType.GOAT);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// {3}, Discard a card: Put three +1/+1 counters on Possessed Goat and it becomes a black Demon in addition to its other colors and types. Activate only once.
Ability ability = new ActivateOncePerGameActivatedAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), new GenericManaCost(3)
);
ability.addCost(new DiscardCardCost());
ability.addEffect(new PossessedGoatEffect());
this.addAbility(ability);
}
private PossessedGoat(final PossessedGoat card) {
super(card);
}
@Override
public PossessedGoat copy() {
return new PossessedGoat(this);
}
}
class PossessedGoatEffect extends ContinuousEffectImpl {
PossessedGoatEffect() {
super(Duration.Custom, Outcome.Benefit);
staticText = "and it becomes a black Demon in addition to its other colors and types";
}
private PossessedGoatEffect(final PossessedGoatEffect effect) {
super(effect);
}
@Override
public PossessedGoatEffect copy() {
return new PossessedGoatEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
discard();
return false;
}
switch (layer) {
case TypeChangingEffects_4:
permanent.addSubType(game, SubType.DEMON);
return true;
case ColorChangingEffects_5:
permanent.getColor(game).setBlack(true);
return true;
}
return false;
}
@Override
public boolean hasLayer(Layer layer) {
switch (layer) {
case TypeChangingEffects_4:
case ColorChangingEffects_5:
return true;
}
return false;
}
}

View file

@ -8,6 +8,7 @@ import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -38,7 +39,8 @@ public final class PrecipitousDrop extends CardImpl {
this.addAbility(ability);
// When Precipitous Drop enters the battlefield, venture into the dungeon.
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect()));
this.addAbility(new EntersBattlefieldTriggeredAbility(new VentureIntoTheDungeonEffect())
.addHint(CurrentDungeonHint.instance));
// Enchanted creature gets -2/-2. It gets -5/-5 instead as long as you've completed a dungeon.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(

View file

@ -8,6 +8,7 @@ import mage.abilities.costs.common.DiscardSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.cards.CardImpl;
@ -48,7 +49,7 @@ public final class RadiantSolar extends CardImpl {
// Whenever Radiant Solar or another nontoken creature you control enters, venture into the dungeon.
this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility(
new VentureIntoTheDungeonEffect(), filter, false, true
));
).addHint(CurrentDungeonHint.instance));
// {W}, Discard Radiant Solar: Venture into the dungeon and you gain 3 life.
Ability ability = new SimpleActivatedAbility(

View file

@ -7,6 +7,7 @@ import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.common.TapTargetCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
import mage.abilities.hint.common.CurrentDungeonHint;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -49,6 +50,7 @@ public final class RangersHawk extends CardImpl {
);
ability.addCost(new TapSourceCost());
ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter)));
ability.addHint(CurrentDungeonHint.instance);
this.addAbility(ability);
}

View file

@ -46,8 +46,8 @@ public final class RestlessSpire extends CardImpl {
new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield),
MyTurnCondition.instance, "As long as it's your turn, this creature has first strike."
)).addHint(MyTurnHint.instance)),
CardType.LAND, Duration.EndOfTurn, true
), new ManaCostsImpl<>("{U}{R}")));
CardType.LAND, Duration.EndOfTurn
).withDurationRuleAtStart(true), new ManaCostsImpl<>("{U}{R}")));
// Whenever Restless Spire attacks, scry 1.
this.addAbility(new AttacksTriggeredAbility(new ScryEffect(1, false), false));

View file

@ -48,8 +48,8 @@ public final class RestlessVinestalk extends CardImpl {
new CreatureToken(5, 5, "5/5 green and blue Plant creature with trample")
.withColor("GU").withSubType(SubType.PLANT)
.withAbility(TrampleAbility.getInstance()),
CardType.LAND, Duration.EndOfTurn, true
), new ManaCostsImpl<>("{3}{G}{U}")));
CardType.LAND, Duration.EndOfTurn
).withDurationRuleAtStart(true), new ManaCostsImpl<>("{3}{G}{U}")));
// Whenever Restless Vinestalk attacks, up to one other target creature has base power and toughness 3/3 until end of turn.
Ability ability = new AttacksTriggeredAbility(new SetBasePowerToughnessTargetEffect(3, 3, Duration.EndOfTurn), false);

View file

@ -0,0 +1,135 @@
package mage.cards.r;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.abilityword.SurvivalAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class RipSpawnHunter extends CardImpl {
public RipSpawnHunter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SURVIVOR);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Survival -- At the beginning of your second main phase, if Rip, Spawn Hunter is tapped, reveal the top X cards of your library, where X is its power. Put any number of creature and/or Vehicle cards with different powers from among them into your hand. Put the rest on the bottom of your library in a random order.
this.addAbility(new SurvivalAbility(new RipSpawnHunterEffect()));
}
private RipSpawnHunter(final RipSpawnHunter card) {
super(card);
}
@Override
public RipSpawnHunter copy() {
return new RipSpawnHunter(this);
}
}
class RipSpawnHunterEffect extends OneShotEffect {
RipSpawnHunterEffect() {
super(Outcome.Benefit);
staticText = "reveal the top X cards of your library, where X is its power. " +
"Put any number of creature and/or Vehicle cards with different powers from among them into your hand. " +
"Put the rest on the bottom of your library in a random order";
}
private RipSpawnHunterEffect(final RipSpawnHunterEffect effect) {
super(effect);
}
@Override
public RipSpawnHunterEffect copy() {
return new RipSpawnHunterEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
int power = Optional
.ofNullable(source.getSourcePermanentOrLKI(game))
.map(MageObject::getPower)
.map(MageInt::getValue)
.orElse(0);
if (player == null || power < 1) {
return false;
}
Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, power));
if (cards.isEmpty()) {
return false;
}
player.revealCards(source, cards, game);
TargetCard target = new RipSpawnHunterTarget();
player.choose(Outcome.ReturnToHand, cards, target, source, game);
player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game);
cards.retainZone(Zone.LIBRARY, game);
player.putCardsOnBottomOfLibrary(cards, game, source, false);
return true;
}
}
class RipSpawnHunterTarget extends TargetCardInLibrary {
private static final FilterCard filter = new FilterCard("creature and/or Vehicle cards with different powers");
static {
filter.add(Predicates.or(
CardType.CREATURE.getPredicate(),
SubType.VEHICLE.getPredicate()
));
}
public RipSpawnHunterTarget() {
super(0, Integer.MAX_VALUE, filter);
}
private RipSpawnHunterTarget(final RipSpawnHunterTarget target) {
super(target);
}
@Override
public RipSpawnHunterTarget copy() {
return new RipSpawnHunterTarget(this);
}
@Override
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
if (!super.canTarget(playerId, id, source, game)) {
return false;
}
Card card = game.getCard(id);
if (card == null) {
return false;
}
int power = card.getPower().getValue();
return this
.getTargets()
.stream()
.map(game::getCard)
.filter(Objects::nonNull)
.map(MageObject::getPower)
.mapToInt(MageInt::getValue)
.noneMatch(x -> x == power);
}
}

View file

@ -34,7 +34,7 @@ public final class SakashimasWill extends CardImpl {
this.getSpellAbility().getModes().setChooseText(
"Choose one. If you control a commander as you cast this spell, you may choose both."
);
this.getSpellAbility().getModes().setMoreCondition(ControlACommanderCondition.instance);
this.getSpellAbility().getModes().setMoreCondition(2, ControlACommanderCondition.instance);
// Target opponent chooses a creature they control. You gain control of it.
this.getSpellAbility().addEffect(new SakashimasWillStealEffect());

View file

@ -0,0 +1,93 @@
package mage.cards.s;
import mage.MageItem;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAttachedTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.permanent.PermanentIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetSacrifice;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class Saw extends CardImpl {
public Saw(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
this.subtype.add(SubType.EQUIPMENT);
// Equipped creature gets +2/+0.
this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0)));
// Whenever equipped creature attacks, you may sacrifice a permanent other than that creature or Saw. If you do, draw a card.
this.addAbility(new AttacksAttachedTriggeredAbility(
new SawEffect(), AttachmentType.EQUIPMENT, false, SetTargetPointer.PERMANENT
));
// Equip {2}
this.addAbility(new EquipAbility(2));
}
private Saw(final Saw card) {
super(card);
}
@Override
public Saw copy() {
return new Saw(this);
}
}
class SawEffect extends OneShotEffect {
SawEffect() {
super(Outcome.Benefit);
staticText = "you may sacrifice a permanent other than that creature or {this}. If you do, draw a card";
}
private SawEffect(final SawEffect effect) {
super(effect);
}
@Override
public SawEffect copy() {
return new SawEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
FilterPermanent filter = new FilterPermanent("another permanent");
filter.add(AnotherPredicate.instance);
Optional.ofNullable(getTargetPointer().getFirst(game, source))
.map(game::getPermanent)
.map(MageItem::getId)
.map(PermanentIdPredicate::new)
.map(Predicates::not)
.ifPresent(filter::add);
TargetSacrifice target = new TargetSacrifice(0, 1, filter);
player.choose(outcome, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget());
return permanent != null && permanent.sacrifice(source, game) && player.drawCards(1, source, game) > 0;
}
}
// I see, said the blind man

View file

@ -44,7 +44,7 @@ public final class SeasonOfGathering extends CardImpl {
// {P} -- Put a +1/+1 counter on a creature you control. It gains vigilance and trample until end of turn.
this.getSpellAbility().addEffect(new SeasonOfGatheringCounterEffect());
this.spellAbility.getModes().getMode().withPawPrintValue(1);
this.getSpellAbility().getModes().getMode().withPawPrintValue(1);
// {P}{P} -- Choose artifact or enchantment. Destroy all permanents of the chosen type.
Mode mode2 = new Mode(new SeasonOfGatheringRemovalEffect());
@ -159,4 +159,4 @@ class SeasonOfGatheringRemovalEffect extends OneShotEffect {
game.informPlayers(controller.getLogName() + " has chosen " + choiceImpl.getChoiceKey());
return new DestroyAllEffect(filter).apply(game, source);
}
}
}

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