mirror of
https://github.com/magefree/mage.git
synced 2026-01-09 04:12:14 -08:00
refactor selecting cards from multiple zones (#11584)
* refactor selecting cards from multiple zones fix MV <= controlled lands predicate fix filter checks without source parameter * fix test choice
This commit is contained in:
parent
8459babbcd
commit
e6bd35eb77
19 changed files with 258 additions and 319 deletions
|
|
@ -0,0 +1,69 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class PutCardFromHandOrGraveyardOntoBattlefieldEffect extends OneShotEffect {
|
||||
|
||||
private final FilterCard filter;
|
||||
private final boolean tapped;
|
||||
|
||||
/**
|
||||
* @param filter for selecting a card (don't include zone-related text in filter message)
|
||||
* @param tapped ETB tapped if true
|
||||
*/
|
||||
public PutCardFromHandOrGraveyardOntoBattlefieldEffect(FilterCard filter, boolean tapped) {
|
||||
super(Outcome.PutCardInPlay);
|
||||
this.filter = filter;
|
||||
this.tapped = tapped;
|
||||
this.staticText = "you may put " + CardUtil.addArticle(filter.getMessage())
|
||||
+ " from your hand or graveyard onto the battlefield" + (tapped ? " tapped" : "");
|
||||
}
|
||||
|
||||
private PutCardFromHandOrGraveyardOntoBattlefieldEffect(final PutCardFromHandOrGraveyardOntoBattlefieldEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.tapped = effect.tapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PutCardFromHandOrGraveyardOntoBattlefieldEffect copy() {
|
||||
return new PutCardFromHandOrGraveyardOntoBattlefieldEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Cards cards = new CardsImpl();
|
||||
cards.addAllCards(controller.getHand().getCards(filter, source.getControllerId(), source, game));
|
||||
cards.addAllCards(controller.getGraveyard().getCards(filter, source.getControllerId(), source, game));
|
||||
if (cards.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
TargetCard target = new TargetCard(0, 1, Zone.ALL, filter);
|
||||
target.withNotTarget(true);
|
||||
controller.choose(outcome, cards, target, source, game);
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.CommanderCardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.common.TargetCardInCommandZone;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* "Put a {filter} card from {zone 1} or {zone 2} onto the battlefield.
|
||||
*
|
||||
* @author TheElk801, Alex-Vasile
|
||||
*/
|
||||
public class PutCardFromOneOfTwoZonesOntoBattlefieldEffect extends OneShotEffect {
|
||||
|
||||
private final FilterCard filterCard;
|
||||
private final boolean tapped;
|
||||
private final Effect effectToApplyOnPermanent;
|
||||
private final Zone zone1;
|
||||
private final Zone zone2;
|
||||
|
||||
public PutCardFromOneOfTwoZonesOntoBattlefieldEffect(FilterCard filterCard) {
|
||||
this(filterCard, false);
|
||||
}
|
||||
|
||||
public PutCardFromOneOfTwoZonesOntoBattlefieldEffect(FilterCard filterCard, boolean tapped) {
|
||||
this(filterCard, tapped, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param filterCard Filter used to filter which cards are valid choices. (no default)
|
||||
* @param tapped If the permanent should enter the battlefield tapped (default is False)
|
||||
* @param effectToApplyOnPermanent An effect to apply to the permanent after it enters (default null)
|
||||
* See "Swift Warkite" or "Nissa of Shadowed Boughs".
|
||||
* @param zone1 The first zone to pick from (default of HAND)
|
||||
* @param zone2 The second zone to pick from (defualt of GRAVEYARD)
|
||||
*/
|
||||
public PutCardFromOneOfTwoZonesOntoBattlefieldEffect(FilterCard filterCard, boolean tapped, Effect effectToApplyOnPermanent, Zone zone1, Zone zone2) {
|
||||
super(filterCard instanceof FilterCreatureCard ? Outcome.PutCreatureInPlay : Outcome.PutCardInPlay);
|
||||
this.filterCard = filterCard;
|
||||
this.tapped = tapped;
|
||||
this.effectToApplyOnPermanent = effectToApplyOnPermanent;
|
||||
this.zone1 = zone1;
|
||||
this.zone2 = zone2;
|
||||
}
|
||||
|
||||
public PutCardFromOneOfTwoZonesOntoBattlefieldEffect(FilterCard filterCard, boolean tapped, Effect effectToApplyOnPermanent) {
|
||||
this(filterCard, tapped, effectToApplyOnPermanent, Zone.HAND, Zone.GRAVEYARD);
|
||||
}
|
||||
|
||||
public PutCardFromOneOfTwoZonesOntoBattlefieldEffect(FilterCard filterCard, Zone zone1, Zone zone2) {
|
||||
this(filterCard, false, null, zone1, zone2);
|
||||
}
|
||||
|
||||
private PutCardFromOneOfTwoZonesOntoBattlefieldEffect(final PutCardFromOneOfTwoZonesOntoBattlefieldEffect effect) {
|
||||
super(effect);
|
||||
this.filterCard = effect.filterCard;
|
||||
this.tapped = effect.tapped;
|
||||
this.zone1 = effect.zone1;
|
||||
this.zone2 = effect.zone2;
|
||||
if (effect.effectToApplyOnPermanent != null) {
|
||||
this.effectToApplyOnPermanent = effect.effectToApplyOnPermanent.copy();
|
||||
} else {
|
||||
this.effectToApplyOnPermanent = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Cards cardsInZone1 = getCardsFromZone(game, controller, zone1);
|
||||
Cards cardsInZone2 = getCardsFromZone(game, controller, zone2);
|
||||
|
||||
boolean cardsAvailableInZone1 = cardsInZone1.count(filterCard, game) > 0;
|
||||
boolean cardsAvailableInZone2 = cardsInZone2.count(filterCard, game) > 0;
|
||||
if (!cardsAvailableInZone1 && !cardsAvailableInZone2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean choose1stZone;
|
||||
if (cardsAvailableInZone1 && cardsAvailableInZone2) {
|
||||
choose1stZone = controller.chooseUse(outcome, "Where do you want to chose the card from?",
|
||||
null, zone1.name(), zone2.name(), source, game);
|
||||
} else {
|
||||
choose1stZone = cardsAvailableInZone1;
|
||||
}
|
||||
|
||||
Zone zone = choose1stZone ? zone1 : zone2;
|
||||
Cards cards = choose1stZone ? cardsInZone1 : cardsInZone2;
|
||||
TargetCard targetCard;
|
||||
|
||||
switch (zone) {
|
||||
case HAND:
|
||||
targetCard = new TargetCardInHand(filterCard);
|
||||
break;
|
||||
case GRAVEYARD:
|
||||
targetCard = new TargetCardInGraveyard(filterCard);
|
||||
break;
|
||||
case COMMAND:
|
||||
targetCard = new TargetCardInCommandZone(filterCard);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
controller.choose(outcome, cards, targetCard, source, game);
|
||||
Card card = game.getCard(targetCard.getFirstTarget());
|
||||
if (card == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (effectToApplyOnPermanent != null) {
|
||||
effectToApplyOnPermanent.setTargetPointer(new FixedTarget(card.getId()));
|
||||
effectToApplyOnPermanent.apply(game, source);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Cards getCardsFromZone(Game game, Player player, Zone zone) {
|
||||
switch (zone) {
|
||||
case HAND:
|
||||
return player.getHand();
|
||||
case COMMAND:
|
||||
return new CardsImpl(game.getCommanderCardsFromCommandZone(player, CommanderCardType.ANY));
|
||||
case GRAVEYARD:
|
||||
return player.getGraveyard();
|
||||
default:
|
||||
return new CardsImpl();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PutCardFromOneOfTwoZonesOntoBattlefieldEffect copy() {
|
||||
return new PutCardFromOneOfTwoZonesOntoBattlefieldEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
return "you may put " + CardUtil.addArticle(this.filterCard.getMessage()) +
|
||||
" from your hand or graveyard onto the battlefield" +
|
||||
(this.tapped ? " tapped" : "") +
|
||||
(effectToApplyOnPermanent == null ? "" : ". " + effectToApplyOnPermanent.getText(mode));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package mage.filter.predicate.card;
|
||||
|
||||
import mage.cards.Card;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author Plopman, Alex-Vasile
|
||||
*/
|
||||
public class CardManaCostLessThanControlledLandCountPredicate implements Predicate<Card> {
|
||||
|
||||
private static final String string = "card with mana value less than or equal to the number of lands you control";
|
||||
private static final CardManaCostLessThanControlledLandCountPredicate instance = new CardManaCostLessThanControlledLandCountPredicate();
|
||||
|
||||
private CardManaCostLessThanControlledLandCountPredicate() { }
|
||||
|
||||
public static CardManaCostLessThanControlledLandCountPredicate getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Card input, Game game) {
|
||||
return input.getManaValue() <= game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, input.getOwnerId(), game).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package mage.filter.predicate.card;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public enum ManaValueLessThanControlledLandCountPredicate implements ObjectSourcePlayerPredicate<MageObject> {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
|
||||
return input.getObject().getManaValue() <= game.getBattlefield().countAll(StaticFilters.FILTER_LAND, game.getControllerId(input.getSourceId()), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "mana value less than or equal to the number of lands you control";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue