implement [MH3] Nethergoyf, refactor targets usages by game param (#12267)

This commit is contained in:
Susucre 2024-05-21 13:34:38 +02:00 committed by GitHub
parent 88b6f4036f
commit 754b382e78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 592 additions and 285 deletions

View file

@ -1147,7 +1147,7 @@ public class CardView extends SimpleCardView {
// from normal targets // from normal targets
for (Target target : targets) { for (Target target : targets) {
if (target.isChosen()) { if (target.isChosen(game)) {
newTargets.addAll(target.getTargets()); newTargets.addAll(target.getTargets());
} }
} }

View file

@ -34,7 +34,6 @@ import mage.target.Targets;
import mage.util.RandomUtil; import mage.util.RandomUtil;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.io.File;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -392,7 +391,7 @@ public class ComputerPlayer6 extends ComputerPlayer {
if (effect != null if (effect != null
&& stackObject.getControllerId().equals(playerId)) { && stackObject.getControllerId().equals(playerId)) {
Target target = effect.getTarget(); Target target = effect.getTarget();
if (!target.doneChoosing()) { if (!target.doneChoosing(game)) {
for (UUID targetId : target.possibleTargets(stackObject.getControllerId(), stackObject.getStackAbility(), game)) { for (UUID targetId : target.possibleTargets(stackObject.getControllerId(), stackObject.getStackAbility(), game)) {
Game sim = game.createSimulationForAI(); Game sim = game.createSimulationForAI();
StackAbility newAbility = (StackAbility) stackObject.copy(); StackAbility newAbility = (StackAbility) stackObject.copy();
@ -740,10 +739,10 @@ public class ComputerPlayer6 extends ComputerPlayer {
if (targets.isEmpty()) { if (targets.isEmpty()) {
return super.chooseTarget(outcome, cards, target, source, game); return super.chooseTarget(outcome, cards, target, source, game);
} }
if (!target.doneChoosing()) { if (!target.doneChoosing(game)) {
for (UUID targetId : targets) { for (UUID targetId : targets) {
target.addTarget(targetId, source, game); target.addTarget(targetId, source, game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
targets.clear(); targets.clear();
return true; return true;
} }
@ -758,10 +757,10 @@ public class ComputerPlayer6 extends ComputerPlayer {
if (targets.isEmpty()) { if (targets.isEmpty()) {
return super.choose(outcome, cards, target, source, game); return super.choose(outcome, cards, target, source, game);
} }
if (!target.doneChoosing()) { if (!target.doneChoosing(game)) {
for (UUID targetId : targets) { for (UUID targetId : targets) {
target.add(targetId, game); target.add(targetId, game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
targets.clear(); targets.clear();
return true; return true;
} }

View file

@ -10,7 +10,6 @@ import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.cards.Card;
import mage.game.Game; import mage.game.Game;
import mage.game.combat.Combat; import mage.game.combat.Combat;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -149,7 +148,7 @@ public final class SimulatedPlayer2 extends ComputerPlayer {
} }
newAbility.adjustTargets(game); newAbility.adjustTargets(game);
// add the different possible target option for the specific X value // 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); addTargetOptions(options, newAbility, targetNum, game);
} }
} }

View file

@ -174,7 +174,7 @@ public class ComputerPlayer extends PlayerImpl {
for (int i = unplayable.size() - 1; i >= 0; i--) { for (int i = unplayable.size() - 1; i >= 0; i--) {
if (target.canTarget(abilityControllerId, unplayable.values().toArray(new Card[0])[i].getId(), null, game)) { 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); target.add(unplayable.values().toArray(new Card[0])[i].getId(), game);
if (target.isChosen()) { if (target.isChosen(game)) {
return true; return true;
} }
} }
@ -184,7 +184,7 @@ public class ComputerPlayer extends PlayerImpl {
for (int i = 0; i < hand.size(); i++) { for (int i = 0; i < hand.size(); i++) {
if (target.canTarget(abilityControllerId, hand.toArray(new UUID[0])[i], null, game)) { if (target.canTarget(abilityControllerId, hand.toArray(new UUID[0])[i], null, game)) {
target.add(hand.toArray(new UUID[0])[i], game); target.add(hand.toArray(new UUID[0])[i], game);
if (target.isChosen()) { if (target.isChosen(game)) {
return true; return true;
} }
} }
@ -252,12 +252,12 @@ public class ComputerPlayer extends PlayerImpl {
} }
// add the target // add the target
target.add(permanent.getId(), game); target.add(permanent.getId(), game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
return true; return true;
} }
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetCardInHand if (target.getOriginalTarget() instanceof TargetCardInHand
@ -269,7 +269,7 @@ public class ComputerPlayer extends PlayerImpl {
cards.add(card); 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()) { && !cards.isEmpty()) {
Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game); Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (pick != null) { if (pick != null) {
@ -277,7 +277,7 @@ public class ComputerPlayer extends PlayerImpl {
cards.remove(pick); cards.remove(pick);
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetAnyTarget) { 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) // 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; 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()) { && !cards.isEmpty()) {
Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game); Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (pick != null) { if (pick != null) {
@ -421,7 +421,7 @@ public class ComputerPlayer extends PlayerImpl {
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetCardInGraveyard 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) // 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; 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()) { && !cards.isEmpty()) {
Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game); Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (pick != null) { if (pick != null) {
@ -448,7 +448,7 @@ public class ComputerPlayer extends PlayerImpl {
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard
@ -460,7 +460,7 @@ public class ComputerPlayer extends PlayerImpl {
Card card = pickTarget(abilityControllerId, cards, outcome, target, null, game); Card card = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (card != null && alreadyTargeted != null && !alreadyTargeted.contains(card.getId())) { if (card != null && alreadyTargeted != null && !alreadyTargeted.contains(card.getId())) {
target.add(card.getId(), game); target.add(card.getId(), game);
if (target.isChosen()) { if (target.isChosen(game)) {
return true; return true;
} }
} }
@ -485,7 +485,7 @@ public class ComputerPlayer extends PlayerImpl {
Card card = pickTarget(abilityControllerId, cards, outcome, target, null, game); Card card = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (card != null && alreadyTargeted != null && !alreadyTargeted.contains(card.getId())) { if (card != null && alreadyTargeted != null && !alreadyTargeted.contains(card.getId())) {
target.add(card.getId(), game); target.add(card.getId(), game);
if (target.isChosen()) { if (target.isChosen(game)) {
return true; return true;
} }
} }
@ -517,14 +517,14 @@ public class ComputerPlayer extends PlayerImpl {
if (target.getOriginalTarget() instanceof TargetPermanentOrSuspendedCard) { if (target.getOriginalTarget() instanceof TargetPermanentOrSuspendedCard) {
Cards cards = new CardsImpl(possibleTargets); Cards cards = new CardsImpl(possibleTargets);
List<Card> possibleCards = new ArrayList<>(cards.getCards(game)); List<Card> 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); Card pick = pickTarget(abilityControllerId, possibleCards, outcome, target, null, game);
if (pick != null) { if (pick != null) {
target.addTarget(pick.getId(), null, game); target.addTarget(pick.getId(), null, game);
possibleCards.remove(pick); possibleCards.remove(pick);
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetCard 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); Card pick = pickTarget(abilityControllerId, cardsInCommandZone, outcome, target, null, game);
if (pick != null) { if (pick != null) {
target.addTarget(pick.getId(), null, game); target.addTarget(pick.getId(), null, game);
cardsInCommandZone.remove(pick); 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()); 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 if (target.getOriginalTarget() instanceof TargetDiscard
@ -650,7 +650,7 @@ public class ComputerPlayer extends PlayerImpl {
// good // good
Cards cards = new CardsImpl(possibleTargets); Cards cards = new CardsImpl(possibleTargets);
List<Card> cardsInHand = new ArrayList<>(cards.getCards(game)); List<Card> cardsInHand = new ArrayList<>(cards.getCards(game));
while (!target.isChosen() while (!target.isChosen(game)
&& !cardsInHand.isEmpty() && !cardsInHand.isEmpty()
&& target.getMaxNumberOfTargets() > target.getTargets().size()) { && target.getMaxNumberOfTargets() > target.getTargets().size()) {
Card card = pickBestCard(cardsInHand, null, target, source, game); 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)) { if (target.canTarget(abilityControllerId, card.getId(), source, game)) {
target.addTarget(card.getId(), source, game); target.addTarget(card.getId(), source, game);
cardsInHand.remove(card); cardsInHand.remove(card);
if (target.isChosen()) { if (target.isChosen(game)) {
return true; return true;
} }
} }
@ -671,7 +671,7 @@ public class ComputerPlayer extends PlayerImpl {
if (possibleTargets.contains(card.getId()) if (possibleTargets.contains(card.getId())
&& target.canTarget(abilityControllerId, card.getId(), source, game)) { && target.canTarget(abilityControllerId, card.getId(), source, game)) {
target.addTarget(card.getId(), source, game); target.addTarget(card.getId(), source, game);
if (target.isChosen()) { if (target.isChosen(game)) {
return true; return true;
} }
} }
@ -681,7 +681,7 @@ public class ComputerPlayer extends PlayerImpl {
if (possibleTargets.contains(card.getId()) if (possibleTargets.contains(card.getId())
&& target.canTarget(abilityControllerId, card.getId(), source, game)) { && target.canTarget(abilityControllerId, card.getId(), source, game)) {
target.addTarget(card.getId(), source, game); target.addTarget(card.getId(), source, game);
if (target.isChosen()) { if (target.isChosen(game)) {
return true; 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); target.addTarget(permanent.getId(), source, game);
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) { if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) {
@ -956,14 +956,14 @@ public class ComputerPlayer extends PlayerImpl {
if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard) { if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard) {
List<Card> cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards((FilterCard) target.getFilter(), game)); List<Card> 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); Card card = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (card != null) { if (card != null) {
target.addTarget(card.getId(), source, game); target.addTarget(card.getId(), source, game);
cards.remove(card); // pickTarget don't remove cards (only on second+ tries) cards.remove(card); // pickTarget don't remove cards (only on second+ tries)
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetSpell if (target.getOriginalTarget() instanceof TargetSpell
@ -1034,7 +1034,7 @@ public class ComputerPlayer extends PlayerImpl {
if (target.getOriginalTarget() instanceof TargetDefender) { if (target.getOriginalTarget() instanceof TargetDefender) {
UUID randomDefender = RandomUtil.randomFromCollection(possibleTargets); UUID randomDefender = RandomUtil.randomFromCollection(possibleTargets);
target.addTarget(randomDefender, source, game); target.addTarget(randomDefender, source, game);
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) { if (target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) {
@ -1042,14 +1042,14 @@ public class ComputerPlayer extends PlayerImpl {
for (Player player : game.getPlayers().values()) { for (Player player : game.getPlayers().values()) {
cards.addAll(player.getGraveyard().getCards(game)); 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); Card pick = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (pick != null) { if (pick != null) {
target.addTarget(pick.getId(), source, game); target.addTarget(pick.getId(), source, game);
cards.remove(pick); // pickTarget don't remove cards (only on second+ tries) cards.remove(pick); // pickTarget don't remove cards (only on second+ tries)
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetCardInExile) { if (target.getOriginalTarget() instanceof TargetCardInExile) {
@ -1070,14 +1070,14 @@ public class ComputerPlayer extends PlayerImpl {
cards.add(card); cards.add(card);
} }
} }
while (!target.isChosen() && !cards.isEmpty()) { while (!target.isChosen(game) && !cards.isEmpty()) {
Card pick = pickTarget(abilityControllerId, cards, outcome, target, source, game); Card pick = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (pick != null) { if (pick != null) {
target.addTarget(pick.getId(), source, game); target.addTarget(pick.getId(), source, game);
cards.remove(pick); // pickTarget don't remove cards (only on second+ tries) cards.remove(pick); // pickTarget don't remove cards (only on second+ tries)
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetActivatedAbility) { if (target.getOriginalTarget() instanceof TargetActivatedAbility) {
@ -1088,22 +1088,22 @@ public class ComputerPlayer extends PlayerImpl {
stackObjects.add(stackObject); stackObjects.add(stackObject);
} }
} }
while (!target.isChosen() && !stackObjects.isEmpty()) { while (!target.isChosen(game) && !stackObjects.isEmpty()) {
StackObject pick = stackObjects.get(0); StackObject pick = stackObjects.get(0);
if (pick != null) { if (pick != null) {
target.addTarget(pick.getId(), source, game); target.addTarget(pick.getId(), source, game);
stackObjects.remove(0); stackObjects.remove(0);
} }
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetActivatedOrTriggeredAbility) { if (target.getOriginalTarget() instanceof TargetActivatedOrTriggeredAbility) {
Iterator<UUID> iterator = target.possibleTargets(source.getControllerId(), source, game).iterator(); Iterator<UUID> 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); target.addTarget(iterator.next(), source, game);
} }
return target.isChosen(); return target.isChosen(game);
} }
if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) { if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) {
@ -1121,14 +1121,14 @@ public class ComputerPlayer extends PlayerImpl {
if (target.getOriginalTarget() instanceof TargetPermanentOrSuspendedCard) { if (target.getOriginalTarget() instanceof TargetPermanentOrSuspendedCard) {
Cards cards = new CardsImpl(possibleTargets); Cards cards = new CardsImpl(possibleTargets);
List<Card> possibleCards = new ArrayList<>(cards.getCards(game)); List<Card> 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); Card pick = pickTarget(abilityControllerId, possibleCards, outcome, target, source, game);
if (pick != null) { if (pick != null) {
target.addTarget(pick.getId(), source, game); target.addTarget(pick.getId(), source, game);
possibleCards.remove(pick); 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()); 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 // we still use playerId when getting cards even if they don't control the search
List<Card> cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), playerId, source, game)); List<Card> 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); Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, source, game);
if (card != null) { if (card != null) {
target.addTarget(card.getId(), source, game); target.addTarget(card.getId(), source, game);
@ -2094,7 +2094,7 @@ public class ComputerPlayer extends PlayerImpl {
} }
List<Card> cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), abilityControllerId, source, game)); List<Card> 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); Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, source, game);
if (card != null) { if (card != null) {
target.add(card.getId(), game); target.add(card.getId(), game);

View file

@ -674,7 +674,7 @@ public class HumanPlayer extends PlayerImpl {
prepareForResponse(game); prepareForResponse(game);
if (!isExecutingMacro()) { 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); waitForResponse(game);
responseId = getFixedResponseUUID(game); responseId = getFixedResponseUUID(game);
@ -696,7 +696,7 @@ public class HumanPlayer extends PlayerImpl {
if (target instanceof TargetPermanent) { if (target instanceof TargetPermanent) {
if (((TargetPermanent) target).canTarget(abilityControllerId, responseId, source, game, false)) { if (((TargetPermanent) target).canTarget(abilityControllerId, responseId, source, game, false)) {
target.add(responseId, game); target.add(responseId, game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
return true; return true;
} }
} }
@ -708,7 +708,7 @@ public class HumanPlayer extends PlayerImpl {
target.remove(responseId); target.remove(responseId);
} else { } else {
target.addTarget(responseId, (Ability) object, game); target.addTarget(responseId, (Ability) object, game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
return true; return true;
} }
} }
@ -718,7 +718,7 @@ public class HumanPlayer extends PlayerImpl {
target.remove(responseId); target.remove(responseId);
} else { } else {
target.addTarget(responseId, null, game); target.addTarget(responseId, null, game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
return true; return true;
} }
} }
@ -775,7 +775,7 @@ public class HumanPlayer extends PlayerImpl {
prepareForResponse(game); prepareForResponse(game);
if (!isExecutingMacro()) { 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)); possibleTargetIds, required, getOptions(target, options));
} }
waitForResponse(game); waitForResponse(game);
@ -792,7 +792,7 @@ public class HumanPlayer extends PlayerImpl {
if (possibleTargetIds.contains(responseId)) { if (possibleTargetIds.contains(responseId)) {
if (target.canTarget(abilityControllerId, responseId, source, game)) { if (target.canTarget(abilityControllerId, responseId, source, game)) {
target.addTarget(responseId, source, game); target.addTarget(responseId, source, game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
return true; return true;
} }
} }
@ -873,7 +873,7 @@ public class HumanPlayer extends PlayerImpl {
prepareForResponse(game); prepareForResponse(game);
if (!isExecutingMacro()) { 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); waitForResponse(game);
@ -886,7 +886,7 @@ public class HumanPlayer extends PlayerImpl {
} else { } else {
if (target.canTarget(abilityControllerId, responseId, source, cards, game)) { if (target.canTarget(abilityControllerId, responseId, source, cards, game)) {
target.add(responseId, game); target.add(responseId, game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
return true; return true;
} }
} }
@ -956,7 +956,7 @@ public class HumanPlayer extends PlayerImpl {
prepareForResponse(game); prepareForResponse(game);
if (!isExecutingMacro()) { 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); waitForResponse(game);
@ -968,7 +968,7 @@ public class HumanPlayer extends PlayerImpl {
target.remove(responseId); target.remove(responseId);
} else if (target.canTarget(abilityControllerId, responseId, source, cards, game)) { } else if (target.canTarget(abilityControllerId, responseId, source, cards, game)) {
target.addTarget(responseId, source, game); target.addTarget(responseId, source, game);
if (target.doneChoosing()) { if (target.doneChoosing(game)) {
return true; return true;
} }
} }
@ -1051,7 +1051,7 @@ public class HumanPlayer extends PlayerImpl {
prepareForResponse(game); prepareForResponse(game);
if (!isExecutingMacro()) { if (!isExecutingMacro()) {
String multiType = multiAmountType == MultiAmountType.DAMAGE ? " to divide %d damage" : " to distribute %d counters"; 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); game.fireSelectTargetEvent(playerId, new MessageToClient(message, getRelatedObjectName(source, game)), possibleTargetIds, required, options);
} }
waitForResponse(game); waitForResponse(game);

View file

@ -115,7 +115,7 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect {
TargetPermanent target = new TargetPermanent(filter); TargetPermanent target = new TargetPermanent(filter);
target.withNotTarget(true); target.withNotTarget(true);
if (target.canChoose(controller.getId(), source, game)) { 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); controller.chooseTarget(outcome, target, source, game);
} }
} else { } else {

View file

@ -1,6 +1,5 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamageAllEffect;
@ -17,14 +16,15 @@ import mage.target.Target;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author Plopman * @author Plopman
*/ */
public final class BurningOfXinye extends CardImpl { public final class BurningOfXinye extends CardImpl {
public BurningOfXinye(UUID ownerId, CardSetInfo setInfo) { 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. // 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() { BurningOfXinyeEffect() {
super(Outcome.DestroyPermanent); super(Outcome.DestroyPermanent);
staticText = "You destroy four lands you control, then target opponent destroys four lands they control"; 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); super(effect);
} }
@ -73,16 +73,16 @@ class BurningOfXinyeEffect extends OneShotEffect{
return abilityApplied; return abilityApplied;
} }
private boolean playerDestroys(Game game, Ability source, Player player){ private boolean playerDestroys(Game game, Ability source, Player player) {
boolean abilityApplied = false; boolean abilityApplied = false;
int realCount = game.getBattlefield().countAll(filter, player.getId(), game); int realCount = game.getBattlefield().countAll(filter, player.getId(), game);
int amount = Math.min(4, realCount); int amount = Math.min(4, realCount);
Target target = new TargetControlledPermanent(amount, amount, filter, true); Target target = new TargetControlledPermanent(amount, amount, filter, true);
if (amount > 0 && target.canChoose(player.getId(), source, game)) { 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); player.choose(Outcome.DestroyPermanent, target, source, game);
} }

View file

@ -1,7 +1,6 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -17,11 +16,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.choices.Choice; import mage.choices.Choice;
import mage.choices.ChoiceCreatureType; import mage.choices.ChoiceCreatureType;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -30,8 +25,9 @@ import mage.target.common.TargetCreaturePermanent;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class CallousOppressor extends CardImpl { public final class CallousOppressor extends CardImpl {
@ -118,7 +114,7 @@ class CallousOppressorChooseCreatureTypeEffect extends OneShotEffect {
if (controller != null) { if (controller != null) {
TargetOpponent target = new TargetOpponent(true); TargetOpponent target = new TargetOpponent(true);
if (target.canChoose(controller.getId(), source, game)) { 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); controller.chooseTarget(outcome, target, source, game);
} }
} else { } else {

View file

@ -1,9 +1,6 @@
package mage.cards.c; package mage.cards.c;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; import mage.cards.Card;
@ -21,14 +18,17 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
*
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public final class Cataclysm extends CardImpl { public final class Cataclysm extends CardImpl {
public Cataclysm(UUID ownerId, CardSetInfo setInfo) { 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. // 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()); this.getSpellAbility().addEffect(new CataclysmEffect());
@ -68,7 +68,7 @@ class CataclysmEffect extends OneShotEffect {
Target target4 = new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent(), true); Target target4 = new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent(), true);
if (target1.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target1, source, game);
} }
Permanent artifact = game.getPermanent(target1.getFirstTarget()); Permanent artifact = game.getPermanent(target1.getFirstTarget());
@ -79,7 +79,7 @@ class CataclysmEffect extends OneShotEffect {
} }
if (target2.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target2, source, game);
} }
Permanent creature = game.getPermanent(target2.getFirstTarget()); Permanent creature = game.getPermanent(target2.getFirstTarget());
@ -90,7 +90,7 @@ class CataclysmEffect extends OneShotEffect {
} }
if (target3.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target3, source, game);
} }
Permanent enchantment = game.getPermanent(target3.getFirstTarget()); Permanent enchantment = game.getPermanent(target3.getFirstTarget());
@ -99,9 +99,9 @@ class CataclysmEffect extends OneShotEffect {
} }
target3.clearChosen(); target3.clearChosen();
} }
if (target4.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target4, source, game);
} }
Permanent land = game.getPermanent(target4.getFirstTarget()); Permanent land = game.getPermanent(target4.getFirstTarget());

View file

@ -101,7 +101,7 @@ class CataclysmicGearhulkEffect extends OneShotEffect {
Target target4 = new TargetControlledPermanent(1, 1, filterPlaneswalker, true); Target target4 = new TargetControlledPermanent(1, 1, filterPlaneswalker, true);
if (target1.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target1, source, game);
} }
Permanent artifact = game.getPermanent(target1.getFirstTarget()); Permanent artifact = game.getPermanent(target1.getFirstTarget());
@ -112,7 +112,7 @@ class CataclysmicGearhulkEffect extends OneShotEffect {
} }
if (target2.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target2, source, game);
} }
Permanent creature = game.getPermanent(target2.getFirstTarget()); Permanent creature = game.getPermanent(target2.getFirstTarget());
@ -123,7 +123,7 @@ class CataclysmicGearhulkEffect extends OneShotEffect {
} }
if (target3.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target3, source, game);
} }
Permanent enchantment = game.getPermanent(target3.getFirstTarget()); Permanent enchantment = game.getPermanent(target3.getFirstTarget());
@ -134,7 +134,7 @@ class CataclysmicGearhulkEffect extends OneShotEffect {
} }
if (target4.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target4, source, game);
} }
Permanent planeswalker = game.getPermanent(target4.getFirstTarget()); Permanent planeswalker = game.getPermanent(target4.getFirstTarget());

View file

@ -1,9 +1,6 @@
package mage.cards.c; package mage.cards.c;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -26,6 +23,10 @@ import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public final class CatchRelease extends SplitCard { public final class CatchRelease extends SplitCard {
public CatchRelease(UUID ownerId, CardSetInfo setInfo) { public CatchRelease(UUID ownerId, CardSetInfo setInfo) {
@ -87,7 +88,7 @@ class ReleaseSacrificeEffect extends OneShotEffect {
Target target5 = new TargetControlledPermanent(1, 1, new FilterControlledPlaneswalkerPermanent(), true); Target target5 = new TargetControlledPermanent(1, 1, new FilterControlledPlaneswalkerPermanent(), true);
if (target1.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target1, source, game);
} }
Permanent artifact = game.getPermanent(target1.getFirstTarget()); Permanent artifact = game.getPermanent(target1.getFirstTarget());
@ -98,7 +99,7 @@ class ReleaseSacrificeEffect extends OneShotEffect {
} }
if (target2.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target2, source, game);
} }
Permanent creature = game.getPermanent(target2.getFirstTarget()); Permanent creature = game.getPermanent(target2.getFirstTarget());
@ -109,7 +110,7 @@ class ReleaseSacrificeEffect extends OneShotEffect {
} }
if (target3.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target3, source, game);
} }
Permanent enchantment = game.getPermanent(target3.getFirstTarget()); Permanent enchantment = game.getPermanent(target3.getFirstTarget());
@ -120,7 +121,7 @@ class ReleaseSacrificeEffect extends OneShotEffect {
} }
if (target4.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target4, source, game);
} }
Permanent land = game.getPermanent(target4.getFirstTarget()); Permanent land = game.getPermanent(target4.getFirstTarget());
@ -131,7 +132,7 @@ class ReleaseSacrificeEffect extends OneShotEffect {
} }
if (target5.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target5, source, game);
} }
Permanent planeswalker = game.getPermanent(target5.getFirstTarget()); Permanent planeswalker = game.getPermanent(target5.getFirstTarget());

View file

@ -1,7 +1,6 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility;
@ -10,7 +9,10 @@ import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; 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.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.game.Game; import mage.game.Game;
@ -20,8 +22,9 @@ import mage.target.Target;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class Clambassadors extends CardImpl { public final class Clambassadors extends CardImpl {
@ -82,7 +85,7 @@ class ClambassadorsEffect extends OneShotEffect {
if (controller != null) { if (controller != null) {
Target target = new TargetControlledPermanent(1, 1, filter, true); Target target = new TargetControlledPermanent(1, 1, filter, true);
if (target.canChoose(controller.getId(), source, game)) { 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); controller.chooseTarget(outcome, target, source, game);
} }
} }

View file

@ -19,19 +19,16 @@ import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice; import mage.target.common.TargetSacrifice;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author anonymous * @author anonymous
*/ */
public final class CurseOfTheCabal extends CardImpl { public final class CurseOfTheCabal extends CardImpl {
@ -87,7 +84,7 @@ class CurseOfTheCabalSacrificeEffect extends OneShotEffect {
} }
Target target = new TargetSacrifice(amount, StaticFilters.FILTER_CONTROLLED_PERMANENT); Target target = new TargetSacrifice(amount, StaticFilters.FILTER_CONTROLLED_PERMANENT);
if (target.canChoose(targetPlayer.getId(), source, game)) { if (target.canChoose(targetPlayer.getId(), source, game)) {
while (!target.isChosen() while (!target.isChosen(game)
&& target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) { && target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) {
targetPlayer.choose(Outcome.Sacrifice, target, source, game); targetPlayer.choose(Outcome.Sacrifice, target, source, game);
} }
@ -107,9 +104,9 @@ class CurseOfTheCabalInterveningIfTriggeredAbility extends ConditionalIntervenin
public CurseOfTheCabalInterveningIfTriggeredAbility() { public CurseOfTheCabalInterveningIfTriggeredAbility() {
super(new BeginningOfUpkeepTriggeredAbility( super(new BeginningOfUpkeepTriggeredAbility(
Zone.EXILED, new CurseOfTheCabalTriggeredAbilityConditionalDelay(), Zone.EXILED, new CurseOfTheCabalTriggeredAbilityConditionalDelay(),
TargetController.ANY, false, true TargetController.ANY, false, true
), ),
SuspendedCondition.instance, SuspendedCondition.instance,
"At the beginning of each player's upkeep, if {this} is suspended, " "At the beginning of each player's upkeep, if {this} is suspended, "
+ "that player may sacrifice a permanent. If the player does, " + "that player may sacrifice a permanent. If the player does, "

View file

@ -18,7 +18,6 @@ import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class DevourFlesh extends CardImpl { 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) { if (game.getBattlefield().count(TargetSacrifice.makeFilter(StaticFilters.FILTER_PERMANENT_CREATURE), player.getId(), source, game) > 0) {
Target target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE); 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -1,10 +1,6 @@
package mage.cards.d; package mage.cards.d;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -22,6 +18,10 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* @author nantuko * @author nantuko
*/ */
@ -68,7 +68,7 @@ class DivineReckoningEffect extends OneShotEffect {
if (player != null) { if (player != null) {
Target target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true); Target target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true);
if (target.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.Benefit, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -108,7 +108,7 @@ class DrainPowerEffect extends OneShotEffect {
FilterLandPermanent filter2 = new FilterLandPermanent("land you control to tap for mana (remaining: " + permList.size() + ')'); FilterLandPermanent filter2 = new FilterLandPermanent("land you control to tap for mana (remaining: " + permList.size() + ')');
filter2.add(new PermanentReferenceInCollectionPredicate(permList, game)); filter2.add(new PermanentReferenceInCollectionPredicate(permList, game));
target = new TargetPermanent(1, 1, filter2, true); 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); targetPlayer.chooseTarget(Outcome.Neutral, target, source, game);
} }
permanent = game.getPermanent(target.getFirstTarget()); permanent = game.getPermanent(target.getFirstTarget());

View file

@ -20,7 +20,6 @@ import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author fireshoes * @author fireshoes
*/ */
public final class EntrapmentManeuver extends CardImpl { 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) { if (game.getBattlefield().count(TargetSacrifice.makeFilter(StaticFilters.FILTER_ATTACKING_CREATURE), player.getId(), source, game) > 0) {
Target target = new TargetSacrifice(StaticFilters.FILTER_ATTACKING_CREATURE); 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -68,7 +68,7 @@ class EunuchsIntriguesEffect extends OneShotEffect {
filter.add(new ControllerIdPredicate(player.getId())); filter.add(new ControllerIdPredicate(player.getId()));
Target target = new TargetPermanent(1, 1, filter, true); Target target = new TargetPermanent(1, 1, filter, true);
if (target.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.DestroyPermanent, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -33,7 +33,6 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author notgreat * @author notgreat
*/ */
public final class FabricationFoundry extends CardImpl { public final class FabricationFoundry extends CardImpl {
@ -96,6 +95,7 @@ enum ArtifactSpellOrActivatedAbilityCondition implements Condition {
return object != null && object.isArtifact(game) && !source.isActivated(); return object != null && object.isArtifact(game) && !source.isActivated();
} }
} }
//Cost based on Kozilek, The Great Distortion and CrewAbility //Cost based on Kozilek, The Great Distortion and CrewAbility
class ExileTargetsTotalManaValueCost extends CostImpl { class ExileTargetsTotalManaValueCost extends CostImpl {
private static final FilterPermanent filter = new FilterControlledArtifactPermanent("one or more other artifacts you control with total mana value X"); 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 { static {
filter.add(AnotherPredicate.instance); filter.add(AnotherPredicate.instance);
} }
public ExileTargetsTotalManaValueCost() { public ExileTargetsTotalManaValueCost() {
this.text = "Exile one or more other artifacts you control with total mana value X"; 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 minX = abilityTarget.getManaValue();
int sum = 0; int sum = 0;
Target target = new TargetPermanent(1, Integer.MAX_VALUE, filter, true){ Target target = new TargetPermanent(1, Integer.MAX_VALUE, filter, true) {
@Override @Override
public String getMessage() { public String getMessage(Game game) {
// shows selected mana value // shows selected mana value
int selectedPower = this.targets.keySet().stream() int selectedPower = this.targets.keySet().stream()
.map(game::getPermanent) .map(game::getPermanent)
@ -136,10 +137,10 @@ class ExileTargetsTotalManaValueCost extends CostImpl {
if (selectedPower >= minX) { if (selectedPower >= minX) {
extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN); 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; return paid;
} }
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();
@ -152,7 +153,7 @@ class ExileTargetsTotalManaValueCost extends CostImpl {
} }
paid = (sum >= minX); paid = (sum >= minX);
if (paid) { if (paid) {
player.moveCardsToExile(cards.getCards(game), source, game, false,null,null); player.moveCardsToExile(cards.getCards(game), source, game, false, null, null);
} }
return paid; return paid;
} }
@ -161,12 +162,12 @@ class ExileTargetsTotalManaValueCost extends CostImpl {
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
int totalExileMV = 0; int totalExileMV = 0;
boolean anyExileFound = false; 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(); totalExileMV += permanent.getManaValue();
anyExileFound = true; anyExileFound = true;
} }
int minTargetMV = Integer.MAX_VALUE; 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()); minTargetMV = Integer.min(minTargetMV, card.getManaValue());
} }
return anyExileFound && totalExileMV >= minTargetMV; return anyExileFound && totalExileMV >= minTargetMV;

View file

@ -129,7 +129,7 @@ class FalseOrdersUnblockEffect extends OneShotEffect {
TargetPermanent target = new TargetPermanent(filter); TargetPermanent target = new TargetPermanent(filter);
target.withNotTarget(true); target.withNotTarget(true);
if (target.canChoose(controller.getId(), source, game)) { 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); controller.chooseTarget(outcome, target, source, game);
} }
} else { } else {

View file

@ -143,9 +143,9 @@ class FireballTargetCreatureOrPlayer extends TargetAnyTarget {
chosen = true; chosen = true;
} }
if (!target.isChosen()) { if (!target.isChosen(game)) {
Iterator<UUID> it2 = possibleTargets.iterator(); Iterator<UUID> it2 = possibleTargets.iterator();
while (it2.hasNext() && !target.isChosen()) { while (it2.hasNext() && !target.isChosen(game)) {
UUID nextTargetId = it2.next(); UUID nextTargetId = it2.next();
target.addTarget(nextTargetId, source, game, true); target.addTarget(nextTargetId, source, game, true);
@ -155,7 +155,7 @@ class FireballTargetCreatureOrPlayer extends TargetAnyTarget {
} }
} }
if (target.isChosen()) { if (target.isChosen(game)) {
options.add(target); options.add(target);
} }
} }

View file

@ -1,9 +1,7 @@
package mage.cards.g; package mage.cards.g;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
@ -21,14 +19,15 @@ import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class GoblinFestival extends CardImpl { public final class GoblinFestival extends CardImpl {
public GoblinFestival(UUID ownerId, CardSetInfo setInfo) { 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. // {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}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl<>("{2}"));
@ -72,7 +71,7 @@ class GoblinFestivalChangeControlEffect extends OneShotEffect {
if (sourcePermanent != null) { if (sourcePermanent != null) {
Target target = new TargetOpponent(true); Target target = new TargetOpponent(true);
if (target.canChoose(controller.getId(), source, game)) { 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); controller.chooseTarget(outcome, target, source, game);
} }
} }

View file

@ -68,7 +68,7 @@ class GoblinWarCryEffect extends OneShotEffect {
filter.add(new ControllerIdPredicate(player.getId())); filter.add(new ControllerIdPredicate(player.getId()));
Target target = new TargetPermanent(1, 1, filter, true); Target target = new TargetPermanent(1, 1, filter, true);
if (target.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.DestroyPermanent, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -1,7 +1,6 @@
package mage.cards.i; package mage.cards.i;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -17,8 +16,9 @@ import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class ImperialEdict extends CardImpl { public final class ImperialEdict extends CardImpl {
@ -67,7 +67,7 @@ class ImperialEdictEffect extends OneShotEffect {
filter.add(new ControllerIdPredicate(player.getId())); filter.add(new ControllerIdPredicate(player.getId()));
Target target = new TargetPermanent(1, 1, filter, true); Target target = new TargetPermanent(1, 1, filter, true);
if (target.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.DestroyPermanent, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -1,10 +1,6 @@
package mage.cards.j; 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.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -15,11 +11,7 @@ import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledLandPermanent;
import mage.game.Game; import mage.game.Game;
@ -31,14 +23,18 @@ import mage.target.TargetPermanent;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class JalumGrifter extends CardImpl { public final class JalumGrifter extends CardImpl {
public JalumGrifter(UUID ownerId, CardSetInfo setInfo) { 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.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.DEVIL); this.subtype.add(SubType.DEVIL);
this.power = new MageInt(3); this.power = new MageInt(3);
@ -80,7 +76,7 @@ class JalumGrifterEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Player opponent = game.getPlayer(source.getTargets().get(0).getFirstTarget()); Player opponent = game.getPlayer(source.getTargets().get(0).getFirstTarget());
if (controller != null && opponent != null) { if (controller != null && opponent != null) {
@ -92,15 +88,15 @@ class JalumGrifterEffect extends OneShotEffect {
shellGamePile.add(sourceCard); shellGamePile.add(sourceCard);
game.informPlayers(controller.getLogName() + " turns " + sourceCard.getLogName() + " face down"); game.informPlayers(controller.getLogName() + " turns " + sourceCard.getLogName() + " face down");
} }
Target target = new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent(), true); Target target = new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent(), true);
if (target.canChoose(controller.getId(), source, game)) { 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); controller.chooseTarget(outcome, target, source, game);
} }
} }
for (UUID cardId: target.getTargets()) { for (UUID cardId : target.getTargets()) {
Card card = game.getCard(cardId); Card card = game.getCard(cardId);
if (card != null) { if (card != null) {
card = card.copy(); card = card.copy();

View file

@ -91,7 +91,7 @@ class LegateLaniusCaesarsAceSacrificeEffect extends OneShotEffect {
continue; continue;
} }
TargetSacrifice target = new TargetSacrifice(numTargets, filter); 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
perms.addAll(target.getTargets()); perms.addAll(target.getTargets());

View file

@ -1,8 +1,5 @@
package mage.cards.l; package mage.cards.l;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -11,11 +8,7 @@ import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.filter.FilterPlayer; import mage.filter.FilterPlayer;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.other.PlayerIdPredicate; import mage.filter.predicate.other.PlayerIdPredicate;
@ -25,16 +18,19 @@ import mage.players.Player;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class LoxodonPeacekeeper extends CardImpl { public final class LoxodonPeacekeeper extends CardImpl {
public LoxodonPeacekeeper(UUID ownerId, CardSetInfo setInfo) { 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.ELEPHANT);
this.subtype.add(SubType.SOLDIER); this.subtype.add(SubType.SOLDIER);
this.power = new MageInt(4); this.power = new MageInt(4);
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
@ -93,7 +89,7 @@ class LoxodonPeacekeeperEffect extends OneShotEffect {
} }
} }
} }
if (!tiedPlayers.isEmpty()) { if (!tiedPlayers.isEmpty()) {
UUID newControllerId = null; UUID newControllerId = null;
if (tiedPlayers.size() > 1) { if (tiedPlayers.size() > 1) {
@ -105,7 +101,7 @@ class LoxodonPeacekeeperEffect extends OneShotEffect {
} }
TargetPlayer target = new TargetPlayer(1, 1, true, filter); TargetPlayer target = new TargetPlayer(1, 1, true, filter);
if (target.canChoose(controller.getId(), source, game)) { 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); controller.chooseTarget(outcome, target, source, game);
} }
} else { } else {

View file

@ -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. // Escape-{4}{G}{U}, Exile a land you control, Exile five other cards from your graveyard.
CostsImpl<Cost> additionalCost = new CostsImpl(); CostsImpl<Cost> additionalCost = new CostsImpl();
additionalCost.add(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_A_LAND))); 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) { private LunarHatchling(final LunarHatchling card) {

View file

@ -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<Cost> 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<CardType> 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<CardType> typesAmongSelection(Collection<UUID> 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<UUID> cardsIds, Game game) {
return typesAmongSelection(cardsIds, game).size() >= 4;
}
}

View file

@ -70,7 +70,7 @@ enum NotOfThisWorldCondition implements Condition {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
StackObject sourceSpell = game.getStack().getStackObject(source.getSourceId()); StackObject sourceSpell = game.getStack().getStackObject(source.getSourceId());
if (sourceSpell == null || !sourceSpell.getStackAbility().getTargets().isChosen()) { if (sourceSpell == null || !sourceSpell.getStackAbility().getTargets().isChosen(game)) {
return false; return false;
} }
StackObject objectToCounter = game.getStack().getStackObject(sourceSpell.getStackAbility().getTargets().getFirstTarget()); StackObject objectToCounter = game.getStack().getStackObject(sourceSpell.getStackAbility().getTargets().getFirstTarget());

View file

@ -12,12 +12,9 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice; import mage.target.common.TargetSacrifice;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
@ -88,7 +85,7 @@ class PlaguecrafterEffect extends OneShotEffect {
} }
TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER); TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER);
if (target.canChoose(player.getId(), source, game)) { 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
perms.addAll(target.getTargets()); perms.addAll(target.getTargets());

View file

@ -1,9 +1,6 @@
package mage.cards.r; package mage.cards.r;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; import mage.cards.Card;
@ -18,8 +15,11 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
*
* @author spjspj * @author spjspj
*/ */
public final class RaziasPurification extends CardImpl { public final class RaziasPurification extends CardImpl {
@ -63,7 +63,7 @@ class RaziasPurificationEffect extends OneShotEffect {
if (player != null && target1.canChoose(player.getId(), source, game)) { if (player != null && target1.canChoose(player.getId(), source, game)) {
int chosenPermanents = 0; 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); player.chooseTarget(Outcome.Benefit, target1, source, game);
for (UUID targetId : target1.getTargets()) { for (UUID targetId : target1.getTargets()) {
Permanent p = game.getPermanent(targetId); Permanent p = game.getPermanent(targetId);

View file

@ -69,7 +69,7 @@ class ReignOfThePitEffect extends OneShotEffect {
if (player != null) { if (player != null) {
TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE); TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE);
if (target.canChoose(player.getId(), source, game)) { 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
perms.addAll(target.getTargets()); perms.addAll(target.getTargets());

View file

@ -147,14 +147,14 @@ class RiskyMoveFlipCoinEffect extends OneShotEffect {
Target target2 = new TargetOpponent(true); Target target2 = new TargetOpponent(true);
if (target1.canChoose(controller.getId(), source, game)) { if (target1.canChoose(controller.getId(), source, game)) {
while (!target1.isChosen() while (!target1.isChosen(game)
&& target1.canChoose(controller.getId(), source, game) && target1.canChoose(controller.getId(), source, game)
&& controller.canRespond()) { && controller.canRespond()) {
controller.chooseTarget(outcome, target1, source, game); controller.chooseTarget(outcome, target1, source, game);
} }
} }
if (target2.canChoose(controller.getId(), source, game)) { if (target2.canChoose(controller.getId(), source, game)) {
while (!target2.isChosen() while (!target2.isChosen(game)
&& target2.canChoose(controller.getId(), source, game) && target2.canChoose(controller.getId(), source, game)
&& controller.canRespond()) { && controller.canRespond()) {
controller.chooseTarget(outcome, target2, source, game); controller.chooseTarget(outcome, target2, source, game);

View file

@ -1,7 +1,6 @@
package mage.cards.r; package mage.cards.r;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.DamageEverythingEffect;
@ -11,24 +10,23 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetSacrifice; import mage.target.common.TargetSacrifice;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class Rupture extends CardImpl { public final class Rupture extends CardImpl {
public Rupture(UUID ownerId, CardSetInfo setInfo) { 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. // 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()); this.getSpellAbility().addEffect(new RuptureEffect());
@ -68,7 +66,7 @@ class RuptureEffect extends OneShotEffect {
int power = 0; int power = 0;
TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE); TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE);
if (target.canChoose(player.getId(), source, game)) { 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -1,7 +1,6 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -13,16 +12,14 @@ import mage.constants.Outcome;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice; import mage.target.common.TargetSacrifice;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class Smokestack extends CardImpl { 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 //A spell or ability could have removed the only legal target this player
//had, if thats the case this ability should fizzle. //had, if thats the case this ability should fizzle.
if (target.canChoose(activePlayer.getId(), source, game)) { 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); activePlayer.choose(Outcome.Sacrifice, target, source, game);
} }

View file

@ -1,7 +1,6 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -22,8 +21,9 @@ import mage.players.Player;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
*
* @author L_J * @author L_J
*/ */
public final class SpyNetwork extends CardImpl { public final class SpyNetwork extends CardImpl {
@ -109,7 +109,7 @@ class SpyNetworkFaceDownEffect extends OneShotEffect {
if (target.canChoose(controller.getId(), source, game)) { if (target.canChoose(controller.getId(), source, game)) {
while (controller.chooseUse(outcome, "Look at a face down creature controlled by " + player.getLogName() + "?", source, game)) { while (controller.chooseUse(outcome, "Look at a face down creature controlled by " + player.getLogName() + "?", source, game)) {
target.clearChosen(); 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); controller.chooseTarget(outcome, target, source, game);
} }
Permanent faceDownCreature = game.getPermanent(target.getFirstTarget()); Permanent faceDownCreature = game.getPermanent(target.getFirstTarget());

View file

@ -1,6 +1,5 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -16,8 +15,9 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class SunkenHope extends CardImpl { public final class SunkenHope extends CardImpl {
@ -66,7 +66,7 @@ class SunkenHopeReturnToHandEffect extends OneShotEffect {
Target target = new TargetControlledCreaturePermanent().withNotTarget(true); Target target = new TargetControlledCreaturePermanent().withNotTarget(true);
if (target.canChoose(player.getId(), source, game)) { if (target.canChoose(player.getId(), source, game)) {
while (player.canRespond() && !target.isChosen() while (player.canRespond() && !target.isChosen(game)
&& target.canChoose(player.getId(), source, game)) { && target.canChoose(player.getId(), source, game)) {
player.chooseTarget(Outcome.ReturnToHand, target, source, game); player.chooseTarget(Outcome.ReturnToHand, target, source, game);
} }

View file

@ -1,20 +1,19 @@
package mage.cards.t; package mage.cards.t;
import java.util.UUID;
import mage.Mana; import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SagaAbility; import mage.abilities.common.SagaAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamageAllEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.constants.SubType;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SagaChapter; import mage.constants.SagaChapter;
import mage.constants.SubType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
@ -24,11 +23,11 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice; import mage.target.common.TargetSacrifice;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class TheFirstEruption extends CardImpl { public final class TheFirstEruption extends CardImpl {
@ -101,7 +100,7 @@ class TheFirstEruptionEffect extends OneShotEffect {
Target target = new TargetSacrifice(filter); Target target = new TargetSacrifice(filter);
boolean sacrificed = false; boolean sacrificed = false;
if (target.canChoose(controller.getId(), source, game)) { 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); controller.choose(Outcome.Sacrifice, target, source, game);
} }

View file

@ -443,7 +443,7 @@ class UrzaAcademyHeadmasterRandomEffect extends OneShotEffect {
} }
source.addTarget(target); source.addTarget(target);
} }
if (target == null || target.isChosen()) { if (target == null || target.isChosen(game)) {
for (Effect effect : effects) { for (Effect effect : effects) {
if (effect instanceof ContinuousEffect) { if (effect instanceof ContinuousEffect) {
game.addEffect((ContinuousEffect) effect, source); game.addEffect((ContinuousEffect) effect, source);

View file

@ -134,7 +134,7 @@ class VodalianWarMachineWatcher extends Watcher {
for (Cost cost : ability.getCosts()) { for (Cost cost : ability.getCosts()) {
if (cost instanceof TapTargetCost && cost.isPaid()) { if (cost instanceof TapTargetCost && cost.isPaid()) {
TapTargetCost tapCost = (TapTargetCost) cost; TapTargetCost tapCost = (TapTargetCost) cost;
if (tapCost.getTarget().isChosen()) { if (tapCost.getTarget().isChosen(game)) {
MageObjectReference mor = new MageObjectReference(sourcePermanent.getId(), sourcePermanent.getZoneChangeCounter(game), game); MageObjectReference mor = new MageObjectReference(sourcePermanent.getId(), sourcePermanent.getZoneChangeCounter(game), game);
Set<MageObjectReference> toAdd; Set<MageObjectReference> toAdd;
if (tappedMerfolkIds.get(mor) == null) { if (tappedMerfolkIds.get(mor) == null) {

View file

@ -10,15 +10,12 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SetTargetPointer;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.token.FoodToken; import mage.game.permanent.token.FoodToken;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetSacrifice; import mage.target.common.TargetSacrifice;
import java.util.ArrayList; import java.util.ArrayList;
@ -26,14 +23,13 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author Susucr * @author Susucr
*/ */
public final class VoraciousFellBeast extends CardImpl { public final class VoraciousFellBeast extends CardImpl {
public VoraciousFellBeast(UUID ownerId, CardSetInfo setInfo) { public VoraciousFellBeast(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}");
this.subtype.add(SubType.DRAKE); this.subtype.add(SubType.DRAKE);
this.subtype.add(SubType.BEAST); this.subtype.add(SubType.BEAST);
this.power = new MageInt(4); this.power = new MageInt(4);
@ -63,7 +59,7 @@ class VoraciousFellBeastEffect extends OneShotEffect {
VoraciousFellBeastEffect() { VoraciousFellBeastEffect() {
super(Outcome.Sacrifice); super(Outcome.Sacrifice);
this.staticText = "each opponent sacrifices a creature. " + 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) { private VoraciousFellBeastEffect(final VoraciousFellBeastEffect effect) {
@ -91,7 +87,7 @@ class VoraciousFellBeastEffect extends OneShotEffect {
TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE); TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_PERMANENT_CREATURE);
if (target.canChoose(player.getId(), source, game)) { 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
perms.addAll(target.getTargets()); perms.addAll(target.getTargets());

View file

@ -1,16 +1,15 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.constants.SubType;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game; import mage.game.Game;
@ -20,8 +19,9 @@ import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class WeiAssassins extends CardImpl { public final class WeiAssassins extends CardImpl {
@ -77,7 +77,7 @@ class WeiAssassinsEffect extends OneShotEffect {
filter.add(new ControllerIdPredicate(player.getId())); filter.add(new ControllerIdPredicate(player.getId()));
Target target = new TargetPermanent(1, 1, filter, true); Target target = new TargetPermanent(1, 1, filter, true);
if (target.canChoose(player.getId(), source, game)) { 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); player.chooseTarget(Outcome.DestroyPermanent, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -18,8 +18,6 @@ import mage.filter.common.FilterControlledPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice; import mage.target.common.TargetSacrifice;
import java.util.*; import java.util.*;
@ -119,7 +117,7 @@ class WorldQuellerEffect extends OneShotEffect {
for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
Player player2 = game.getPlayer(playerId); Player player2 = game.getPlayer(playerId);
if (player2 != null && target.canChoose(playerId, source, game)) { 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); player2.choose(Outcome.Sacrifice, target, source, game);
} }
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());

View file

@ -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("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("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("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("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("Nulldrifter", 13, Rarity.RARE, mage.cards.n.Nulldrifter.class));
cards.add(new SetCardInfo("Orim's Chant", 265, Rarity.RARE, mage.cards.o.OrimsChant.class)); cards.add(new SetCardInfo("Orim's Chant", 265, Rarity.RARE, mage.cards.o.OrimsChant.class));

View file

@ -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
* Nethergoyfs 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 arent 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 arent 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);
}
}

View file

@ -2001,8 +2001,8 @@ public class TestPlayer implements Player {
return "Ability: null"; return "Ability: null";
} }
private String getInfo(Target o) { private String getInfo(Target o, Game game) {
return "Target: " + (o != null ? o.getClass().getSimpleName() + ": " + o.getMessage() : "null"); return "Target: " + (o != null ? o.getClass().getSimpleName() + ": " + o.getMessage(game) : "null");
} }
private void assertAliasSupportInChoices(boolean methodSupportAliases) { private void assertAliasSupportInChoices(boolean methodSupportAliases) {
@ -2167,7 +2167,7 @@ public class TestPlayer implements Player {
} }
// ignore player select // 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); return computerPlayer.choose(outcome, target, source, game, options);
} }
@ -2317,7 +2317,7 @@ public class TestPlayer implements Player {
// apply only on ALL targets or revert // apply only on ALL targets or revert
if (usedChoices.size() > 0) { if (usedChoices.size() > 0) {
if (target.isChosen()) { if (target.isChosen(game)) {
// remove all used choices // remove all used choices
for (int i = choices.size(); i >= 0; i--) { for (int i = choices.size(); i >= 0; i--) {
if (usedChoices.contains(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); 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" message = this.getName() + " - Targets list was setup by addTarget with " + targets + ", but not used"
+ "\nCard: " + source.getSourceObject(game) + "\nCard: " + source.getSourceObject(game)
+ "\nAbility: " + source.getClass().getSimpleName() + " (" + source.getRule() + ")" + "\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"; + "\nYou must implement target class support in TestPlayer, \"filter instanceof\", or setup good targets";
} else { } else {
message = this.getName() + " - Targets list was setup by addTarget with " + targets + ", but not used" message = this.getName() + " - Targets list was setup by addTarget with " + targets + ", but not used"
+ "\nCard: unknown source" + "\nCard: unknown source"
+ "\nAbility: 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"; + "\nYou must implement target class support in TestPlayer, \"filter instanceof\", or setup good targets";
} }
Assert.fail(message); 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); return computerPlayer.chooseTarget(outcome, target, source, game);
} }
@ -2748,7 +2748,7 @@ public class TestPlayer implements Player {
LOGGER.warn("Wrong target"); 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); 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"); 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); 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); return computerPlayer.chooseTargetAmount(outcome, target, source, game);
} }

View file

@ -67,7 +67,7 @@ public class CollectEvidenceCost extends CostImpl {
// TODO: require target to have minimum selected total mana value (requires refactor) // TODO: require target to have minimum selected total mana value (requires refactor)
Target target = new TargetCardInYourGraveyard(1, Integer.MAX_VALUE) { Target target = new TargetCardInYourGraveyard(1, Integer.MAX_VALUE) {
@Override @Override
public String getMessage() { public String getMessage(Game game) {
// shows selected mana value // shows selected mana value
int totalMV = this int totalMV = this
.getTargets() .getTargets()
@ -76,7 +76,7 @@ public class CollectEvidenceCost extends CostImpl {
.filter(Objects::nonNull) .filter(Objects::nonNull)
.mapToInt(MageObject::getManaValue) .mapToInt(MageObject::getManaValue)
.sum(); .sum();
return super.getMessage() + HintUtils.prepareText( return super.getMessage(game) + HintUtils.prepareText(
" (selected mana value " + totalMV + " of " + amount + ")", " (selected mana value " + totalMV + " of " + amount + ")",
totalMV >= amount ? Color.GREEN : Color.RED totalMV >= amount ? Color.GREEN : Color.RED
); );

View file

@ -31,7 +31,7 @@ public class ExileTargetCost extends CostImpl {
this.text = "exile " + target.getDescription(); this.text = "exile " + target.getDescription();
} }
public ExileTargetCost(ExileTargetCost cost) { protected ExileTargetCost(ExileTargetCost cost) {
super(cost); super(cost);
for (Permanent permanent : cost.permanents) { for (Permanent permanent : cost.permanents) {
this.permanents.add(permanent.copy()); this.permanents.add(permanent.copy());

View file

@ -75,7 +75,7 @@ public class RollPlanarDieEffect extends OneShotEffect {
} }
boolean done = false; boolean done = false;
while (controller.canRespond() && effect != null && !done) { 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); controller.chooseTarget(Outcome.Benefit, target, source, game);
source.addTarget(target); source.addTarget(target);
} }

View file

@ -27,6 +27,7 @@ public class SacrificeAllEffect extends OneShotEffect {
/** /**
* Each player sacrifices a permanent * Each player sacrifices a permanent
*
* @param filter can be generic, will automatically add article and necessary sacrifice predicates * @param filter can be generic, will automatically add article and necessary sacrifice predicates
*/ */
public SacrificeAllEffect(FilterPermanent filter) { public SacrificeAllEffect(FilterPermanent filter) {
@ -35,6 +36,7 @@ public class SacrificeAllEffect extends OneShotEffect {
/** /**
* Each player sacrifices N permanents * Each player sacrifices N permanents
*
* @param filter can be generic, will automatically add necessary sacrifice predicates * @param filter can be generic, will automatically add necessary sacrifice predicates
*/ */
public SacrificeAllEffect(int amount, FilterPermanent filter) { public SacrificeAllEffect(int amount, FilterPermanent filter) {
@ -43,6 +45,7 @@ public class SacrificeAllEffect extends OneShotEffect {
/** /**
* Each player sacrifices X permanents * Each player sacrifices X permanents
*
* @param filter can be generic, will automatically add necessary sacrifice predicates * @param filter can be generic, will automatically add necessary sacrifice predicates
*/ */
public SacrificeAllEffect(DynamicValue amount, FilterPermanent filter) { public SacrificeAllEffect(DynamicValue amount, FilterPermanent filter) {
@ -91,7 +94,7 @@ public class SacrificeAllEffect extends OneShotEffect {
continue; continue;
} }
TargetSacrifice target = new TargetSacrifice(numTargets, filter); 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
perms.addAll(target.getTargets()); perms.addAll(target.getTargets());

View file

@ -64,7 +64,7 @@ public class SacrificeEffect extends OneShotEffect {
continue; continue;
} }
TargetSacrifice target = new TargetSacrifice(amount, filter); 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); player.choose(Outcome.Sacrifice, target, source, game);
} }
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {

View file

@ -151,7 +151,7 @@ class CrewCost extends CostImpl {
} }
Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) { Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) {
@Override @Override
public String getMessage() { public String getMessage(Game game) {
// shows selected power // shows selected power
int selectedPower = this.targets.keySet().stream() int selectedPower = this.targets.keySet().stream()
.map(game::getPermanent) .map(game::getPermanent)
@ -162,7 +162,7 @@ class CrewCost extends CostImpl {
if (selectedPower >= value) { if (selectedPower >= value) {
extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN); extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN);
} }
return super.getMessage() + " " + extraInfo; return super.getMessage(game) + " " + extraInfo;
} }
}; };

View file

@ -32,10 +32,14 @@ public class EscapeAbility extends SpellAbility {
private final String staticText; private final String staticText;
public EscapeAbility(Card card, String manaCost, int exileCount) { 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<Cost> additionalCosts) { public EscapeAbility(Card card, String manaCost, Costs<Cost> additionalCost) {
this(card, manaCost, additionalCost, 0);
}
public EscapeAbility(Card card, String manaCost, Costs<Cost> additionalCosts, int exileCount) {
super(card.getSpellAbility()); super(card.getSpellAbility());
this.newId(); this.newId();
this.setCardName(card.getName() + " with Escape"); this.setCardName(card.getName() + " with Escape");
@ -45,17 +49,22 @@ public class EscapeAbility extends SpellAbility {
this.clearManaCosts(); this.clearManaCosts();
this.clearManaCostsToPay(); this.clearManaCostsToPay();
String text = "Escape&mdash;" + manaCost;
this.addCost(new ManaCostsImpl<>(manaCost)); this.addCost(new ManaCostsImpl<>(manaCost));
for (Cost cost : additionalCosts) { for (Cost cost : additionalCosts) {
text += ", " + CardUtil.getTextWithFirstCharUpperCase(cost.getText());
this.addCost(cost.copy().setText("")); // hide additional cost text from rules 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." String text = "Escape&mdash;" + manaCost;
+ " <i>(You may cast this card from your graveyard for its escape cost.)</i>"; for (Cost cost : additionalCosts) {
this.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(exileCount, filter), "")); // hide additional cost text from rules text += ", " + CardUtil.getTextWithFirstCharUpperCase(cost.getText());
}
if (exileCount > 0) {
text += ", Exile " + CardUtil.numberToText(exileCount) + " other cards from your graveyard";
}
text += ". <i>(You may cast this card from your graveyard for its escape cost.)</i>";
this.staticText = text; this.staticText = text;
} }

View file

@ -177,7 +177,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
&& player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + '?', source, game)) { && player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + '?', source, game)) {
Target target = new TargetSacrifice(filter); Target target = new TargetSacrifice(filter);
player.choose(Outcome.Sacrifice, target, source, game); player.choose(Outcome.Sacrifice, target, source, game);
if (!target.isChosen()) { if (!target.isChosen(game)) {
return false; return false;
} }
game.getState().setValue("offering_" + card.getId(), true); game.getState().setValue("offering_" + card.getId(), true);

View file

@ -113,7 +113,7 @@ class SaddleCost extends CostImpl {
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { 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) { Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) {
@Override @Override
public String getMessage() { public String getMessage(Game game) {
// shows selected power // shows selected power
int selectedPower = this.targets.keySet().stream() int selectedPower = this.targets.keySet().stream()
.map(game::getPermanent) .map(game::getPermanent)
@ -125,7 +125,7 @@ class SaddleCost extends CostImpl {
if (selectedPower >= value) { if (selectedPower >= value) {
extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN); extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN);
} }
return super.getMessage() + " " + extraInfo; return super.getMessage(game) + " " + extraInfo;
} }
}; };

View file

@ -4349,14 +4349,14 @@ public abstract class PlayerImpl implements Player, Serializable {
List<Ability> options = new ArrayList<>(); List<Ability> options = new ArrayList<>();
if (ability.isModal()) { if (ability.isModal()) {
addModeOptions(options, ability, game); 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 // TODO: Handle other variable costs than mana costs
if (!ability.getManaCosts().getVariableCosts().isEmpty()) { if (!ability.getManaCosts().getVariableCosts().isEmpty()) {
addVariableXOptions(options, ability, 0, game); addVariableXOptions(options, ability, 0, game);
} else { } else {
addTargetOptions(options, ability, 0, game); 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); addCostTargetOptions(options, ability, 0, game);
} }
@ -4371,13 +4371,13 @@ public abstract class PlayerImpl implements Player, Serializable {
newOption.getModes().clearSelectedModes(); newOption.getModes().clearSelectedModes();
newOption.getModes().addSelectedMode(mode.getId()); newOption.getModes().addSelectedMode(mode.getId());
newOption.getModes().setActiveMode(mode); newOption.getModes().setActiveMode(mode);
if (!newOption.getTargets().getUnchosen().isEmpty()) { if (!newOption.getTargets().getUnchosen(game).isEmpty()) {
if (!newOption.getManaCosts().getVariableCosts().isEmpty()) { if (!newOption.getManaCosts().getVariableCosts().isEmpty()) {
addVariableXOptions(options, newOption, 0, game); addVariableXOptions(options, newOption, 0, game);
} else { } else {
addTargetOptions(options, newOption, 0, game); 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); addCostTargetOptions(options, newOption, 0, game);
} else { } else {
options.add(newOption); options.add(newOption);
@ -4390,7 +4390,7 @@ public abstract class PlayerImpl implements Player, Serializable {
} }
protected void addTargetOptions(List<Ability> options, Ability option, int targetNum, Game game) { protected void addTargetOptions(List<Ability> 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(); Ability newOption = option.copy();
if (target instanceof TargetAmount) { if (target instanceof TargetAmount) {
for (UUID targetId : target.getTargets()) { for (UUID targetId : target.getTargets()) {

View file

@ -19,9 +19,9 @@ import java.util.UUID;
*/ */
public interface Target extends Serializable { public interface Target extends Serializable {
boolean isChosen(); boolean isChosen(Game game);
boolean doneChoosing(); boolean doneChoosing(Game game);
void clearChosen(); void clearChosen();
@ -98,7 +98,10 @@ public interface Target extends Serializable {
*/ */
String getDescription(); 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 * @return single target name

View file

@ -44,12 +44,12 @@ public abstract class TargetAmount extends TargetImpl {
} }
@Override @Override
public boolean isChosen() { public boolean isChosen(Game game) {
return doneChoosing(); return doneChoosing(game);
} }
@Override @Override
public boolean doneChoosing() { public boolean doneChoosing(Game game) {
return amountWasSet return amountWasSet
&& (remainingAmount == 0 && (remainingAmount == 0
|| (getMinNumberOfTargets() < getMaxNumberOfTargets() || (getMinNumberOfTargets() < getMaxNumberOfTargets()
@ -104,7 +104,7 @@ public abstract class TargetAmount extends TargetImpl {
if (!amountWasSet) { if (!amountWasSet) {
setAmount(source, game); setAmount(source, game);
} }
chosen = isChosen(); chosen = isChosen(game);
while (remainingAmount > 0) { while (remainingAmount > 0) {
if (!player.canRespond()) { if (!player.canRespond()) {
return chosen; return chosen;
@ -112,7 +112,7 @@ public abstract class TargetAmount extends TargetImpl {
if (!getTargetController(game, playerId).chooseTargetAmount(outcome, this, source, game)) { if (!getTargetController(game, playerId).chooseTargetAmount(outcome, this, source, game)) {
return chosen; return chosen;
} }
chosen = isChosen(); chosen = isChosen(game);
} }
return chosen; return chosen;
} }

View file

@ -143,7 +143,7 @@ public abstract class TargetImpl implements Target {
} }
@Override @Override
public String getMessage() { public String getMessage(Game game) {
// UI choose message // UI choose message
String suffix = ""; String suffix = "";
if (this.chooseHint != null) { if (this.chooseHint != null) {
@ -215,7 +215,7 @@ public abstract class TargetImpl implements Target {
} }
@Override @Override
public boolean isChosen() { public boolean isChosen(Game game) {
if (getMaxNumberOfTargets() == 0 && getNumberOfTargets() == 0) { if (getMaxNumberOfTargets() == 0 && getNumberOfTargets() == 0) {
return true; return true;
} }
@ -223,7 +223,7 @@ public abstract class TargetImpl implements Target {
} }
@Override @Override
public boolean doneChoosing() { public boolean doneChoosing(Game game) {
return getMaxNumberOfTargets() != 0 && targets.size() == getMaxNumberOfTargets(); return getMaxNumberOfTargets() != 0 && targets.size() == getMaxNumberOfTargets();
} }
@ -332,7 +332,7 @@ public abstract class TargetImpl implements Target {
return chosen; return chosen;
} }
chosen = targets.size() >= getNumberOfTargets(); chosen = targets.size() >= getNumberOfTargets();
} while (!isChosen() && !doneChoosing()); } while (!isChosen(game) && !doneChoosing(game));
return chosen; return chosen;
} }
@ -375,7 +375,7 @@ public abstract class TargetImpl implements Target {
} }
} }
chosen = targets.size() >= getNumberOfTargets(); chosen = targets.size() >= getNumberOfTargets();
} while (!isChosen() && !doneChoosing()); } while (!isChosen(game) && !doneChoosing(game));
return chosen; return chosen;
} }

View file

@ -37,8 +37,8 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
return this; return this;
} }
public List<Target> getUnchosen() { public List<Target> getUnchosen(Game game) {
return stream().filter(target -> !target.isChosen()).collect(Collectors.toList()); return stream().filter(target -> !target.isChosen(game)).collect(Collectors.toList());
} }
public void clearChosen() { public void clearChosen() {
@ -47,8 +47,8 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
} }
} }
public boolean isChosen() { public boolean isChosen(Game game) {
return stream().allMatch(Target::isChosen); return stream().allMatch(t -> t.isChosen(game));
} }
public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game) { public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game) {
@ -56,8 +56,8 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
if (!canChoose(playerId, source, game)) { if (!canChoose(playerId, source, game)) {
return false; return false;
} }
while (!isChosen()) { while (!isChosen(game)) {
Target target = this.getUnchosen().get(0); Target target = this.getUnchosen(game).get(0);
if (!target.choose(outcome, playerId, sourceId, source, game)) { if (!target.choose(outcome, playerId, sourceId, source, game)) {
return false; return false;
} }
@ -73,8 +73,8 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
} }
//int state = game.bookmarkState(); //int state = game.bookmarkState();
while (!isChosen()) { while (!isChosen(game)) {
Target target = this.getUnchosen().get(0); Target target = this.getUnchosen(game).get(0);
UUID targetController = playerId; UUID targetController = playerId;
// some targets can have controller different than ability controller // some targets can have controller different than ability controller
@ -97,7 +97,7 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
return false; return false;
} }
// Check if there are some rules for targets are violated, if so reset the targets and start again // 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.replaceEvent(new GameEvent(GameEvent.EventType.TARGETS_VALID, source.getSourceId(), source, source.getControllerId()), source)) {
//game.restoreState(state, "Targets"); //game.restoreState(state, "Targets");
clearChosen(); clearChosen();

View file

@ -85,7 +85,7 @@ public class TargetCardInLibrary extends TargetCard {
return chosen; return chosen;
} }
chosen = targets.size() >= getMinNumberOfTargets(); chosen = targets.size() >= getMinNumberOfTargets();
} while (!isChosen() && !doneChoosing()); } while (!isChosen(game) && !doneChoosing(game));
return chosen; return chosen;
} }