diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 0adecfe96e8..d15b7bf311b 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -496,6 +496,24 @@ public class PlayerControllerAi extends PlayerController { } } + /* + * (non-Javadoc) + * + * @see + * forge.game.player.PlayerController#chooseBinary(forge.game.spellability. + * SpellAbility, java.lang.String, + * forge.game.player.PlayerController.BinaryChoiceType, java.util.Map) + */ + @Override + public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, + Map params) { + ApiType api = sa.getApi(); + if (null == api) { + throw new InvalidParameterException("SA is not api-based, this is not supported yet"); + } + return SpellApiToAi.Converter.get(api).chooseBinary(kindOfChoice, sa, params); + } + @Override public Card chooseProtectionShield(GameEntity entityBeingDamaged, List options, Map choiceMap) { int i = MyRandom.getRandom().nextInt(options.size()); @@ -521,46 +539,6 @@ public class PlayerControllerAi extends PlayerController { } return sa.getChosenList(); } - - @Override - public Pair chooseAndRemoveOrPutCounter(Card cardWithCounter) { - if (!cardWithCounter.hasCounters()) { - System.out.println("chooseCounterType was reached with a card with no counters on it. Consider filtering this card out earlier"); - return null; - } - - final Player controller = cardWithCounter.getController(); - final List enemies = player.getOpponents(); - final List allies = player.getAllies(); - allies.add(player); - - List countersToIncrease = new ArrayList(); - List countersToDecrease = new ArrayList(); - - for (final CounterType counter : cardWithCounter.getCounters().keySet()) { - if ((!ComputerUtil.isNegativeCounter(counter, cardWithCounter) && allies.contains(controller)) - || (ComputerUtil.isNegativeCounter(counter, cardWithCounter) && enemies.contains(controller))) { - countersToIncrease.add(counter); - } else { - countersToDecrease.add(counter); - } - } - - if (!countersToIncrease.isEmpty()) { - int random = MyRandom.getRandom().nextInt(countersToIncrease.size()); - return new ImmutablePair(countersToIncrease.get(random),"Put"); - } - else if (!countersToDecrease.isEmpty()) { - int random = MyRandom.getRandom().nextInt(countersToDecrease.size()); - return new ImmutablePair(countersToDecrease.get(random),"Remove"); - } - - // shouldn't reach here but just in case, remove random counter - List countersOnCard = new ArrayList(); - int random = MyRandom.getRandom().nextInt(countersOnCard.size()); - return new ImmutablePair(countersOnCard.get(random),"Remove"); - } - @Override public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) { diff --git a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java index b9139eca9f1..c9b3636acd0 100644 --- a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java @@ -16,6 +16,7 @@ import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; +import forge.game.player.PlayerController.BinaryChoiceType; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.util.MyRandom; @@ -329,4 +330,8 @@ public abstract class SpellAbilityAi { public CounterType chooseCounterType(List options, SpellAbility sa, Map params) { return Iterables.getFirst(options, null); } + + public boolean chooseBinary(BinaryChoiceType kindOfChoice, SpellAbility sa, Map params) { + return MyRandom.getRandom().nextBoolean(); + } } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java index 6544eabf646..28fb39547d2 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java @@ -17,17 +17,24 @@ */ package forge.ai.ability; -import com.google.common.base.Predicate; +import java.util.List; +import java.util.Map; + +import forge.ai.ComputerUtil; +import forge.ai.ComputerUtilCard; import forge.ai.SpellAbilityAi; +import forge.game.Game; +import forge.game.GlobalRuleChange; import forge.game.card.Card; +import forge.game.card.CardCollection; +import forge.game.card.CardCollectionView; import forge.game.card.CardLists; +import forge.game.card.CardPredicates; +import forge.game.card.CounterType; import forge.game.player.Player; +import forge.game.player.PlayerController.BinaryChoiceType; import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetRestrictions; -import forge.game.zone.ZoneType; -import forge.util.MyRandom; - -import java.util.List; /** *

@@ -39,54 +46,252 @@ import java.util.List; */ public class CountersPutOrRemoveAi extends SpellAbilityAi { + /* + * (non-Javadoc) + * + * @see forge.ai.SpellAbilityAi#checkApiLogic(forge.game.player.Player, + * forge.game.spellability.SpellAbility) + */ @Override - protected boolean canPlayAI(Player ai, SpellAbility sa) { - return doTriggerAINoCost(ai, sa, false); + protected boolean checkApiLogic(Player ai, SpellAbility sa) { + if (sa.usesTargeting()) { + return doTgt(ai, sa, false); + } + return super.checkApiLogic(ai, sa); + } + + private boolean doTgt(Player ai, SpellAbility sa, boolean mandatory) { + final Card source = sa.getHostCard(); + final Game game = ai.getGame(); + + final int amount = Integer.valueOf(sa.getParam("CounterNum")); + + // remove counter with Time might use Exile Zone too + final TargetRestrictions tgt = sa.getTargetRestrictions(); + // need to targetable + CardCollection list = CardLists.getTargetableCards(game.getCardsIn(tgt.getZone()), sa); + + if (list.isEmpty()) { + return false; + } + + if (sa.hasParam("AITgts")) { + String aiTgts = sa.getParam("AITgts"); + CardCollection prefList = CardLists.getValidCards(list, aiTgts.split(","), ai, source, sa); + if (!prefList.isEmpty() || sa.hasParam("AITgtsStrict")) { + list = prefList; + } + } + + if (sa.hasParam("CounterType")) { + // currently only Jhoira's Timebug + final CounterType type = CounterType.valueOf(sa.getParam("CounterType")); + + CardCollection countersList = CardLists.filter(list, CardPredicates.hasCounter(type, amount)); + + if (countersList.isEmpty()) { + return false; + } + + // currently can only target cards you control or you own + final Card best = ComputerUtilCard.getBestAI(countersList); + + // currently both cards only has one target + sa.getTargets().add(best); + return true; + } else { + // currently only Clockspinning + boolean noLegendary = game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule); + + // logic to remove some counter + CardCollection countersList = CardLists.filter(list, CardPredicates.hasCounters()); + + if (!countersList.isEmpty()) { + + if (!ai.isCardInPlay("Marit Lage") || noLegendary) { + CardCollectionView depthsList = CardLists.filter(countersList, + CardPredicates.nameEquals("Dark Depths"), CardPredicates.hasCounter(CounterType.ICE)); + + if (!depthsList.isEmpty()) { + sa.getTargets().add(depthsList.getFirst()); + return true; + } + } + + // Get rid of Planeswalkers, currently only if it can kill them + // with one touch + CardCollection planeswalkerList = CardLists.filter( + CardLists.filterControlledBy(countersList, ai.getOpponents()), + CardPredicates.Presets.PLANEWALKERS, + CardPredicates.hasLessCounter(CounterType.LOYALTY, amount)); + + if (!planeswalkerList.isEmpty()) { + sa.getTargets().add(ComputerUtilCard.getBestPlaneswalkerAI(planeswalkerList)); + return true; + } + + // do as M1M1 part + CardCollection aiList = CardLists.filterControlledBy(countersList, ai); + + CardCollection aiM1M1List = CardLists.filter(aiList, CardPredicates.hasCounter(CounterType.M1M1)); + + CardCollection aiPersistList = CardLists.getKeyword(aiM1M1List, "Persist"); + if (!aiPersistList.isEmpty()) { + aiM1M1List = aiPersistList; + } + + if (!aiM1M1List.isEmpty()) { + sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(aiM1M1List)); + return true; + } + + // do as P1P1 part + CardCollection aiP1P1List = CardLists.filter(aiList, CardPredicates.hasCounter(CounterType.P1P1)); + CardCollection aiUndyingList = CardLists.getKeyword(aiM1M1List, "Undying"); + + if (!aiUndyingList.isEmpty()) { + aiP1P1List = aiUndyingList; + } + if (!aiP1P1List.isEmpty()) { + sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(aiP1P1List)); + return true; + } + + // fallback to remove any counter from opponent + CardCollection oppList = CardLists.filterControlledBy(countersList, ai.getOpponents()); + oppList = CardLists.filter(oppList, CardPredicates.hasCounters()); + if (!oppList.isEmpty()) { + final Card best = ComputerUtilCard.getBestAI(oppList); + + for (final CounterType aType : best.getCounters().keySet()) { + if (!ComputerUtil.isNegativeCounter(aType, best)) { + sa.getTargets().add(best); + return true; + } else if (!ComputerUtil.isUselessCounter(aType)) { + // whould remove positive counter + if (best.getCounters(aType) <= amount) { + sa.getTargets().add(best); + return true; + } + } + } + } + } + } + + if (mandatory) { + sa.getTargets().add(ComputerUtilCard.getWorstAI(list)); + return true; + } + return false; } @Override protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); - // if Defined, don't worry about targeting + return doTgt(ai, sa, true); + } - List zones = ZoneType.listValueOf(sa.getParamOrDefault("TgtZones", "Battlefield")); - List validCards = CardLists.getValidCards(ai.getGame().getCardsIn(zones), - tgt.getValidTgts(), sa.getActivatingPlayer(), sa.getHostCard(), sa); + /* + * (non-Javadoc) + * + * @see forge.ai.SpellAbilityAi#chooseCounterType(java.util.List, + * forge.game.spellability.SpellAbility, java.util.Map) + */ + @Override + public CounterType chooseCounterType(List options, SpellAbility sa, Map params) { - if (validCards.isEmpty()) { - return false; - } + if (options.size() > 1) { + final Player ai = sa.getActivatingPlayer(); + final Game game = ai.getGame(); - List cWithCounters = CardLists.filter(validCards, new Predicate() { - @Override - public boolean apply(final Card crd) { - return crd.hasCounters(); + boolean noLegendary = game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule); + + Card tgt = (Card) params.get("Target"); + + // planeswalker has high priority for loyalty counters + if (tgt.isPlaneswalker() && options.contains(CounterType.LOYALTY)) { + return CounterType.LOYALTY; } - }); - if (cWithCounters.isEmpty()) { - if (mandatory) { - cWithCounters = validCards; + if (tgt.getController().isOpponentOf(ai)) { + // creatures with BaseToughness below or equal zero might be + // killed if their counters are removed + if (tgt.isCreature() && tgt.getBaseToughness() <= 0) { + if (options.contains(CounterType.P1P1)) { + return CounterType.P1P1; + } else if (options.contains(CounterType.M1M1)) { + return CounterType.M1M1; + } + } + + // fallback logic, select positive counter to remove it + for (final CounterType type : options) { + if (!ComputerUtil.isNegativeCounter(type, tgt)) { + return type; + } + } } else { - return false; + // this counters are treat first to be removed + if ("Dark Depths".equals(tgt.getName()) && options.contains(CounterType.ICE)) { + if (!ai.isCardInPlay("Marit Lage") || noLegendary) { + return CounterType.ICE; + } + } else if (tgt.hasKeyword("Undying") && options.contains(CounterType.P1P1)) { + return CounterType.P1P1; + } else if (tgt.hasKeyword("Persist") && options.contains(CounterType.M1M1)) { + return CounterType.M1M1; + } + + // fallback logic, select positive counter to add more + for (final CounterType type : options) { + if (!ComputerUtil.isNegativeCounter(type, tgt)) { + return type; + } + } } } - while (sa.getTargets().getNumTargeted() < tgt.getMaxTargets(sa.getHostCard(), sa)) { - Card targetCard = null; - if (cWithCounters.isEmpty() && ((sa.getTargets().getNumTargeted() < tgt.getMinTargets(sa.getHostCard(), sa)) - || (sa.getTargets().getNumTargeted() == 0))) { - sa.resetTargets(); - return false; - } - - int random = MyRandom.getRandom().nextInt(cWithCounters.size()); - targetCard = cWithCounters.get(random); + return super.chooseCounterType(options, sa, params); + } - sa.getTargets().add(targetCard); - cWithCounters.remove(targetCard); + /* + * (non-Javadoc) + * + * @see + * forge.ai.SpellAbilityAi#chooseBinary(forge.game.player.PlayerController. + * BinaryChoiceType, forge.game.spellability.SpellAbility, java.util.Map) + */ + @Override + public boolean chooseBinary(BinaryChoiceType kindOfChoice, SpellAbility sa, Map params) { + if (kindOfChoice.equals(BinaryChoiceType.AddOrRemove)) { + final Player ai = sa.getActivatingPlayer(); + final Game game = ai.getGame(); + Card tgt = (Card) params.get("Target"); + CounterType type = (CounterType) params.get("CounterType"); + + boolean noLegendary = game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule); + + if (tgt.getController().isOpponentOf(ai)) { + if (type.equals(CounterType.LOYALTY) && tgt.isPlaneswalker()) { + return false; + } + + return ComputerUtil.isNegativeCounter(type, tgt); + } else { + if (type.equals(CounterType.ICE) && "Dark Depths".equals(tgt.getName())) { + if (!ai.isCardInPlay("Marit Lage") || noLegendary) { + return false; + } + } else if (type.equals(CounterType.M1M1) && tgt.hasKeyword("Persist")) { + return false; + } else if (type.equals(CounterType.P1P1) && tgt.hasKeyword("Undying")) { + return false; + } + + return !ComputerUtil.isNegativeCounter(type, tgt); + } } - return true; + return super.chooseBinary(kindOfChoice, sa, params); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java index 00084e686d1..c896d1ed8b0 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java @@ -1,18 +1,22 @@ package forge.game.ability.effects; -import forge.game.GameObject; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CounterType; import forge.game.player.Player; +import forge.game.player.PlayerController; +import forge.game.player.PlayerController.BinaryChoiceType; import forge.game.spellability.SpellAbility; import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.util.Lang; -import org.apache.commons.lang3.tuple.Pair; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import java.util.List; +import java.util.Map; /** * API for adding to or subtracting from existing counters on a target. @@ -23,10 +27,16 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect { protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); sb.append(sa.getActivatingPlayer().getName()); - sb.append(" removes a counter from or puts another of those counters on "); - final List targets = getTargets(sa); - sb.append(Lang.joinHomogenous(targets)); + if (sa.hasParam("CounterType")) { + CounterType ctype = CounterType.valueOf(sa.getParam("CounterType")); + sb.append(" removes a ").append(ctype.getName()); + sb.append(" counter from or put another ").append(ctype.getName()).append(" counter on "); + } else { + sb.append(" removes a counter from or puts another of those counters on "); + } + + sb.append(Lang.joinHomogenous(getTargets(sa))); return sb.toString(); } @@ -34,28 +44,47 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final Player activator = sa.getActivatingPlayer(); - final int counterAmount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("CounterNum"), sa); + final Card source = sa.getHostCard(); + final int counterAmount = AbilityUtils.calculateAmount(source, sa.getParam("CounterNum"), sa); + + CounterType ctype = null; + if (sa.hasParam("CounterType")) { + ctype = CounterType.valueOf(sa.getParam("CounterType")); + } + + PlayerController pc = activator.getController(); - List tgtCards = getDefinedCardsOrTargeted(sa); - - for (final Card tgtCard : tgtCards) { + for (final Card tgtCard : getDefinedCardsOrTargeted(sa)) { if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) { if (tgtCard.hasCounters()) { - Pair selection = activator.getController().chooseAndRemoveOrPutCounter(tgtCard); - final CounterType chosenCounter = selection.getLeft(); - final boolean putCounter = selection.getRight().startsWith("Put"); + + final Map tgtCounters = tgtCard.getCounters(); + Map params = Maps.newHashMap(); + params.put("Target", tgtCard); + + List list = Lists.newArrayList(tgtCounters.keySet()); + if (ctype != null) { + list = Lists.newArrayList(ctype); + } + + String prompt = "Select type of counters to add or remove"; + CounterType chosenType = pc.chooseCounterType(list, sa, prompt, params); + + params.put("CounterType", chosenType); + prompt = "What to do with that '" + chosenType.getName() + "' counter "; + Boolean putCounter = pc.chooseBinary(sa, prompt, BinaryChoiceType.AddOrRemove, params); if (putCounter) { // Put another of the chosen counter on card final Zone zone = tgtCard.getGame().getZoneOf(tgtCard); if (zone == null || zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack)) { - tgtCard.addCounter(chosenCounter, counterAmount, true); + tgtCard.addCounter(chosenType, counterAmount, true); } else { // adding counters to something like re-suspend cards - tgtCard.addCounter(chosenCounter, counterAmount, false); + tgtCard.addCounter(chosenType, counterAmount, false); } } else { - tgtCard.subtractCounter(chosenCounter, counterAmount); + tgtCard.subtractCounter(chosenType, counterAmount); } } } diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java index 4178d7d1d41..352a7cde0be 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -38,7 +38,6 @@ import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetChoices; -import forge.game.trigger.Trigger; import forge.game.trigger.WrappedAbility; import forge.game.zone.ZoneType; import forge.item.PaperCard; @@ -69,6 +68,7 @@ public abstract class PlayerController { UntapOrLeaveTapped, UntapTimeVault, LeftOrRight, + AddOrRemove, } protected final Game game; @@ -164,7 +164,6 @@ public abstract class PlayerController { } public abstract Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes); - public abstract Pair chooseAndRemoveOrPutCounter(Card cardWithCounter); public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question); public abstract CardCollectionView getCardsToMulligan(Player firstPlayer); @@ -182,8 +181,10 @@ public abstract class PlayerController { return chooseNumber(sa, string, min, max); }; - public final boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice) { return chooseBinary(sa, question, kindOfChoice, null); } + public final boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice) { return chooseBinary(sa, question, kindOfChoice, (Boolean) null); } public abstract boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Boolean defaultChioce); + public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Map params) { return chooseBinary(sa, question, kindOfChoice); } + public abstract boolean chooseFlipResult(SpellAbility sa, Player flipper, boolean[] results, boolean call); public abstract Card chooseProtectionShield(GameEntity entityBeingDamaged, List options, Map choiceMap); diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index 10bf4db847a..1575798bbec 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -57,7 +57,6 @@ import forge.game.spellability.Spell; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetChoices; -import forge.game.trigger.Trigger; import forge.game.trigger.WrappedAbility; import forge.game.zone.ZoneType; import forge.gamesimulationtests.util.card.CardSpecification; @@ -294,11 +293,6 @@ public class PlayerControllerForTests extends PlayerController { return chooseItem(manaChoices); } - @Override - public Pair chooseAndRemoveOrPutCounter(Card cardWithCounter) { - throw new IllegalStateException("Erring on the side of caution here..."); - } - @Override public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question) { return true; diff --git a/forge-gui/res/cardsfolder/j/jhoiras_timebug.txt b/forge-gui/res/cardsfolder/j/jhoiras_timebug.txt index fba5a9580e1..acfb3595c61 100644 --- a/forge-gui/res/cardsfolder/j/jhoiras_timebug.txt +++ b/forge-gui/res/cardsfolder/j/jhoiras_timebug.txt @@ -2,9 +2,7 @@ Name:Jhoira's Timebug ManaCost:2 Types:Artifact Creature Insect PT:1/2 -A:AB$ GenericChoice | Cost$ T | ValidTgts$ Permanent.inZoneBattlefield+YouCtrl,Card.suspended+YouOwn | TgtPrompt$ Choose target permanent you control or suspended card you own | Defined$ You | Choices$ LoseTime,AddTime | TgtZone$ Battlefield,Exile | ConditionDefined$ Targeted | ConditionPresent$ Card.counters_GE1_TIME | ConditionCompare$ GE1 | SpellDescription$ Choose target permanent you control or suspended card you own. If that permanent or card has a time counter on it, you may remove a time counter from it or put another time counter on it. -SVar:LoseTime:DB$ RemoveCounter | Defined$ Targeted | TgtPrompt$ Select target permanent or suspended card. | CounterType$ TIME | CounterNum$ 1 | SpellDescription$ Remove a time counter. -SVar:AddTime:DB$ PutCounter | Defined$ Targeted | TgtPrompt$ Select target permanent with a time counter on it or suspended card. | CounterType$ TIME | CounterNum$ 1 | TgtZone$ Battlefield,Exile | SpellDescription$ Add a time counter. -SVar:RemAIDeck:True +A:AB$ AddOrRemoveCounter | Cost$ T | CounterNum$ 1 | ValidTgts$ Permanent.inZoneBattlefield+YouCtrl,Card.suspended+YouOwn | TgtPrompt$ Choose target permanent you control or suspended card you own | TgtZone$ Battlefield,Exile | ConditionDefined$ Targeted | ConditionPresent$ Card.counters_GE1_TIME | SpellDescription$ Choose target permanent you control or suspended card you own. If that permanent or card has a time counter on it, you may remove a time counter from it or put another time counter on it. +DeckNeeds:Keyword$Suspend & Keyword$Vanishing SVar:Picture:http://www.wizards.com/global/images/magic/general/jhoiras_timebug.jpg Oracle:{T}: Choose target permanent you control or suspended card you own. If that permanent or card has a time counter on it, you may remove a time counter from it or put another time counter on it. diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index d15ca9fd52e..780c07226b5 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -1009,13 +1009,14 @@ public class PlayerControllerHuman public boolean chooseBinary(final SpellAbility sa, final String question, final BinaryChoiceType kindOfChoice, final Boolean defaultVal) { final List labels; switch (kindOfChoice) { - case HeadsOrTails: labels = ImmutableList.of("Heads", "Tails"); break; - case TapOrUntap: labels = ImmutableList.of("Tap", "Untap"); break; - case OddsOrEvens: labels = ImmutableList.of("Odds", "Evens"); break; - case UntapOrLeaveTapped: labels = ImmutableList.of("Untap", "Leave tapped"); break; - case UntapTimeVault: labels = ImmutableList.of("Untap (and skip this turn)", "Leave tapped"); break; - case PlayOrDraw: labels = ImmutableList.of("Play", "Draw"); break; - case LeftOrRight: labels = ImmutableList.of("Left", "Right"); break; + case HeadsOrTails: labels = ImmutableList.of("Heads", "Tails"); break; + case TapOrUntap: labels = ImmutableList.of("Tap", "Untap"); break; + case OddsOrEvens: labels = ImmutableList.of("Odds", "Evens"); break; + case UntapOrLeaveTapped: labels = ImmutableList.of("Untap", "Leave tapped"); break; + case UntapTimeVault: labels = ImmutableList.of("Untap (and skip this turn)", "Leave tapped"); break; + case PlayOrDraw: labels = ImmutableList.of("Play", "Draw"); break; + case LeftOrRight: labels = ImmutableList.of("Left", "Right"); break; + case AddOrRemove: labels = ImmutableList.of("Add Counter", "Remove Counter"); break; default: labels = ImmutableList.copyOf(kindOfChoice.toString().split("Or")); } @@ -1038,24 +1039,6 @@ public class PlayerControllerHuman return choiceMap.get(getGui().one(title, options)); } - @Override - public Pair chooseAndRemoveOrPutCounter(final Card cardWithCounter) { - if (!cardWithCounter.hasCounters()) { - System.out.println("chooseCounterType was reached with a card with no counters on it. Consider filtering this card out earlier"); - return null; - } - - final String counterChoiceTitle = "Choose a counter type on " + cardWithCounter; - final CounterType chosen = getGui().one(counterChoiceTitle, ImmutableList.copyOf(cardWithCounter.getCounters().keySet())); - - final String putOrRemoveTitle = "What to do with that '" + chosen.getName() + "' counter "; - final String putString = "Put another " + chosen.getName() + " counter on " + cardWithCounter; - final String removeString = "Remove a " + chosen.getName() + " counter from " + cardWithCounter; - final String addOrRemove = getGui().one(putOrRemoveTitle, ImmutableList.of(putString, removeString)); - - return new ImmutablePair(chosen,addOrRemove); - } - @Override public Pair chooseTarget(final SpellAbility saSpellskite, final List> allTargets) { if (allTargets.size() < 2) {