InputSelectManyCards - a common class for all those inlined target-choosing inputs

a fix for Phantasmal Terrain and Convincing Mirage
This commit is contained in:
Maxmtg
2012-11-11 20:07:49 +00:00
parent b4421ab594
commit af983044d1
7 changed files with 173 additions and 128 deletions

1
.gitattributes vendored
View File

@@ -12851,6 +12851,7 @@ src/main/java/forge/control/input/InputPayManaCostUtil.java svneol=native#text/p
src/main/java/forge/control/input/InputPayManaX.java -text src/main/java/forge/control/input/InputPayManaX.java -text
src/main/java/forge/control/input/InputPayReturnCost.java -text src/main/java/forge/control/input/InputPayReturnCost.java -text
src/main/java/forge/control/input/InputPaySacCost.java -text src/main/java/forge/control/input/InputPaySacCost.java -text
src/main/java/forge/control/input/InputSelectManyCards.java -text
src/main/java/forge/control/input/package-info.java svneol=native#text/plain src/main/java/forge/control/input/package-info.java svneol=native#text/plain
src/main/java/forge/control/package-info.java -text src/main/java/forge/control/package-info.java -text
src/main/java/forge/deck/CardCollections.java -text src/main/java/forge/deck/CardCollections.java -text

View File

@@ -2,13 +2,13 @@ package forge;
/** /**
* <p> * <p>
* Command interface. * Command interface, just like Guava Function but return type is void.
* </p> * </p>
* *
* @author Forge * @author Forge
* @version $Id: Command.java 12297 2011-11-28 19:56:47Z jendave $ * @version $Id: Command.java 12297 2011-11-28 19:56:47Z jendave $
*/ */
public interface Action<T> extends java.io.Serializable { public interface Action<T> {
/** /**
* <p> * <p>
* execute. * execute.

View File

@@ -5,6 +5,9 @@ import java.util.List;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import forge.Card; import forge.Card;
import forge.Command; import forge.Command;
@@ -16,6 +19,7 @@ import forge.card.spellability.AbilityActivated;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target; import forge.card.spellability.Target;
import forge.control.input.Input; import forge.control.input.Input;
import forge.control.input.InputSelectManyCards;
import forge.game.player.ComputerUtil; import forge.game.player.ComputerUtil;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.PlayerZone; import forge.game.zone.PlayerZone;
@@ -24,8 +28,6 @@ import forge.game.zone.ZoneType;
import forge.gui.GuiChoose; import forge.gui.GuiChoose;
import forge.gui.match.CMatchUI; import forge.gui.match.CMatchUI;
import forge.view.ButtonUtil;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
@@ -369,36 +371,19 @@ class CardFactoryArtifacts {
public void resolve() { public void resolve() {
// not implemented for compy // not implemented for compy
if (card.getController().isHuman()) { if (card.getController().isHuman()) {
Singletons.getModel().getMatch().getInput().setInput(new Input() {
private static final long serialVersionUID = -2305549394512889450L;
private final List<Card> exiled = new ArrayList<Card>();
Predicate<Card> validForPick = new Predicate<Card>() {
@Override @Override
public void showMessage() { public boolean apply(Card c) {
final StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" - Exile cards from hand. Currently, ");
sb.append(this.exiled.size()).append(" selected. (Press OK when done.)");
CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString());
ButtonUtil.enableOnlyOK();
}
@Override
public void selectButtonOK() {
this.done();
}
@Override
public void selectCard(final Card c) {
Zone zone = Singletons.getModel().getGame().getZoneOf(c); Zone zone = Singletons.getModel().getGame().getZoneOf(c);
if (zone.is(ZoneType.Hand) && c.getController() == card.getController() && !this.exiled.contains(c)) { return zone.is(ZoneType.Hand) && c.getController() == card.getController();
this.exiled.add(c);
this.showMessage();
}
} }
};
public void done() { Function<List<Card>, Input> onSelected = new Function<List<Card>, Input>() {
// exile those cards @Override
for (final Card c : this.exiled) { public Input apply(List<Card> exiled) {
for (final Card c : exiled) {
Singletons.getModel().getGame().getAction().exile(c); Singletons.getModel().getGame().getAction().exile(c);
} }
@@ -407,7 +392,7 @@ class CardFactoryArtifacts {
// Ruling: This is not a draw... // Ruling: This is not a draw...
final PlayerZone lib = card.getController().getZone(ZoneType.Library); final PlayerZone lib = card.getController().getZone(ZoneType.Library);
int numCards = 0; int numCards = 0;
while ((lib.size() > 0) && (numCards < this.exiled.size())) { while ((lib.size() > 0) && (numCards < exiled.size())) {
Singletons.getModel().getGame().getAction().moveToHand(lib.get(0)); Singletons.getModel().getGame().getAction().moveToHand(lib.get(0));
numCards++; numCards++;
} }
@@ -418,15 +403,20 @@ class CardFactoryArtifacts {
// Then look at the exiled cards and put them on // Then look at the exiled cards and put them on
// top of your library in any order. // top of your library in any order.
while (this.exiled.size() > 0) { while (exiled.size() > 0) {
final Card c1 = GuiChoose.one("Put a card on top of your library.", this.exiled); final Card c1 = GuiChoose.one("Put a card on top of your library.", exiled);
Singletons.getModel().getGame().getAction().moveToLibrary(c1); Singletons.getModel().getGame().getAction().moveToLibrary(c1);
this.exiled.remove(c1); exiled.remove(c1);
} }
return null;
};
};
InputSelectManyCards inp = new InputSelectManyCards(validForPick, 0, Integer.MAX_VALUE, onSelected);
inp.setMessage(card.getName() + " - Exile cards from hand. Currently, %d selected. (Press OK when done.)");
Singletons.getModel().getMatch().getInput().setInput(inp);
this.stop();
}
});
} }
} }

View File

@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import com.esotericsoftware.minlog.Log; import com.esotericsoftware.minlog.Log;
import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@@ -31,6 +32,7 @@ import forge.CardLists;
import forge.CardPredicates.Presets; import forge.CardPredicates.Presets;
import forge.CardUtil; import forge.CardUtil;
import forge.Command; import forge.Command;
import forge.Constant;
import forge.Singletons; import forge.Singletons;
import forge.card.cost.Cost; import forge.card.cost.Cost;
import forge.card.spellability.Ability; import forge.card.spellability.Ability;
@@ -39,11 +41,14 @@ import forge.card.spellability.SpellAbility;
import forge.card.spellability.SpellPermanent; import forge.card.spellability.SpellPermanent;
import forge.card.spellability.Target; import forge.card.spellability.Target;
import forge.control.input.Input; import forge.control.input.Input;
import forge.control.input.InputPayManaCost;
import forge.control.input.InputSelectManyCards;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.PlayerZone; import forge.game.zone.PlayerZone;
import forge.game.zone.Zone; import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose; import forge.gui.GuiChoose;
import forge.gui.match.CMatchUI;
/** /**
@@ -129,7 +134,7 @@ class CardFactoryAuras {
public void resolve() { public void resolve() {
// Only query player, AI will have decided already. // Only query player, AI will have decided already.
if (card.getController().isHuman()) { if (card.getController().isHuman()) {
newType[0] = GuiChoose.one("Select land type.", CardUtil.getLandTypes()); newType[0] = GuiChoose.one("Select land type.", Constant.CardTypes.BASIC_TYPES);
} }
Singletons.getModel().getGame().getAction().moveToPlay(card); Singletons.getModel().getGame().getAction().moveToPlay(card);
@@ -243,17 +248,36 @@ class CardFactoryAuras {
card.addUnEnchantCommand(onUnEnchant); card.addUnEnchantCommand(onUnEnchant);
card.addLeavesPlayCommand(onLeavesPlay); card.addLeavesPlayCommand(onLeavesPlay);
final Input runtime = new Input() { Function<List<Card>, Input> onSelected = new Function<List<Card>, Input>() {
private static final long serialVersionUID = -62372711146079880L;
@Override @Override
public void showMessage() { public final Input apply(List<Card> selected) {
final List<Card> land = Singletons.getModel().getGame().getLandsInPlay(); spell.setTargetCard(selected.get(0));
this.stopSetNext(CardFactoryUtil if (spell.getManaCost().equals("0")) {
.inputTargetSpecific(spell, land, "Select target land", true, false)); Singletons.getModel().getGame().getStack().add(spell);
return null;
} else {
return new InputPayManaCost(spell);
}
} }
}; };
Predicate<Card> canTarget = new Predicate<Card>() {
@Override
public boolean apply(Card c) {
if (!c.isLand() || !c.isInZone(ZoneType.Battlefield))
return false;
if (!c.canBeTargetedBy(spell)) {
CMatchUI.SINGLETON_INSTANCE.showMessage("Cannot target this card (Shroud? Protection?).");
return false;
}
return true;
}
};
InputSelectManyCards runtime = new InputSelectManyCards(canTarget, 1, 1, onSelected);
runtime.setMessage("Select target land");
spell.setBeforePayMana(runtime); spell.setBeforePayMana(runtime);
} // *************** END ************ END ************************** } // *************** END ************ END **************************

View File

@@ -67,7 +67,6 @@ import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerHandler; import forge.card.trigger.TriggerHandler;
import forge.card.trigger.TriggerType; import forge.card.trigger.TriggerType;
import forge.control.input.Input; import forge.control.input.Input;
import forge.control.input.InputPayManaCost;
import forge.control.input.InputPayManaCostUtil; import forge.control.input.InputPayManaCostUtil;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -1203,85 +1202,6 @@ public class CardFactoryUtil {
return entersBattleFieldWithCounters(sourceCard, Counters.TIME, power); return entersBattleFieldWithCounters(sourceCard, Counters.TIME, power);
} // vanishing } // vanishing
// List<Card> choices are the only cards the user can successful select
/**
* <p>
* inputTargetSpecific.
* </p>
*
* @param spell
* a {@link forge.card.spellability.SpellAbility} object.
* @param choices
* a {@link forge.CardList} object.
* @param message
* a {@link java.lang.String} object.
* @param targeted
* a boolean.
* @param free
* a boolean.
* @return a {@link forge.control.input.Input} object.
*/
public static Input inputTargetSpecific(final SpellAbility spell, final List<Card> choices, final String message,
final boolean targeted, final boolean free) {
return CardFactoryUtil.inputTargetSpecific(spell, choices, message, Command.BLANK, targeted, free);
}
// List<Card> choices are the only cards the user can successful select
/**
* <p>
* inputTargetSpecific.
* </p>
*
* @param spell
* a {@link forge.card.spellability.SpellAbility} object.
* @param choices
* a {@link forge.CardList} object.
* @param message
* a {@link java.lang.String} object.
* @param paid
* a {@link forge.Command} object.
* @param targeted
* a boolean.
* @param free
* a boolean.
* @return a {@link forge.control.input.Input} object.
*/
public static Input inputTargetSpecific(final SpellAbility spell, final List<Card> choices, final String message,
final Command paid, final boolean targeted, final boolean free) {
final Input target = new Input() {
private static final long serialVersionUID = -1779224307654698954L;
@Override
public void showMessage() {
CMatchUI.SINGLETON_INSTANCE.showMessage(message);
ButtonUtil.enableOnlyCancel();
}
@Override
public void selectButtonCancel() {
this.stop();
}
@Override
public void selectCard(final Card card) {
if (targeted && !card.canBeTargetedBy(spell)) {
CMatchUI.SINGLETON_INSTANCE.showMessage("Cannot target this card (Shroud? Protection?).");
} else if (choices.contains(card)) {
spell.setTargetCard(card);
if (spell.getManaCost().equals("0") || free) {
Singletons.getModel().getGame().getStack().add(spell);
this.stop();
} else {
this.stopSetNext(new InputPayManaCost(spell));
}
paid.execute();
}
} // selectCard()
};
return target;
} // inputTargetSpecific()
// List<Card> choices are the only cards the user can successful select // List<Card> choices are the only cards the user can successful select
/** /**
* <p> * <p>

View File

@@ -0,0 +1,110 @@
package forge.control.input;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import forge.Card;
import forge.gui.match.CMatchUI;
import forge.view.ButtonUtil;
/**
* TODO: Write javadoc for this type.
*
*/
public class InputSelectManyCards extends Input {
private static final long serialVersionUID = -2305549394512889450L;
private List<Card> allowedCards = null;
private Predicate<Card> allowedFilter = null;
private final List<Card> selected = new ArrayList<Card>();
private final Function<List<Card>, Input> onComplete;
private final int min;
private final int max;
private String message = "Source-Card-Name - Select %d more card(s)";
private InputSelectManyCards(int min, int max, final Function<List<Card>, Input> onDone)
{
onComplete = onDone;
if( min > max ) throw new IllegalArgumentException("Min must not be greater than Max");
this.min = min;
this.max = max;
}
public InputSelectManyCards(final List<Card> allowedList, int min, int max, final Function<List<Card>, Input> onDone)
{
this(min, max, onDone);
allowedCards = allowedList;
}
public InputSelectManyCards(final Predicate<Card> allowedRule, int min, int max, final Function<List<Card>, Input> onDone)
{
this(min, max, onDone);
allowedFilter = allowedRule;
}
@Override
public void showMessage() {
String msgToShow = max == Integer.MAX_VALUE ? String.format(message, selected.size()) : String.format(message, max - selected.size());
CMatchUI.SINGLETON_INSTANCE.showMessage(msgToShow);
boolean canCancel = min == 0 && selected.isEmpty();
boolean canOk = min <= selected.size();
if (canOk && canCancel) ButtonUtil.enableAll();
if (!canOk && canCancel) ButtonUtil.enableOnlyCancel();
if (canOk && !canCancel) ButtonUtil.enableOnlyOK();
if (!canOk && !canCancel) ButtonUtil.disableAll();
}
@Override
public void selectButtonOK() {
this.done();
}
@Override
public void selectButtonCancel() {
this.stop();
}
@Override
public void selectCard(final Card c) {
if ( selected.contains(c) ) return;
if ( allowedCards != null && !allowedCards.contains(c)) return;
if ( allowedFilter != null && !allowedFilter.apply(c)) return;
this.selected.add(c);
this.showMessage();
if ( selected.size() == max )
done();
}
public void done() {
Input next = onComplete.apply(selected);
if ( null == next )
this.stop();
else
this.stopSetNext(next);
}
@Override
public void isClassUpdated() {}
public String getMessage() {
return message;
}
public void setMessage(String message0) {
this.message = message0; // TODO: Add 0 to parameter's name.
}
}