diff --git a/Mage.Sets/src/mage/cards/b/BrineHag.java b/Mage.Sets/src/mage/cards/b/BrineHag.java new file mode 100644 index 0000000000..5050409b69 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrineHag.java @@ -0,0 +1,93 @@ + +package mage.cards.b; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.PermanentInListPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author L_J + */ +public final class BrineHag extends CardImpl { + + public BrineHag(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); + this.subtype.add(SubType.HAG); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Brine Hag dies, change the base power and toughness of all creatures that dealt damage to it this turn to 0/2. + this.addAbility(new DiesTriggeredAbility(new BrineHagEffect())); + } + + public BrineHag(final BrineHag card) { + super(card); + } + + @Override + public BrineHag copy() { + return new BrineHag(this); + } +} + +class BrineHagEffect extends OneShotEffect { + + public BrineHagEffect() { + super(Outcome.Detriment); + this.staticText = "change the base power and toughness of all creatures that dealt damage to it this turn to 0/2"; + } + + public BrineHagEffect(final BrineHagEffect effect) { + super(effect); + } + + @Override + public BrineHagEffect copy() { + return new BrineHagEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourcePermanent != null) { + List list = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) { + if (sourcePermanent.getDealtDamageByThisTurn().contains(new MageObjectReference(creature.getId(), game))) { + list.add(creature); + } + } + } + } + if (!list.isEmpty()) { + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new PermanentInListPredicate(list)); + game.addEffect(new SetPowerToughnessAllEffect(0, 2, Duration.Custom, filter, true), source); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VenarianGold.java b/Mage.Sets/src/mage/cards/v/VenarianGold.java new file mode 100644 index 0000000000..cb25f2c231 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenarianGold.java @@ -0,0 +1,94 @@ + +package mage.cards.v; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.AttachedToCounterCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.effects.common.TapEnchantedEffect; +import mage.abilities.effects.common.counter.AddCountersAttachedEffect; +import mage.abilities.effects.common.counter.RemoveCountersAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * @author L_J + */ +public final class VenarianGold extends CardImpl { + + public VenarianGold(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{X}{U}{U}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // When Venarian Gold enters the battlefield, tap enchanted creature and put a number of sleep counters on it equal to the value of X as you cast Venarian Gold. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()); + ability.addEffect(new AddCountersAttachedEffect(CounterType.SLEEP.createInstance(), new VenarianGoldValue(), "it equal to the value of X as you cast {this}")); + this.addAbility(ability); + + // Enchanted creature doesn’t untap during its controller’s untap step if it has a sleep counter on it. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(), + new AttachedToCounterCondition(CounterType.SLEEP, 1)).setText("Enchanted creature doesn't untap during its controller's untap step if it has a sleep counter on it"))); + + // At the beginning of the upkeep of enchanted creature’s controller, remove a sleep counter from that creature. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new RemoveCountersAttachedEffect(CounterType.SLEEP.createInstance(), "that creature"), + TargetController.CONTROLLER_ATTACHED_TO, false)); + + } + + public VenarianGold(final VenarianGold card) { + super(card); + } + + @Override + public VenarianGold copy() { + return new VenarianGold(this); + } +} + +class VenarianGoldValue implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + MageObject mageObject = game.getLastKnownInformation(sourceAbility.getSourceId(), Zone.STACK); + if (mageObject != null && mageObject instanceof StackObject) { + return ((StackObject) mageObject).getStackAbility().getManaCostsToPay().getX(); + } + return 0; + } + + @Override + public VenarianGoldValue copy() { + return new VenarianGoldValue(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WallOfShadows.java b/Mage.Sets/src/mage/cards/w/WallOfShadows.java new file mode 100644 index 0000000000..d87ffe7d98 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfShadows.java @@ -0,0 +1,138 @@ + +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.CantBeTargetedSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.FilterObject; +import mage.filter.FilterPermanent; +import mage.filter.FilterStackObject; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.BlockedByIdPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.DamageCreatureEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.target.Target; + +/** + * + * @author L_J + */ +public final class WallOfShadows extends CardImpl { + + private static final FilterObject filter = new FilterStackObject("spells that can target only Walls or of abilities that can target only Walls"); + static { + filter.add(new CanTargetOnlyWallsPredicate()); + } + + public WallOfShadows(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Prevent all damage that would be dealt to Wall of Vapor by creatures it's blocking. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WallOfShadowsEffect())); + + // Wall of Shadows can't be the target of spells that can target only Walls or of abilities that can target only Walls. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedSourceEffect(filter, Duration.WhileOnBattlefield))); + } + + public WallOfShadows(final WallOfShadows card) { + super(card); + } + + @Override + public WallOfShadows copy() { + return new WallOfShadows(this); + } +} + +class WallOfShadowsEffect extends PreventionEffectImpl { + + WallOfShadowsEffect() { + super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false); + staticText = "Prevent all damage that would be dealt to {this} by creatures it's blocking"; + } + + WallOfShadowsEffect(final WallOfShadowsEffect effect) { + super(effect); + } + + @Override + public WallOfShadowsEffect copy() { + return new WallOfShadowsEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game) && event instanceof DamageCreatureEvent && event.getAmount() > 0) { + DamageCreatureEvent damageEvent = (DamageCreatureEvent) event; + if (event.getTargetId().equals(source.getSourceId())) { + Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId()); + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new BlockedByIdPredicate(source.getSourceId())); + if (permanent != null && filter.match(permanent, game)) { + return true; + } + } + } + return false; + } +} + +class CanTargetOnlyWallsPredicate implements Predicate { + + @Override + public boolean apply(MageObject input, Game game) { + boolean canTargetOnlyWalls = false; + StackObject stackObject = game.getStack().getSpell(input.getId()); + if (stackObject != null) { + for (Mode mode : stackObject.getStackAbility().getModes().values()) { + for (Target target : mode.getTargets()) { + Filter filter = target.getFilter(); + if (filter != null && filter instanceof FilterPermanent) { + for (Object predicate : filter.getPredicates()) { + if (predicate instanceof SubtypePredicate) { + if (predicate.toString().equals("Subtype(Wall)")) { + canTargetOnlyWalls = true; // can target a Wall + } else { + return false; // can target a non-Wall permanent + } + } + // no return statement here, as different predicates might still apply (e.g. "blocking Wall") + } + } else { + return false; // can target non-permanents (i.e. not Walls) + } + } + } + } + return canTargetOnlyWalls; + } + + @Override + public String toString() { + return "can target only Walls"; + } +} diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index 87857da7c8..c62c211ba4 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -60,6 +60,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Blue Mana Battery", 275, Rarity.UNCOMMON, mage.cards.b.BlueManaBattery.class)); cards.add(new SetCardInfo("Boomerang", 48, Rarity.COMMON, mage.cards.b.Boomerang.class)); cards.add(new SetCardInfo("Boris Devilboon", 223, Rarity.RARE, mage.cards.b.BorisDevilboon.class)); + cards.add(new SetCardInfo("Brine Hag", 49, Rarity.UNCOMMON, mage.cards.b.BrineHag.class)); cards.add(new SetCardInfo("Bronze Horse", 276, Rarity.RARE, mage.cards.b.BronzeHorse.class)); cards.add(new SetCardInfo("Carrion Ants", 90, Rarity.RARE, mage.cards.c.CarrionAnts.class)); cards.add(new SetCardInfo("Cat Warriors", 177, Rarity.COMMON, mage.cards.c.CatWarriors.class)); @@ -300,6 +301,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Urborg", 310, Rarity.UNCOMMON, mage.cards.u.Urborg.class)); cards.add(new SetCardInfo("Vaevictis Asmadi", 269, Rarity.RARE, mage.cards.v.VaevictisAsmadi.class)); cards.add(new SetCardInfo("Vampire Bats", 125, Rarity.COMMON, mage.cards.v.VampireBats.class)); + cards.add(new SetCardInfo("Venarian Gold", 83, Rarity.COMMON, mage.cards.v.VenarianGold.class)); cards.add(new SetCardInfo("Visions", 41, Rarity.UNCOMMON, mage.cards.v.Visions.class)); cards.add(new SetCardInfo("Voodoo Doll", 298, Rarity.RARE, mage.cards.v.VoodooDoll.class)); cards.add(new SetCardInfo("Walking Dead", 126, Rarity.COMMON, mage.cards.w.WalkingDead.class)); @@ -310,6 +312,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Wall of Light", 43, Rarity.UNCOMMON, mage.cards.w.WallOfLight.class)); cards.add(new SetCardInfo("Wall of Opposition", 171, Rarity.RARE, mage.cards.w.WallOfOpposition.class)); cards.add(new SetCardInfo("Wall of Putrid Flesh", 127, Rarity.UNCOMMON, mage.cards.w.WallOfPutridFlesh.class)); + cards.add(new SetCardInfo("Wall of Shadows", 128, Rarity.COMMON, mage.cards.w.WallOfShadows.class)); cards.add(new SetCardInfo("Wall of Tombstones", 129, Rarity.UNCOMMON, mage.cards.w.WallOfTombstones.class)); cards.add(new SetCardInfo("Wall of Vapor", 84, Rarity.COMMON, mage.cards.w.WallOfVapor.class)); cards.add(new SetCardInfo("Wall of Wonder", 85, Rarity.UNCOMMON, mage.cards.w.WallOfWonder.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAttachedEffect.java index afc03b0b89..0687972d50 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAttachedEffect.java @@ -23,7 +23,7 @@ public class AddCountersAttachedEffect extends OneShotEffect { private String textEnchanted; public AddCountersAttachedEffect(Counter counter, String textEnchanted) { - this(counter, new StaticValue(0), textEnchanted); + this(counter, new StaticValue(1), textEnchanted); } /** @@ -56,8 +56,12 @@ public class AddCountersAttachedEffect extends OneShotEffect { Permanent attachedTo = game.getPermanent(permanent.getAttachedTo()); if (attachedTo != null && counter != null) { Counter newCounter = counter.copy(); - newCounter.add(amount.calculate(game, source, this)); - attachedTo.addCounters(newCounter, source, game); + int countersToAdd = amount.calculate(game, source, this); + if (countersToAdd > 0) { + countersToAdd--; + newCounter.add(countersToAdd); + attachedTo.addCounters(newCounter, source, game); + } } return true; } diff --git a/Mage/src/main/java/mage/filter/Filter.java b/Mage/src/main/java/mage/filter/Filter.java index 7da73e2776..3f839a0f64 100644 --- a/Mage/src/main/java/mage/filter/Filter.java +++ b/Mage/src/main/java/mage/filter/Filter.java @@ -2,6 +2,7 @@ package mage.filter; import java.io.Serializable; +import java.util.List; import mage.filter.predicate.Predicate; import mage.game.Game; @@ -28,4 +29,5 @@ public interface Filter extends Serializable { Filter copy(); + List> getPredicates(); } diff --git a/Mage/src/main/java/mage/filter/FilterImpl.java b/Mage/src/main/java/mage/filter/FilterImpl.java index cf1c847b7b..192b574d92 100644 --- a/Mage/src/main/java/mage/filter/FilterImpl.java +++ b/Mage/src/main/java/mage/filter/FilterImpl.java @@ -75,4 +75,8 @@ public abstract class FilterImpl implements Filter { this.lockedFilter = lockedFilter; } + public List> getPredicates() { + return predicates; + } + }