mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 03:38:01 +00:00
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:
@@ -11,6 +11,7 @@ import forge.LobbyPlayer;
|
||||
import forge.ai.ability.ChangeZoneAi;
|
||||
import forge.ai.ability.ProtectAi;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardFace;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
@@ -577,8 +578,8 @@ public class PlayerControllerAi extends PlayerController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard chooseSinglePaperCard(SpellAbility sa, String message,
|
||||
Predicate<PaperCard> cpp, String name) {
|
||||
public ICardFace chooseSingleCardFace(SpellAbility sa, String message,
|
||||
Predicate<ICardFace> cpp, String name) {
|
||||
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
|
||||
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")) {
|
||||
final String logic = sa.getParam("AILogic");
|
||||
if (logic.equals("MostProminentInComputerDeck")) {
|
||||
@@ -850,7 +851,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
return ComputerUtilCard.getMostProminentCardName(cards);
|
||||
}
|
||||
} 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));
|
||||
if (!list.isEmpty()) {
|
||||
return list.get(0).getName();
|
||||
@@ -889,4 +890,13 @@ public class PlayerControllerAi extends PlayerController {
|
||||
public void cancelAwaitNextInput() {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.card.ICardFace;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.cost.Cost;
|
||||
@@ -269,6 +270,13 @@ public abstract class SpellAbilityAi {
|
||||
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) {
|
||||
if (c == null) {
|
||||
return true;
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
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.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilMana;
|
||||
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.CardUtil;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
public class ChooseCardNameAi extends SpellAbilityAi {
|
||||
|
||||
@@ -68,4 +81,42 @@ public class ChooseCardNameAi extends SpellAbilityAi {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.StaticData;
|
||||
import forge.card.CardFacePredicates;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.card.CardSplitType;
|
||||
import forge.card.ICardFace;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
@@ -22,6 +25,8 @@ import forge.util.ComparableOp;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
@@ -60,17 +65,18 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
|
||||
if (randomChoice) {
|
||||
// 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";
|
||||
final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) :
|
||||
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));
|
||||
if (!cards.isEmpty()) {
|
||||
chosen = Aggregates.random(cards).getName();
|
||||
@@ -80,23 +86,36 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
} else if (chooseFromDefined) {
|
||||
CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa);
|
||||
choices = CardLists.getValidCards(choices, valid, host.getController(), host);
|
||||
Card c = p.getController().chooseSingleEntityForEffect(choices, sa, "Choose a card name");
|
||||
chosen = c != null ? c.getName() : "";
|
||||
List<ICardFace> faces = Lists.newArrayList();
|
||||
// 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 {
|
||||
// use CardFace because you might name a alternate name
|
||||
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") ) {
|
||||
cpp = Predicates.compose(CardRulesPredicates.Presets.IS_NON_LAND, PaperCard.FN_GET_RULES);
|
||||
cpp = CardFacePredicates.Presets.IS_NON_LAND;
|
||||
}
|
||||
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") ) {
|
||||
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") ) {
|
||||
cpp = Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES);
|
||||
cpp = CardFacePredicates.Presets.IS_CREATURE;
|
||||
}
|
||||
|
||||
chosen = p.getController().chooseCardName(sa, cpp, valid, message);
|
||||
|
||||
@@ -38,6 +38,7 @@ import forge.GameCommand;
|
||||
import forge.card.CardStateName;
|
||||
import forge.card.CardType;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardFace;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
@@ -74,7 +75,6 @@ import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.collect.FCollectionView;
|
||||
import forge.util.Lang;
|
||||
@@ -222,7 +222,7 @@ public class CardFactoryUtil {
|
||||
public static boolean handleHiddenAgenda(Player player, Card card) {
|
||||
SpellAbility sa = new SpellAbility.EmptySa(card);
|
||||
sa.getMapParams().put("AILogic", card.getSVar("AgendaLogic"));
|
||||
Predicate<PaperCard> cpp = Predicates.alwaysTrue();
|
||||
Predicate<ICardFace> cpp = Predicates.alwaysTrue();
|
||||
//Predicate<Card> pc = Predicates.in(player.getAllCards());
|
||||
// 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());
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.google.common.collect.Multimap;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardFace;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.deck.Deck;
|
||||
@@ -189,7 +190,7 @@ public abstract class PlayerController {
|
||||
public abstract byte chooseColor(String message, SpellAbility sa, 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 CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, String prompt);
|
||||
|
||||
@@ -222,8 +223,9 @@ public abstract class PlayerController {
|
||||
|
||||
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
|
||||
public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional, Player decider);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import forge.ai.ability.ChangeZoneAi;
|
||||
import forge.ai.ability.DrawAi;
|
||||
import forge.ai.ability.GameWinAi;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardFace;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
@@ -488,11 +489,6 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
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
|
||||
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");
|
||||
@@ -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
|
||||
public Card chooseSingleCardForZoneChange(ZoneType destination,
|
||||
List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal,
|
||||
@@ -668,4 +657,23 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
public void cancelAwaitNextInput() {
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,9 @@ import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.achievement.AchievementCollection;
|
||||
import forge.ai.GameState;
|
||||
import forge.card.CardDb;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardFace;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
@@ -1148,9 +1150,9 @@ public class PlayerControllerHuman
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard chooseSinglePaperCard(final SpellAbility sa, final String message, final Predicate<PaperCard> cpp, final String name) {
|
||||
final Iterable<PaperCard> cardsFromDb = FModel.getMagicDb().getCommonCards().getUniqueCards();
|
||||
final List<PaperCard> cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp));
|
||||
public ICardFace chooseSingleCardFace(final SpellAbility sa, final String message, final Predicate<ICardFace> cpp, final String name) {
|
||||
final Iterable<ICardFace> cardsFromDb = FModel.getMagicDb().getCommonCards().getAllFaces();
|
||||
final List<ICardFace> cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp));
|
||||
Collections.sort(cards);
|
||||
return getGui().one(message, cards);
|
||||
}
|
||||
@@ -1372,9 +1374,10 @@ public class PlayerControllerHuman
|
||||
}
|
||||
|
||||
@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) {
|
||||
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
|
||||
if (instanceForPlayer.isValid(valid, sa.getHostCard().getController(), sa.getHostCard(), sa)) {
|
||||
return cp.getName();
|
||||
@@ -1768,15 +1771,18 @@ public class PlayerControllerHuman
|
||||
return;
|
||||
}
|
||||
|
||||
final List<PaperCard> cards = Lists.newArrayList(FModel.getMagicDb().getCommonCards().getUniqueCards());
|
||||
Collections.sort(cards);
|
||||
final CardDb carddb = FModel.getMagicDb().getCommonCards();
|
||||
final List<ICardFace> faces = Lists.newArrayList(carddb.getAllFaces());
|
||||
Collections.sort(faces);
|
||||
|
||||
// use standard forge's list selection dialog
|
||||
final IPaperCard c = getGui().oneOrNone("Name the card", cards);
|
||||
if (c == null) {
|
||||
final ICardFace f = getGui().oneOrNone("Name the card", faces);
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PaperCard c = carddb.getUniqueByName(f.getName());
|
||||
|
||||
game.getAction().invoke(new Runnable() { @Override public void run() {
|
||||
game.getAction().moveToHand(Card.fromPaperCard(c, p));
|
||||
}});
|
||||
@@ -1792,15 +1798,18 @@ public class PlayerControllerHuman
|
||||
return;
|
||||
}
|
||||
|
||||
final List<PaperCard> cards = Lists.newArrayList(FModel.getMagicDb().getCommonCards().getUniqueCards());
|
||||
Collections.sort(cards);
|
||||
final CardDb carddb = FModel.getMagicDb().getCommonCards();
|
||||
final List<ICardFace> faces = Lists.newArrayList(carddb.getAllFaces());
|
||||
Collections.sort(faces);
|
||||
|
||||
// use standard forge's list selection dialog
|
||||
final IPaperCard c = getGui().oneOrNone("Name the card", cards);
|
||||
if (c == null) {
|
||||
final ICardFace f = getGui().oneOrNone("Name the card", faces);
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PaperCard c = carddb.getUniqueByName(f.getName());
|
||||
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override public void run() {
|
||||
final Card forgeCard = Card.fromPaperCard(c, p);
|
||||
@@ -1931,4 +1940,10 @@ public class PlayerControllerHuman
|
||||
hand.reorder(game.getCard(card), index);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user