ChooseName now uses ICardFaces for selecting a CardName.

that now makes it working for naming an alternate state of a card.
This commit is contained in:
Hanmac
2016-08-18 08:29:11 +00:00
parent 157c20a82b
commit b65a16acf2
8 changed files with 463 additions and 350 deletions

View File

@@ -11,6 +11,7 @@ import forge.LobbyPlayer;
import forge.ai.ability.ChangeZoneAi; import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.ProtectAi; import forge.ai.ability.ProtectAi;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.ICardFace;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
@@ -577,8 +578,8 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public PaperCard chooseSinglePaperCard(SpellAbility sa, String message, public ICardFace chooseSingleCardFace(SpellAbility sa, String message,
Predicate<PaperCard> cpp, String name) { Predicate<ICardFace> cpp, String name) {
throw new UnsupportedOperationException("Should not be called for AI"); // or implement it if you know how throw new UnsupportedOperationException("Should not be called for AI"); // or implement it if you know how
} }
@@ -831,7 +832,7 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public String chooseCardName(SpellAbility sa, Predicate<PaperCard> cpp, String valid, String message) { public String chooseCardName(SpellAbility sa, Predicate<ICardFace> cpp, String valid, String message) {
if (sa.hasParam("AILogic")) { if (sa.hasParam("AILogic")) {
final String logic = sa.getParam("AILogic"); final String logic = sa.getParam("AILogic");
if (logic.equals("MostProminentInComputerDeck")) { if (logic.equals("MostProminentInComputerDeck")) {
@@ -850,7 +851,7 @@ public class PlayerControllerAi extends PlayerController {
return ComputerUtilCard.getMostProminentCardName(cards); return ComputerUtilCard.getMostProminentCardName(cards);
} }
} else { } else {
CardCollectionView list = CardLists.filterControlledBy(game.getCardsInGame(), player.getOpponent()); CardCollectionView list = CardLists.filterControlledBy(game.getCardsInGame(), player.getOpponents());
list = CardLists.filter(list, Predicates.not(Presets.LANDS)); list = CardLists.filter(list, Predicates.not(Presets.LANDS));
if (!list.isEmpty()) { if (!list.isEmpty()) {
return list.get(0).getName(); return list.get(0).getName();
@@ -889,4 +890,13 @@ public class PlayerControllerAi extends PlayerController {
public void cancelAwaitNextInput() { public void cancelAwaitNextInput() {
// Do nothing // Do nothing
} }
@Override
public String chooseCardName(SpellAbility sa, List<ICardFace> faces, String message) {
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).chooseCardName(player, sa, faces);
}
} }

View File

@@ -5,6 +5,7 @@ import java.util.List;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.card.ICardFace;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.cost.Cost; import forge.game.cost.Cost;
@@ -269,6 +270,13 @@ public abstract class SpellAbilityAi {
return Iterables.getFirst(options, null); return Iterables.getFirst(options, null);
} }
public String chooseCardName(Player ai, SpellAbility sa, List<ICardFace> faces) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseCardName is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
final ICardFace face = Iterables.getFirst(faces, null);
return face == null ? "" : face.getName();
}
protected static boolean isUselessCreature(Player ai, Card c) { protected static boolean isUselessCreature(Player ai, Card c) {
if (c == null) { if (c == null) {
return true; return true;

View File

@@ -1,14 +1,27 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.List;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.StaticData;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilMana; import forge.ai.ComputerUtilMana;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.card.CardDb;
import forge.card.CardRules;
import forge.card.CardSplitType;
import forge.card.CardStateName;
import forge.card.ICardFace;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardUtil;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.item.PaperCard;
public class ChooseCardNameAi extends SpellAbilityAi { public class ChooseCardNameAi extends SpellAbilityAi {
@@ -68,4 +81,42 @@ public class ChooseCardNameAi extends SpellAbilityAi {
return ComputerUtilCard.getBestAI(options); return ComputerUtilCard.getBestAI(options);
} }
@Override
public String chooseCardName(Player ai, SpellAbility sa, List<ICardFace> faces) {
// this function is only for "Alhammarret, High Arbiter"
if (faces.isEmpty()) {
return "";
} else if (faces.size() == 1) {
return Iterables.getFirst(faces, null).getName();
}
List<Card> cards = Lists.newArrayList();
final CardDb cardDb = StaticData.instance().getCommonCards();
for (ICardFace face : faces) {
final CardRules rules = cardDb.getRules(face.getName());
boolean isOther = rules.getOtherPart() == face;
final PaperCard paper = cardDb.getCard(rules.getName());
final Card card = Card.fromPaperCard(paper, ai);
if (rules.getSplitType() == CardSplitType.Split) {
Card copy = CardUtil.getLKICopy(card);
// for calcing i need only one split side
if (isOther) {
copy.getCurrentState().copyFrom(card, card.getState(CardStateName.RightSplit));
} else {
copy.getCurrentState().copyFrom(card, card.getState(CardStateName.LeftSplit));
}
copy.updateStateForView();
cards.add(copy);
} else if (!isOther) {
// other can't be cast that way, not need to prevent that
cards.add(card);
}
}
return ComputerUtilCard.getBestAI(cards).getName();
}
} }

View File

@@ -6,8 +6,11 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.StaticData; import forge.StaticData;
import forge.card.CardFacePredicates;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.CardRulesPredicates; import forge.card.CardRulesPredicates;
import forge.card.CardSplitType;
import forge.card.ICardFace;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -22,6 +25,8 @@ import forge.util.ComparableOp;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
public class ChooseCardNameEffect extends SpellAbilityEffect { public class ChooseCardNameEffect extends SpellAbilityEffect {
@@ -60,17 +65,18 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
if (randomChoice) { if (randomChoice) {
// Currently only used for Momir Avatar, if something else gets added here, make it more generic // Currently only used for Momir Avatar, if something else gets added here, make it more generic
Predicate<CardRules> baseRule = CardRulesPredicates.Presets.IS_CREATURE;
String numericAmount = "X"; String numericAmount = "X";
final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) : final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) :
AbilityUtils.calculateAmount(host, numericAmount, sa); AbilityUtils.calculateAmount(host, numericAmount, sa);
Predicate<CardRules> additionalRule = CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount); // Momir needs PaperCard
Collection<PaperCard> cards = StaticData.instance().getCommonCards().getUniqueCards();
Predicate<PaperCard> cpp = Predicates.and(
Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES),
Predicates.compose(CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount), PaperCard.FN_GET_RULES)
);
List<PaperCard> cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards());
Predicate<PaperCard> cpp = Predicates.and(Predicates.compose(baseRule, PaperCard.FN_GET_RULES),
Predicates.compose(additionalRule, PaperCard.FN_GET_RULES));
cards = Lists.newArrayList(Iterables.filter(cards, cpp)); cards = Lists.newArrayList(Iterables.filter(cards, cpp));
if (!cards.isEmpty()) { if (!cards.isEmpty()) {
chosen = Aggregates.random(cards).getName(); chosen = Aggregates.random(cards).getName();
@@ -80,25 +86,38 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
} else if (chooseFromDefined) { } else if (chooseFromDefined) {
CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa); CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa);
choices = CardLists.getValidCards(choices, valid, host.getController(), host); choices = CardLists.getValidCards(choices, valid, host.getController(), host);
Card c = p.getController().chooseSingleEntityForEffect(choices, sa, "Choose a card name"); List<ICardFace> faces = Lists.newArrayList();
chosen = c != null ? c.getName() : ""; // get Card
for (final Card c : choices) {
final CardRules rules = c.getRules();
if (faces.contains(rules.getMainPart()))
continue;
faces.add(rules.getMainPart());
// Alhammarret only allows Split for other faces
if (rules.getSplitType() == CardSplitType.Split) {
faces.add(rules.getOtherPart());
}
}
Collections.sort(faces);
chosen = p.getController().chooseCardName(sa, faces, "Choose a card name");
} else { } else {
// use CardFace because you might name a alternate name
final String message = validDesc.equals("card") ? "Name a card" : "Name a " + validDesc + " card."; final String message = validDesc.equals("card") ? "Name a card" : "Name a " + validDesc + " card.";
Predicate<PaperCard> cpp = Predicates.alwaysTrue(); Predicate<ICardFace> cpp = Predicates.alwaysTrue();
if ( StringUtils.containsIgnoreCase(valid, "nonland") ) { if ( StringUtils.containsIgnoreCase(valid, "nonland") ) {
cpp = Predicates.compose(CardRulesPredicates.Presets.IS_NON_LAND, PaperCard.FN_GET_RULES); cpp = CardFacePredicates.Presets.IS_NON_LAND;
} }
if ( StringUtils.containsIgnoreCase(valid, "nonbasic") ) { if ( StringUtils.containsIgnoreCase(valid, "nonbasic") ) {
cpp = Predicates.compose(Predicates.not(CardRulesPredicates.Presets.IS_BASIC_LAND), PaperCard.FN_GET_RULES); cpp = Predicates.not(CardFacePredicates.Presets.IS_BASIC_LAND);
} }
if ( StringUtils.containsIgnoreCase(valid, "noncreature") ) { if ( StringUtils.containsIgnoreCase(valid, "noncreature") ) {
cpp = Predicates.compose(Predicates.not(CardRulesPredicates.Presets.IS_CREATURE), PaperCard.FN_GET_RULES); cpp = Predicates.not(CardFacePredicates.Presets.IS_CREATURE);
} else if ( StringUtils.containsIgnoreCase(valid, "creature") ) { } else if ( StringUtils.containsIgnoreCase(valid, "creature") ) {
cpp = Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES); cpp = CardFacePredicates.Presets.IS_CREATURE;
} }
chosen = p.getController().chooseCardName(sa, cpp, valid, message); chosen = p.getController().chooseCardName(sa, cpp, valid, message);
} }

View File

@@ -38,6 +38,7 @@ import forge.GameCommand;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.card.CardType; import forge.card.CardType;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.ICardFace;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostParser;
@@ -74,7 +75,6 @@ import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler; import forge.game.trigger.TriggerHandler;
import forge.game.zone.Zone; import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.item.PaperCard;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import forge.util.Lang; import forge.util.Lang;
@@ -222,7 +222,7 @@ public class CardFactoryUtil {
public static boolean handleHiddenAgenda(Player player, Card card) { public static boolean handleHiddenAgenda(Player player, Card card) {
SpellAbility sa = new SpellAbility.EmptySa(card); SpellAbility sa = new SpellAbility.EmptySa(card);
sa.getMapParams().put("AILogic", card.getSVar("AgendaLogic")); sa.getMapParams().put("AILogic", card.getSVar("AgendaLogic"));
Predicate<PaperCard> cpp = Predicates.alwaysTrue(); Predicate<ICardFace> cpp = Predicates.alwaysTrue();
//Predicate<Card> pc = Predicates.in(player.getAllCards()); //Predicate<Card> pc = Predicates.in(player.getAllCards());
// TODO This would be better to send in the player's deck, not all cards // TODO This would be better to send in the player's deck, not all cards
String name = player.getController().chooseCardName(sa, cpp, "Card", "Name a card for " + card.getName()); String name = player.getController().chooseCardName(sa, cpp, "Card", "Name a card for " + card.getName());

View File

@@ -13,6 +13,7 @@ import com.google.common.collect.Multimap;
import forge.LobbyPlayer; import forge.LobbyPlayer;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.ICardFace;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
import forge.deck.Deck; import forge.deck.Deck;
@@ -189,15 +190,15 @@ public abstract class PlayerController {
public abstract byte chooseColor(String message, SpellAbility sa, ColorSet colors); public abstract byte chooseColor(String message, SpellAbility sa, ColorSet colors);
public abstract byte chooseColorAllowColorless(String message, Card c, ColorSet colors); public abstract byte chooseColorAllowColorless(String message, Card c, ColorSet colors);
public abstract PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate<PaperCard> cpp, String name); public abstract ICardFace chooseSingleCardFace(SpellAbility sa, String message, Predicate<ICardFace> cpp, String name);
public abstract List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options); public abstract List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options);
public abstract CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, String prompt); public abstract CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, String prompt);
public abstract boolean confirmPayment(CostPart costPart, String string); public abstract boolean confirmPayment(CostPart costPart, String string);
public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers, Map<String, Object> runParams); public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers, Map<String, Object> runParams);
public abstract String chooseProtectionType(String string, SpellAbility sa, List<String> choices); public abstract String chooseProtectionType(String string, SpellAbility sa, List<String> choices);
public abstract CardShields chooseRegenerationShield(Card c); public abstract CardShields chooseRegenerationShield(Card c);
// these 4 need some refining. // these 4 need some refining.
public abstract boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, FCollectionView<Player> allPayers); public abstract boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, FCollectionView<Player> allPayers);
public abstract void orderAndPlaySimultaneousSa(List<SpellAbility> activePlayerSAs); public abstract void orderAndPlaySimultaneousSa(List<SpellAbility> activePlayerSAs);
@@ -222,8 +223,9 @@ public abstract class PlayerController {
public abstract Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCreats); public abstract Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCreats);
public abstract String chooseCardName(SpellAbility sa, Predicate<PaperCard> cpp, String valid, String message); public abstract String chooseCardName(SpellAbility sa, Predicate<ICardFace> cpp, String valid, String message);
public abstract String chooseCardName(SpellAbility sa, List<ICardFace> faces, String message);
// better to have this odd method than those if playerType comparison in ChangeZone // better to have this odd method than those if playerType comparison in ChangeZone
public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional, Player decider); public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional, Player decider);

