From 9eeebcd3d35ee71a3554b5cfa0db922f64161fb0 Mon Sep 17 00:00:00 2001 From: Noah Gleason Date: Fri, 22 Jun 2018 18:27:21 -0400 Subject: [PATCH 1/3] Start implementing Joven's Ferrets --- Mage.Sets/src/mage/cards/j/JovensFerrets.java | 108 ++++++++++++++++++ Mage.Sets/src/mage/sets/Homelands.java | 1 + Mage.Sets/src/mage/sets/MastersEditionII.java | 1 + 3 files changed, 110 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/j/JovensFerrets.java diff --git a/Mage.Sets/src/mage/cards/j/JovensFerrets.java b/Mage.Sets/src/mage/cards/j/JovensFerrets.java new file mode 100644 index 00000000000..abf0696185f --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JovensFerrets.java @@ -0,0 +1,108 @@ +package mage.cards.j; + +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.Mode; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EndOfCombatTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.TapAllEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +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; +import mage.players.Player; +import mage.watchers.common.BlockedAttackerWatcher; + +/** + * + * @author noahg + */ +public final class JovensFerrets extends CardImpl { + + public JovensFerrets(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.FERRET); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Joven's Ferrets attacks, it gets +0/+2 until end of turn. + Effect boostSourceEffect = new BoostSourceEffect(0, 2, Duration.EndOfTurn); + boostSourceEffect.setText("it gets +0/+2 until end of turn"); + this.addAbility(new AttacksTriggeredAbility(boostSourceEffect, false)); + + // At end of combat, tap all creatures that blocked Joven's Ferrets this turn. They don't untap during their controller's next untap step. + Ability eocAbility = new EndOfCombatTriggeredAbility(new JovensFerretsEffect(), false); + eocAbility.addWatcher(new BlockedAttackerWatcher()); + this.addAbility(eocAbility); + } + + public JovensFerrets(final JovensFerrets card) { + super(card); + } + + @Override + public JovensFerrets copy() { + return new JovensFerrets(this); + } +} + +class JovensFerretsEffect extends DontUntapInControllersNextUntapStepTargetEffect { + + public JovensFerretsEffect() { + super(); + } + + public JovensFerretsEffect(final JovensFerretsEffect effect) { + super(effect); + } + + @Override + public JovensFerretsEffect copy() { + return new JovensFerretsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && sourcePermanent != null) { + BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + if (watcher != null) { + List toTap = new ArrayList<>(); + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + if (!creature.getId().equals(source.getSourceId())) { + if (watcher.creatureHasBlockedAttacker(sourcePermanent, creature, game)) { + toTap.add(creature); + } + } + } + for (Permanent creature : toTap) { + creature.tap(game); + getTargetPointer().getTargets(game, source).add(creature.getId()); + } + return true; + } + } + return false; + } + + @Override + public String getText(Mode mode) { + return "tap all creatures that blocked {this} this turn. They don't untap during their controller's next untap step."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/Homelands.java b/Mage.Sets/src/mage/sets/Homelands.java index 5de1fb7d4e6..76daaa08075 100644 --- a/Mage.Sets/src/mage/sets/Homelands.java +++ b/Mage.Sets/src/mage/sets/Homelands.java @@ -114,6 +114,7 @@ public final class Homelands extends ExpansionSet { cards.add(new SetCardInfo("Ironclaw Curse", 76, Rarity.RARE, mage.cards.i.IronclawCurse.class)); cards.add(new SetCardInfo("Jinx", 29, Rarity.COMMON, mage.cards.j.Jinx.class)); cards.add(new SetCardInfo("Joven", 77, Rarity.COMMON, mage.cards.j.Joven.class)); + cards.add(new SetCardInfo("Joven's Ferrets", 89, Rarity.COMMON, mage.cards.j.JovensFerrets.class)); cards.add(new SetCardInfo("Joven's Tools", 108, Rarity.UNCOMMON, mage.cards.j.JovensTools.class)); cards.add(new SetCardInfo("Koskun Falls", 55, Rarity.RARE, mage.cards.k.KoskunFalls.class)); cards.add(new SetCardInfo("Koskun Keep", 114, Rarity.UNCOMMON, mage.cards.k.KoskunKeep.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionII.java b/Mage.Sets/src/mage/sets/MastersEditionII.java index d466ec8914b..bee97c5b587 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionII.java @@ -144,6 +144,7 @@ public final class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Jester's Mask", 211, Rarity.RARE, mage.cards.j.JestersMask.class)); cards.add(new SetCardInfo("Jeweled Amulet", 212, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); cards.add(new SetCardInfo("Johtull Wurm", 168, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); + cards.add(new SetCardInfo("Joven's Ferrets", 169, Rarity.UNCOMMON, mage.cards.j.JovensFerrets.class)); cards.add(new SetCardInfo("Juniper Order Advocate", 20, Rarity.UNCOMMON, mage.cards.j.JuniperOrderAdvocate.class)); cards.add(new SetCardInfo("Karplusan Giant", 133, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); cards.add(new SetCardInfo("Kaysa", 170, Rarity.RARE, mage.cards.k.Kaysa.class)); From c78cbc40eb2644acc07067a374cdbb12229082af Mon Sep 17 00:00:00 2001 From: Noah Gleason Date: Sat, 23 Jun 2018 11:11:35 -0400 Subject: [PATCH 2/3] Fix Heat Stroke --- Mage.Sets/src/mage/cards/h/HeatStroke.java | 68 ++++++++++++++++--- Mage.Sets/src/mage/cards/j/JovensFerrets.java | 9 ++- .../common/WasBlockedThisTurnWatcher.java | 53 +++++++++++++++ 3 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 Mage/src/main/java/mage/watchers/common/WasBlockedThisTurnWatcher.java diff --git a/Mage.Sets/src/mage/cards/h/HeatStroke.java b/Mage.Sets/src/mage/cards/h/HeatStroke.java index e2b04db1869..60ed8c12d15 100644 --- a/Mage.Sets/src/mage/cards/h/HeatStroke.java +++ b/Mage.Sets/src/mage/cards/h/HeatStroke.java @@ -1,35 +1,46 @@ package mage.cards.h; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.UUID; + +import mage.MageObjectReference; +import mage.abilities.Ability; import mage.abilities.common.EndOfCombatTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.BlockedPredicate; import mage.filter.predicate.permanent.BlockingPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.common.BlockedThisTurnWatcher; +import mage.watchers.common.WasBlockedThisTurnWatcher; /** * @author dustinroepsch */ public final class HeatStroke extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent(); - - static { - filter.add(Predicates.or(new BlockedPredicate(), new BlockingPredicate())); - } - public HeatStroke(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // At end of combat, destroy each creature that blocked or was blocked this turn. - this.addAbility(new EndOfCombatTriggeredAbility(new DestroyAllEffect(filter) - .setText("destroy each creature that blocked or was blocked this turn"), false)); + Ability ability = new EndOfCombatTriggeredAbility(new HeatStrokeEffect(), false); + ability.addWatcher(new BlockedThisTurnWatcher()); + ability.addWatcher(new WasBlockedThisTurnWatcher()); + this.addAbility(ability); } public HeatStroke(final HeatStroke card) { @@ -41,3 +52,44 @@ public final class HeatStroke extends CardImpl { return new HeatStroke(this); } } + +class HeatStrokeEffect extends OneShotEffect { + + public HeatStrokeEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "destroy each creature that blocked or was blocked this turn"; + } + + public HeatStrokeEffect(HeatStrokeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + BlockedThisTurnWatcher blockedWatcher = (BlockedThisTurnWatcher) game.getState().getWatchers().get(BlockedThisTurnWatcher.class.getSimpleName()); + WasBlockedThisTurnWatcher wasBlockedThisTurnWatcher = (WasBlockedThisTurnWatcher) game.getState().getWatchers().get(WasBlockedThisTurnWatcher.class.getSimpleName()); + boolean toRet = false; + Set toDestroy = new HashSet<>(); + + if (blockedWatcher != null){ + toDestroy.addAll(blockedWatcher.getBlockedThisTurnCreatures()); + } + if (wasBlockedThisTurnWatcher != null){ + toDestroy.addAll(wasBlockedThisTurnWatcher.getWasBlockedThisTurnCreatures()); + } + + for (MageObjectReference mor : toDestroy) { + Permanent permanent = mor.getPermanent(game); + if (permanent != null && permanent.isCreature()){ + permanent.destroy(source.getSourceId(), game, false); + toRet = true; + } + } + return toRet; + } + + @Override + public HeatStrokeEffect copy() { + return new HeatStrokeEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/j/JovensFerrets.java b/Mage.Sets/src/mage/cards/j/JovensFerrets.java index abf0696185f..a4df82c443c 100644 --- a/Mage.Sets/src/mage/cards/j/JovensFerrets.java +++ b/Mage.Sets/src/mage/cards/j/JovensFerrets.java @@ -25,6 +25,7 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.targetpointer.FixedTarget; import mage.watchers.common.BlockedAttackerWatcher; /** @@ -61,10 +62,10 @@ public final class JovensFerrets extends CardImpl { } } -class JovensFerretsEffect extends DontUntapInControllersNextUntapStepTargetEffect { +class JovensFerretsEffect extends OneShotEffect { public JovensFerretsEffect() { - super(); + super(Outcome.Benefit); } public JovensFerretsEffect(final JovensFerretsEffect effect) { @@ -93,7 +94,9 @@ class JovensFerretsEffect extends DontUntapInControllersNextUntapStepTargetEffec } for (Permanent creature : toTap) { creature.tap(game); - getTargetPointer().getTargets(game, source).add(creature.getId()); + DontUntapInControllersNextUntapStepTargetEffect effect = new DontUntapInControllersNextUntapStepTargetEffect(); + effect.setTargetPointer(new FixedTarget(creature.getId())); + game.addEffect(effect, source); } return true; } diff --git a/Mage/src/main/java/mage/watchers/common/WasBlockedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/WasBlockedThisTurnWatcher.java new file mode 100644 index 00000000000..65e44a07afc --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/WasBlockedThisTurnWatcher.java @@ -0,0 +1,53 @@ + +package mage.watchers.common; + +import mage.MageObjectReference; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author noahg + */ +public class WasBlockedThisTurnWatcher extends Watcher { + + private final Set wasBlockedThisTurnCreatures; + + public WasBlockedThisTurnWatcher() { + super(WasBlockedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + wasBlockedThisTurnCreatures = new HashSet<>(); + } + + public WasBlockedThisTurnWatcher(final WasBlockedThisTurnWatcher watcher) { + super(watcher); + wasBlockedThisTurnCreatures = new HashSet<>(watcher.wasBlockedThisTurnCreatures); + } + + @Override + public Watcher copy() { + return new WasBlockedThisTurnWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { + this.wasBlockedThisTurnCreatures.add(new MageObjectReference(event.getTargetId(), game)); + } + } + + public Set getWasBlockedThisTurnCreatures() { + return this.wasBlockedThisTurnCreatures; + } + + @Override + public void reset() { + super.reset(); + wasBlockedThisTurnCreatures.clear(); + } + +} From 4fc42adb32fc0c29d61b996c22158859ec5a3a62 Mon Sep 17 00:00:00 2001 From: Noah Gleason Date: Sat, 23 Jun 2018 11:31:37 -0400 Subject: [PATCH 3/3] Fix Heat Stroke area of influence --- Mage.Sets/src/mage/cards/h/HeatStroke.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/h/HeatStroke.java b/Mage.Sets/src/mage/cards/h/HeatStroke.java index 60ed8c12d15..130b465e313 100644 --- a/Mage.Sets/src/mage/cards/h/HeatStroke.java +++ b/Mage.Sets/src/mage/cards/h/HeatStroke.java @@ -68,6 +68,7 @@ class HeatStrokeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { BlockedThisTurnWatcher blockedWatcher = (BlockedThisTurnWatcher) game.getState().getWatchers().get(BlockedThisTurnWatcher.class.getSimpleName()); WasBlockedThisTurnWatcher wasBlockedThisTurnWatcher = (WasBlockedThisTurnWatcher) game.getState().getWatchers().get(WasBlockedThisTurnWatcher.class.getSimpleName()); + Set inROI = new HashSet<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)); boolean toRet = false; Set toDestroy = new HashSet<>(); @@ -80,7 +81,7 @@ class HeatStrokeEffect extends OneShotEffect { for (MageObjectReference mor : toDestroy) { Permanent permanent = mor.getPermanent(game); - if (permanent != null && permanent.isCreature()){ + if (permanent != null && permanent.isCreature() && inROI.contains(permanent)){ permanent.destroy(source.getSourceId(), game, false); toRet = true; }