diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index d9cd63777e9..bbf603a4ac3 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -1147,7 +1147,7 @@ public class CardView extends SimpleCardView { // from normal targets for (Target target : targets) { - if (target.isChosen()) { + if (target.isChosen(game)) { newTargets.addAll(target.getTargets()); } } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index ba0bc4f1432..b2d6069bba0 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -34,7 +34,6 @@ import mage.target.Targets; import mage.util.RandomUtil; import org.apache.log4j.Logger; -import java.io.File; import java.util.*; import java.util.concurrent.*; import java.util.stream.Collectors; @@ -392,7 +391,7 @@ public class ComputerPlayer6 extends ComputerPlayer { if (effect != null && stackObject.getControllerId().equals(playerId)) { Target target = effect.getTarget(); - if (!target.doneChoosing()) { + if (!target.doneChoosing(game)) { for (UUID targetId : target.possibleTargets(stackObject.getControllerId(), stackObject.getStackAbility(), game)) { Game sim = game.createSimulationForAI(); StackAbility newAbility = (StackAbility) stackObject.copy(); @@ -740,10 +739,10 @@ public class ComputerPlayer6 extends ComputerPlayer { if (targets.isEmpty()) { return super.chooseTarget(outcome, cards, target, source, game); } - if (!target.doneChoosing()) { + if (!target.doneChoosing(game)) { for (UUID targetId : targets) { target.addTarget(targetId, source, game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { targets.clear(); return true; } @@ -758,10 +757,10 @@ public class ComputerPlayer6 extends ComputerPlayer { if (targets.isEmpty()) { return super.choose(outcome, cards, target, source, game); } - if (!target.doneChoosing()) { + if (!target.doneChoosing(game)) { for (UUID targetId : targets) { target.add(targetId, game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { targets.clear(); return true; } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java index f059ae68de6..071455a5a82 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java @@ -10,7 +10,6 @@ import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.Effect; -import mage.cards.Card; import mage.game.Game; import mage.game.combat.Combat; import mage.game.events.GameEvent; @@ -149,7 +148,7 @@ public final class SimulatedPlayer2 extends ComputerPlayer { } newAbility.adjustTargets(game); // add the different possible target option for the specific X value - if (!newAbility.getTargets().getUnchosen().isEmpty()) { + if (!newAbility.getTargets().getUnchosen(game).isEmpty()) { addTargetOptions(options, newAbility, targetNum, game); } } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 78fc8df8671..f37e48f06f5 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -174,7 +174,7 @@ public class ComputerPlayer extends PlayerImpl { for (int i = unplayable.size() - 1; i >= 0; i--) { if (target.canTarget(abilityControllerId, unplayable.values().toArray(new Card[0])[i].getId(), null, game)) { target.add(unplayable.values().toArray(new Card[0])[i].getId(), game); - if (target.isChosen()) { + if (target.isChosen(game)) { return true; } } @@ -184,7 +184,7 @@ public class ComputerPlayer extends PlayerImpl { for (int i = 0; i < hand.size(); i++) { if (target.canTarget(abilityControllerId, hand.toArray(new UUID[0])[i], null, game)) { target.add(hand.toArray(new UUID[0])[i], game); - if (target.isChosen()) { + if (target.isChosen(game)) { return true; } } @@ -252,12 +252,12 @@ public class ComputerPlayer extends PlayerImpl { } // add the target target.add(permanent.getId(), game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { return true; } } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetCardInHand @@ -269,7 +269,7 @@ public class ComputerPlayer extends PlayerImpl { cards.add(card); } } - while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen()) + while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen(game)) && !cards.isEmpty()) { Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game); if (pick != null) { @@ -277,7 +277,7 @@ public class ComputerPlayer extends PlayerImpl { cards.remove(pick); } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetAnyTarget) { @@ -410,7 +410,7 @@ public class ComputerPlayer extends PlayerImpl { // exile cost workaround: exile is bad, but exile from graveyard in most cases is good (more exiled -- more good things you get, e.g. delve's pay) boolean isRealGood = outcome.isGood() || outcome == Outcome.Exile; - while ((isRealGood ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen()) + while ((isRealGood ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen(game)) && !cards.isEmpty()) { Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game); if (pick != null) { @@ -421,7 +421,7 @@ public class ComputerPlayer extends PlayerImpl { } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetCardInGraveyard @@ -437,7 +437,7 @@ public class ComputerPlayer extends PlayerImpl { // exile cost workaround: exile is bad, but exile from graveyard in most cases is good (more exiled -- more good things you get, e.g. delve's pay) boolean isRealGood = outcome.isGood() || outcome == Outcome.Exile; - while ((isRealGood ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen()) + while ((isRealGood ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen(game)) && !cards.isEmpty()) { Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game); if (pick != null) { @@ -448,7 +448,7 @@ public class ComputerPlayer extends PlayerImpl { } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard @@ -460,7 +460,7 @@ public class ComputerPlayer extends PlayerImpl { Card card = pickTarget(abilityControllerId, cards, outcome, target, null, game); if (card != null && alreadyTargeted != null && !alreadyTargeted.contains(card.getId())) { target.add(card.getId(), game); - if (target.isChosen()) { + if (target.isChosen(game)) { return true; } } @@ -485,7 +485,7 @@ public class ComputerPlayer extends PlayerImpl { Card card = pickTarget(abilityControllerId, cards, outcome, target, null, game); if (card != null && alreadyTargeted != null && !alreadyTargeted.contains(card.getId())) { target.add(card.getId(), game); - if (target.isChosen()) { + if (target.isChosen(game)) { return true; } } @@ -517,14 +517,14 @@ public class ComputerPlayer extends PlayerImpl { if (target.getOriginalTarget() instanceof TargetPermanentOrSuspendedCard) { Cards cards = new CardsImpl(possibleTargets); List possibleCards = new ArrayList<>(cards.getCards(game)); - while (!target.isChosen() && !possibleCards.isEmpty()) { + while (!target.isChosen(game) && !possibleCards.isEmpty()) { Card pick = pickTarget(abilityControllerId, possibleCards, outcome, target, null, game); if (pick != null) { target.addTarget(pick.getId(), null, game); possibleCards.remove(pick); } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetCard @@ -537,14 +537,14 @@ public class ComputerPlayer extends PlayerImpl { } } } - while (!target.isChosen() && !cardsInCommandZone.isEmpty()) { + while (!target.isChosen(game) && !cardsInCommandZone.isEmpty()) { Card pick = pickTarget(abilityControllerId, cardsInCommandZone, outcome, target, null, game); if (pick != null) { target.addTarget(pick.getId(), null, game); cardsInCommandZone.remove(pick); } } - return target.isChosen(); + return target.isChosen(game); } throw new IllegalStateException("Target wasn't handled in computer's choose method: " + target.getClass().getCanonicalName()); @@ -641,7 +641,7 @@ public class ComputerPlayer extends PlayerImpl { } } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetDiscard @@ -650,7 +650,7 @@ public class ComputerPlayer extends PlayerImpl { // good Cards cards = new CardsImpl(possibleTargets); List cardsInHand = new ArrayList<>(cards.getCards(game)); - while (!target.isChosen() + while (!target.isChosen(game) && !cardsInHand.isEmpty() && target.getMaxNumberOfTargets() > target.getTargets().size()) { Card card = pickBestCard(cardsInHand, null, target, source, game); @@ -658,7 +658,7 @@ public class ComputerPlayer extends PlayerImpl { if (target.canTarget(abilityControllerId, card.getId(), source, game)) { target.addTarget(card.getId(), source, game); cardsInHand.remove(card); - if (target.isChosen()) { + if (target.isChosen(game)) { return true; } } @@ -671,7 +671,7 @@ public class ComputerPlayer extends PlayerImpl { if (possibleTargets.contains(card.getId()) && target.canTarget(abilityControllerId, card.getId(), source, game)) { target.addTarget(card.getId(), source, game); - if (target.isChosen()) { + if (target.isChosen(game)) { return true; } } @@ -681,7 +681,7 @@ public class ComputerPlayer extends PlayerImpl { if (possibleTargets.contains(card.getId()) && target.canTarget(abilityControllerId, card.getId(), source, game)) { target.addTarget(card.getId(), source, game); - if (target.isChosen()) { + if (target.isChosen(game)) { return true; } } @@ -707,7 +707,7 @@ public class ComputerPlayer extends PlayerImpl { } } } - return target.isChosen(); + return target.isChosen(game); } @@ -749,7 +749,7 @@ public class ComputerPlayer extends PlayerImpl { target.addTarget(permanent.getId(), source, game); } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) { @@ -956,14 +956,14 @@ public class ComputerPlayer extends PlayerImpl { if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard) { List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards((FilterCard) target.getFilter(), game)); - while (!target.isChosen() && !cards.isEmpty()) { + while (!target.isChosen(game) && !cards.isEmpty()) { Card card = pickTarget(abilityControllerId, cards, outcome, target, source, game); if (card != null) { target.addTarget(card.getId(), source, game); cards.remove(card); // pickTarget don't remove cards (only on second+ tries) } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetSpell @@ -1034,7 +1034,7 @@ public class ComputerPlayer extends PlayerImpl { if (target.getOriginalTarget() instanceof TargetDefender) { UUID randomDefender = RandomUtil.randomFromCollection(possibleTargets); target.addTarget(randomDefender, source, game); - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) { @@ -1042,14 +1042,14 @@ public class ComputerPlayer extends PlayerImpl { for (Player player : game.getPlayers().values()) { cards.addAll(player.getGraveyard().getCards(game)); } - while (!target.isChosen() && !cards.isEmpty()) { + while (!target.isChosen(game) && !cards.isEmpty()) { Card pick = pickTarget(abilityControllerId, cards, outcome, target, source, game); if (pick != null) { target.addTarget(pick.getId(), source, game); cards.remove(pick); // pickTarget don't remove cards (only on second+ tries) } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetCardInExile) { @@ -1070,14 +1070,14 @@ public class ComputerPlayer extends PlayerImpl { cards.add(card); } } - while (!target.isChosen() && !cards.isEmpty()) { + while (!target.isChosen(game) && !cards.isEmpty()) { Card pick = pickTarget(abilityControllerId, cards, outcome, target, source, game); if (pick != null) { target.addTarget(pick.getId(), source, game); cards.remove(pick); // pickTarget don't remove cards (only on second+ tries) } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetActivatedAbility) { @@ -1088,22 +1088,22 @@ public class ComputerPlayer extends PlayerImpl { stackObjects.add(stackObject); } } - while (!target.isChosen() && !stackObjects.isEmpty()) { + while (!target.isChosen(game) && !stackObjects.isEmpty()) { StackObject pick = stackObjects.get(0); if (pick != null) { target.addTarget(pick.getId(), source, game); stackObjects.remove(0); } } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetActivatedOrTriggeredAbility) { Iterator iterator = target.possibleTargets(source.getControllerId(), source, game).iterator(); - while (!target.isChosen() && iterator.hasNext()) { + while (!target.isChosen(game) && iterator.hasNext()) { target.addTarget(iterator.next(), source, game); } - return target.isChosen(); + return target.isChosen(game); } if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) { @@ -1121,14 +1121,14 @@ public class ComputerPlayer extends PlayerImpl { if (target.getOriginalTarget() instanceof TargetPermanentOrSuspendedCard) { Cards cards = new CardsImpl(possibleTargets); List possibleCards = new ArrayList<>(cards.getCards(game)); - while (!target.isChosen() && !possibleCards.isEmpty()) { + while (!target.isChosen(game) && !possibleCards.isEmpty()) { Card pick = pickTarget(abilityControllerId, possibleCards, outcome, target, source, game); if (pick != null) { target.addTarget(pick.getId(), source, game); possibleCards.remove(pick); } } - return target.isChosen(); + return target.isChosen(game); } throw new IllegalStateException("Target wasn't handled in computer's chooseTarget method: " + target.getClass().getCanonicalName()); @@ -2063,7 +2063,7 @@ public class ComputerPlayer extends PlayerImpl { // we still use playerId when getting cards even if they don't control the search List cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), playerId, source, game)); - while (!target.doneChoosing()) { + while (!target.doneChoosing(game)) { Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, source, game); if (card != null) { target.addTarget(card.getId(), source, game); @@ -2094,7 +2094,7 @@ public class ComputerPlayer extends PlayerImpl { } List cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), abilityControllerId, source, game)); - while (!target.doneChoosing()) { + while (!target.doneChoosing(game)) { Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, source, game); if (card != null) { target.add(card.getId(), game); diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 2dd6a504907..cc3d60a9fa7 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -674,7 +674,7 @@ public class HumanPlayer extends PlayerImpl { prepareForResponse(game); if (!isExecutingMacro()) { - game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), possibleTargetIds, required, getOptions(target, options)); + game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(game), getRelatedObjectName(source, game)), possibleTargetIds, required, getOptions(target, options)); } waitForResponse(game); responseId = getFixedResponseUUID(game); @@ -696,7 +696,7 @@ public class HumanPlayer extends PlayerImpl { if (target instanceof TargetPermanent) { if (((TargetPermanent) target).canTarget(abilityControllerId, responseId, source, game, false)) { target.add(responseId, game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { return true; } } @@ -708,7 +708,7 @@ public class HumanPlayer extends PlayerImpl { target.remove(responseId); } else { target.addTarget(responseId, (Ability) object, game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { return true; } } @@ -718,7 +718,7 @@ public class HumanPlayer extends PlayerImpl { target.remove(responseId); } else { target.addTarget(responseId, null, game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { return true; } } @@ -775,7 +775,7 @@ public class HumanPlayer extends PlayerImpl { prepareForResponse(game); if (!isExecutingMacro()) { - game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), + game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(game), getRelatedObjectName(source, game)), possibleTargetIds, required, getOptions(target, options)); } waitForResponse(game); @@ -792,7 +792,7 @@ public class HumanPlayer extends PlayerImpl { if (possibleTargetIds.contains(responseId)) { if (target.canTarget(abilityControllerId, responseId, source, game)) { target.addTarget(responseId, source, game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { return true; } } @@ -873,7 +873,7 @@ public class HumanPlayer extends PlayerImpl { prepareForResponse(game); if (!isExecutingMacro()) { - game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage()), cards, required, options); + game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage(game)), cards, required, options); } waitForResponse(game); @@ -886,7 +886,7 @@ public class HumanPlayer extends PlayerImpl { } else { if (target.canTarget(abilityControllerId, responseId, source, cards, game)) { target.add(responseId, game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { return true; } } @@ -956,7 +956,7 @@ public class HumanPlayer extends PlayerImpl { prepareForResponse(game); if (!isExecutingMacro()) { - game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), cards, required, options); + game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage(game), getRelatedObjectName(source, game)), cards, required, options); } waitForResponse(game); @@ -968,7 +968,7 @@ public class HumanPlayer extends PlayerImpl { target.remove(responseId); } else if (target.canTarget(abilityControllerId, responseId, source, cards, game)) { target.addTarget(responseId, source, game); - if (target.doneChoosing()) { + if (target.doneChoosing(game)) { return true; } } @@ -1051,7 +1051,7 @@ public class HumanPlayer extends PlayerImpl { prepareForResponse(game); if (!isExecutingMacro()) { String multiType = multiAmountType == MultiAmountType.DAMAGE ? " to divide %d damage" : " to distribute %d counters"; - String message = target.getMessage() + String.format(multiType, amountTotal); + String message = target.getMessage(game) + String.format(multiType, amountTotal); game.fireSelectTargetEvent(playerId, new MessageToClient(message, getRelatedObjectName(source, game)), possibleTargetIds, required, options); } waitForResponse(game); diff --git a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java index 3d82c25bfd4..4b922159db5 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java @@ -115,7 +115,7 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); if (target.canChoose(controller.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { + while (!target.isChosen(game) && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } else { diff --git a/Mage.Sets/src/mage/cards/b/BurningOfXinye.java b/Mage.Sets/src/mage/cards/b/BurningOfXinye.java index d0c1ff41a4c..a81caec204d 100644 --- a/Mage.Sets/src/mage/cards/b/BurningOfXinye.java +++ b/Mage.Sets/src/mage/cards/b/BurningOfXinye.java @@ -1,6 +1,5 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageAllEffect; @@ -17,14 +16,15 @@ import mage.target.Target; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author Plopman */ public final class BurningOfXinye extends CardImpl { public BurningOfXinye(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); // You destroy four lands you control, then target opponent destroys four lands they control. Then Burning of Xinye deals 4 damage to each creature. @@ -44,16 +44,16 @@ public final class BurningOfXinye extends CardImpl { } -class BurningOfXinyeEffect extends OneShotEffect{ +class BurningOfXinyeEffect extends OneShotEffect { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); - private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); - BurningOfXinyeEffect() { super(Outcome.DestroyPermanent); staticText = "You destroy four lands you control, then target opponent destroys four lands they control"; } - public BurningOfXinyeEffect ( BurningOfXinyeEffect effect ) { + private BurningOfXinyeEffect(final BurningOfXinyeEffect effect) { super(effect); } @@ -73,16 +73,16 @@ class BurningOfXinyeEffect extends OneShotEffect{ return abilityApplied; } - - private boolean playerDestroys(Game game, Ability source, Player player){ + + private boolean playerDestroys(Game game, Ability source, Player player) { boolean abilityApplied = false; - + int realCount = game.getBattlefield().countAll(filter, player.getId(), game); int amount = Math.min(4, realCount); Target target = new TargetControlledPermanent(amount, amount, filter, true); if (amount > 0 && target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.choose(Outcome.DestroyPermanent, target, source, game); } diff --git a/Mage.Sets/src/mage/cards/c/CallousOppressor.java b/Mage.Sets/src/mage/cards/c/CallousOppressor.java index 2c20592dc9b..19cb217790d 100644 --- a/Mage.Sets/src/mage/cards/c/CallousOppressor.java +++ b/Mage.Sets/src/mage/cards/c/CallousOppressor.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -17,11 +16,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.Choice; import mage.choices.ChoiceCreatureType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -30,8 +25,9 @@ import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author L_J */ public final class CallousOppressor extends CardImpl { @@ -118,7 +114,7 @@ class CallousOppressorChooseCreatureTypeEffect extends OneShotEffect { if (controller != null) { TargetOpponent target = new TargetOpponent(true); if (target.canChoose(controller.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { + while (!target.isChosen(game) && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } else { diff --git a/Mage.Sets/src/mage/cards/c/Cataclysm.java b/Mage.Sets/src/mage/cards/c/Cataclysm.java index 804ad573a2e..b63db3a06cb 100644 --- a/Mage.Sets/src/mage/cards/c/Cataclysm.java +++ b/Mage.Sets/src/mage/cards/c/Cataclysm.java @@ -1,9 +1,6 @@ package mage.cards.c; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -21,14 +18,17 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetControlledPermanent; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class Cataclysm extends CardImpl { public Cataclysm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); // Each player chooses from the permanents they control an artifact, a creature, an enchantment, and a land, then sacrifices the rest. this.getSpellAbility().addEffect(new CataclysmEffect()); @@ -68,7 +68,7 @@ class CataclysmEffect extends OneShotEffect { Target target4 = new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent(), true); if (target1.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target1.isChosen(game) && target1.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target1, source, game); } Permanent artifact = game.getPermanent(target1.getFirstTarget()); @@ -79,7 +79,7 @@ class CataclysmEffect extends OneShotEffect { } if (target2.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target2.isChosen() && target2.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target2.isChosen(game) && target2.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target2, source, game); } Permanent creature = game.getPermanent(target2.getFirstTarget()); @@ -90,7 +90,7 @@ class CataclysmEffect extends OneShotEffect { } if (target3.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target3.isChosen() && target3.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target3.isChosen(game) && target3.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target3, source, game); } Permanent enchantment = game.getPermanent(target3.getFirstTarget()); @@ -99,9 +99,9 @@ class CataclysmEffect extends OneShotEffect { } target3.clearChosen(); } - + if (target4.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target4.isChosen() && target4.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target4.isChosen(game) && target4.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target4, source, game); } Permanent land = game.getPermanent(target4.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/CataclysmicGearhulk.java b/Mage.Sets/src/mage/cards/c/CataclysmicGearhulk.java index ab83abee0d5..c4eb8159726 100644 --- a/Mage.Sets/src/mage/cards/c/CataclysmicGearhulk.java +++ b/Mage.Sets/src/mage/cards/c/CataclysmicGearhulk.java @@ -101,7 +101,7 @@ class CataclysmicGearhulkEffect extends OneShotEffect { Target target4 = new TargetControlledPermanent(1, 1, filterPlaneswalker, true); if (target1.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target1.isChosen(game) && target1.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target1, source, game); } Permanent artifact = game.getPermanent(target1.getFirstTarget()); @@ -112,7 +112,7 @@ class CataclysmicGearhulkEffect extends OneShotEffect { } if (target2.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target2.isChosen() && target2.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target2.isChosen(game) && target2.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target2, source, game); } Permanent creature = game.getPermanent(target2.getFirstTarget()); @@ -123,7 +123,7 @@ class CataclysmicGearhulkEffect extends OneShotEffect { } if (target3.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target3.isChosen() && target3.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target3.isChosen(game) && target3.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target3, source, game); } Permanent enchantment = game.getPermanent(target3.getFirstTarget()); @@ -134,7 +134,7 @@ class CataclysmicGearhulkEffect extends OneShotEffect { } if (target4.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target4.isChosen() && target4.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target4.isChosen(game) && target4.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target4, source, game); } Permanent planeswalker = game.getPermanent(target4.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/CatchRelease.java b/Mage.Sets/src/mage/cards/c/CatchRelease.java index 827078d62ee..1881c23d991 100644 --- a/Mage.Sets/src/mage/cards/c/CatchRelease.java +++ b/Mage.Sets/src/mage/cards/c/CatchRelease.java @@ -1,9 +1,6 @@ package mage.cards.c; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -26,6 +23,10 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + public final class CatchRelease extends SplitCard { public CatchRelease(UUID ownerId, CardSetInfo setInfo) { @@ -87,7 +88,7 @@ class ReleaseSacrificeEffect extends OneShotEffect { Target target5 = new TargetControlledPermanent(1, 1, new FilterControlledPlaneswalkerPermanent(), true); if (target1.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target1.isChosen(game) && target1.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target1, source, game); } Permanent artifact = game.getPermanent(target1.getFirstTarget()); @@ -98,7 +99,7 @@ class ReleaseSacrificeEffect extends OneShotEffect { } if (target2.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target2.isChosen() && target2.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target2.isChosen(game) && target2.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target2, source, game); } Permanent creature = game.getPermanent(target2.getFirstTarget()); @@ -109,7 +110,7 @@ class ReleaseSacrificeEffect extends OneShotEffect { } if (target3.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target3.isChosen() && target3.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target3.isChosen(game) && target3.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target3, source, game); } Permanent enchantment = game.getPermanent(target3.getFirstTarget()); @@ -120,7 +121,7 @@ class ReleaseSacrificeEffect extends OneShotEffect { } if (target4.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target4.isChosen() && target4.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target4.isChosen(game) && target4.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target4, source, game); } Permanent land = game.getPermanent(target4.getFirstTarget()); @@ -131,7 +132,7 @@ class ReleaseSacrificeEffect extends OneShotEffect { } if (target5.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target5.isChosen() && target5.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target5.isChosen(game) && target5.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target5, source, game); } Permanent planeswalker = game.getPermanent(target5.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/Clambassadors.java b/Mage.Sets/src/mage/cards/c/Clambassadors.java index f1246de0c94..afbd79a8000 100644 --- a/Mage.Sets/src/mage/cards/c/Clambassadors.java +++ b/Mage.Sets/src/mage/cards/c/Clambassadors.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; @@ -10,7 +9,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.game.Game; @@ -20,8 +22,9 @@ import mage.target.Target; import mage.target.common.TargetControlledPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author L_J */ public final class Clambassadors extends CardImpl { @@ -82,7 +85,7 @@ class ClambassadorsEffect extends OneShotEffect { if (controller != null) { Target target = new TargetControlledPermanent(1, 1, filter, true); if (target.canChoose(controller.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { + while (!target.isChosen(game) && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java b/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java index f285f671c90..1e20dc95ac1 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java @@ -19,19 +19,16 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetSacrifice; import java.util.Objects; import java.util.UUID; /** - * * @author anonymous */ public final class CurseOfTheCabal extends CardImpl { @@ -87,7 +84,7 @@ class CurseOfTheCabalSacrificeEffect extends OneShotEffect { } Target target = new TargetSacrifice(amount, StaticFilters.FILTER_CONTROLLED_PERMANENT); if (target.canChoose(targetPlayer.getId(), source, game)) { - while (!target.isChosen() + while (!target.isChosen(game) && target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) { targetPlayer.choose(Outcome.Sacrifice, target, source, game); } @@ -107,9 +104,9 @@ class CurseOfTheCabalInterveningIfTriggeredAbility extends ConditionalIntervenin public CurseOfTheCabalInterveningIfTriggeredAbility() { super(new BeginningOfUpkeepTriggeredAbility( - Zone.EXILED, new CurseOfTheCabalTriggeredAbilityConditionalDelay(), - TargetController.ANY, false, true - ), + Zone.EXILED, new CurseOfTheCabalTriggeredAbilityConditionalDelay(), + TargetController.ANY, false, true + ), SuspendedCondition.instance, "At the beginning of each player's upkeep, if {this} is suspended, " + "that player may sacrifice a permanent. If the player does, " diff --git a/Mage.Sets/src/mage/cards/d/DevourFlesh.java b/Mage.Sets/src/mage/cards/d/DevourFlesh.java index 750c575f8c7..103e65e2f0d 100644 --- a/Mage.Sets/src/mage/cards/d/DevourFlesh.java +++ b/Mage.Sets/src/mage/cards/d/DevourFlesh.java @@ -18,7 +18,6 @@ import mage.target.common.TargetSacrifice; import java.util.UUID; /** - * * @author LevelX2 */ public final class DevourFlesh extends CardImpl { @@ -65,7 +64,7 @@ class DevourFleshSacrificeEffect extends OneShotEffect { } if (game.getBattlefield().count(TargetSacrifice.makeFilter(StaticFilters.FILTER_PERMANENT_CREATURE), player.getId(), source, game) > 0) { Target target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE); - while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target.isChosen(game) && target.canChoose(player.getId(), source, game)) { player.choose(Outcome.Sacrifice, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/d/DivineReckoning.java b/Mage.Sets/src/mage/cards/d/DivineReckoning.java index 6a1760124c5..b16bfdbc3eb 100644 --- a/Mage.Sets/src/mage/cards/d/DivineReckoning.java +++ b/Mage.Sets/src/mage/cards/d/DivineReckoning.java @@ -1,10 +1,6 @@ package mage.cards.d; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -22,6 +18,10 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetControlledPermanent; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** * @author nantuko */ @@ -68,7 +68,7 @@ class DivineReckoningEffect extends OneShotEffect { if (player != null) { Target target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true); if (target.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target.isChosen(game) && target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/d/DrainPower.java b/Mage.Sets/src/mage/cards/d/DrainPower.java index d9d2c88c386..6a5b4ae07ac 100644 --- a/Mage.Sets/src/mage/cards/d/DrainPower.java +++ b/Mage.Sets/src/mage/cards/d/DrainPower.java @@ -108,7 +108,7 @@ class DrainPowerEffect extends OneShotEffect { FilterLandPermanent filter2 = new FilterLandPermanent("land you control to tap for mana (remaining: " + permList.size() + ')'); filter2.add(new PermanentReferenceInCollectionPredicate(permList, game)); target = new TargetPermanent(1, 1, filter2, true); - while (!target.isChosen() && target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) { + while (!target.isChosen(game) && target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) { targetPlayer.chooseTarget(Outcome.Neutral, target, source, game); } permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java b/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java index bb2ab0da234..87f020ada89 100644 --- a/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java +++ b/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java @@ -20,7 +20,6 @@ import mage.target.common.TargetSacrifice; import java.util.UUID; /** - * * @author fireshoes */ public final class EntrapmentManeuver extends CardImpl { @@ -67,7 +66,7 @@ class EntrapmentManeuverSacrificeEffect extends OneShotEffect { } if (game.getBattlefield().count(TargetSacrifice.makeFilter(StaticFilters.FILTER_ATTACKING_CREATURE), player.getId(), source, game) > 0) { Target target = new TargetSacrifice(StaticFilters.FILTER_ATTACKING_CREATURE); - while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target.isChosen(game) && target.canChoose(player.getId(), source, game)) { player.choose(Outcome.Sacrifice, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java b/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java index 9b34f51698a..ff4e69d2012 100644 --- a/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java +++ b/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java @@ -68,7 +68,7 @@ class EunuchsIntriguesEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(player.getId())); Target target = new TargetPermanent(1, 1, filter, true); if (target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.DestroyPermanent, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/f/FabricationFoundry.java b/Mage.Sets/src/mage/cards/f/FabricationFoundry.java index 51048566128..c04a7bc62e0 100644 --- a/Mage.Sets/src/mage/cards/f/FabricationFoundry.java +++ b/Mage.Sets/src/mage/cards/f/FabricationFoundry.java @@ -33,7 +33,6 @@ import java.util.Objects; import java.util.UUID; /** - * * @author notgreat */ public final class FabricationFoundry extends CardImpl { @@ -96,6 +95,7 @@ enum ArtifactSpellOrActivatedAbilityCondition implements Condition { return object != null && object.isArtifact(game) && !source.isActivated(); } } + //Cost based on Kozilek, The Great Distortion and CrewAbility class ExileTargetsTotalManaValueCost extends CostImpl { private static final FilterPermanent filter = new FilterControlledArtifactPermanent("one or more other artifacts you control with total mana value X"); @@ -103,6 +103,7 @@ class ExileTargetsTotalManaValueCost extends CostImpl { static { filter.add(AnotherPredicate.instance); } + public ExileTargetsTotalManaValueCost() { this.text = "Exile one or more other artifacts you control with total mana value X"; } @@ -123,9 +124,9 @@ class ExileTargetsTotalManaValueCost extends CostImpl { } int minX = abilityTarget.getManaValue(); int sum = 0; - Target target = new TargetPermanent(1, Integer.MAX_VALUE, filter, true){ + Target target = new TargetPermanent(1, Integer.MAX_VALUE, filter, true) { @Override - public String getMessage() { + public String getMessage(Game game) { // shows selected mana value int selectedPower = this.targets.keySet().stream() .map(game::getPermanent) @@ -136,10 +137,10 @@ class ExileTargetsTotalManaValueCost extends CostImpl { if (selectedPower >= minX) { extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN); } - return super.getMessage() + " " + extraInfo; + return super.getMessage(game) + " " + extraInfo; } }; - if (!target.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)){ + if (!target.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) { return paid; } Cards cards = new CardsImpl(); @@ -152,7 +153,7 @@ class ExileTargetsTotalManaValueCost extends CostImpl { } paid = (sum >= minX); if (paid) { - player.moveCardsToExile(cards.getCards(game), source, game, false,null,null); + player.moveCardsToExile(cards.getCards(game), source, game, false, null, null); } return paid; } @@ -161,12 +162,12 @@ class ExileTargetsTotalManaValueCost extends CostImpl { public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { int totalExileMV = 0; boolean anyExileFound = false; - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controllerId, source, game)){ + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controllerId, source, game)) { totalExileMV += permanent.getManaValue(); anyExileFound = true; } int minTargetMV = Integer.MAX_VALUE; - for (Card card : game.getPlayer(controllerId).getGraveyard().getCards(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD, game)){ + for (Card card : game.getPlayer(controllerId).getGraveyard().getCards(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD, game)) { minTargetMV = Integer.min(minTargetMV, card.getManaValue()); } return anyExileFound && totalExileMV >= minTargetMV; diff --git a/Mage.Sets/src/mage/cards/f/FalseOrders.java b/Mage.Sets/src/mage/cards/f/FalseOrders.java index 587edda9082..cd722afb7dc 100644 --- a/Mage.Sets/src/mage/cards/f/FalseOrders.java +++ b/Mage.Sets/src/mage/cards/f/FalseOrders.java @@ -129,7 +129,7 @@ class FalseOrdersUnblockEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); if (target.canChoose(controller.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { + while (!target.isChosen(game) && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } else { diff --git a/Mage.Sets/src/mage/cards/f/Fireball.java b/Mage.Sets/src/mage/cards/f/Fireball.java index db7580636dd..620514ae30e 100644 --- a/Mage.Sets/src/mage/cards/f/Fireball.java +++ b/Mage.Sets/src/mage/cards/f/Fireball.java @@ -143,9 +143,9 @@ class FireballTargetCreatureOrPlayer extends TargetAnyTarget { chosen = true; } - if (!target.isChosen()) { + if (!target.isChosen(game)) { Iterator it2 = possibleTargets.iterator(); - while (it2.hasNext() && !target.isChosen()) { + while (it2.hasNext() && !target.isChosen(game)) { UUID nextTargetId = it2.next(); target.addTarget(nextTargetId, source, game, true); @@ -155,7 +155,7 @@ class FireballTargetCreatureOrPlayer extends TargetAnyTarget { } } - if (target.isChosen()) { + if (target.isChosen(game)) { options.add(target); } } diff --git a/Mage.Sets/src/mage/cards/g/GoblinFestival.java b/Mage.Sets/src/mage/cards/g/GoblinFestival.java index 867d480e63f..c084aa9b76f 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinFestival.java +++ b/Mage.Sets/src/mage/cards/g/GoblinFestival.java @@ -1,9 +1,7 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffect; @@ -21,14 +19,15 @@ import mage.target.common.TargetAnyTarget; import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author L_J */ public final class GoblinFestival extends CardImpl { public GoblinFestival(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); // {2}: Goblin Festival deals 1 damage to any target. Flip a coin. If you lose the flip, choose one of your opponents. That player gains control of Goblin Festival. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl<>("{2}")); @@ -72,7 +71,7 @@ class GoblinFestivalChangeControlEffect extends OneShotEffect { if (sourcePermanent != null) { Target target = new TargetOpponent(true); if (target.canChoose(controller.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { + while (!target.isChosen(game) && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } diff --git a/Mage.Sets/src/mage/cards/g/GoblinWarCry.java b/Mage.Sets/src/mage/cards/g/GoblinWarCry.java index 8d56b9ea651..243edcf07cc 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinWarCry.java +++ b/Mage.Sets/src/mage/cards/g/GoblinWarCry.java @@ -68,7 +68,7 @@ class GoblinWarCryEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(player.getId())); Target target = new TargetPermanent(1, 1, filter, true); if (target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.DestroyPermanent, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/i/ImperialEdict.java b/Mage.Sets/src/mage/cards/i/ImperialEdict.java index 45fa9c6570d..4749cf35661 100644 --- a/Mage.Sets/src/mage/cards/i/ImperialEdict.java +++ b/Mage.Sets/src/mage/cards/i/ImperialEdict.java @@ -1,7 +1,6 @@ package mage.cards.i; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -17,8 +16,9 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ImperialEdict extends CardImpl { @@ -67,7 +67,7 @@ class ImperialEdictEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(player.getId())); Target target = new TargetPermanent(1, 1, filter, true); if (target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.DestroyPermanent, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/j/JalumGrifter.java b/Mage.Sets/src/mage/cards/j/JalumGrifter.java index d73209e7e9d..ca3ab81af94 100644 --- a/Mage.Sets/src/mage/cards/j/JalumGrifter.java +++ b/Mage.Sets/src/mage/cards/j/JalumGrifter.java @@ -1,10 +1,6 @@ package mage.cards.j; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -15,11 +11,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; @@ -31,14 +23,18 @@ import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetOpponent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + /** - * * @author L_J */ public final class JalumGrifter extends CardImpl { public JalumGrifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.DEVIL); this.power = new MageInt(3); @@ -80,7 +76,7 @@ class JalumGrifterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - + Player controller = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(source.getTargets().get(0).getFirstTarget()); if (controller != null && opponent != null) { @@ -92,15 +88,15 @@ class JalumGrifterEffect extends OneShotEffect { shellGamePile.add(sourceCard); game.informPlayers(controller.getLogName() + " turns " + sourceCard.getLogName() + " face down"); } - + Target target = new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent(), true); if (target.canChoose(controller.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { + while (!target.isChosen(game) && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } - - for (UUID cardId: target.getTargets()) { + + for (UUID cardId : target.getTargets()) { Card card = game.getCard(cardId); if (card != null) { card = card.copy(); diff --git a/Mage.Sets/src/mage/cards/l/LegateLaniusCaesarsAce.java b/Mage.Sets/src/mage/cards/l/LegateLaniusCaesarsAce.java index 8d833a5ddf2..51e9c7640b9 100644 --- a/Mage.Sets/src/mage/cards/l/LegateLaniusCaesarsAce.java +++ b/Mage.Sets/src/mage/cards/l/LegateLaniusCaesarsAce.java @@ -91,7 +91,7 @@ class LegateLaniusCaesarsAceSacrificeEffect extends OneShotEffect { continue; } TargetSacrifice target = new TargetSacrifice(numTargets, filter); - while (!target.isChosen() && target.canChoose(playerId, source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(playerId, source, game) && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source, game); } perms.addAll(target.getTargets()); diff --git a/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java b/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java index fe5dceb3b7d..6bb6b9a7ca4 100644 --- a/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java +++ b/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java @@ -1,8 +1,5 @@ package mage.cards.l; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -11,11 +8,7 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; +import mage.constants.*; import mage.filter.FilterPlayer; import mage.filter.predicate.Predicates; import mage.filter.predicate.other.PlayerIdPredicate; @@ -25,16 +18,19 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.target.targetpointer.FixedTarget; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author L_J */ public final class LoxodonPeacekeeper extends CardImpl { public LoxodonPeacekeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.ELEPHANT); - this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.SOLDIER); this.power = new MageInt(4); this.toughness = new MageInt(4); @@ -93,7 +89,7 @@ class LoxodonPeacekeeperEffect extends OneShotEffect { } } } - + if (!tiedPlayers.isEmpty()) { UUID newControllerId = null; if (tiedPlayers.size() > 1) { @@ -105,7 +101,7 @@ class LoxodonPeacekeeperEffect extends OneShotEffect { } TargetPlayer target = new TargetPlayer(1, 1, true, filter); if (target.canChoose(controller.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { + while (!target.isChosen(game) && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } else { diff --git a/Mage.Sets/src/mage/cards/l/LunarHatchling.java b/Mage.Sets/src/mage/cards/l/LunarHatchling.java index 6b17638e061..871f9af2876 100644 --- a/Mage.Sets/src/mage/cards/l/LunarHatchling.java +++ b/Mage.Sets/src/mage/cards/l/LunarHatchling.java @@ -43,7 +43,7 @@ public final class LunarHatchling extends CardImpl { // Escape-{4}{G}{U}, Exile a land you control, Exile five other cards from your graveyard. CostsImpl additionalCost = new CostsImpl(); additionalCost.add(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_A_LAND))); - this.addAbility(new EscapeAbility(this, "{4}{G}{U}", 5, additionalCost)); + this.addAbility(new EscapeAbility(this, "{4}{G}{U}", additionalCost, 5)); } private LunarHatchling(final LunarHatchling card) { diff --git a/Mage.Sets/src/mage/cards/n/Nethergoyf.java b/Mage.Sets/src/mage/cards/n/Nethergoyf.java new file mode 100644 index 00000000000..5b71e4679bb --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/Nethergoyf.java @@ -0,0 +1,128 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessPlusOneSourceEffect; +import mage.abilities.hint.HintUtils; +import mage.abilities.keyword.EscapeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.awt.*; +import java.util.Collection; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author Susucr + */ +public final class Nethergoyf extends CardImpl { + + private static final DynamicValue powerValue = CardTypesInGraveyardCount.YOU; + + public Nethergoyf(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.LHURGOYF); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // Nethergoyf's power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessPlusOneSourceEffect(powerValue))); + + // Escape--{2}{B}, Exile any number of other cards from your graveyard with four or more card types among them. + CostsImpl additionalCost = new CostsImpl(); + additionalCost.add(new ExileFromGraveCost( + new NethergoyfTarget(), + "exile any number of other cards from your graveyard with four or more card types among them") + ); + this.addAbility(new EscapeAbility(this, "{2}{B}", additionalCost)); + } + + private Nethergoyf(final Nethergoyf card) { + super(card); + } + + @Override + public Nethergoyf copy() { + return new Nethergoyf(this); + } +} + +class NethergoyfTarget extends TargetCardInYourGraveyard { + + private static final FilterCard filter = new FilterCard("other cards from your graveyard with four or more card types among them"); + + static { + filter.add(AnotherPredicate.instance); + } + + NethergoyfTarget() { + super(1, Integer.MAX_VALUE, filter, true); + } + + private NethergoyfTarget(final NethergoyfTarget target) { + super(target); + } + + @Override + public NethergoyfTarget copy() { + return new NethergoyfTarget(this); + } + + @Override + public boolean isChosen(Game game) { + return super.isChosen(game) && metCondition(this.getTargets(), game); + } + + @Override + public String getMessage(Game game) { + String text = "Select " + CardUtil.addArticle(targetName); + Set types = typesAmongSelection(this.getTargets(), game); + text += " (selected " + this.getTargets().size() + " cards; card types: "; + text += HintUtils.prepareText( + types.size() + " of 4", + types.size() >= 4 ? Color.GREEN : Color.RED + ); + text += " [" + types.stream().map(CardType::toString).collect(Collectors.joining(", ")) + "])"; + return text; + } + + @Override + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + if (!super.canChoose(sourceControllerId, source, game)) { + return false; + } + // Check that exiling all the possible cards would have >= 4 different card types + return metCondition(this.possibleTargets(sourceControllerId, source, game), game); + } + + private static Set typesAmongSelection(Collection cardsIds, Game game) { + return cardsIds + .stream() + .map(game::getCard) + .filter(Objects::nonNull) + .flatMap(c -> c.getCardType(game).stream()) + .collect(Collectors.toSet()); + } + + private static boolean metCondition(Collection cardsIds, Game game) { + return typesAmongSelection(cardsIds, game).size() >= 4; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NotOfThisWorld.java b/Mage.Sets/src/mage/cards/n/NotOfThisWorld.java index a9bb1965ebe..ed520d023d0 100644 --- a/Mage.Sets/src/mage/cards/n/NotOfThisWorld.java +++ b/Mage.Sets/src/mage/cards/n/NotOfThisWorld.java @@ -70,7 +70,7 @@ enum NotOfThisWorldCondition implements Condition { @Override public boolean apply(Game game, Ability source) { StackObject sourceSpell = game.getStack().getStackObject(source.getSourceId()); - if (sourceSpell == null || !sourceSpell.getStackAbility().getTargets().isChosen()) { + if (sourceSpell == null || !sourceSpell.getStackAbility().getTargets().isChosen(game)) { return false; } StackObject objectToCounter = game.getStack().getStackObject(sourceSpell.getStackAbility().getTargets().getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/p/Plaguecrafter.java b/Mage.Sets/src/mage/cards/p/Plaguecrafter.java index 2a2db8f7acf..77fc9965d6a 100644 --- a/Mage.Sets/src/mage/cards/p/Plaguecrafter.java +++ b/Mage.Sets/src/mage/cards/p/Plaguecrafter.java @@ -12,12 +12,9 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetSacrifice; import mage.target.targetpointer.FixedTarget; @@ -88,7 +85,7 @@ class PlaguecrafterEffect extends OneShotEffect { } TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER); if (target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && player.canRespond()) { + while (!target.isChosen(game) && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source, game); } perms.addAll(target.getTargets()); diff --git a/Mage.Sets/src/mage/cards/r/RaziasPurification.java b/Mage.Sets/src/mage/cards/r/RaziasPurification.java index 681b9f70b4b..0e3f2372137 100644 --- a/Mage.Sets/src/mage/cards/r/RaziasPurification.java +++ b/Mage.Sets/src/mage/cards/r/RaziasPurification.java @@ -1,9 +1,6 @@ package mage.cards.r; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -18,8 +15,11 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetControlledPermanent; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author spjspj */ public final class RaziasPurification extends CardImpl { @@ -63,7 +63,7 @@ class RaziasPurificationEffect extends OneShotEffect { if (player != null && target1.canChoose(player.getId(), source, game)) { int chosenPermanents = 0; - while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), source, game) && chosenPermanents < 3) { + while (player.canRespond() && !target1.isChosen(game) && target1.canChoose(player.getId(), source, game) && chosenPermanents < 3) { player.chooseTarget(Outcome.Benefit, target1, source, game); for (UUID targetId : target1.getTargets()) { Permanent p = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/cards/r/ReignOfThePit.java b/Mage.Sets/src/mage/cards/r/ReignOfThePit.java index 943df3ae447..f7151bd5721 100644 --- a/Mage.Sets/src/mage/cards/r/ReignOfThePit.java +++ b/Mage.Sets/src/mage/cards/r/ReignOfThePit.java @@ -69,7 +69,7 @@ class ReignOfThePitEffect extends OneShotEffect { if (player != null) { TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE); if (target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && player.canRespond()) { + while (!target.isChosen(game) && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source, game); } perms.addAll(target.getTargets()); diff --git a/Mage.Sets/src/mage/cards/r/RiskyMove.java b/Mage.Sets/src/mage/cards/r/RiskyMove.java index 641e989da14..09c22f682df 100644 --- a/Mage.Sets/src/mage/cards/r/RiskyMove.java +++ b/Mage.Sets/src/mage/cards/r/RiskyMove.java @@ -147,14 +147,14 @@ class RiskyMoveFlipCoinEffect extends OneShotEffect { Target target2 = new TargetOpponent(true); if (target1.canChoose(controller.getId(), source, game)) { - while (!target1.isChosen() + while (!target1.isChosen(game) && target1.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target1, source, game); } } if (target2.canChoose(controller.getId(), source, game)) { - while (!target2.isChosen() + while (!target2.isChosen(game) && target2.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target2, source, game); diff --git a/Mage.Sets/src/mage/cards/r/Rupture.java b/Mage.Sets/src/mage/cards/r/Rupture.java index da43d281a8d..c322b10d4e2 100644 --- a/Mage.Sets/src/mage/cards/r/Rupture.java +++ b/Mage.Sets/src/mage/cards/r/Rupture.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageEverythingEffect; @@ -11,24 +10,23 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetSacrifice; +import java.util.UUID; + /** - * * @author L_J */ public final class Rupture extends CardImpl { public Rupture(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); // Sacrifice a creature. Rupture deals damage equal to that creature's power to each creature without flying and each player. this.getSpellAbility().addEffect(new RuptureEffect()); @@ -68,7 +66,7 @@ class RuptureEffect extends OneShotEffect { int power = 0; TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE); if (target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/s/Smokestack.java b/Mage.Sets/src/mage/cards/s/Smokestack.java index 50d172d4249..9ad0312232a 100644 --- a/Mage.Sets/src/mage/cards/s/Smokestack.java +++ b/Mage.Sets/src/mage/cards/s/Smokestack.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -13,16 +12,14 @@ import mage.constants.Outcome; import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetSacrifice; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Smokestack extends CardImpl { @@ -75,7 +72,7 @@ class SmokestackEffect extends OneShotEffect { //A spell or ability could have removed the only legal target this player //had, if thats the case this ability should fizzle. if (target.canChoose(activePlayer.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(activePlayer.getId(), source, game) && activePlayer.canRespond()) { + while (!target.isChosen(game) && target.canChoose(activePlayer.getId(), source, game) && activePlayer.canRespond()) { activePlayer.choose(Outcome.Sacrifice, target, source, game); } diff --git a/Mage.Sets/src/mage/cards/s/SpyNetwork.java b/Mage.Sets/src/mage/cards/s/SpyNetwork.java index ba690b666fd..53703b76e27 100644 --- a/Mage.Sets/src/mage/cards/s/SpyNetwork.java +++ b/Mage.Sets/src/mage/cards/s/SpyNetwork.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -22,8 +21,9 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author L_J */ public final class SpyNetwork extends CardImpl { @@ -109,7 +109,7 @@ class SpyNetworkFaceDownEffect extends OneShotEffect { if (target.canChoose(controller.getId(), source, game)) { while (controller.chooseUse(outcome, "Look at a face down creature controlled by " + player.getLogName() + "?", source, game)) { target.clearChosen(); - while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { + while (!target.isChosen(game) && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } Permanent faceDownCreature = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/s/SunkenHope.java b/Mage.Sets/src/mage/cards/s/SunkenHope.java index d0b88ed6ed0..edeee56b2fa 100644 --- a/Mage.Sets/src/mage/cards/s/SunkenHope.java +++ b/Mage.Sets/src/mage/cards/s/SunkenHope.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -16,8 +15,9 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SunkenHope extends CardImpl { @@ -66,7 +66,7 @@ class SunkenHopeReturnToHandEffect extends OneShotEffect { Target target = new TargetControlledCreaturePermanent().withNotTarget(true); if (target.canChoose(player.getId(), source, game)) { - while (player.canRespond() && !target.isChosen() + while (player.canRespond() && !target.isChosen(game) && target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.ReturnToHand, target, source, game); } diff --git a/Mage.Sets/src/mage/cards/t/TheFirstEruption.java b/Mage.Sets/src/mage/cards/t/TheFirstEruption.java index 789a9be3b63..4c5b0fb0806 100644 --- a/Mage.Sets/src/mage/cards/t/TheFirstEruption.java +++ b/Mage.Sets/src/mage/cards/t/TheFirstEruption.java @@ -1,20 +1,19 @@ package mage.cards.t; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.keyword.FlyingAbility; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SagaChapter; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; @@ -24,11 +23,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetSacrifice; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class TheFirstEruption extends CardImpl { @@ -101,7 +100,7 @@ class TheFirstEruptionEffect extends OneShotEffect { Target target = new TargetSacrifice(filter); boolean sacrificed = false; if (target.canChoose(controller.getId(), source, game)) { - while (controller.canRespond() && !target.isChosen() && target.canChoose(controller.getId(), source, game)) { + while (controller.canRespond() && !target.isChosen(game) && target.canChoose(controller.getId(), source, game)) { controller.choose(Outcome.Sacrifice, target, source, game); } diff --git a/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java b/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java index ef298ac5997..19abcd3c94e 100644 --- a/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java +++ b/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java @@ -443,7 +443,7 @@ class UrzaAcademyHeadmasterRandomEffect extends OneShotEffect { } source.addTarget(target); } - if (target == null || target.isChosen()) { + if (target == null || target.isChosen(game)) { for (Effect effect : effects) { if (effect instanceof ContinuousEffect) { game.addEffect((ContinuousEffect) effect, source); diff --git a/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java b/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java index fe4ab8aad6e..0e62215d50b 100644 --- a/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java +++ b/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java @@ -134,7 +134,7 @@ class VodalianWarMachineWatcher extends Watcher { for (Cost cost : ability.getCosts()) { if (cost instanceof TapTargetCost && cost.isPaid()) { TapTargetCost tapCost = (TapTargetCost) cost; - if (tapCost.getTarget().isChosen()) { + if (tapCost.getTarget().isChosen(game)) { MageObjectReference mor = new MageObjectReference(sourcePermanent.getId(), sourcePermanent.getZoneChangeCounter(game), game); Set toAdd; if (tappedMerfolkIds.get(mor) == null) { diff --git a/Mage.Sets/src/mage/cards/v/VoraciousFellBeast.java b/Mage.Sets/src/mage/cards/v/VoraciousFellBeast.java index d608b9b44e1..c1e25aa83b8 100644 --- a/Mage.Sets/src/mage/cards/v/VoraciousFellBeast.java +++ b/Mage.Sets/src/mage/cards/v/VoraciousFellBeast.java @@ -10,15 +10,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.SetTargetPointer; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.FoodToken; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetSacrifice; import java.util.ArrayList; @@ -26,14 +23,13 @@ import java.util.List; import java.util.UUID; /** - * * @author Susucr */ public final class VoraciousFellBeast extends CardImpl { public VoraciousFellBeast(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); - + this.subtype.add(SubType.DRAKE); this.subtype.add(SubType.BEAST); this.power = new MageInt(4); @@ -63,7 +59,7 @@ class VoraciousFellBeastEffect extends OneShotEffect { VoraciousFellBeastEffect() { super(Outcome.Sacrifice); this.staticText = "each opponent sacrifices a creature. " + - "Create a Food token for each creature sacrificed this way"; + "Create a Food token for each creature sacrificed this way"; } private VoraciousFellBeastEffect(final VoraciousFellBeastEffect effect) { @@ -91,7 +87,7 @@ class VoraciousFellBeastEffect extends OneShotEffect { TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE); if (target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && player.canRespond()) { + while (!target.isChosen(game) && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source, game); } perms.addAll(target.getTargets()); diff --git a/Mage.Sets/src/mage/cards/w/WeiAssassins.java b/Mage.Sets/src/mage/cards/w/WeiAssassins.java index b238226b6b1..d99f62b01a9 100644 --- a/Mage.Sets/src/mage/cards/w/WeiAssassins.java +++ b/Mage.Sets/src/mage/cards/w/WeiAssassins.java @@ -1,16 +1,15 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; @@ -20,8 +19,9 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class WeiAssassins extends CardImpl { @@ -77,7 +77,7 @@ class WeiAssassinsEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(player.getId())); Target target = new TargetPermanent(1, 1, filter, true); if (target.canChoose(player.getId(), source, game)) { - while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.DestroyPermanent, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/w/WorldQueller.java b/Mage.Sets/src/mage/cards/w/WorldQueller.java index 8e04aee4cbf..38240821f0b 100644 --- a/Mage.Sets/src/mage/cards/w/WorldQueller.java +++ b/Mage.Sets/src/mage/cards/w/WorldQueller.java @@ -18,8 +18,6 @@ import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetSacrifice; import java.util.*; @@ -119,7 +117,7 @@ class WorldQuellerEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player2 = game.getPlayer(playerId); if (player2 != null && target.canChoose(playerId, source, game)) { - while (player2.canRespond() && !target.isChosen() && target.canChoose(playerId, source, game)) { + while (player2.canRespond() && !target.isChosen(game) && target.canChoose(playerId, source, game)) { player2.choose(Outcome.Sacrifice, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/ModernHorizons3.java b/Mage.Sets/src/mage/sets/ModernHorizons3.java index 59e2d3c6f15..a397fd2c763 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons3.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons3.java @@ -42,6 +42,7 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Laelia, the Blade Reforged", 281, Rarity.RARE, mage.cards.l.LaeliaTheBladeReforged.class)); cards.add(new SetCardInfo("Meltdown", 282, Rarity.UNCOMMON, mage.cards.m.Meltdown.class)); cards.add(new SetCardInfo("Mountain", 307, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Nethergoyf", 103, Rarity.MYTHIC, mage.cards.n.Nethergoyf.class)); cards.add(new SetCardInfo("Null Elemental Blast", 12, Rarity.UNCOMMON, mage.cards.n.NullElementalBlast.class)); cards.add(new SetCardInfo("Nulldrifter", 13, Rarity.RARE, mage.cards.n.Nulldrifter.class)); cards.add(new SetCardInfo("Orim's Chant", 265, Rarity.RARE, mage.cards.o.OrimsChant.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/NethergoyfTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/NethergoyfTest.java new file mode 100644 index 00000000000..8d2db6405d7 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/NethergoyfTest.java @@ -0,0 +1,193 @@ +package org.mage.test.cards.single.mh3; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; + +/** + * @author Susucr + */ +public class NethergoyfTest extends CardTestPlayerBaseWithAIHelps { + + /** + * {@link mage.cards.n.Nethergoyf Nethergoyf} {B} + * Creature — Lhurgoyf + * Nethergoyf’s power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1. + * Escape—{2}{B}, Exile any number of other cards from your graveyard with four or more card types among them. (You may cast this card from your graveyard for its escape cost.) + * * / 1+* + */ + private static final String nethergoyf = "Nethergoyf"; + + @Test + public void test_Escape_Two_DualTypes() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, nethergoyf); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.GRAVEYARD, playerA, "Memnite"); // Creature Artifact + addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment + + checkPlayableAbility("can escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nethergoyf + " with Escape"); + setChoice(playerA, "Memnite^Bitterblossom"); // cards exiled for escape cost + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, nethergoyf, 1); + assertPowerToughness(playerA, nethergoyf, 0, 1); + assertExileCount(playerA, 2); + } + + @Test + public void test_AI_Escape_Two_DualTypes() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, nethergoyf); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.GRAVEYARD, playerA, "Memnite"); // Creature Artifact + addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment + + checkPlayableAbility("can escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", true); + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, nethergoyf, 1); + assertPowerToughness(playerA, nethergoyf, 0, 1); + assertExileCount(playerA, 2); + } + + @Test + public void test_Escape_MoreCardsThanNeeded() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, nethergoyf); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.GRAVEYARD, playerA, "Memnite", 5); // Creature Artifact + addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment + + checkPlayableAbility("can escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nethergoyf + " with Escape"); + setChoice(playerA, "Memnite^Memnite^Memnite^Memnite^Bitterblossom"); // cards exiled for escape cost: Exile all the Memnite but one. + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, nethergoyf, 1); + assertPowerToughness(playerA, nethergoyf, 2, 3); // 1 Memnite in graveyard + assertExileCount(playerA, 5); + assertGraveyardCount(playerA, 1); + } + + @Test + public void test_AI_Escape_MoreCardsThanNeeded() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, nethergoyf); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment + addCard(Zone.GRAVEYARD, playerA, "Memnite", 5); // Creature Artifact + + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, nethergoyf, 1); + assertPowerToughness(playerA, nethergoyf, 0, 1); + assertExileCount(playerA, 6); // It is weird, but AI likes to choose all to be exiled, even though the Outcome is Exile (so detriment) + assertGraveyardCount(playerA, 0); + } + + + @Test + public void test_CantEscape_Without4TypesInGraveyard() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, nethergoyf); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.GRAVEYARD, playerA, "Taiga"); // Land + addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment + + checkPlayableAbility("can't escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", false); + // 3 types from other cards in graveyard, Nethergoyf can't escape + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, 3); + } + + @Test + public void test_AI_CantEscape_Without4TypesInGraveyard() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, nethergoyf); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.GRAVEYARD, playerA, "Taiga"); // Land + addCard(Zone.GRAVEYARD, playerA, "Bitterblossom"); // Tribal Enchantment + + checkPlayableAbility("can't escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", false); + // 3 types from other cards in graveyard, Nethergoyf can't escape + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, 3); + } + + @Test + public void test_DynamicGameType() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, nethergoyf); + addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 7); + addCard(Zone.GRAVEYARD, playerA, "Taiga"); // Land + addCard(Zone.GRAVEYARD, playerA, "Grist, the Hunger Tide"); // Planeswalker, is a Creature if not in play + // Nonland permanents you control are artifacts in addition to their other types. + // The same is true for permanent spells you control and nonland permanent cards you own that aren’t on the battlefield. + addCard(Zone.HAND, playerA, "Encroaching Mycosynth"); + + checkPlayableAbility("1: can't escape", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", false); + // 3 types from other cards in graveyard, Nethergoyf can't escape + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Encroaching Mycosynth", true); + // After Mycosynth in play, Grist is now an Artifact in addition to its other types + checkPlayableAbility("2: can", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nethergoyf + " with Escape", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nethergoyf + " with Escape"); + setChoice(playerA, "Taiga^Grist, the Hunger Tide"); // cards exiled for escape cost + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, nethergoyf, 1); + assertPowerToughness(playerA, nethergoyf, 0, 1); + assertExileCount(playerA, 2); + } + + @Test + public void test_AI_DynamicGameType() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, nethergoyf); + addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 7); + addCard(Zone.GRAVEYARD, playerA, "Taiga"); // Land + addCard(Zone.GRAVEYARD, playerA, "Grist, the Hunger Tide"); // Planeswalker, is a Creature if not in play + + // Nonland permanents you control are artifacts in addition to their other types. + // The same is true for permanent spells you control and nonland permanent cards you own that aren’t on the battlefield. + addCard(Zone.HAND, playerA, "Encroaching Mycosynth"); + + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, nethergoyf, 1); + assertPowerToughness(playerA, nethergoyf, 0, 1); + assertExileCount(playerA, 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 3ffb6a13a3d..132de48c496 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -2001,8 +2001,8 @@ public class TestPlayer implements Player { return "Ability: null"; } - private String getInfo(Target o) { - return "Target: " + (o != null ? o.getClass().getSimpleName() + ": " + o.getMessage() : "null"); + private String getInfo(Target o, Game game) { + return "Target: " + (o != null ? o.getClass().getSimpleName() + ": " + o.getMessage(game) : "null"); } private void assertAliasSupportInChoices(boolean methodSupportAliases) { @@ -2167,7 +2167,7 @@ public class TestPlayer implements Player { } // ignore player select - if (target.getMessage().equals("Select a starting player")) { + if (target.getMessage(game).equals("Select a starting player")) { return computerPlayer.choose(outcome, target, source, game, options); } @@ -2317,7 +2317,7 @@ public class TestPlayer implements Player { // apply only on ALL targets or revert if (usedChoices.size() > 0) { - if (target.isChosen()) { + if (target.isChosen(game)) { // remove all used choices for (int i = choices.size(); i >= 0; i--) { if (usedChoices.contains(i)) { @@ -2369,7 +2369,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target)); + this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target, game)); return computerPlayer.choose(outcome, target, source, game, options); } @@ -2690,19 +2690,19 @@ public class TestPlayer implements Player { message = this.getName() + " - Targets list was setup by addTarget with " + targets + ", but not used" + "\nCard: " + source.getSourceObject(game) + "\nAbility: " + source.getClass().getSimpleName() + " (" + source.getRule() + ")" - + "\nTarget: " + target.getClass().getSimpleName() + " (" + target.getMessage() + ")" + + "\nTarget: " + target.getClass().getSimpleName() + " (" + target.getMessage(game) + ")" + "\nYou must implement target class support in TestPlayer, \"filter instanceof\", or setup good targets"; } else { message = this.getName() + " - Targets list was setup by addTarget with " + targets + ", but not used" + "\nCard: unknown source" + "\nAbility: unknown source" - + "\nTarget: " + target.getClass().getSimpleName() + " (" + target.getMessage() + ")" + + "\nTarget: " + target.getClass().getSimpleName() + " (" + target.getMessage(game) + ")" + "\nYou must implement target class support in TestPlayer, \"filter instanceof\", or setup good targets"; } Assert.fail(message); } - this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target)); + this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, game)); return computerPlayer.chooseTarget(outcome, target, source, game); } @@ -2748,7 +2748,7 @@ public class TestPlayer implements Player { LOGGER.warn("Wrong target"); } - this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target)); + this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, game)); return computerPlayer.chooseTarget(outcome, cards, target, source, game); } @@ -4134,7 +4134,7 @@ public class TestPlayer implements Player { assertWrongChoiceUsage(choices.size() > 0 ? choices.get(0) : "empty list"); } - this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target)); + this.chooseStrictModeFailed("choice", game, getInfo(source, game) + "\n" + getInfo(target, game)); return computerPlayer.choose(outcome, cards, target, source, game); } @@ -4207,7 +4207,7 @@ public class TestPlayer implements Player { } } - this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target)); + this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target, game)); return computerPlayer.chooseTargetAmount(outcome, target, source, game); } diff --git a/Mage/src/main/java/mage/abilities/costs/common/CollectEvidenceCost.java b/Mage/src/main/java/mage/abilities/costs/common/CollectEvidenceCost.java index 363bf5c1605..f061d48e90e 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/CollectEvidenceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/CollectEvidenceCost.java @@ -67,7 +67,7 @@ public class CollectEvidenceCost extends CostImpl { // TODO: require target to have minimum selected total mana value (requires refactor) Target target = new TargetCardInYourGraveyard(1, Integer.MAX_VALUE) { @Override - public String getMessage() { + public String getMessage(Game game) { // shows selected mana value int totalMV = this .getTargets() @@ -76,7 +76,7 @@ public class CollectEvidenceCost extends CostImpl { .filter(Objects::nonNull) .mapToInt(MageObject::getManaValue) .sum(); - return super.getMessage() + HintUtils.prepareText( + return super.getMessage(game) + HintUtils.prepareText( " (selected mana value " + totalMV + " of " + amount + ")", totalMV >= amount ? Color.GREEN : Color.RED ); diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java index 0c194f32ed1..c71f98d225b 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java @@ -31,7 +31,7 @@ public class ExileTargetCost extends CostImpl { this.text = "exile " + target.getDescription(); } - public ExileTargetCost(ExileTargetCost cost) { + protected ExileTargetCost(ExileTargetCost cost) { super(cost); for (Permanent permanent : cost.permanents) { this.permanents.add(permanent.copy()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java index b0378d78153..175c683f1e9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java @@ -75,7 +75,7 @@ public class RollPlanarDieEffect extends OneShotEffect { } boolean done = false; while (controller.canRespond() && effect != null && !done) { - if (target != null && !target.isChosen() && target.canChoose(controller.getId(), source, game)) { + if (target != null && !target.isChosen(game) && target.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Benefit, target, source, game); source.addTarget(target); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeAllEffect.java index 02eaf42c17d..99c0bc6cfad 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeAllEffect.java @@ -27,6 +27,7 @@ public class SacrificeAllEffect extends OneShotEffect { /** * Each player sacrifices a permanent + * * @param filter can be generic, will automatically add article and necessary sacrifice predicates */ public SacrificeAllEffect(FilterPermanent filter) { @@ -35,6 +36,7 @@ public class SacrificeAllEffect extends OneShotEffect { /** * Each player sacrifices N permanents + * * @param filter can be generic, will automatically add necessary sacrifice predicates */ public SacrificeAllEffect(int amount, FilterPermanent filter) { @@ -43,6 +45,7 @@ public class SacrificeAllEffect extends OneShotEffect { /** * Each player sacrifices X permanents + * * @param filter can be generic, will automatically add necessary sacrifice predicates */ public SacrificeAllEffect(DynamicValue amount, FilterPermanent filter) { @@ -91,7 +94,7 @@ public class SacrificeAllEffect extends OneShotEffect { continue; } TargetSacrifice target = new TargetSacrifice(numTargets, filter); - while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source, game); } perms.addAll(target.getTargets()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java index 2a0367c9edf..32577d03b00 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java @@ -64,7 +64,7 @@ public class SacrificeEffect extends OneShotEffect { continue; } TargetSacrifice target = new TargetSacrifice(amount, filter); - while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + while (!target.isChosen(game) && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source, game); } for (UUID targetId : target.getTargets()) { diff --git a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java index 04967f90f02..a715e5d05c2 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java @@ -151,7 +151,7 @@ class CrewCost extends CostImpl { } Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) { @Override - public String getMessage() { + public String getMessage(Game game) { // shows selected power int selectedPower = this.targets.keySet().stream() .map(game::getPermanent) @@ -162,7 +162,7 @@ class CrewCost extends CostImpl { if (selectedPower >= value) { extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN); } - return super.getMessage() + " " + extraInfo; + return super.getMessage(game) + " " + extraInfo; } }; diff --git a/Mage/src/main/java/mage/abilities/keyword/EscapeAbility.java b/Mage/src/main/java/mage/abilities/keyword/EscapeAbility.java index d46f4b5c4e4..840779b1936 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EscapeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EscapeAbility.java @@ -32,10 +32,14 @@ public class EscapeAbility extends SpellAbility { private final String staticText; public EscapeAbility(Card card, String manaCost, int exileCount) { - this(card, manaCost, exileCount, new CostsImpl<>()); + this(card, manaCost, new CostsImpl<>(), exileCount); } - public EscapeAbility(Card card, String manaCost, int exileCount, Costs additionalCosts) { + public EscapeAbility(Card card, String manaCost, Costs additionalCost) { + this(card, manaCost, additionalCost, 0); + } + + public EscapeAbility(Card card, String manaCost, Costs additionalCosts, int exileCount) { super(card.getSpellAbility()); this.newId(); this.setCardName(card.getName() + " with Escape"); @@ -45,17 +49,22 @@ public class EscapeAbility extends SpellAbility { this.clearManaCosts(); this.clearManaCostsToPay(); - String text = "Escape—" + manaCost; this.addCost(new ManaCostsImpl<>(manaCost)); for (Cost cost : additionalCosts) { - text += ", " + CardUtil.getTextWithFirstCharUpperCase(cost.getText()); this.addCost(cost.copy().setText("")); // hide additional cost text from rules } + if (exileCount > 0) { + this.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(exileCount, filter), "")); // hide additional cost text from rules + } - text += ", Exile " + CardUtil.numberToText(exileCount) + " other cards from your graveyard." - + " (You may cast this card from your graveyard for its escape cost.)"; - this.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(exileCount, filter), "")); // hide additional cost text from rules - + String text = "Escape—" + manaCost; + for (Cost cost : additionalCosts) { + text += ", " + CardUtil.getTextWithFirstCharUpperCase(cost.getText()); + } + if (exileCount > 0) { + text += ", Exile " + CardUtil.numberToText(exileCount) + " other cards from your graveyard"; + } + text += ". (You may cast this card from your graveyard for its escape cost.)"; this.staticText = text; } diff --git a/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java b/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java index cd7ac510f7f..a4e5a792c7a 100644 --- a/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java @@ -177,7 +177,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl { && player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + '?', source, game)) { Target target = new TargetSacrifice(filter); player.choose(Outcome.Sacrifice, target, source, game); - if (!target.isChosen()) { + if (!target.isChosen(game)) { return false; } game.getState().setValue("offering_" + card.getId(), true); diff --git a/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java b/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java index 61fbec35e35..a960b5c2c50 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java @@ -113,7 +113,7 @@ class SaddleCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) { @Override - public String getMessage() { + public String getMessage(Game game) { // shows selected power int selectedPower = this.targets.keySet().stream() .map(game::getPermanent) @@ -125,7 +125,7 @@ class SaddleCost extends CostImpl { if (selectedPower >= value) { extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN); } - return super.getMessage() + " " + extraInfo; + return super.getMessage(game) + " " + extraInfo; } }; diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 96eff0bd30b..8df1a12963f 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -4349,14 +4349,14 @@ public abstract class PlayerImpl implements Player, Serializable { List options = new ArrayList<>(); if (ability.isModal()) { addModeOptions(options, ability, game); - } else if (!ability.getTargets().getUnchosen().isEmpty()) { + } else if (!ability.getTargets().getUnchosen(game).isEmpty()) { // TODO: Handle other variable costs than mana costs if (!ability.getManaCosts().getVariableCosts().isEmpty()) { addVariableXOptions(options, ability, 0, game); } else { addTargetOptions(options, ability, 0, game); } - } else if (!ability.getCosts().getTargets().getUnchosen().isEmpty()) { + } else if (!ability.getCosts().getTargets().getUnchosen(game).isEmpty()) { addCostTargetOptions(options, ability, 0, game); } @@ -4371,13 +4371,13 @@ public abstract class PlayerImpl implements Player, Serializable { newOption.getModes().clearSelectedModes(); newOption.getModes().addSelectedMode(mode.getId()); newOption.getModes().setActiveMode(mode); - if (!newOption.getTargets().getUnchosen().isEmpty()) { + if (!newOption.getTargets().getUnchosen(game).isEmpty()) { if (!newOption.getManaCosts().getVariableCosts().isEmpty()) { addVariableXOptions(options, newOption, 0, game); } else { addTargetOptions(options, newOption, 0, game); } - } else if (!newOption.getCosts().getTargets().getUnchosen().isEmpty()) { + } else if (!newOption.getCosts().getTargets().getUnchosen(game).isEmpty()) { addCostTargetOptions(options, newOption, 0, game); } else { options.add(newOption); @@ -4390,7 +4390,7 @@ public abstract class PlayerImpl implements Player, Serializable { } protected void addTargetOptions(List options, Ability option, int targetNum, Game game) { - for (Target target : option.getTargets().getUnchosen().get(targetNum).getTargetOptions(option, game)) { + for (Target target : option.getTargets().getUnchosen(game).get(targetNum).getTargetOptions(option, game)) { Ability newOption = option.copy(); if (target instanceof TargetAmount) { for (UUID targetId : target.getTargets()) { diff --git a/Mage/src/main/java/mage/target/Target.java b/Mage/src/main/java/mage/target/Target.java index 8e674c693b9..f7bd9f14142 100644 --- a/Mage/src/main/java/mage/target/Target.java +++ b/Mage/src/main/java/mage/target/Target.java @@ -19,9 +19,9 @@ import java.util.UUID; */ public interface Target extends Serializable { - boolean isChosen(); + boolean isChosen(Game game); - boolean doneChoosing(); + boolean doneChoosing(Game game); void clearChosen(); @@ -98,7 +98,10 @@ public interface Target extends Serializable { */ String getDescription(); - String getMessage(); + /** + * @return message displayed on choosing targets (can be dynamically changed on more target selected) + */ + String getMessage(Game game); /** * @return single target name diff --git a/Mage/src/main/java/mage/target/TargetAmount.java b/Mage/src/main/java/mage/target/TargetAmount.java index 870eb0526fe..76ac8c7186f 100644 --- a/Mage/src/main/java/mage/target/TargetAmount.java +++ b/Mage/src/main/java/mage/target/TargetAmount.java @@ -44,12 +44,12 @@ public abstract class TargetAmount extends TargetImpl { } @Override - public boolean isChosen() { - return doneChoosing(); + public boolean isChosen(Game game) { + return doneChoosing(game); } @Override - public boolean doneChoosing() { + public boolean doneChoosing(Game game) { return amountWasSet && (remainingAmount == 0 || (getMinNumberOfTargets() < getMaxNumberOfTargets() @@ -104,7 +104,7 @@ public abstract class TargetAmount extends TargetImpl { if (!amountWasSet) { setAmount(source, game); } - chosen = isChosen(); + chosen = isChosen(game); while (remainingAmount > 0) { if (!player.canRespond()) { return chosen; @@ -112,7 +112,7 @@ public abstract class TargetAmount extends TargetImpl { if (!getTargetController(game, playerId).chooseTargetAmount(outcome, this, source, game)) { return chosen; } - chosen = isChosen(); + chosen = isChosen(game); } return chosen; } diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index e5ace6d73e5..8e414f45296 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -143,7 +143,7 @@ public abstract class TargetImpl implements Target { } @Override - public String getMessage() { + public String getMessage(Game game) { // UI choose message String suffix = ""; if (this.chooseHint != null) { @@ -215,7 +215,7 @@ public abstract class TargetImpl implements Target { } @Override - public boolean isChosen() { + public boolean isChosen(Game game) { if (getMaxNumberOfTargets() == 0 && getNumberOfTargets() == 0) { return true; } @@ -223,7 +223,7 @@ public abstract class TargetImpl implements Target { } @Override - public boolean doneChoosing() { + public boolean doneChoosing(Game game) { return getMaxNumberOfTargets() != 0 && targets.size() == getMaxNumberOfTargets(); } @@ -332,7 +332,7 @@ public abstract class TargetImpl implements Target { return chosen; } chosen = targets.size() >= getNumberOfTargets(); - } while (!isChosen() && !doneChoosing()); + } while (!isChosen(game) && !doneChoosing(game)); return chosen; } @@ -375,7 +375,7 @@ public abstract class TargetImpl implements Target { } } chosen = targets.size() >= getNumberOfTargets(); - } while (!isChosen() && !doneChoosing()); + } while (!isChosen(game) && !doneChoosing(game)); return chosen; } diff --git a/Mage/src/main/java/mage/target/Targets.java b/Mage/src/main/java/mage/target/Targets.java index ace3a3cc975..7499467e02c 100644 --- a/Mage/src/main/java/mage/target/Targets.java +++ b/Mage/src/main/java/mage/target/Targets.java @@ -37,8 +37,8 @@ public class Targets extends ArrayList implements Copyable { return this; } - public List getUnchosen() { - return stream().filter(target -> !target.isChosen()).collect(Collectors.toList()); + public List getUnchosen(Game game) { + return stream().filter(target -> !target.isChosen(game)).collect(Collectors.toList()); } public void clearChosen() { @@ -47,8 +47,8 @@ public class Targets extends ArrayList implements Copyable { } } - public boolean isChosen() { - return stream().allMatch(Target::isChosen); + public boolean isChosen(Game game) { + return stream().allMatch(t -> t.isChosen(game)); } public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game) { @@ -56,8 +56,8 @@ public class Targets extends ArrayList implements Copyable { if (!canChoose(playerId, source, game)) { return false; } - while (!isChosen()) { - Target target = this.getUnchosen().get(0); + while (!isChosen(game)) { + Target target = this.getUnchosen(game).get(0); if (!target.choose(outcome, playerId, sourceId, source, game)) { return false; } @@ -73,8 +73,8 @@ public class Targets extends ArrayList implements Copyable { } //int state = game.bookmarkState(); - while (!isChosen()) { - Target target = this.getUnchosen().get(0); + while (!isChosen(game)) { + Target target = this.getUnchosen(game).get(0); UUID targetController = playerId; // some targets can have controller different than ability controller @@ -97,7 +97,7 @@ public class Targets extends ArrayList implements Copyable { return false; } // Check if there are some rules for targets are violated, if so reset the targets and start again - if (this.getUnchosen().isEmpty() + if (this.getUnchosen(game).isEmpty() && game.replaceEvent(new GameEvent(GameEvent.EventType.TARGETS_VALID, source.getSourceId(), source, source.getControllerId()), source)) { //game.restoreState(state, "Targets"); clearChosen(); diff --git a/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java b/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java index 75908154a8a..0b4735a40c6 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java @@ -85,7 +85,7 @@ public class TargetCardInLibrary extends TargetCard { return chosen; } chosen = targets.size() >= getMinNumberOfTargets(); - } while (!isChosen() && !doneChoosing()); + } while (!isChosen(game) && !doneChoosing(game)); return chosen; }