package magic.model.choice; import java.util.Collection; import java.util.HashSet; import java.util.Set; import magic.data.GeneralConfig; import magic.exception.UndoClickedException; import magic.model.IUIGameController; import magic.model.MagicCard; import magic.model.MagicCardList; import magic.model.MagicGame; import magic.model.MagicPermanent; import magic.model.MagicPlayer; import magic.model.MagicSource; import magic.model.MurmurHash3; import magic.model.event.MagicEvent; import magic.model.target.MagicOtherPermanentTargetFilter; import magic.model.target.MagicTarget; import magic.model.target.MagicTargetFilter; import magic.model.target.MagicTargetFilterFactory; import magic.model.target.MagicTargetHint; import magic.model.target.MagicTargetNone; import magic.model.target.MagicTargetPicker; import magic.model.target.MagicTargetType; public class MagicTargetChoice extends MagicChoice { public static final MagicTargetChoice NONE = new MagicTargetChoice(MagicTargetFilterFactory.NONE,MagicTargetHint.None,"nothing") { @Override public boolean isValid() { return false; } }; public static final MagicTargetChoice A_PAYABLE_CREATURE_CARD_FROM_YOUR_GRAVEYARD = new MagicTargetChoice("a creature card with scavenge from your graveyard"); public static final MagicTargetChoice TARGET_SPELL = new MagicTargetChoice("target spell"); public static final MagicTargetChoice NEG_TARGET_SPELL = MagicTargetChoice.Negative("target spell"); public static final MagicTargetChoice NEG_TARGET_CREATURE_SPELL = MagicTargetChoice.Negative("target creature spell"); public static final MagicTargetChoice TARGET_INSTANT_OR_SORCERY_SPELL = new MagicTargetChoice("target instant or sorcery spell"); public static final MagicTargetChoice NEG_TARGET_INSTANT_SPELL = MagicTargetChoice.Negative("target instant spell"); public static final MagicTargetChoice TARGET_PLAYER = new MagicTargetChoice("target player"); public static final MagicTargetChoice TARGET_PLAYER_CONTROLS_CREATURE = new MagicTargetChoice("target player that controls a creature"); public static final MagicTargetChoice TARGET_OPPONENT = new MagicTargetChoice("target opponent"); public static final MagicTargetChoice POS_TARGET_PLAYER = MagicTargetChoice.Positive("target player"); public static final MagicTargetChoice NEG_TARGET_PLAYER = MagicTargetChoice.Negative("target player"); public static final MagicTargetChoice NEG_TARGET_SPELL_OR_PERMANENT = MagicTargetChoice.Negative("target spell or permanent"); public static final MagicTargetChoice TARGET_PERMANENT = new MagicTargetChoice("target permanent"); public static final MagicTargetChoice A_PERMANENT_YOU_CONTROL = new MagicTargetChoice("a permanent you control"); public static final MagicTargetChoice TARGET_PERMANENT_YOU_CONTROL = new MagicTargetChoice("target permanent you control"); public static final MagicTargetChoice TARGET_PERMANENT_YOU_OWN = new MagicTargetChoice("target permanent you own"); public static final MagicTargetChoice NEG_TARGET_PERMANENT = MagicTargetChoice.Negative("target permanent"); public static final MagicTargetChoice TARGET_LAND = new MagicTargetChoice("target land"); public static final MagicTargetChoice NEG_TARGET_LAND = MagicTargetChoice.Negative("target land"); public static final MagicTargetChoice A_LAND_YOU_CONTROL = new MagicTargetChoice("a land you control"); public static final MagicTargetChoice FOREST_YOU_CONTROL = new MagicTargetChoice("a Forest you control"); public static final MagicTargetChoice ISLAND_YOU_CONTROL = new MagicTargetChoice("an Island you control"); public static final MagicTargetChoice TARGET_NONLAND_PERMANENT = new MagicTargetChoice("target nonland permanent"); public static final MagicTargetChoice NEG_TARGET_NONLAND_PERMANENT = MagicTargetChoice.Negative("target nonland permanent"); public static final MagicTargetChoice TARGET_ARTIFACT = new MagicTargetChoice("target artifact"); public static final MagicTargetChoice NEG_TARGET_ARTIFACT = MagicTargetChoice.Negative("target artifact"); public static final MagicTargetChoice POS_TARGET_ARTIFACT = MagicTargetChoice.Positive("target artifact"); public static final MagicTargetChoice TARGET_NONCREATURE_ARTIFACT = new MagicTargetChoice("target noncreature artifact"); public static final MagicTargetChoice POS_TARGET_NONCREATURE_ARTIFACT = MagicTargetChoice.Positive("target noncreature artifact"); public static final MagicTargetChoice TARGET_ARTIFACT_OR_ENCHANTMENT = new MagicTargetChoice("target artifact or enchantment"); public static final MagicTargetChoice NEG_TARGET_ARTIFACT_OR_ENCHANTMENT = MagicTargetChoice.Negative("target artifact or enchantment"); public static final MagicTargetChoice AN_ARTIFACT_OR_CREATURE = new MagicTargetChoice("an artifact or creature"); public static final MagicTargetChoice AN_UNTAPPED_CREATURE_YOU_CONTROL = new MagicTargetChoice("an untapped creature you control"); public static final MagicTargetChoice TARGET_ARTIFACT_OR_CREATURE = new MagicTargetChoice("target artifact or creature"); public static final MagicTargetChoice NEG_TARGET_ARTIFACT_OR_CREATURE = MagicTargetChoice.Negative("target artifact or creature"); public static final MagicTargetChoice TARGET_ARTIFACT_OR_ENCHANTMENT_YOUR_OPPONENT_CONTROLS = new MagicTargetChoice("target artifact or enchantment an opponent controls"); public static final MagicTargetChoice POS_TARGET_ARTIFACT_CREATURE = MagicTargetChoice.Positive("target artifact creature"); public static final MagicTargetChoice TARGET_ENCHANTMENT = new MagicTargetChoice("target enchantment"); public static final MagicTargetChoice TARGET_ENCHANTMENT_YOU_CONTROL = new MagicTargetChoice("target enchantment you control"); public static final MagicTargetChoice TARGET_ENCHANTMENT_YOUR_OPPONENT_CONTROLS = new MagicTargetChoice("target enchantment an opponent controls"); public static final MagicTargetChoice NEG_TARGET_ENCHANTMENT = MagicTargetChoice.Negative("target enchantment"); public static final MagicTargetChoice TARGET_CREATURE = new MagicTargetChoice("target creature"); public static final MagicTargetChoice NEG_TARGET_CREATURE = MagicTargetChoice.Negative("target creature"); public static final MagicTargetChoice POS_TARGET_CREATURE = MagicTargetChoice.Positive("target creature"); public static final MagicTargetChoice TARGET_NONCREATURE = new MagicTargetChoice("target noncreature"); public static final MagicTargetChoice NEG_TARGET_NONCREATURE = MagicTargetChoice.Negative("target noncreature"); public static final MagicTargetChoice NEG_TARGET_NONBLACK_CREATURE = MagicTargetChoice.Negative("target nonblack creature"); public static final MagicTargetChoice NEG_TARGET_UNTAPPED_CREATURE = MagicTargetChoice.Negative("target untapped creature"); public static final MagicTargetChoice A_CREATURE_YOU_CONTROL = new MagicTargetChoice("a creature you control"); public static final MagicTargetChoice A_CREATURE = new MagicTargetChoice("a creature"); public static final MagicTargetChoice POS_CREATURE = MagicTargetChoice.Positive("a creature"); public static final MagicTargetChoice TARGET_CREATURE_PLUSONE_COUNTER = new MagicTargetChoice("target creature with a +1/+1 counter on it"); public static final MagicTargetChoice TARGET_CREATURE_WITH_FLYING = new MagicTargetChoice("target creature with flying"); public static final MagicTargetChoice NEG_TARGET_CREATURE_WITH_FLYING = MagicTargetChoice.Negative("target creature with flying"); public static final MagicTargetChoice NEG_TARGET_ATTACKING_CREATURE = MagicTargetChoice.Negative("target attacking creature"); public static final MagicTargetChoice NEG_WHITE_OR_BLUE_CREATURE = MagicTargetChoice.Negative("target white or blue creature"); public static final MagicTargetChoice TARGET_CREATURE_YOU_CONTROL = new MagicTargetChoice("target creature you control"); public static final MagicTargetChoice NEG_TARGET_EQUIPPED_CREATURE = MagicTargetChoice.Negative("target creature that is equipped"); public static final MagicTargetChoice TARGET_CREATURE_OR_PLAYER = new MagicTargetChoice("target creature or player"); public static final MagicTargetChoice NEG_TARGET_CREATURE_OR_PLAYER = MagicTargetChoice.Negative("target creature or player"); public static final MagicTargetChoice POS_TARGET_CREATURE_OR_PLAYER = MagicTargetChoice.Positive("target creature or player"); public static final MagicTargetChoice NEG_TARGET_VAMPIRE = MagicTargetChoice.Negative("target Vampire"); public static final MagicTargetChoice SACRIFICE_PERMANENT = new MagicTargetChoice("a permanent to sacrifice"); public static final MagicTargetChoice SACRIFICE_CREATURE = new MagicTargetChoice("a creature to sacrifice"); public static final MagicTargetChoice SACRIFICE_ARTIFACT = new MagicTargetChoice("an artifact to sacrifice"); public static final MagicTargetChoice SACRIFICE_LAND = new MagicTargetChoice("a land to sacrifice"); public static final MagicTargetChoice SACRIFICE_ENCHANTMENT = new MagicTargetChoice("an enchantment to sacrifice"); public static final MagicTargetChoice SACRIFICE_FOREST = new MagicTargetChoice("a Forest to sacrifice"); public static final MagicTargetChoice SACRIFICE_GOBLIN = new MagicTargetChoice("a Goblin to sacrifice"); public static final MagicTargetChoice SACRIFICE_CLERIC = new MagicTargetChoice("a Cleric creature to sacrifice"); public static final MagicTargetChoice TARGET_CARD_FROM_GRAVEYARD = new MagicTargetChoice("target card from your graveyard"); public static final MagicTargetChoice NEG_TARGET_CARD_FROM_ALL_GRAVEYARDS = MagicTargetChoice.Negative("target card from a graveyard"); public static final MagicTargetChoice TARGET_CREATURE_CARD_FROM_GRAVEYARD = new MagicTargetChoice("target creature card from your graveyard"); public static final MagicTargetChoice AN_UNBLOCKED_ATTACKING_CREATURE_YOU_CONTROL = new MagicTargetChoice("an unblocked attacking creature you control"); public static final MagicTargetChoice TARGET_CARD_FROM_OPPONENTS_GRAVEYARD = new MagicTargetChoice("target card from an opponent's graveyard"); public static final MagicTargetChoice TARGET_CREATURE_CARD_FROM_OPPONENTS_GRAVEYARD = new MagicTargetChoice("target creature card from an opponent's graveyard"); public static final MagicTargetChoice TARGET_INSTANT_OR_SORCERY_CARD_FROM_OPPONENTS_GRAVEYARD = new MagicTargetChoice("target instant or sorcery card from an opponent's graveyard"); public static final MagicTargetChoice TARGET_CREATURE_CARD_FROM_ALL_GRAVEYARDS = new MagicTargetChoice("target creature card from a graveyard"); public static final MagicTargetChoice A_CARD_FROM_HAND = new MagicTargetChoice("a card from your hand"); public static final MagicTargetChoice A_CARD_FROM_GRAVEYARD = new MagicTargetChoice("a card from your graveyard"); public static final MagicTargetChoice A_CREATURE_CARD_FROM_HAND = new MagicTargetChoice("a creature card from your hand"); public static final MagicTargetChoice A_BASIC_LAND_CARD_FROM_LIBRARY = new MagicTargetChoice("a basic land card from your library"); public static final MagicTargetChoice A_CREATURE_CARD_FROM_LIBRARY = new MagicTargetChoice("a creature card from your library"); public static final MagicTargetChoice LAND_CARD_WITH_BASIC_LAND_TYPE_FROM_LIBRARY = new MagicTargetChoice("a land card with a basic land type from your library"); public static final MagicTargetChoice LAND_CARD_FROM_HAND = new MagicTargetChoice("a land card from your hand"); public static final MagicTargetChoice CREATURE_TOKEN_YOU_CONTROL = new MagicTargetChoice("a creature token you control"); public static final MagicTargetChoice PLANESWALKER_YOUR_OPPONENT_CONTROLS = new MagicTargetChoice("a planeswalker an opponent controls"); public static final MagicTargetChoice TARGET_CREATURE_YOUR_OPPONENT_CONTROLS = new MagicTargetChoice("target creature an opponent controls"); public static final MagicTargetChoice TARGET_ARTIFACT_YOUR_OPPONENT_CONTROLS = new MagicTargetChoice("target artifact an opponent controls"); public static final MagicTargetChoice ANOTHER_CREATURE_YOU_CONTROL = new MagicTargetChoice("another creature you control"); private final String targetDescription; private final MagicTargetFilter<? extends MagicTarget> targetFilter; private final boolean targeted; private final MagicTargetHint targetHint; public static MagicTargetChoice Positive(final String aTargetDescription) { return new MagicTargetChoice(MagicTargetHint.Positive, aTargetDescription); } public static MagicTargetChoice Negative(final String aTargetDescription) { return new MagicTargetChoice(MagicTargetHint.Negative, aTargetDescription); } public static MagicTargetChoice Other(final String aTargetDescription, final MagicPermanent permanent) { return Other(aTargetDescription, permanent, MagicTargetHint.None); } public static MagicTargetChoice PosOther(final String aTargetDescription, final MagicPermanent permanent) { return Other(aTargetDescription, permanent, MagicTargetHint.Positive); } public static MagicTargetChoice NegOther(final String aTargetDescription, final MagicPermanent permanent) { return Other(aTargetDescription, permanent, MagicTargetHint.Negative); } private static MagicTargetChoice Other(final String aTargetDescription, final MagicPermanent permanent, final MagicTargetHint hint) { final MagicTargetChoice withoutOther = new MagicTargetChoice(aTargetDescription); final String compactDescription = aTargetDescription.replaceFirst("^a(n)? ", ""); return new MagicTargetChoice( new MagicOtherPermanentTargetFilter( withoutOther.getPermanentFilter(), permanent ), hint, "another " + compactDescription ); } public MagicTargetChoice(final String aTargetDescription) { this(MagicTargetHint.None, aTargetDescription); } private static String decapitalize(final String text) { return Character.toLowerCase(text.charAt(0)) + text.substring(1); } public MagicTargetChoice(final MagicTargetHint aTargetHint, final String aTargetDescription) { super("Choose " + decapitalize(aTargetDescription) + '.'); targetHint = aTargetHint; targetDescription = decapitalize(aTargetDescription); if (targetDescription.matches("target .*")) { targetFilter = MagicTargetFilterFactory.single(targetDescription.replaceFirst("target ", "")); targeted = true; } else if (targetDescription.matches("another target .*")) { targetFilter = new MagicOtherPermanentTargetFilter(MagicTargetFilterFactory.Permanent(targetDescription.replaceFirst("another target ", ""))); targeted = true; } else if (targetDescription.matches("another .*")) { targetFilter = new MagicOtherPermanentTargetFilter(MagicTargetFilterFactory.Permanent(targetDescription.replaceFirst("another ", ""))); targeted = false; } else if (targetDescription.matches("a(n)? .*")) { targetFilter = MagicTargetFilterFactory.single(targetDescription.replaceFirst("a(n)? ", "")); targeted = false; } else { throw new RuntimeException("unknown target choice: \"" + aTargetDescription + "\""); } } public MagicTargetChoice( final MagicTargetFilter<? extends MagicTarget> aTargetFilter, final String aTargetDescription ) { super("Choose " + aTargetDescription + '.'); targetFilter = aTargetFilter; targeted = aTargetDescription.contains("target"); targetHint = MagicTargetHint.None; targetDescription = aTargetDescription; } public MagicTargetChoice( final MagicTargetFilter<? extends MagicTarget> aTargetFilter, final MagicTargetHint aTargetHint, final String aTargetDescription ) { super("Choose " + aTargetDescription + '.'); targetFilter = aTargetFilter; targeted = aTargetDescription.contains("target"); targetHint = aTargetHint; targetDescription = aTargetDescription; } public MagicTargetChoice( final MagicTargetChoice copy, final boolean targeted ) { super("Choose "+copy.targetDescription+'.'); this.targetFilter=copy.targetFilter; this.targeted=targeted; this.targetHint=copy.targetHint; this.targetDescription=copy.targetDescription; } public final String getTargetDescription() { return targetDescription; } @SuppressWarnings("unchecked") public final MagicTargetFilter<MagicTarget> getTargetFilter() { return (MagicTargetFilter<MagicTarget>)targetFilter; } @SuppressWarnings("unchecked") public final MagicTargetFilter<MagicCard> getCardFilter() { return (MagicTargetFilter<MagicCard>)targetFilter; } @SuppressWarnings("unchecked") public final MagicTargetFilter<MagicPermanent> getPermanentFilter() { return (MagicTargetFilter<MagicPermanent>)targetFilter; } public final boolean isTargeted() { return targeted; } public final MagicTargetHint getTargetHint(final boolean hints) { return hints?targetHint:MagicTargetHint.None; } @Override public final MagicTargetChoice getTargetChoice() { return this; } @Override public final int getTargetChoiceResultIndex() { return 0; } @Override public long getStateId() { return MurmurHash3.hash(new long[] { targetDescription.hashCode(), targetFilter.hashCode(), (targeted ? 1L : -1L), targetHint.hashCode() }); } @Override public final boolean hasOptions(final MagicGame game, final MagicPlayer player, final MagicSource source, final boolean hints) { return game.hasLegalTargets(player,source,this,hints); } @Override final Collection<?> getArtificialOptions(final MagicGame game, final MagicEvent event) { final MagicPlayer player = event.getPlayer(); final MagicSource source = event.getSource(); Collection<MagicTarget> targets = game.getLegalTargets(player,source,this,targetHint); if (game.getFastTarget()) { @SuppressWarnings("unchecked") final MagicTargetPicker<MagicTarget> targetPicker = (MagicTargetPicker<MagicTarget>)event.getTargetPicker(); targets = targetPicker.pickTargets(game,event,targets); } return targets; } @Override public final Object[] getPlayerChoiceResults(final IUIGameController controller, final MagicGame game, final MagicEvent event) throws UndoClickedException { final MagicPlayer player = event.getPlayer(); final MagicSource source = event.getSource(); controller.disableActionButton(false); controller.showMessage(source,getDescription()); if (targetFilter.acceptType(MagicTargetType.Hand)) { controller.focusViewers(0); } else if (targetFilter.acceptType(MagicTargetType.Graveyard)) { controller.focusViewers(1); } else if (targetFilter.acceptType(MagicTargetType.OpponentsGraveyard)) { controller.focusViewers(2); } final MagicTargetHint usedTargetHint=getTargetHint(GeneralConfig.getInstance().getSmartTarget()); final Set<Object> validChoices=new HashSet<Object>(game.getLegalTargets(player,source,this,usedTargetHint)); if (validChoices.size()==1) { // There are no valid choices. if (validChoices.contains(MagicTargetNone.getInstance())) { return new Object[]{MagicTargetNone.getInstance()}; } // Only valid choice is player. if (validChoices.contains(player)) { return new Object[]{player}; } // Only valid choice is opponent. final MagicPlayer opponent=player.getOpponent(); if (validChoices.contains(opponent)) { return new Object[]{opponent}; } } // There is at least one card if (targetFilter.acceptType(MagicTargetType.Library)) { int showViewer = 5; final MagicCardList cards = new MagicCardList(); for (final Object obj : validChoices) { final MagicCard card = (MagicCard)obj; if (card.isInHand()) { showViewer = Math.min(showViewer, 0); } else if (card.isInGraveyard()) { showViewer = Math.min(showViewer, 1); } else if (card.isInLibrary()) { cards.add(card); } } controller.showCards(cards); controller.focusViewers(showViewer); } controller.setValidChoices(validChoices,false); controller.waitForInput(); if (targetFilter.acceptType(MagicTargetType.Library)) { controller.clearCards(); } return new Object[]{controller.getChoiceClicked()}; } }