mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
Fix auto-choose targets for activated abilities and spells (#13036)
* rework Armory Automaton
* remove redundant "setRequired(false)" from effects that separate into piles
* replace setRequired(false) with minTargets 0
* remove setRequired(false) where minTargets already 0
* remove setRequired(false) where preceded by chooseUse
* Revert "Player auto-choose respects required targets (#10557)"
This reverts commit fb8424556e.
This commit is contained in:
parent
737e67963d
commit
5070f8bef7
19 changed files with 32 additions and 83 deletions
|
|
@ -681,7 +681,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
required = false;
|
||||
}
|
||||
|
||||
UUID responseId = required ? target.tryToAutoChoose(abilityControllerId, source, game) : null;
|
||||
UUID responseId = target.tryToAutoChoose(abilityControllerId, source, game);
|
||||
|
||||
// responseId is null if a choice couldn't be automatically made
|
||||
if (responseId == null) {
|
||||
|
|
@ -780,7 +780,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
required = false;
|
||||
}
|
||||
|
||||
UUID responseId = required ? target.tryToAutoChoose(abilityControllerId, source, game) : null;
|
||||
UUID responseId = target.tryToAutoChoose(abilityControllerId, source, game);
|
||||
|
||||
// responseId is null if a choice couldn't be automatically made
|
||||
if (responseId == null) {
|
||||
|
|
@ -877,8 +877,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
required = false;
|
||||
}
|
||||
|
||||
UUID responseId = required ? target.tryToAutoChoose(abilityControllerId, source, game, possibleTargets)
|
||||
: null;
|
||||
UUID responseId = target.tryToAutoChoose(abilityControllerId, source, game, possibleTargets);
|
||||
|
||||
if (responseId == null) {
|
||||
Map<String, Serializable> options = getOptions(target, null);
|
||||
|
|
@ -958,8 +957,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
required = false;
|
||||
}
|
||||
|
||||
UUID responseId = required ? target.tryToAutoChoose(abilityControllerId, source, game, possibleTargets)
|
||||
: null;
|
||||
UUID responseId = target.tryToAutoChoose(abilityControllerId, source, game, possibleTargets);
|
||||
|
||||
if (responseId == null) {
|
||||
List<UUID> chosenTargets = target.getTargets();
|
||||
|
|
@ -1041,7 +1039,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
required = false;
|
||||
}
|
||||
|
||||
UUID responseId = required ? target.tryToAutoChoose(abilityControllerId, source, game) : null;
|
||||
UUID responseId = target.tryToAutoChoose(abilityControllerId, source, game);
|
||||
|
||||
// responseId is null if a choice couldn't be automatically made
|
||||
if (responseId == null) {
|
||||
|
|
|
|||
|
|
@ -10,25 +10,23 @@ import mage.constants.CardType;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterArtifactPermanent;
|
||||
import mage.filter.common.FilterEquipmentPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.CardIdPredicate;
|
||||
import mage.filter.predicate.permanent.AttachedToPredicate;
|
||||
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.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
* @author xenohedron
|
||||
*/
|
||||
public final class ArmoryAutomaton extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterPermanent("Equipment");
|
||||
|
||||
static {
|
||||
filter.add(SubType.EQUIPMENT.getPredicate());
|
||||
}
|
||||
|
||||
public ArmoryAutomaton(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}");
|
||||
|
||||
|
|
@ -36,8 +34,10 @@ public final class ArmoryAutomaton extends CardImpl {
|
|||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Whenever Armory Automaton enters the battlefield or attacks, attach any number of target Equipment to it.
|
||||
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new ArmoryAutomatonEffect()));
|
||||
// Whenever Armory Automaton enters or attacks, you may attach any number of target Equipment to it.
|
||||
Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new ArmoryAutomatonEffect(), true);
|
||||
ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private ArmoryAutomaton(final ArmoryAutomaton card) {
|
||||
|
|
@ -52,12 +52,6 @@ public final class ArmoryAutomaton extends CardImpl {
|
|||
|
||||
class ArmoryAutomatonEffect extends OneShotEffect {
|
||||
|
||||
private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("Equipment");
|
||||
|
||||
static {
|
||||
filter.add(SubType.EQUIPMENT.getPredicate());
|
||||
}
|
||||
|
||||
ArmoryAutomatonEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "attach any number of target Equipment to it";
|
||||
|
|
@ -74,38 +68,16 @@ class ArmoryAutomatonEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && sourcePermanent != null) {
|
||||
|
||||
// dynamic filter (can't selects own attaches and can't selects twice)
|
||||
FilterPermanent currentFilter = new FilterEquipmentPermanent();
|
||||
FilterPermanent filterSourceId = new FilterPermanent();
|
||||
filterSourceId.add(new CardIdPredicate(source.getSourceId()));
|
||||
currentFilter.add(Predicates.not(new AttachedToPredicate(filterSourceId)));
|
||||
|
||||
int countBattlefield = game.getBattlefield().getActivePermanents(currentFilter, source.getControllerId(), source, game).size();
|
||||
while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Select and attach a target Equipment?", source, game)) {
|
||||
Target targetEquipment = new TargetPermanent(currentFilter);
|
||||
targetEquipment.setRequired(false);
|
||||
if (player.choose(Outcome.Benefit, targetEquipment, source, game) && targetEquipment.getFirstTarget() != null) {
|
||||
currentFilter.add(Predicates.not(new PermanentIdPredicate(targetEquipment.getFirstTarget()))); // exclude selected for next time
|
||||
|
||||
Permanent aura = game.getPermanent(targetEquipment.getFirstTarget());
|
||||
if (aura != null) {
|
||||
Permanent attachedTo = game.getPermanent(aura.getAttachedTo());
|
||||
if (attachedTo != null) {
|
||||
attachedTo.removeAttachment(aura.getId(), source, game);
|
||||
}
|
||||
sourcePermanent.addAttachment(aura.getId(), source, game);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
countBattlefield = game.getBattlefield().getActivePermanents(currentFilter, source.getControllerId(), source, game).size();
|
||||
}
|
||||
return true;
|
||||
Permanent creature = source.getSourcePermanentIfItStillExists(game);
|
||||
if (creature == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
|
||||
Permanent equipment = game.getPermanent(targetId);
|
||||
if (equipment != null) {
|
||||
creature.addAttachment(equipment.getId(), source, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ class BrilliantUltimatumEffect extends OneShotEffect {
|
|||
Player opponent = game.getPlayer(targetOpponent.getFirstTarget());
|
||||
if (opponent != null) {
|
||||
TargetCard target = new TargetCard(0, pile2.size(), Zone.EXILED, new FilterCard("cards to put in the first pile"));
|
||||
target.setRequired(false);
|
||||
Cards pile1 = new CardsImpl();
|
||||
List<Card> pileOne = new ArrayList<>();
|
||||
List<Card> pileTwo = new ArrayList<>();
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ class CreditVoucherEffect extends OneShotEffect {
|
|||
if (controller != null && sourceObject != null) {
|
||||
FilterCard filter = new FilterCard("card in your hand to shuffle away");
|
||||
TargetCardInHand target = new TargetCardInHand(0, controller.getHand().size(), filter);
|
||||
target.setRequired(false);
|
||||
int amountShuffled = 0;
|
||||
if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ class DoOrDieEffect extends OneShotEffect {
|
|||
filter.add(new ControllerIdPredicate(targetPlayer.getId()));
|
||||
TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true);
|
||||
List<Permanent> pile1 = new ArrayList<>();
|
||||
creatures.setRequired(false);
|
||||
if (player.choose(Outcome.Neutral, creatures, source, game)) {
|
||||
List<UUID> targets = creatures.getTargets();
|
||||
for (UUID targetId : targets) {
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ class FightOrFlightEffect extends OneShotEffect {
|
|||
filter.add(new ControllerIdPredicate(targetPlayer.getId()));
|
||||
TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true);
|
||||
List<Permanent> pile1 = new ArrayList<>();
|
||||
creatures.setRequired(false);
|
||||
if (player.choose(Outcome.Neutral, creatures, source, game)) {
|
||||
List<UUID> targets = creatures.getTargets();
|
||||
for (UUID targetId : targets) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.cards.g;
|
||||
|
||||
import mage.MageInt;
|
||||
|
|
@ -76,8 +75,7 @@ class GenesisHydraPutOntoBattlefieldEffect extends OneShotEffect {
|
|||
FilterCard filter = new FilterPermanentCard("a nonland permanent card with mana value " + count + " or less to put onto the battlefield");
|
||||
filter.add(Predicates.not(CardType.LAND.getPredicate()));
|
||||
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, count + 1));
|
||||
TargetCard target1 = new TargetCard(Zone.LIBRARY, filter);
|
||||
target1.setRequired(false);
|
||||
TargetCard target1 = new TargetCard(0, 1, Zone.LIBRARY, filter);
|
||||
if (cards.count(filter, source.getSourceId(), source, game) > 0) {
|
||||
if (controller.choose(Outcome.PutCardInPlay, cards, target1, source, game)) {
|
||||
Card card = cards.get(target1.getFirstTarget(), game);
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ class KnickknackOuphePutOntoBattlefieldEffect extends OneShotEffect {
|
|||
|
||||
if (cards.count(filter, controller.getId(), source, game) > 0) {
|
||||
TargetCard targetAuras = new TargetCard(0, count, Zone.LIBRARY, filter);
|
||||
targetAuras.setRequired(false);
|
||||
|
||||
if (controller.choose(Outcome.PutCardInPlay, cards, targetAuras, source, game)) {
|
||||
targetAuras.getTargets().stream().forEach(t -> {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ class LilianaOfTheVeilEffect extends OneShotEffect {
|
|||
filter.add(new ControllerIdPredicate(targetPlayer.getId()));
|
||||
TargetPermanent target = new TargetPermanent(0, count, filter, true);
|
||||
List<Permanent> pile1 = new ArrayList<>();
|
||||
target.setRequired(false);
|
||||
if (player.choose(Outcome.Neutral, target, source, game)) {
|
||||
List<UUID> targets = target.getTargets();
|
||||
for (UUID targetId : targets) {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ class MercadianLiftEffect extends OneShotEffect {
|
|||
if (target.canChoose(controller.getId(), source, game)
|
||||
&& controller.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game)
|
||||
&& controller.choose(Outcome.PutCardInPlay, target, source, game)) {
|
||||
target.setRequired(false);
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
return controller.moveCards(card, Zone.BATTLEFIELD, source, game);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import mage.abilities.effects.common.InfoEffect;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.filter.common.FilterCreatureSpell;
|
||||
import mage.game.permanent.token.KithkinSoldierToken;
|
||||
import mage.target.TargetSpell;
|
||||
|
|
@ -24,15 +23,13 @@ public final class RepelIntruders extends CardImpl {
|
|||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W/U}");
|
||||
|
||||
// Create two 1/1 white Kithkin Soldier creature tokens if {W} was spent to cast Repel Intruders. Counter up to one target creature spell if {U} was spent to cast Repel Intruders.
|
||||
TargetSpell target = new TargetSpell(0, 1, new FilterCreatureSpell());
|
||||
target.setRequired(false);
|
||||
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
|
||||
new CreateTokenEffect(new KithkinSoldierToken(), 2),
|
||||
ManaWasSpentCondition.WHITE, "Create two 1/1 white Kithkin Soldier creature tokens if {W} was spent to cast this spell"));
|
||||
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
|
||||
new CounterTargetEffect(),
|
||||
ManaWasSpentCondition.BLUE, "Counter up to one target creature spell if {U} was spent to cast this spell"));
|
||||
this.getSpellAbility().addTarget(target);
|
||||
this.getSpellAbility().addTarget(new TargetSpell(0, 1, new FilterCreatureSpell()));
|
||||
this.getSpellAbility().addEffect(new InfoEffect("<i>(Do both if {W}{U} was spent.)</i>"));
|
||||
|
||||
}
|
||||
|
|
@ -46,4 +43,3 @@ public final class RepelIntruders extends CardImpl {
|
|||
return new RepelIntruders(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,8 +74,7 @@ class ReversalOfFortuneEffect extends OneShotEffect {
|
|||
opponent.revealCards("Reveal", revealedCards, game);
|
||||
|
||||
//You may copy an instant or sorcery card in it
|
||||
TargetCard target = new TargetCard(1, Zone.HAND, new FilterInstantOrSorceryCard());
|
||||
target.setRequired(false);
|
||||
TargetCard target = new TargetCard(0, 1, Zone.HAND, new FilterInstantOrSorceryCard());
|
||||
if (controller.choose(Outcome.PlayForFree, revealedCards, target, source, game)) {
|
||||
Card card = revealedCards.get(target.getFirstTarget(), game);
|
||||
//If you do, you may cast the copy without paying its mana cost
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ class ScrollRackEffect extends OneShotEffect {
|
|||
if (controller != null && sourceObject != null) {
|
||||
FilterCard filter = new FilterCard("card in your hand to exile");
|
||||
TargetCardInHand target = new TargetCardInHand(0, controller.getHand().size(), filter);
|
||||
target.setRequired(false);
|
||||
int amountExiled = 0;
|
||||
if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -76,9 +76,8 @@ class SpectersShriekEffect extends OneShotEffect {
|
|||
+ player.getName() + "'s hand?", source, game)) {
|
||||
return false;
|
||||
}
|
||||
TargetCard target = new TargetCard(Zone.HAND, new FilterNonlandCard());
|
||||
TargetCard target = new TargetCard(0, 1, Zone.HAND, new FilterNonlandCard());
|
||||
target.withNotTarget(true);
|
||||
target.setRequired(false);
|
||||
if (!controller.chooseTarget(Outcome.Benefit, player.getHand(), target, source, game)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ class StandOrFallEffect extends OneShotEffect {
|
|||
FilterCreaturePermanent opponentFilter = new FilterCreaturePermanent();
|
||||
opponentFilter.add(new ControllerIdPredicate(oppId));
|
||||
TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, Integer.MAX_VALUE, opponentFilter, true);
|
||||
creatures.setRequired(false);
|
||||
List<Permanent> pile1 = new ArrayList<>();
|
||||
if (player.choose(Outcome.Neutral, creatures, source, game)) {
|
||||
List<UUID> targets = creatures.getTargets();
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ class TruthOrTaleEffect extends OneShotEffect {
|
|||
if (opponent != null) {
|
||||
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile"));
|
||||
List<Card> pile1 = new ArrayList<>();
|
||||
target.setRequired(false);
|
||||
if (controller.choose(Outcome.Neutral, cards, target, source, game)) {
|
||||
List<UUID> targets = target.getTargets();
|
||||
for (UUID targetId : targets) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.cards.v;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -76,8 +75,7 @@ class VendilionCliqueEffect extends OneShotEffect {
|
|||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (player != null && controller != null && sourceObject != null) {
|
||||
TargetCard targetCard = new TargetCard(Zone.ALL, new FilterNonlandCard());
|
||||
targetCard.setRequired(false);
|
||||
TargetCard targetCard = new TargetCard(0, 1, Zone.ALL, new FilterNonlandCard());
|
||||
if (controller.choose(Outcome.Discard, player.getHand(), targetCard, source, game)) {
|
||||
Card card = game.getCard(targetCard.getFirstTarget());
|
||||
if (card != null) {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ class WhimsOfTheFateEffect extends OneShotEffect {
|
|||
} else {
|
||||
target = new TargetSecondPilePermanent(playerPiles.get(1), filter);
|
||||
}
|
||||
target.setRequired(false);
|
||||
currentPlayer.chooseTarget(outcome, target, source, game);
|
||||
StringBuilder message = new StringBuilder(currentPlayer.getLogName()).append(" pile ").append(i).append(": ");
|
||||
if (target.getTargets().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ public abstract class TargetImpl implements Target {
|
|||
}
|
||||
} else {
|
||||
// Try to autochoosen
|
||||
UUID autoChosenId = required ? tryToAutoChoose(playerId, source, game) : null;
|
||||
UUID autoChosenId = tryToAutoChoose(playerId, source, game);
|
||||
if (autoChosenId != null) {
|
||||
addTarget(autoChosenId, source, game);
|
||||
} else if (!targetController.chooseTarget(outcome, this, source, game)) { // If couldn't autochoose ask player
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue