Merge branch 'master' into c17KindredCycle

This commit is contained in:
theelk801 2017-08-17 11:13:44 -04:00 committed by GitHub
commit df02c32b0d
11 changed files with 1186 additions and 2 deletions

View file

@ -317,8 +317,17 @@ public class GameController implements GameCallback {
for (final Entry<UUID, GameSessionPlayer> entry : gameSessions.entrySet()) {
entry.getValue().init();
}
GameWorker worker = new GameWorker(game, choosingPlayerId, this);
gameFuture = gameExecutor.submit(worker);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
if (game.getState().getChoosingPlayerId() != null) {
// start timer to force player to choose starting player otherwise loosing by being idle
setupTimeout(game.getState().getChoosingPlayerId());
}
}
}

View file

@ -0,0 +1,84 @@
/*
* 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.b;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.keyword.LifelinkAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.target.Target;
import mage.target.common.TargetCardInYourGraveyard;
/**
*
* @author TheElk801
*/
public class BloodlineNecromancer extends CardImpl {
private static final FilterCreatureCard filter = new FilterCreatureCard("Vampire or Wizard creature card from your graveyard");
static {
filter.add(Predicates.or(new SubtypePredicate(SubType.VAMPIRE), new SubtypePredicate(SubType.WIZARD)));
}
public BloodlineNecromancer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}");
this.subtype.add("Vampire");
this.subtype.add("Wizard");
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// Lifelink
this.addAbility(LifelinkAbility.getInstance());
// When Bloodline Necromancer enters the battlefield, you may return target Vampire or Wizard creature card from your graveyard to the battlefield.
Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true);
Target target = new TargetCardInYourGraveyard(filter);
ability.addTarget(target);
this.addAbility(ability);
}
public BloodlineNecromancer(final BloodlineNecromancer card) {
super(card);
}
@Override
public BloodlineNecromancer copy() {
return new BloodlineNecromancer(this);
}
}

View file

@ -0,0 +1,128 @@
/*
* 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.f;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
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.common.FilterNonlandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.filter.predicate.permanent.PermanentIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetNonlandPermanent;
/**
*
* @author spjspj
*/
public class FortunateFew extends CardImpl {
public FortunateFew(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{W}");
// Choose a nonland permanent you don't control, then each other player chooses a nonland permanent he or she doesn't control that hasn't been chosen this way. Destroy all other nonland permanents.
this.getSpellAbility().addEffect(new FortunateFewEffect());
}
public FortunateFew(final FortunateFew card) {
super(card);
}
@Override
public FortunateFew copy() {
return new FortunateFew(this);
}
}
class FortunateFewEffect extends OneShotEffect {
public FortunateFewEffect() {
super(Outcome.DestroyPermanent);
staticText = "Choose a nonland permanent you don't control, then each other player chooses a nonland permanent he or she doesn't control that hasn't been chosen this way. Destroy all other nonland permanents";
}
public FortunateFewEffect(FortunateFewEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Map<Permanent, Integer> chosenCards = new HashMap<>(2);
int maxCount = 0;
// Players each choose a legal permanent
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
FilterNonlandPermanent filter = new FilterNonlandPermanent("a nonland permanent you don't control");
filter.add(Predicates.not(new ControllerIdPredicate(player.getId())));
for (Permanent chosenPerm : chosenCards.keySet()) {
filter.add(Predicates.not(new PermanentIdPredicate(chosenPerm.getId())));
}
Target target = new TargetNonlandPermanent(filter);
target.setNotTarget(true);
if (player.choose(Outcome.Exile, target, source.getSourceId(), game)) {
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
chosenCards.put(permanent, 1);
game.informPlayers(player.getLogName() + " has chosen: " + permanent.getName());
}
}
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source.getSourceId(), game)) {
if (!chosenCards.containsKey(permanent)) {
permanent.destroy(source.getSourceId(), game, false);
}
}
return true;
}
return false;
}
@Override
public FortunateFewEffect copy() {
return new FortunateFewEffect(this);
}
}

View file

