diff --git a/Mage.Sets/src/mage/cards/i/IchneumonDruid.java b/Mage.Sets/src/mage/cards/i/IchneumonDruid.java new file mode 100644 index 0000000000..04ed82b35c --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IchneumonDruid.java @@ -0,0 +1,135 @@ + +package mage.cards.i; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.stack.Spell; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.Watcher; + +/** + * + * @author L_J + */ +public final class IchneumonDruid extends CardImpl { + + public IchneumonDruid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, Ichneumon Druid deals 4 damage to that player. + this.addAbility(new IchneumonDruidAbility(), new IchneumonDruidWatcher()); + } + + public IchneumonDruid(final IchneumonDruid card) { + super(card); + } + + @Override + public IchneumonDruid copy() { + return new IchneumonDruid(this); + } +} + +class IchneumonDruidAbility extends TriggeredAbilityImpl { + + public IchneumonDruidAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(new StaticValue(4), false, "that player", true)); + } + + public IchneumonDruidAbility(final IchneumonDruidAbility ability) { + super(ability); + } + + @Override + public IchneumonDruidAbility copy() { + return new IchneumonDruidAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!event.getPlayerId().equals(controllerId)) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.isInstant()) { + IchneumonDruidWatcher watcher = (IchneumonDruidWatcher) game.getState().getWatchers().get(IchneumonDruidWatcher.class.getSimpleName()); + if (watcher != null && watcher.moreThanTwoInstantsCast(event.getPlayerId(), game)) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getPlayerId())); + } + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, {this} deals 4 damage to that player."; + } +} + +class IchneumonDruidWatcher extends Watcher { + + private final Map playerInstantCount = new HashMap<>(); + + public IchneumonDruidWatcher() { + super(IchneumonDruidWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public IchneumonDruidWatcher(final IchneumonDruidWatcher watcher) { + super(watcher); + for (Map.Entry entry : watcher.playerInstantCount.entrySet()) { + playerInstantCount.put(entry.getKey(), entry.getValue()); + } + } + + @Override + public IchneumonDruidWatcher copy() { + return new IchneumonDruidWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == EventType.SPELL_CAST) { + UUID playerId = event.getPlayerId(); + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.isInstant()) { + playerInstantCount.putIfAbsent(event.getPlayerId(), 0); + playerInstantCount.compute(playerId, (k, v) -> v + 1); + } + } + } + + public boolean moreThanTwoInstantsCast(UUID playerId, Game game) { + return playerInstantCount.get(playerId) > 1; + } + + @Override + public void reset() { + playerInstantCount.clear(); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnowledgeVault.java b/Mage.Sets/src/mage/cards/k/KnowledgeVault.java new file mode 100644 index 0000000000..9cb731ba9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnowledgeVault.java @@ -0,0 +1,120 @@ + +package mage.cards.k; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +import mage.abilities.effects.common.discard.DiscardHandControllerEffect; +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.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author emerald000 & L_J + */ +public final class KnowledgeVault extends CardImpl { + + public KnowledgeVault(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // {2}, {T}: Exile the top card of your library face down. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KnowledgeVaultExileEffect(), new GenericManaCost(2))); + + // {0}: Sacrifice Knowledge Vault. If you do, discard your hand, then put all cards exiled with Knowledge Vault into their owner’s hand. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KnowledgeVaultReturnEffect(), new GenericManaCost(0))); + + // When Knowledge Vault leaves the battlefield, put all cards exiled with Knowledge Vault into their owner’s graveyard. + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.GRAVEYARD), false)); + } + + public KnowledgeVault(final KnowledgeVault card) { + super(card); + } + + @Override + public KnowledgeVault copy() { + return new KnowledgeVault(this); + } +} + +class KnowledgeVaultExileEffect extends OneShotEffect { + + KnowledgeVaultExileEffect() { + super(Outcome.Exile); + this.staticText = "exile the top card of your library face down"; + } + + KnowledgeVaultExileEffect(final KnowledgeVaultExileEffect effect) { + super(effect); + } + + @Override + public KnowledgeVaultExileEffect copy() { + return new KnowledgeVaultExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + Card card = controller.getLibrary().getFromTop(game); + if (card != null) { + UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + card.setFaceDown(true, game); + controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName()); + card.setFaceDown(true, game); + return true; + } + } + return false; + } +} + +class KnowledgeVaultReturnEffect extends OneShotEffect { + + KnowledgeVaultReturnEffect() { + super(Outcome.DrawCard); + this.staticText = "Sacrifice {this}. If you do, discard your hand, then put all cards exiled with {this} into their owners' hands"; + } + + KnowledgeVaultReturnEffect(final KnowledgeVaultReturnEffect effect) { + super(effect); + } + + @Override + public KnowledgeVaultReturnEffect copy() { + return new KnowledgeVaultReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (sourcePermanent != null && controller != null) { + if (sourcePermanent.sacrifice(source.getSourceId(), game)) { + new DiscardHandControllerEffect().apply(game, source); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); + if (exileZone != null) { + controller.moveCards(exileZone, Zone.HAND, source, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LifeMatrix.java b/Mage.Sets/src/mage/cards/l/LifeMatrix.java new file mode 100644 index 0000000000..09bb4c904e --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LifeMatrix.java @@ -0,0 +1,51 @@ + +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class LifeMatrix extends CardImpl { + + public LifeMatrix(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // {4}, {T}: Put a matrix counter on target creature and that creature gains “Remove a matrix counter from this creature: Regenerate this creature.” Activate this ability only during your upkeep. + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.MATRIX.createInstance()), new GenericManaCost(4), + new IsStepCondition(PhaseStep.UPKEEP), null); + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new RemoveCountersSourceCost(CounterType.MATRIX.createInstance())); + ability.addEffect(new GainAbilityTargetEffect(ability2, Duration.Custom)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public LifeMatrix(final LifeMatrix card) { + super(card); + } + + @Override + public LifeMatrix copy() { + return new LifeMatrix(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index f62c528b51..8a0061c965 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -145,6 +145,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Horror of Horrors", 106, Rarity.UNCOMMON, mage.cards.h.HorrorOfHorrors.class)); cards.add(new SetCardInfo("Hunding Gjornersen", 231, Rarity.UNCOMMON, mage.cards.h.HundingGjornersen.class)); cards.add(new SetCardInfo("Hyperion Blacksmith", 152, Rarity.UNCOMMON, mage.cards.h.HyperionBlacksmith.class)); + cards.add(new SetCardInfo("Ichneumon Druid", 191, Rarity.UNCOMMON, mage.cards.i.IchneumonDruid.class)); cards.add(new SetCardInfo("Immolation", 153, Rarity.COMMON, mage.cards.i.Immolation.class)); cards.add(new SetCardInfo("Imprison", 107, Rarity.RARE, mage.cards.i.Imprison.class)); cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); @@ -165,6 +166,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Kei Takahashi", 238, Rarity.RARE, mage.cards.k.KeiTakahashi.class)); cards.add(new SetCardInfo("Killer Bees", 192, Rarity.RARE, mage.cards.k.KillerBees.class)); cards.add(new SetCardInfo("Kismet", 25, Rarity.UNCOMMON, mage.cards.k.Kismet.class)); + cards.add(new SetCardInfo("Knowledge Vault", 281, Rarity.RARE, mage.cards.k.KnowledgeVault.class)); cards.add(new SetCardInfo("Kobold Drill Sergeant", 154, Rarity.UNCOMMON, mage.cards.k.KoboldDrillSergeant.class)); cards.add(new SetCardInfo("Kobold Overlord", 155, Rarity.RARE, mage.cards.k.KoboldOverlord.class)); cards.add(new SetCardInfo("Kobold Taskmaster", 156, Rarity.UNCOMMON, mage.cards.k.KoboldTaskmaster.class)); @@ -178,6 +180,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Land's Edge", 158, Rarity.RARE, mage.cards.l.LandsEdge.class)); cards.add(new SetCardInfo("Lesser Werewolf", 110, Rarity.UNCOMMON, mage.cards.l.LesserWerewolf.class)); cards.add(new SetCardInfo("Life Chisel", 283, Rarity.UNCOMMON, mage.cards.l.LifeChisel.class)); + cards.add(new SetCardInfo("Life Matrix", 284, Rarity.RARE, mage.cards.l.LifeMatrix.class)); cards.add(new SetCardInfo("Lifeblood", 27, Rarity.RARE, mage.cards.l.Lifeblood.class)); cards.add(new SetCardInfo("Living Plane", 193, Rarity.RARE, mage.cards.l.LivingPlane.class)); cards.add(new SetCardInfo("Livonya Silone", 242, Rarity.RARE, mage.cards.l.LivonyaSilone.class));