From f69374be8c2ffb7befc7fca6fdd8352203828414 Mon Sep 17 00:00:00 2001 From: "Saga\\Robert" Date: Thu, 17 Aug 2017 00:18:58 +0200 Subject: [PATCH 1/2] - added a Triggered Ability for ETBs or Attacks --- ...ttlefieldOrAttacksAllTriggeredAbility.java | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrAttacksAllTriggeredAbility.java diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrAttacksAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrAttacksAllTriggeredAbility.java new file mode 100644 index 0000000000..02ffb0e4bf --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrAttacksAllTriggeredAbility.java @@ -0,0 +1,168 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.common; + +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author Saga + */ +public class EntersBattlefieldOrAttacksAllTriggeredAbility extends TriggeredAbilityImpl { + + protected FilterPermanent filter; + protected String rule; + protected boolean controlledText; + protected SetTargetPointer setTargetPointer; + + /** + * zone = BATTLEFIELD optional = false + * + * @param effect + * @param filter + */ + public EntersBattlefieldOrAttacksAllTriggeredAbility(Effect effect, FilterPermanent filter) { + this(Zone.BATTLEFIELD, effect, filter, false); + } + + public EntersBattlefieldOrAttacksAllTriggeredAbility(Effect effect, FilterPermanent filter, String rule) { + this(Zone.BATTLEFIELD, effect, filter, false, rule); + } + + public EntersBattlefieldOrAttacksAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional) { + this(zone, effect, filter, optional, SetTargetPointer.NONE, null, false); + } + + public EntersBattlefieldOrAttacksAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, String rule) { + this(zone, effect, filter, optional, rule, false); + } + + public EntersBattlefieldOrAttacksAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, String rule, boolean controlledText) { + this(zone, effect, filter, optional, SetTargetPointer.NONE, rule, controlledText); + } + + public EntersBattlefieldOrAttacksAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, String rule) { + this(zone, effect, filter, optional, setTargetPointer, rule, false); + } + + public EntersBattlefieldOrAttacksAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, String rule, boolean controlledText) { + super(zone, effect, optional); + this.filter = filter; + this.rule = rule; + this.controlledText = controlledText; + this.setTargetPointer = setTargetPointer; + } + + public EntersBattlefieldOrAttacksAllTriggeredAbility(final EntersBattlefieldOrAttacksAllTriggeredAbility ability) { + super(ability); + this.filter = ability.filter; + this.rule = ability.rule; + this.controlledText = ability.controlledText; + this.setTargetPointer = ability.setTargetPointer; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD || event.getType() == GameEvent.EventType.ATTACKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent attacker = game.getPermanent(event.getSourceId()); + if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD + && permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (setTargetPointer != SetTargetPointer.NONE) { + for (Effect effect : this.getEffects()) { + switch (setTargetPointer) { + case PERMANENT: + effect.setTargetPointer(new FixedTarget(permanent, game)); + break; + case PLAYER: + effect.setTargetPointer(new FixedTarget(permanent.getControllerId())); + break; + } + + } + } + return true; + } + + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED + && attacker != null && filter.match(attacker, getSourceId(), getControllerId(), game)) { + if (setTargetPointer != SetTargetPointer.NONE) { + for (Effect effect : this.getEffects()) { + switch (setTargetPointer) { + case PERMANENT: + effect.setTargetPointer(new FixedTarget(attacker.getId())); + break; + case PLAYER: + UUID playerId = controlledText ? attacker.getControllerId() : game.getCombat().getDefendingPlayerId(attacker.getId(), game); + if (playerId != null) { + effect.setTargetPointer(new FixedTarget(playerId)); + } + break; + } + + } + } + return true; + } + return false; + } + + @Override + public String getRule() { + if (rule != null && !rule.isEmpty()) { + return rule; + } + StringBuilder sb = new StringBuilder("Whenever ").append(filter.getMessage()); + sb.append(" enters the battlefield "); + if (controlledText) { + sb.append("under your control, "); + } else { + sb.append("or attacks, "); + } + sb.append(super.getRule()); + return sb.toString(); + } + + @Override + public EntersBattlefieldOrAttacksAllTriggeredAbility copy() { + return new EntersBattlefieldOrAttacksAllTriggeredAbility(this); + } +} From 2dc674b75c5decff3d400be302722e9aa2db67b7 Mon Sep 17 00:00:00 2001 From: "Saga\\Robert" Date: Thu, 17 Aug 2017 00:22:14 +0200 Subject: [PATCH 2/2] - added Kindred Boon, Charge, Discovery and Summons - updated c17 set class --- Mage.Sets/src/mage/cards/k/KindredBoon.java | 90 +++++++++++++ Mage.Sets/src/mage/cards/k/KindredCharge.java | 117 ++++++++++++++++ .../src/mage/cards/k/KindredDiscovery.java | 68 ++++++++++ .../src/mage/cards/k/KindredSummons.java | 126 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2017.java | 4 + 5 files changed, 405 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/KindredBoon.java create mode 100644 Mage.Sets/src/mage/cards/k/KindredCharge.java create mode 100644 Mage.Sets/src/mage/cards/k/KindredDiscovery.java create mode 100644 Mage.Sets/src/mage/cards/k/KindredSummons.java diff --git a/Mage.Sets/src/mage/cards/k/KindredBoon.java b/Mage.Sets/src/mage/cards/k/KindredBoon.java new file mode 100644 index 0000000000..c0be740e70 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KindredBoon.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.k; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ChosenSubtypePredicate; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.target.TargetPermanent; +/** + * + * @author Saga + */ +public class KindredBoon extends CardImpl { + + private static final FilterControlledCreaturePermanent filterDivinity = new FilterControlledCreaturePermanent("Each creature you control with a divinity counter on it"); + static { + filterDivinity.add(new CounterPredicate(CounterType.DIVINITY)); + } + + public KindredBoon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); + + // As Kindred Boon enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.AddAbility))); + + // {1}{W}: Put a divinity counter on target creature you control of the chosen type. + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control of the chosen type"); + filter.add(new ChosenSubtypePredicate(this.getId())); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.DIVINITY.createInstance()), new ManaCostsImpl("{1}{W}")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // Each creature you control with a divinity counter on it has indestructible. + Effect effect = new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filterDivinity); + effect.setText("Each creature you control with a divinity counter on it has indestructible"); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public KindredBoon(final KindredBoon card) { + super(card); + } + + @Override + public KindredBoon copy() { + return new KindredBoon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KindredCharge.java b/Mage.Sets/src/mage/cards/k/KindredCharge.java new file mode 100644 index 0000000000..bc93536051 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KindredCharge.java @@ -0,0 +1,117 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.k; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.PutTokenOntoBattlefieldCopyTargetEffect; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author Saga + */ +public class KindredCharge extends CardImpl { + + public KindredCharge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); + + // Choose a creature type. For each creature you control of the chosen type, create a token that's a copy of that creature. + // Those tokens gain haste. Exile them at the beginning of the next end step. + this.getSpellAbility().addEffect(new ChooseCreatureTypeEffect(Outcome.Copy)); + this.getSpellAbility().addEffect(new KindredChargeEffect()); + } + + public KindredCharge(final KindredCharge card) { + super(card); + } + + @Override + public KindredCharge copy() { + return new KindredCharge(this); + } +} + +class KindredChargeEffect extends OneShotEffect { + + public KindredChargeEffect() { + super(Outcome.Copy); + this.staticText = "For each creature you control of the chosen type, create a token that's a copy of that creature. " + + "Those tokens gain haste. Exile them at the beginning of the next end step"; + } + + public KindredChargeEffect(final KindredChargeEffect effect) { + super(effect); + } + + @Override + public KindredChargeEffect copy() { + return new KindredChargeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + String creatureType = game.getState().getValue(sourceObject.getId() + "_type").toString(); + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control of the chosen type"); + filter.add(new SubtypePredicate(SubType.byDescription(creatureType))); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { + if (permanent != null) { + PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(source.getControllerId(), null, true); + effect.setTargetPointer(new FixedTarget(permanent, game)); + effect.apply(game, source); + for (Permanent addedToken : effect.getAddedPermanent()) { + Effect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KindredDiscovery.java b/Mage.Sets/src/mage/cards/k/KindredDiscovery.java new file mode 100644 index 0000000000..79069afc07 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KindredDiscovery.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.k; + +import java.util.UUID; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldOrAttacksAllTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ChosenSubtypePredicate; +/** + * + * @author Saga + */ +public class KindredDiscovery extends CardImpl { + + public KindredDiscovery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}{U}"); + + // As Kindred Discovery enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.DrawCard))); + + // Whenever a creature you control of the chosen type enters the battlefield or attacks, draw a card. + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a creature you control of the chosen type"); + filter.add(new ChosenSubtypePredicate(this.getId())); + this.addAbility(new EntersBattlefieldOrAttacksAllTriggeredAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), filter, false)); + } + + public KindredDiscovery(final KindredDiscovery card) { + super(card); + } + + @Override + public KindredDiscovery copy() { + return new KindredDiscovery(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KindredSummons.java b/Mage.Sets/src/mage/cards/k/KindredSummons.java new file mode 100644 index 0000000000..a34f76dc97 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KindredSummons.java @@ -0,0 +1,126 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.k; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.players.Player; +/** + * + * @author Saga + */ +public class KindredSummons extends CardImpl { + + public KindredSummons(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{5}{G}{G}"); + + // Choose a creature type. Reveal cards from the top of your library until you reveal X creature cards of the chosen type, + // where X is the number of creatures you control of that type. Put those cards onto the battlefield, + // then shuffle the rest of the revealed cards into your library. + this.getSpellAbility().addEffect(new ChooseCreatureTypeEffect(Outcome.PutCreatureInPlay)); + this.getSpellAbility().addEffect(new KindredSummonsEffect()); + } + + public KindredSummons(final KindredSummons card) { + super(card); + } + + @Override + public KindredSummons copy() { + return new KindredSummons(this); + } +} + +class KindredSummonsEffect extends OneShotEffect { + + public KindredSummonsEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "Reveal cards from the top of your library until you reveal X creature cards of the chosen type, " + + "where X is the number of creatures you control of that type. Put those cards onto the battlefield, " + + "then shuffle the rest of the revealed cards into your library"; + } + + public KindredSummonsEffect(final KindredSummonsEffect effect) { + super(effect); + } + + @Override + public KindredSummonsEffect copy() { + return new KindredSummonsEffect(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) { + String creatureType = game.getState().getValue(sourceObject.getId() + "_type").toString(); + FilterControlledCreaturePermanent filterPermanent = new FilterControlledCreaturePermanent("creature you control of the chosen type"); + filterPermanent.add(new SubtypePredicate(SubType.byDescription(creatureType))); + int numberOfCards = game.getBattlefield().countAll(filterPermanent, source.getControllerId(), game); + Cards revealed = new CardsImpl(); + Set chosenSubtypeCreatureCards = new LinkedHashSet<>(); + Cards otherCards = new CardsImpl(); + FilterCreatureCard filterCard = new FilterCreatureCard("creature card of the chosen type"); + filterCard.add(new SubtypePredicate(SubType.byDescription(creatureType))); + while (chosenSubtypeCreatureCards.size() < numberOfCards && controller.getLibrary().hasCards()) { + Card card = controller.getLibrary().removeFromTop(game); + revealed.add(card); + if (card != null && filterCard.match(card, game)) { + chosenSubtypeCreatureCards.add(card); + } else { + otherCards.add(card); + } + } + controller.revealCards(sourceObject.getIdName(), revealed, game); + controller.moveCards(chosenSubtypeCreatureCards, Zone.BATTLEFIELD, source, game, false, false, false, null); + controller.putCardsOnTopOfLibrary(otherCards, game, source, false); + controller.shuffleLibrary(source, game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2017.java b/Mage.Sets/src/mage/sets/Commander2017.java index 821b6fdc71..91655e5700 100644 --- a/Mage.Sets/src/mage/sets/Commander2017.java +++ b/Mage.Sets/src/mage/sets/Commander2017.java @@ -62,7 +62,11 @@ public class Commander2017 extends ExpansionSet { cards.add(new SetCardInfo("Hungry Lynx", 31, Rarity.RARE, mage.cards.h.HungryLynx.class)); cards.add(new SetCardInfo("Fractured Identity", 37, Rarity.RARE, mage.cards.f.FracturedIdentity.class)); cards.add(new SetCardInfo("Inalla, Archmage Ritualist", 38, Rarity.MYTHIC, mage.cards.i.InallaArchmageRitualist.class)); + cards.add(new SetCardInfo("Kindred Boon", 5, Rarity.RARE, mage.cards.k.KindredBoon.class)); + cards.add(new SetCardInfo("Kindred Charge", 27, Rarity.RARE, mage.cards.k.KindredCharge.class)); + cards.add(new SetCardInfo("Kindred Discovery", 11, Rarity.RARE, mage.cards.k.KindredDiscovery.class)); cards.add(new SetCardInfo("Kindred Dominance", 18, Rarity.RARE, mage.cards.k.KindredDominance.class)); + cards.add(new SetCardInfo("Kindred Summons", 32, Rarity.RARE, mage.cards.k.KindredSummons.class)); cards.add(new SetCardInfo("Mirror of the Forebears", 54, Rarity.UNCOMMON, mage.cards.m.MirrorOfTheForebears.class)); cards.add(new SetCardInfo("Nazahn, Revered Bladesmith", 44, Rarity.MYTHIC, mage.cards.n.NazahnReveredBladesmith.class)); cards.add(new SetCardInfo("O-Kagachi, Vengeful Kami", 45, Rarity.MYTHIC, mage.cards.o.OKagachiVengefulKami.class));