@ -0,0 +1,88 @@
/*
* 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.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapTargetCost;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetNonlandPermanent;
/**
*
* @author TheElk801
*/
public class GalecasterColossus extends CardImpl {
private static final FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanent you don't control");
private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("untapped Wizard you control");
static {
filter.add(new ControllerPredicate(TargetController.NOT_YOU));
filter2.add(new SubtypePredicate(SubType.WIZARD));
filter2.add(Predicates.not(new TappedPredicate()));
}
public GalecasterColossus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}");
this.subtype.add("Giant");
this.subtype.add("Wizard");
this.power = new MageInt(5);
this.toughness = new MageInt(6);
// Tap an untapped Wizard you control: Return target nonland permanent you don't control to its owner's hand.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new TapTargetCost(new TargetControlledPermanent(1, 1, filter2, true)));
ability.addTarget(new TargetNonlandPermanent(filter));
this.addAbility(ability);
}
public GalecasterColossus(final GalecasterColossus card) {
super(card);
}
@Override
public GalecasterColossus copy() {
return new GalecasterColossus(this);
}
}

View file

@ -0,0 +1,149 @@
/*
* 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.i;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterOwnedCard;
import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInExile;
/**
*
* @author TheElk801
*/
public class IzzetChemister extends CardImpl {
private static final FilterCard filter = new FilterOwnedCard("instant or sorcery card from your graveyard");
public IzzetChemister(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}");
this.subtype.add("Goblin");
this.subtype.add("Wizard");
this.power = new MageInt(1);
this.toughness = new MageInt(3);
// Haste
this.addAbility(HasteAbility.getInstance());
// R, T: Exile target instant or sorcery card from your graveyard.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(this.getId(), this.getIdName()), new ManaCostsImpl("{R}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCard(Zone.GRAVEYARD, filter));
this.addAbility(ability);
// 1R, T: Sacrifice Izzet Chemister: Cast any number of cards exiled with Izzet Chemister without paying their mana costs.
IzzetChemisterCastFromExileEffect returnFromExileEffect = new IzzetChemisterCastFromExileEffect(this.getId(), "Cast any number of cards exiled with {this} without paying their mana costs.");
ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, returnFromExileEffect, new ManaCostsImpl("{1}{R}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
public IzzetChemister(final IzzetChemister card) {
super(card);
}
@Override
public IzzetChemister copy() {
return new IzzetChemister(this);
}
}
class IzzetChemisterCastFromExileEffect extends OneShotEffect {
private UUID exileId;
public IzzetChemisterCastFromExileEffect(UUID exileId, String description) {
super(Outcome.PlayForFree);
this.exileId = exileId;
this.setText(description);
}
public IzzetChemisterCastFromExileEffect(final IzzetChemisterCastFromExileEffect effect) {
super(effect);
this.exileId = effect.exileId;
}
@Override
public IzzetChemisterCastFromExileEffect copy() {
return new IzzetChemisterCastFromExileEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
ExileZone exile = game.getExile().getExileZone(exileId);
Player controller = game.getPlayer(source.getControllerId());
FilterCard filter = new FilterCard();
if (controller != null && exile != null) {
Cards cardsToExile = new CardsImpl();
cardsToExile.addAll(exile.getCards(game));
OuterLoop:
while (cardsToExile.count(filter, game) > 0) {
if (!controller.canRespond()) {
return false;
}
TargetCardInExile target = new TargetCardInExile(0, 1, filter, exileId, false);
target.setNotTarget(true);
while (cardsToExile.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, cardsToExile, target, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
controller.cast(card.getSpellAbility(), game, true);
cardsToExile.remove(card);
} else {
break OuterLoop;
}
target.clearChosen();
}
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,194 @@
/*
* 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.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInHand;
import mage.util.CardUtil;
/**
*
* @author TheElk801
*/
public class KheruMindEater extends CardImpl {
public KheruMindEater(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
this.subtype.add("Vampire");
this.power = new MageInt(1);
this.toughness = new MageInt(3);
// Menace
this.addAbility(new MenaceAbility());
// Whenever Kheru Mind-Eater deals combat damage to a player, that player exiles a card from his or her hand face down.
this.addAbility(new DealsDamageToAPlayerTriggeredAbility(new KheruMindEaterExileEffect(), false, true));
// You may look at and play cards exiled with Kheru Mind-Eater.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KheruMindEaterEffect()));
this.addAbility(new SimpleStaticAbility(Zone.ALL, new KheruMindEaterLookAtCardEffect()));
}
public KheruMindEater(final KheruMindEater card) {
super(card);
}
@Override
public KheruMindEater copy() {
return new KheruMindEater(this);
}
}
class KheruMindEaterExileEffect extends OneShotEffect {
public KheruMindEaterExileEffect() {
super(Outcome.Discard);
staticText = "that player exiles a card of his or her hand face down";
}
public KheruMindEaterExileEffect(final KheruMindEaterExileEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (player != null && player.getHand().size() > 0) {
Target target = new TargetCardInHand(1, new FilterCard());
target.chooseTarget(Outcome.Exile, player.getId(), source, game);
Card card = game.getCard(target.getFirstTarget());
MageObject sourceObject = game.getObject(source.getSourceId());
if (card != null && sourceObject != null) {
if (player.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourceObject.getIdName(), source.getSourceId(), game, Zone.HAND, true)) {
card.setFaceDown(true, game);
}
return true;
}
}
return false;
}
@Override
public KheruMindEaterExileEffect copy() {
return new KheruMindEaterExileEffect(this);
}
}
class KheruMindEaterEffect extends AsThoughEffectImpl {
public KheruMindEaterEffect() {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may play cards exiled with {this}";
}
public KheruMindEaterEffect(final KheruMindEaterEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public KheruMindEaterEffect copy() {
return new KheruMindEaterEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
Card card = game.getCard(objectId);
if (affectedControllerId.equals(source.getControllerId()) && card != null && game.getState().getZone(card.getId()) == Zone.EXILED) {
ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
return zone != null && zone.contains(card.getId());
}
return false;
}
}
class KheruMindEaterLookAtCardEffect extends AsThoughEffectImpl {
public KheruMindEaterLookAtCardEffect() {
super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may look at cards exiled with {this}";
}
public KheruMindEaterLookAtCardEffect(final KheruMindEaterLookAtCardEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public KheruMindEaterLookAtCardEffect copy() {
return new KheruMindEaterLookAtCardEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (affectedControllerId.equals(source.getControllerId())) {
Card card = game.getCard(objectId);
if (card != null) {
MageObject sourceObject = game.getObject(source.getSourceId());
if (sourceObject == null) {
return false;
}
UUID exileId = CardUtil.getCardExileZoneId(game, source);
ExileZone exile = game.getExile().getExileZone(exileId);
return exile != null && exile.contains(objectId);
}
}
return false;
}
}

View file

@ -0,0 +1,169 @@
/*
* 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.m;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.CastSpellLastTurnWatcher;
/**
*
* @author TheElk801
*/
public class MagusOfTheMind extends CardImpl {
public MagusOfTheMind(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}");
this.subtype.add("Human");
this.subtype.add("Wizard");
this.power = new MageInt(4);
this.toughness = new MageInt(5);
// U, T, Sacrifice Magus of the Mind: Shuffle your library, then exile the top X cards, where X is one plus the number of spells cast this turn. Until end of turn, you may play cards exiled this way without paying their mana costs.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MagusOfTheMindEffect(), new ManaCostsImpl("{U}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability, new CastSpellLastTurnWatcher());
}
public MagusOfTheMind(final MagusOfTheMind card) {
super(card);
}
@Override
public MagusOfTheMind copy() {
return new MagusOfTheMind(this);
}
}
class MagusOfTheMindEffect extends OneShotEffect {
MagusOfTheMindEffect() {
super(Outcome.Benefit);
this.staticText = "Shuffle your library, then exile the top X cards, where X is one plus the number of spells cast this turn. Until end of turn, you may play cards exiled this way without paying their mana costs";
}
MagusOfTheMindEffect(final MagusOfTheMindEffect effect) {
super(effect);
}
@Override
public MagusOfTheMindEffect copy() {
return new MagusOfTheMindEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName());
int stormCount = watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn() + 1;
System.out.println(stormCount);
if (controller != null && sourceObject != null) {
controller.shuffleLibrary(source, game);
if (controller.getLibrary().hasCards()) {
Set<Card> cards = controller.getLibrary().getTopCards(game, stormCount);
if (cards != null) {
for (Card card : cards) {
if (card != null) {
controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true);
ContinuousEffect effect = new MagusOfTheMindCastFromExileEffect();
effect.setTargetPointer(new FixedTarget(card.getId()));
game.addEffect(effect, source);
}
}
}
}
return true;
}
return false;
}
}
class MagusOfTheMindCastFromExileEffect extends AsThoughEffectImpl {
MagusOfTheMindCastFromExileEffect() {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
staticText = "you may play that card without paying its mana cost";
}
MagusOfTheMindCastFromExileEffect(final MagusOfTheMindCastFromExileEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public MagusOfTheMindCastFromExileEffect copy() {
return new MagusOfTheMindCastFromExileEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (objectId != null && objectId.equals(getTargetPointer().getFirst(game, source))) {
if (affectedControllerId.equals(source.getControllerId())) {
Card card = game.getCard(objectId);
if (card != null && game.getState().getZone(objectId) == Zone.EXILED) {
if (!card.isLand() && card.getSpellAbility().getCosts() != null) {
Player player = game.getPlayer(affectedControllerId);
if (player != null) {
player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts());
}
}
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,169 @@
/*
* 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.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.AddContinuousEffectToGame;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
/**
*
* @author TheElk801
*/
public class MirriWeatherlightDuelist extends CardImpl {
public MirriWeatherlightDuelist(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add("Cat");
this.subtype.add("Warrior");
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// First Strike
this.addAbility(FirstStrikeAbility.getInstance());
// Whenever Mirri, Weatherlight Duelist attacks, each opponent can't block with more than one creature this combat.
this.addAbility(new AttacksTriggeredAbility(new AddContinuousEffectToGame(new MirriWeatherlightDuelistBlockRestrictionEffect()), false));
// As long as Mirri, Weatherlight Duelist is tapped, no more than one creature can attack you each combat.
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
new MirriWeatherlightDuelistAttackRestrictionEffect(1), SourceTappedCondition.instance,
"As long as {this} is tapped, no more than one creature can attack you each combat."));
this.addAbility(ability);
}
public MirriWeatherlightDuelist(final MirriWeatherlightDuelist card) {
super(card);
}
@Override
public MirriWeatherlightDuelist copy() {
return new MirriWeatherlightDuelist(this);
}
}
class MirriWeatherlightDuelistBlockRestrictionEffect extends RestrictionEffect {
MirriWeatherlightDuelistBlockRestrictionEffect() {
super(Duration.EndOfCombat);
staticText = "each opponent can't block with more than one creature this combat";
}
MirriWeatherlightDuelistBlockRestrictionEffect(final MirriWeatherlightDuelistBlockRestrictionEffect effect) {
super(effect);
}
@Override
public MirriWeatherlightDuelistBlockRestrictionEffect copy() {
return new MirriWeatherlightDuelistBlockRestrictionEffect(this);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return true;
}
@Override
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
for (UUID creature : game.getCombat().getBlockers()) {
if (game.getPlayer(game.getPermanent(creature).getOwnerId()).hasOpponent(attacker.getControllerId(), game)) {
return false;
}
}
return true;
}
}
class MirriWeatherlightDuelistAttackRestrictionEffect extends ContinuousEffectImpl {
private final int maxAttackedBy;
public MirriWeatherlightDuelistAttackRestrictionEffect(int maxAttackedBy) {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
this.maxAttackedBy = maxAttackedBy;
staticText = "No more than one creature can attack you each combat";
}
public MirriWeatherlightDuelistAttackRestrictionEffect(final MirriWeatherlightDuelistAttackRestrictionEffect effect) {
super(effect);
this.maxAttackedBy = effect.maxAttackedBy;
}
@Override
public MirriWeatherlightDuelistAttackRestrictionEffect copy() {
return new MirriWeatherlightDuelistAttackRestrictionEffect(this);
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
switch (layer) {
case RulesEffects:
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
// Change the rule
if (controller.getMaxAttackedBy() > maxAttackedBy) {
controller.setMaxAttackedBy(maxAttackedBy);
}
}
break;
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.RulesEffects;
}
}

View file

@ -0,0 +1,186 @@
/*
* 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.t;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfCombatTriggeredAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttacksIfAbleTargetPlayerSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.util.RandomUtil;
import mage.watchers.Watcher;
/**
*
* @author TheElk801
*/
public class TerritorialHellkite extends CardImpl {
public TerritorialHellkite(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}");
this.subtype.add("Dragon");
this.power = new MageInt(6);
this.toughness = new MageInt(5);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Haste
this.addAbility(HasteAbility.getInstance());
// At the beginning of combat on your turn, choose an opponent at random that Territorial Hellkite didn't attack during your last combat. Territorial Hellkite attacks that player this combat if able. If you can't choose an opponent this way, tap Territorial Hellkite.
this.addAbility(new BeginningOfCombatTriggeredAbility(new AttackIfAbleTargetRandoOpponentSourceEffect(), TargetController.YOU, false), new AttackedLastCombatWatcher());
}
public TerritorialHellkite(final TerritorialHellkite card) {
super(card);
}
@Override
public TerritorialHellkite copy() {
return new TerritorialHellkite(this);
}
}
class AttackedLastCombatWatcher extends Watcher {
public final Map<UUID, UUID> attackedLastCombatPlayers = new HashMap<>();
public AttackedLastCombatWatcher() {
super(AttackedLastCombatWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public AttackedLastCombatWatcher(final AttackedLastCombatWatcher watcher) {
super(watcher);
for (Entry<UUID, UUID> entry : watcher.attackedLastCombatPlayers.entrySet()) {
attackedLastCombatPlayers.put(entry.getKey(), entry.getValue());
}
}
@Override
public void watch(GameEvent event, Game game) {
//TODO: this will have problems if the creature is stolen and then given back before the original controller's next combat
if (event.getType() == GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE) {
if (!attackedLastCombatPlayers.keySet().isEmpty()) {
Iterator<Map.Entry<UUID, UUID>> attackers = attackedLastCombatPlayers.entrySet().iterator();
while (attackers.hasNext()) {
Map.Entry<UUID, UUID> attacker = attackers.next();
if (game.getPermanent(attacker.getKey()).getControllerId().equals(game.getActivePlayerId())) {
attackers.remove();
}
}
}
}
if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) {
attackedLastCombatPlayers.put(event.getSourceId(), game.getCombat().getDefenderId(event.getSourceId()));
}
}
public Map<UUID, UUID> getAttackedLastCombatPlayers() {
return this.attackedLastCombatPlayers;
}
@Override
public AttackedLastCombatWatcher copy() {
return new AttackedLastCombatWatcher(this);
}
}
class AttackIfAbleTargetRandoOpponentSourceEffect extends OneShotEffect {
public AttackIfAbleTargetRandoOpponentSourceEffect() {
super(Outcome.Benefit);
this.staticText = "choose an opponent at random that {this} didn't attack during your last combat. {this} attacks that player this combat if able. If you can't choose an opponent this way, tap {this}";
}
public AttackIfAbleTargetRandoOpponentSourceEffect(final AttackIfAbleTargetRandoOpponentSourceEffect effect) {
super(effect);
}
@Override
public AttackIfAbleTargetRandoOpponentSourceEffect copy() {
return new AttackIfAbleTargetRandoOpponentSourceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
List<UUID> opponents = new ArrayList<>();
AttackedLastCombatWatcher watcher = (AttackedLastCombatWatcher) game.getState().getWatchers().get(AttackedLastCombatWatcher.class.getSimpleName());
if (watcher != null) {
boolean ignoreMe;
for (UUID opp : game.getOpponents(controller.getId())) {
ignoreMe = false;
if (watcher.getAttackedLastCombatPlayers().getOrDefault(source.getSourceId(), source.getControllerId()).equals(opp)) {
ignoreMe = true;
}
if (!ignoreMe) {
opponents.add(opp);
}
}
} else {
opponents.addAll(game.getOpponents(controller.getId()));
}
if (!opponents.isEmpty()) {
Player opponent = game.getPlayer(opponents.get(RandomUtil.nextInt(opponents.size())));
if (opponent != null) {
ContinuousEffect effect = new AttacksIfAbleTargetPlayerSourceEffect();
effect.setTargetPointer(new FixedTarget(opponent.getId()));
game.addEffect(effect, source);
return true;
}
} else {
game.getPermanent(source.getSourceId()).tap(game);
}
}
return false;
}
}

View file

@ -50,6 +50,7 @@ public class Commander2017 extends ExpansionSet {
cards.add(new SetCardInfo("Arahbo, Roar of the World", 35, Rarity.MYTHIC, mage.cards.a.ArahboRoarOfTheWorld.class));
cards.add(new SetCardInfo("Balan, Wandering Knight", 2, Rarity.RARE, mage.cards.b.BalanWanderingKnight.class));
cards.add(new SetCardInfo("Bloodforged War Axe", 50, Rarity.RARE, mage.cards.b.BloodforgedWarAxe.class));
cards.add(new SetCardInfo("Bloodline Necromancer", 14, Rarity.UNCOMMON, mage.cards.b.BloodlineNecromancer.class));
cards.add(new SetCardInfo("Bloodsworn Steward", 22, Rarity.RARE, mage.cards.b.BloodswornSteward.class));
cards.add(new SetCardInfo("Crimson Honor Guard", 23, Rarity.RARE, mage.cards.c.CrimsonHonorGuard.class));
cards.add(new SetCardInfo("Curse of Bounty", 30, Rarity.UNCOMMON, mage.cards.c.CurseOfBounty.class));
@ -58,15 +59,21 @@ public class Commander2017 extends ExpansionSet {
cards.add(new SetCardInfo("Curse of Verbosity", 9, Rarity.UNCOMMON, mage.cards.c.CurseOfVerbosity.class));
cards.add(new SetCardInfo("Curse of Vitality", 3, Rarity.UNCOMMON, mage.cards.c.CurseOfVitality.class));
cards.add(new SetCardInfo("Edgar Markov", 36, Rarity.MYTHIC, mage.cards.e.EdgarMarkov.class));
cards.add(new SetCardInfo("Fortunate Few", 4, Rarity.RARE, mage.cards.f.FortunateFew.class));
cards.add(new SetCardInfo("Fractured Identity", 37, Rarity.RARE, mage.cards.f.FracturedIdentity.class));
cards.add(new SetCardInfo("Galecaster Colossus", 10, Rarity.RARE, mage.cards.g.GalecasterColossus.class));
cards.add(new SetCardInfo("Herald's Horn", 53, Rarity.UNCOMMON, mage.cards.h.HeraldsHorn.class));
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("Izzet Chemister", 26, Rarity.RARE, mage.cards.i.IzzetChemister.class));
cards.add(new SetCardInfo("Kheru Mind-Eater", 17, Rarity.RARE, mage.cards.k.KheruMindEater.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("Magus of the Mind", 12, Rarity.RARE, mage.cards.m.MagusOfTheMind.class));
cards.add(new SetCardInfo("Mirri, Weatherlight Duelist", 43, Rarity.MYTHIC, mage.cards.m.MirriWeatherlightDuelist.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));
@ -77,6 +84,7 @@ public class Commander2017 extends ExpansionSet {
cards.add(new SetCardInfo("Taigam, Ojutai Master", 46, Rarity.MYTHIC, mage.cards.t.TaigamOjutaiMaster.class));
cards.add(new SetCardInfo("Taigam, Sidisi's Hand", 47, Rarity.RARE, mage.cards.t.TaigamSidisisHand.class));
cards.add(new SetCardInfo("Teferi's Protection", 8, Rarity.RARE, mage.cards.t.TeferisProtection.class));
cards.add(new SetCardInfo("Territorial Hellkite", 29, Rarity.RARE, mage.cards.t.TerritorialHellkite.class));
cards.add(new SetCardInfo("The Ur-Dragon", 48, Rarity.MYTHIC, mage.cards.t.TheUrDragon.class));
cards.add(new SetCardInfo("Traverse the Outlands", 34, Rarity.RARE, mage.cards.t.TraverseTheOutlands.class));
cards.add(new SetCardInfo("Wasitora, Nekoru Queen", 49, Rarity.MYTHIC, mage.cards.w.WasitoraNekoruQueen.class));

View file

@ -1948,7 +1948,7 @@ public abstract class GameImpl implements Game, Serializable {
Player controller = this.getPlayer(planeswalker.getControllerId());
if (controller != null) {
Target targetPlaneswalkerToKeep = new TargetPermanent(filterPlaneswalker);
targetPlaneswalkerToKeep.setTargetName(planeswalker.getName() + " to keep?");
targetPlaneswalkerToKeep.setTargetName(planeswalkertype.toString() + " to keep?");
controller.chooseTarget(Outcome.Benefit, targetPlaneswalkerToKeep, null, this);
for (Permanent dupPlaneswalker : this.getBattlefield().getActivePermanents(filterPlaneswalker, planeswalker.getControllerId(), this)) {
if (!targetPlaneswalkerToKeep.getTargets().contains(dupPlaneswalker.getId())) {