mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
InputSelectManyCards - a common class for all those inlined target-choosing inputs
a fix for Phantasmal Terrain and Convincing Mirage
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 **************************
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -122,6 +122,6 @@ public abstract class Input implements java.io.Serializable {
|
|||||||
* This method is used to mark old descendants of Input
|
* This method is used to mark old descendants of Input
|
||||||
* TODO: Write javadoc for this method.
|
* TODO: Write javadoc for this method.
|
||||||
*/
|
*/
|
||||||
public /* abstract */void isClassUpdated(){} //;
|
public /* abstract */ void isClassUpdated() {}//;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
110
src/main/java/forge/control/input/InputSelectManyCards.java
Normal file
110
src/main/java/forge/control/input/InputSelectManyCards.java
Normal 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.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user