View File

@@ -22,6 +22,7 @@ import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.DrawAi; import forge.ai.ability.DrawAi;
import forge.ai.ability.GameWinAi; import forge.ai.ability.GameWinAi;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.ICardFace;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
@@ -82,117 +83,117 @@ import forge.util.MyRandom;
* Test cases that need to override the default behaviour of this class should make sure to do so in a way that does not invalidate their correctness. * Test cases that need to override the default behaviour of this class should make sure to do so in a way that does not invalidate their correctness.
*/ */
public class PlayerControllerForTests extends PlayerController { public class PlayerControllerForTests extends PlayerController {
private PlayerActions playerActions; private PlayerActions playerActions;
public PlayerControllerForTests(Game game, Player player, LobbyPlayer lobbyPlayer) { public PlayerControllerForTests(Game game, Player player, LobbyPlayer lobbyPlayer) {
super(game, player, lobbyPlayer); super(game, player, lobbyPlayer);
} }
public void setPlayerActions(PlayerActions playerActions) { public void setPlayerActions(PlayerActions playerActions) {
this.playerActions = playerActions; this.playerActions = playerActions;
} }
public PlayerActions getPlayerActions() { public PlayerActions getPlayerActions() {
return playerActions; return playerActions;
} }
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
public Game getGame() { public Game getGame() {
return game; return game;
} }
@Override @Override
public void playSpellAbilityForFree(SpellAbility copySA, boolean mayChoseNewTargets) { public void playSpellAbilityForFree(SpellAbility copySA, boolean mayChoseNewTargets) {
throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!"); throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!");
} }
@Override @Override
public void playSpellAbilityNoStack(SpellAbility effectSA, boolean mayChoseNewTargets) { public void playSpellAbilityNoStack(SpellAbility effectSA, boolean mayChoseNewTargets) {
//TODO: eventually (when the real code is refactored) this should be handled normally... //TODO: eventually (when the real code is refactored) this should be handled normally...
if (effectSA.getDescription().equals("At the beginning of your upkeep, if you have exactly 1 life, you win the game.")) {//test_104_2b_effect_may_state_that_player_wins_the_game if (effectSA.getDescription().equals("At the beginning of your upkeep, if you have exactly 1 life, you win the game.")) {//test_104_2b_effect_may_state_that_player_wins_the_game
HumanPlay.playSpellAbilityNoStack(null, player, effectSA, !mayChoseNewTargets); HumanPlay.playSpellAbilityNoStack(null, player, effectSA, !mayChoseNewTargets);
return; return;
} }
SpellAbilityAi sai = SpellApiToAi.Converter.get(effectSA.getApi()); SpellAbilityAi sai = SpellApiToAi.Converter.get(effectSA.getApi());
if ( if (
(effectSA.getHostCard().getName().equals("Nefarious Lich") && sai instanceof DrawAi) || (effectSA.getHostCard().getName().equals("Nefarious Lich") && sai instanceof DrawAi) ||
(effectSA.getHostCard().getName().equals("Laboratory Maniac") && sai instanceof GameWinAi) || (effectSA.getHostCard().getName().equals("Laboratory Maniac") && sai instanceof GameWinAi) ||
(effectSA.getHostCard().getName().equals("Nefarious Lich") && sai instanceof ChangeZoneAi) (effectSA.getHostCard().getName().equals("Nefarious Lich") && sai instanceof ChangeZoneAi)
) {//test_104_3f_if_a_player_would_win_and_lose_simultaneously_he_loses ) {//test_104_3f_if_a_player_would_win_and_lose_simultaneously_he_loses
HumanPlay.playSpellAbilityNoStack(null, player, effectSA, !mayChoseNewTargets); HumanPlay.playSpellAbilityNoStack(null, player, effectSA, !mayChoseNewTargets);
return; return;
} }
throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!"); throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!");
} }
@Override @Override
public List<PaperCard> sideboard(Deck deck, GameType gameType) { public List<PaperCard> sideboard(Deck deck, GameType gameType) {
return null; // refused to side return null; // refused to side
} }
@Override @Override
public Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, int damageDealt, GameEntity defender, boolean overrideOrder) { public Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, int damageDealt, GameEntity defender, boolean overrideOrder) {
if (blockers.size() == 1 && damageDealt == 2 && ( if (blockers.size() == 1 && damageDealt == 2 && (
(attacker.getName().equals("Grizzly Bears") && blockers.get(0).getName().equals("Ajani's Sunstriker")) || (attacker.getName().equals("Grizzly Bears") && blockers.get(0).getName().equals("Ajani's Sunstriker")) ||
(attacker.getName().equals("Ajani's Sunstriker") && blockers.get(0).getName().equals("Grizzly Bears")) (attacker.getName().equals("Ajani's Sunstriker") && blockers.get(0).getName().equals("Grizzly Bears"))
)) {//test_104_3b_player_with_less_than_zero_life_loses_the_game_only_when_a_player_receives_priority_variant_with_combat )) {//test_104_3b_player_with_less_than_zero_life_loses_the_game_only_when_a_player_receives_priority_variant_with_combat
Map<Card, Integer> result = new HashMap<Card, Integer>(); Map<Card, Integer> result = new HashMap<Card, Integer>();
result.put(blockers.get(0), damageDealt); result.put(blockers.get(0), damageDealt);
return result; return result;
} }
throw new IllegalStateException("Erring on the side of caution here..."); throw new IllegalStateException("Erring on the side of caution here...");
} }
@Override @Override
public Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero) { public Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero) {
throw new IllegalStateException("Erring on the side of caution here..."); throw new IllegalStateException("Erring on the side of caution here...");
} }
@Override @Override
public CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message) { public CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message) {
return chooseItems(validTargets, min); return chooseItems(validTargets, min);
} }
@Override @Override
public CardCollectionView choosePermanentsToDestroy(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message) { public CardCollectionView choosePermanentsToDestroy(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message) {
return chooseItems(validTargets, min); return chooseItems(validTargets, min);
} }
@Override @Override
public TargetChoices chooseNewTargetsFor(SpellAbility ability) { public TargetChoices chooseNewTargetsFor(SpellAbility ability) {
throw new IllegalStateException("Erring on the side of caution here..."); throw new IllegalStateException("Erring on the side of caution here...");
} }
@Override @Override
public Pair<SpellAbilityStackInstance, GameObject> chooseTarget(SpellAbility sa, List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) { public Pair<SpellAbilityStackInstance, GameObject> chooseTarget(SpellAbility sa, List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) {
return chooseItem(allTargets); return chooseItem(allTargets);
} }
@Override @Override
public CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title, int min, int max, boolean isOptional) { public CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title, int min, int max, boolean isOptional) {
return chooseItems(sourceList, max); return chooseItems(sourceList, max);
} }
@Override @Override
public <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) { public <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) {
if (delayedReveal != null) { if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix()); reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
} }
return chooseItem(optionList); return chooseItem(optionList);
} }
@Override @Override
public SpellAbility chooseSingleSpellForEffect(List<SpellAbility> spells, SpellAbility sa, String title) { public SpellAbility chooseSingleSpellForEffect(List<SpellAbility> spells, SpellAbility sa, String title) {
return chooseItem(spells); return chooseItem(spells);
} }
@Override @Override
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) { public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return true; return true;
} }
@Override @Override
public boolean confirmBidAction(SpellAbility sa, public boolean confirmBidAction(SpellAbility sa,
@@ -200,12 +201,12 @@ public class PlayerControllerForTests extends PlayerController {
return false; return false;
} }
@Override @Override
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) { public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
return true; return true;
} }
@Override @Override
public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory) { public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory) {
return true; return true;
} }
@@ -215,244 +216,244 @@ public class PlayerControllerForTests extends PlayerController {
return this.player; return this.player;
} }
@Override @Override
public CardCollection orderBlockers(Card attacker, CardCollection blockers) { public CardCollection orderBlockers(Card attacker, CardCollection blockers) {
return blockers; return blockers;
} }
@Override @Override
public CardCollection orderBlocker(final Card attacker, final Card blocker, final CardCollection oldBlockers) { public CardCollection orderBlocker(final Card attacker, final Card blocker, final CardCollection oldBlockers) {
final CardCollection allBlockers = new CardCollection(oldBlockers); final CardCollection allBlockers = new CardCollection(oldBlockers);
allBlockers.add(blocker); allBlockers.add(blocker);
return allBlockers; return allBlockers;
} }
@Override @Override
public CardCollection orderAttackers(Card blocker, CardCollection attackers) { public CardCollection orderAttackers(Card blocker, CardCollection attackers) {
return attackers; return attackers;
} }
@Override @Override
public void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix) { public void reveal(CardCollectionView cards, ZoneType zone, Player owner, String messagePrefix) {
//nothing needs to be done here //nothing needs to be done here
} }
@Override @Override
public void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix) { public void reveal(List<CardView> cards, ZoneType zone, PlayerView owner, String messagePrefix) {
//nothing needs to be done here //nothing needs to be done here
} }
@Override @Override
public void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value) { public void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value) {
//nothing needs to be done here //nothing needs to be done here
} }
@Override @Override
public ImmutablePair<CardCollection, CardCollection> arrangeForScry(CardCollection topN) { public ImmutablePair<CardCollection, CardCollection> arrangeForScry(CardCollection topN) {
return ImmutablePair.of(topN, null); return ImmutablePair.of(topN, null);
} }
@Override @Override
public boolean willPutCardOnTop(Card c) { public boolean willPutCardOnTop(Card c) {
return false; return false;
} }
@Override @Override
public CardCollectionView orderMoveToZoneList(CardCollectionView cards, ZoneType destinationZone) { public CardCollectionView orderMoveToZoneList(CardCollectionView cards, ZoneType destinationZone) {
return cards; return cards;
} }
@Override @Override
public CardCollection chooseCardsToDiscardFrom(Player playerDiscard, SpellAbility sa, CardCollection validCards, int min, int max) { public CardCollection chooseCardsToDiscardFrom(Player playerDiscard, SpellAbility sa, CardCollection validCards, int min, int max) {
return chooseItems(validCards, min); return chooseItems(validCards, min);
} }
@Override @Override
public void playMiracle(SpellAbility miracle, Card card) { public void playMiracle(SpellAbility miracle, Card card) {
throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!"); throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!");
} }
@Override @Override
public CardCollectionView chooseCardsToDelve(int genericAmount, CardCollection grave) { public CardCollectionView chooseCardsToDelve(int genericAmount, CardCollection grave) {
return CardCollection.EMPTY; return CardCollection.EMPTY;
} }
@Override @Override
public CardCollectionView chooseCardsToRevealFromHand(int min, int max, CardCollectionView valid) { public CardCollectionView chooseCardsToRevealFromHand(int min, int max, CardCollectionView valid) {
return chooseItems(valid, min); return chooseItems(valid, min);
} }
@Override @Override
public CardCollectionView chooseCardsToDiscardUnlessType(int min, CardCollectionView hand, String param, SpellAbility sa) { public CardCollectionView chooseCardsToDiscardUnlessType(int min, CardCollectionView hand, String param, SpellAbility sa) {
throw new IllegalStateException("Erring on the side of caution here..."); throw new IllegalStateException("Erring on the side of caution here...");
} }
@Override @Override
public List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand) { public List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand) {
return usableFromOpeningHand; return usableFromOpeningHand;
} }
@Override @Override
public Mana chooseManaFromPool(List<Mana> manaChoices) { public Mana chooseManaFromPool(List<Mana> manaChoices) {
return chooseItem(manaChoices); return chooseItem(manaChoices);
} }
@Override @Override
public Pair<CounterType, String> chooseAndRemoveOrPutCounter(Card cardWithCounter) { public Pair<CounterType, String> chooseAndRemoveOrPutCounter(Card cardWithCounter) {
throw new IllegalStateException("Erring on the side of caution here..."); throw new IllegalStateException("Erring on the side of caution here...");
} }
@Override @Override
public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question) { public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question) {
return true; return true;
} }
@Override @Override
public CardCollectionView getCardsToMulligan(Player firstPlayer) { public CardCollectionView getCardsToMulligan(Player firstPlayer) {
return null; return null;
} }
@Override @Override
public void declareAttackers(Player attacker, Combat combat) { public void declareAttackers(Player attacker, Combat combat) {
//Doing nothing is safe in most cases, but not all (creatures that must attack etc). TODO: introduce checks? //Doing nothing is safe in most cases, but not all (creatures that must attack etc). TODO: introduce checks?
if (playerActions == null) { if (playerActions == null) {
return; return;
} }
DeclareAttackersAction declareAttackers = playerActions.getNextActionIfApplicable(player, game, DeclareAttackersAction.class); DeclareAttackersAction declareAttackers = playerActions.getNextActionIfApplicable(player, game, DeclareAttackersAction.class);
if (declareAttackers == null) { if (declareAttackers == null) {
return; return;
} }
//TODO: check that the chosen attack configuration is legal? (Including creatures that did not attack but should) //TODO: check that the chosen attack configuration is legal? (Including creatures that did not attack but should)
//TODO: check that the chosen attack configuration was a complete match to what was requested? //TODO: check that the chosen attack configuration was a complete match to what was requested?
//TODO: banding (don't really care at the moment...) //TODO: banding (don't really care at the moment...)
for (Map.Entry<CardSpecification, PlayerSpecification> playerAttackAssignment : declareAttackers.getPlayerAttackAssignments().entrySet()) { for (Map.Entry<CardSpecification, PlayerSpecification> playerAttackAssignment : declareAttackers.getPlayerAttackAssignments().entrySet()) {
Player defender = getPlayerBeingAttacked(game, player, playerAttackAssignment.getValue()); Player defender = getPlayerBeingAttacked(game, player, playerAttackAssignment.getValue());
attack(combat, playerAttackAssignment.getKey(), defender); attack(combat, playerAttackAssignment.getKey(), defender);
} }
for (Map.Entry<CardSpecification, CardSpecification> planeswalkerAttackAssignment: declareAttackers.getPlaneswalkerAttackAssignments().entrySet()) { for (Map.Entry<CardSpecification, CardSpecification> planeswalkerAttackAssignment: declareAttackers.getPlaneswalkerAttackAssignments().entrySet()) {
Card defender = CardSpecificationHandler.INSTANCE.find(game.getCardsInGame(), planeswalkerAttackAssignment.getKey()); Card defender = CardSpecificationHandler.INSTANCE.find(game.getCardsInGame(), planeswalkerAttackAssignment.getKey());
attack(combat, planeswalkerAttackAssignment.getKey(), defender); attack(combat, planeswalkerAttackAssignment.getKey(), defender);
} }
if (!CombatUtil.validateAttackers(combat)) { if (!CombatUtil.validateAttackers(combat)) {
throw new IllegalStateException("Illegal attack declaration!"); throw new IllegalStateException("Illegal attack declaration!");
} }
} }
private Player getPlayerBeingAttacked(Game game, Player attacker, PlayerSpecification defenderSpecification) { private Player getPlayerBeingAttacked(Game game, Player attacker, PlayerSpecification defenderSpecification) {
if (defenderSpecification != null) { if (defenderSpecification != null) {
return PlayerSpecificationHandler.INSTANCE.find(game.getPlayers(), defenderSpecification); return PlayerSpecificationHandler.INSTANCE.find(game.getPlayers(), defenderSpecification);
} }
if (game.getPlayers().size() != 2) { if (game.getPlayers().size() != 2) {
throw new IllegalStateException("Can't use implicit defender specification in this situation!"); throw new IllegalStateException("Can't use implicit defender specification in this situation!");
} }
for (Player player : game.getPlayers()) { for (Player player : game.getPlayers()) {
if (!attacker.equals(player)) { if (!attacker.equals(player)) {
return player; return player;
} }
} }
throw new IllegalStateException("Couldn't find implicit defender!"); throw new IllegalStateException("Couldn't find implicit defender!");
} }
private void attack(Combat combat, CardSpecification attackerSpecification, GameEntity defender) { private void attack(Combat combat, CardSpecification attackerSpecification, GameEntity defender) {
Card attacker = CardSpecificationHandler.INSTANCE.find(combat.getAttackingPlayer().getCreaturesInPlay(), attackerSpecification); Card attacker = CardSpecificationHandler.INSTANCE.find(combat.getAttackingPlayer().getCreaturesInPlay(), attackerSpecification);
if (!CombatUtil.canAttack(attacker, defender)) { if (!CombatUtil.canAttack(attacker, defender)) {
throw new IllegalStateException(attacker + " can't attack " + defender); throw new IllegalStateException(attacker + " can't attack " + defender);
} }
combat.addAttacker(attacker, defender); combat.addAttacker(attacker, defender);
} }
@Override @Override
public void declareBlockers(Player defender, Combat combat) { public void declareBlockers(Player defender, Combat combat) {
//Doing nothing is safe in most cases, but not all (creatures that must block, attackers that must be blocked etc). TODO: legality checks? //Doing nothing is safe in most cases, but not all (creatures that must block, attackers that must be blocked etc). TODO: legality checks?
if (playerActions == null) { if (playerActions == null) {
return; return;
} }
DeclareBlockersAction declareBlockers = playerActions.getNextActionIfApplicable(player, game, DeclareBlockersAction.class); DeclareBlockersAction declareBlockers = playerActions.getNextActionIfApplicable(player, game, DeclareBlockersAction.class);
if (declareBlockers == null) { if (declareBlockers == null) {
return; return;
} }
//TODO: check that the chosen block configuration is 100% legal? //TODO: check that the chosen block configuration is 100% legal?
//TODO: check that the chosen block configuration was a 100% match to what was requested? //TODO: check that the chosen block configuration was a 100% match to what was requested?
//TODO: where do damage assignment orders get handled? //TODO: where do damage assignment orders get handled?
for (Map.Entry<CardSpecification, Collection<CardSpecification>> blockingAssignment : declareBlockers.getBlockingAssignments().asMap().entrySet()) { for (Map.Entry<CardSpecification, Collection<CardSpecification>> blockingAssignment : declareBlockers.getBlockingAssignments().asMap().entrySet()) {
Card attacker = CardSpecificationHandler.INSTANCE.find(combat.getAttackers(), blockingAssignment.getKey()); Card attacker = CardSpecificationHandler.INSTANCE.find(combat.getAttackers(), blockingAssignment.getKey());
for (CardSpecification blockerSpecification : blockingAssignment.getValue()) { for (CardSpecification blockerSpecification : blockingAssignment.getValue()) {
Card blocker = CardSpecificationHandler.INSTANCE.find(game, blockerSpecification); Card blocker = CardSpecificationHandler.INSTANCE.find(game, blockerSpecification);
if (!CombatUtil.canBlock(attacker, blocker)) { if (!CombatUtil.canBlock(attacker, blocker)) {
throw new IllegalStateException(blocker + " can't block " + blocker); throw new IllegalStateException(blocker + " can't block " + blocker);
} }
combat.addBlocker(attacker, blocker); combat.addBlocker(attacker, blocker);
} }
} }
String blockValidation = CombatUtil.validateBlocks(combat, player); String blockValidation = CombatUtil.validateBlocks(combat, player);
if (blockValidation != null) { if (blockValidation != null) {
throw new IllegalStateException(blockValidation); throw new IllegalStateException(blockValidation);
} }
} }
@Override @Override
public List<SpellAbility> chooseSpellAbilityToPlay() { public List<SpellAbility> chooseSpellAbilityToPlay() {
//TODO: This method has to return the spellability chosen by player //TODO: This method has to return the spellability chosen by player
// It should not play the sa right from here. The code has been left as it is to quickly adapt to changed playercontroller interface // It should not play the sa right from here. The code has been left as it is to quickly adapt to changed playercontroller interface
if (playerActions != null) { if (playerActions != null) {
CastSpellFromHandAction castSpellFromHand = playerActions.getNextActionIfApplicable(player, game, CastSpellFromHandAction.class); CastSpellFromHandAction castSpellFromHand = playerActions.getNextActionIfApplicable(player, game, CastSpellFromHandAction.class);
if (castSpellFromHand != null) { if (castSpellFromHand != null) {
castSpellFromHand.castSpellFromHand(player, game); castSpellFromHand.castSpellFromHand(player, game);
} }
ActivateAbilityAction activateAbilityAction = playerActions.getNextActionIfApplicable(player, game, ActivateAbilityAction.class); ActivateAbilityAction activateAbilityAction = playerActions.getNextActionIfApplicable(player, game, ActivateAbilityAction.class);
if (activateAbilityAction != null) { if (activateAbilityAction != null) {
activateAbilityAction.activateAbility(player, game); activateAbilityAction.activateAbility(player, game);
} }
} }
return null; return null;
} }
@Override @Override
public CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard) { public CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard) {
return chooseItems(player.getZone(ZoneType.Hand).getCards(), numDiscard); return chooseItems(player.getZone(ZoneType.Hand).getCards(), numDiscard);
} }
@Override @Override
public boolean payManaOptional(Card card, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose) { public boolean payManaOptional(Card card, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose) {
throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!"); throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!");
} }
@Override @Override
public int chooseNumber(SpellAbility sa, String title, int min, int max) { public int chooseNumber(SpellAbility sa, String title, int min, int max) {
return min; return min;
} }
@Override @Override
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Boolean defaultVal) { public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Boolean defaultVal) {
return true; return true;
} }
@Override @Override
public boolean chooseFlipResult(SpellAbility sa, Player flipper, boolean[] results, boolean call) { public boolean chooseFlipResult(SpellAbility sa, Player flipper, boolean[] results, boolean call) {
return true; return true;
} }
@Override @Override
public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap) { public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap) {
return choiceMap.get(options.get(0)); return choiceMap.get(options.get(0));
} }
@Override @Override
public List<AbilitySub> chooseModeForAbility(SpellAbility sa, int min, int num, boolean allowRepeat) { public List<AbilitySub> chooseModeForAbility(SpellAbility sa, int min, int num, boolean allowRepeat) {
throw new IllegalStateException("Erring on the side of caution here..."); throw new IllegalStateException("Erring on the side of caution here...");
} }
@Override @Override
public byte chooseColor(String message, SpellAbility sa, ColorSet colors) { public byte chooseColor(String message, SpellAbility sa, ColorSet colors) {
return Iterables.getFirst(colors, MagicColor.WHITE); return Iterables.getFirst(colors, MagicColor.WHITE);
} }
@Override @Override
public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) { public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) {
return Iterables.getFirst(colors, (byte)0); return Iterables.getFirst(colors, (byte)0);
@@ -488,11 +489,6 @@ public class PlayerControllerForTests extends PlayerController {
return chooseItem(options); return chooseItem(options);
} }
@Override
public PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate<PaperCard> cpp, String name) {
throw new IllegalStateException("Erring on the side of caution here...");
}
@Override @Override
public List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options) { public List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options) {
throw new UnsupportedOperationException("No idea how a test player controller would choose colors"); throw new UnsupportedOperationException("No idea how a test player controller would choose colors");
@@ -594,10 +590,10 @@ public class PlayerControllerForTests extends PlayerController {
// test this! // test this!
} }
@Override @Override
public CardShields chooseRegenerationShield(Card c) { public CardShields chooseRegenerationShield(Card c) {
return Iterables.getFirst(c.getShields(), null); return Iterables.getFirst(c.getShields(), null);
} }
@Override @Override
public List<PaperCard> chooseCardsYouWonToAddToDeck(List<PaperCard> losses) { public List<PaperCard> chooseCardsYouWonToAddToDeck(List<PaperCard> losses) {
@@ -632,13 +628,6 @@ public class PlayerControllerForTests extends PlayerController {
} }
@Override
public String chooseCardName(SpellAbility sa, Predicate<PaperCard> cpp,
String valid, String message) {
return null;
}
@Override @Override
public Card chooseSingleCardForZoneChange(ZoneType destination, public Card chooseSingleCardForZoneChange(ZoneType destination,
List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal,
@@ -668,4 +657,23 @@ public class PlayerControllerForTests extends PlayerController {
public void cancelAwaitNextInput() { public void cancelAwaitNextInput() {
// Not used by the controller for tests // Not used by the controller for tests
} }
@Override
public ICardFace chooseSingleCardFace(SpellAbility sa, String message, Predicate<ICardFace> cpp, String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public String chooseCardName(SpellAbility sa, Predicate<ICardFace> cpp, String valid, String message) {
// TODO Auto-generated method stub
return null;
}
@Override
public String chooseCardName(SpellAbility sa, List<ICardFace> faces, String message) {
// TODO Auto-generated method stub
return null;
}
} }

View File

@@ -38,7 +38,9 @@ import forge.GuiBase;
import forge.LobbyPlayer; import forge.LobbyPlayer;
import forge.achievement.AchievementCollection; import forge.achievement.AchievementCollection;
import forge.ai.GameState; import forge.ai.GameState;
import forge.card.CardDb;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.ICardFace;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
@@ -1148,9 +1150,9 @@ public class PlayerControllerHuman
} }
@Override @Override
public PaperCard chooseSinglePaperCard(final SpellAbility sa, final String message, final Predicate<PaperCard> cpp, final String name) { public ICardFace chooseSingleCardFace(final SpellAbility sa, final String message, final Predicate<ICardFace> cpp, final String name) {
final Iterable<PaperCard> cardsFromDb = FModel.getMagicDb().getCommonCards().getUniqueCards(); final Iterable<ICardFace> cardsFromDb = FModel.getMagicDb().getCommonCards().getAllFaces();
final List<PaperCard> cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp)); final List<ICardFace> cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp));
Collections.sort(cards); Collections.sort(cards);
return getGui().one(message, cards); return getGui().one(message, cards);
} }
@@ -1372,9 +1374,10 @@ public class PlayerControllerHuman
} }
@Override @Override
public String chooseCardName(final SpellAbility sa, final Predicate<PaperCard> cpp, final String valid, final String message) { public String chooseCardName(final SpellAbility sa, final Predicate<ICardFace> cpp, final String valid, final String message) {
while (true) { while (true) {
final PaperCard cp = chooseSinglePaperCard(sa, message, cpp, sa.getHostCard().getName()); final ICardFace cardFace = chooseSingleCardFace(sa, message, cpp, sa.getHostCard().getName());
final PaperCard cp = FModel.getMagicDb().getCommonCards().getCard(cardFace.getName());
final Card instanceForPlayer = Card.fromPaperCard(cp, player); // the Card instance for test needs a game to be tested final Card instanceForPlayer = Card.fromPaperCard(cp, player); // the Card instance for test needs a game to be tested
if (instanceForPlayer.isValid(valid, sa.getHostCard().getController(), sa.getHostCard(), sa)) { if (instanceForPlayer.isValid(valid, sa.getHostCard().getController(), sa.getHostCard(), sa)) {
return cp.getName(); return cp.getName();
@@ -1768,15 +1771,18 @@ public class PlayerControllerHuman
return; return;
} }
final List<PaperCard> cards = Lists.newArrayList(FModel.getMagicDb().getCommonCards().getUniqueCards()); final CardDb carddb = FModel.getMagicDb().getCommonCards();
Collections.sort(cards); final List<ICardFace> faces = Lists.newArrayList(carddb.getAllFaces());
Collections.sort(faces);
// use standard forge's list selection dialog // use standard forge's list selection dialog
final IPaperCard c = getGui().oneOrNone("Name the card", cards); final ICardFace f = getGui().oneOrNone("Name the card", faces);
if (c == null) { if (f == null) {
return; return;
} }
final PaperCard c = carddb.getUniqueByName(f.getName());
game.getAction().invoke(new Runnable() { @Override public void run() { game.getAction().invoke(new Runnable() { @Override public void run() {
game.getAction().moveToHand(Card.fromPaperCard(c, p)); game.getAction().moveToHand(Card.fromPaperCard(c, p));
}}); }});
@@ -1792,15 +1798,18 @@ public class PlayerControllerHuman
return; return;
} }
final List<PaperCard> cards = Lists.newArrayList(FModel.getMagicDb().getCommonCards().getUniqueCards()); final CardDb carddb = FModel.getMagicDb().getCommonCards();
Collections.sort(cards); final List<ICardFace> faces = Lists.newArrayList(carddb.getAllFaces());
Collections.sort(faces);
// use standard forge's list selection dialog // use standard forge's list selection dialog
final IPaperCard c = getGui().oneOrNone("Name the card", cards); final ICardFace f = getGui().oneOrNone("Name the card", faces);
if (c == null) { if (f == null) {
return; return;
} }
final PaperCard c = carddb.getUniqueByName(f.getName());
game.getAction().invoke(new Runnable() { game.getAction().invoke(new Runnable() {
@Override public void run() { @Override public void run() {
final Card forgeCard = Card.fromPaperCard(c, p); final Card forgeCard = Card.fromPaperCard(c, p);
@@ -1931,4 +1940,10 @@ public class PlayerControllerHuman
hand.reorder(game.getCard(card), index); hand.reorder(game.getCard(card), index);
player.updateZoneForView(hand); player.updateZoneForView(hand);
} }
@Override
public String chooseCardName(SpellAbility sa, List<ICardFace> faces, String message) {
ICardFace face = getGui().one(message, faces);
return face == null ? "" : face.getName();
}
} }