Merge branch 'master' into 'master'

use multi-select for dig

Closes #799

See merge request core-developers/forge!1296
This commit is contained in:
Michael Kamensky
2019-01-21 14:47:08 +00:00
12 changed files with 307 additions and 96 deletions

View File

@@ -164,8 +164,34 @@ public class PlayerControllerAi extends PlayerController {
public <T extends GameEntity> List<T> chooseEntitiesForEffect( public <T extends GameEntity> List<T> chooseEntitiesForEffect(
FCollectionView<T> optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, FCollectionView<T> optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title,
Player targetedPlayer) { Player targetedPlayer) {
// this isn't used if (delayedReveal != null) {
return null; reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
}
FCollection<T> remaining = new FCollection<T>(optionList);
List<T> selecteds = new ArrayList<T>();
T selected;
do {
selected = chooseSingleEntityForEffect(remaining, null, sa, title, selecteds.size()>=min, targetedPlayer);
if ( selected != null ) {
remaining.remove(selected);
selecteds.add(selected);
}
} while ( (selected != null ) && (selecteds.size() < max) );
return selecteds;
}
@Override
public <T extends GameEntity> List<T> chooseFromTwoListsForEffect(FCollectionView<T> optionList1, FCollectionView<T> optionList2,
boolean optional, DelayedReveal delayedReveal, SpellAbility sa, String title, Player targetedPlayer) {
if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
}
T selected1 = chooseSingleEntityForEffect(optionList1, null, sa, title, optional, targetedPlayer);
T selected2 = chooseSingleEntityForEffect(optionList2, null, sa, title, optional || selected1!=null, targetedPlayer);
List<T> selecteds = new ArrayList<T>();
if ( selected1 != null ) { selecteds.add(selected1); }
if ( selected2 != null ) { selecteds.add(selected2); }
return selecteds;
} }
@Override @Override

View File

@@ -187,14 +187,14 @@ public class DigEffect extends SpellAbilityEffect {
if (!andOrValid.equals("")) { if (!andOrValid.equals("")) {
andOrCards = CardLists.getValidCards(top, andOrValid.split(","), host.getController(), host, sa); andOrCards = CardLists.getValidCards(top, andOrValid.split(","), host.getController(), host, sa);
andOrCards.removeAll((Collection<?>)valid); andOrCards.removeAll((Collection<?>)valid);
valid.addAll(andOrCards); valid.addAll(andOrCards); //pfps need to add andOr cards to valid to have set of all valid cards set up
} }
else { else {
andOrCards = new CardCollection(); andOrCards = new CardCollection();
} }
} }
else { else {
// If all the cards are valid choices, no need for a separate reveal dialog to the chooser. // If all the cards are valid choices, no need for a separate reveal dialog to the chooser. pfps??
if (p == chooser && destZone1ChangeNum > 1) { if (p == chooser && destZone1ChangeNum > 1) {
delayedReveal = null; delayedReveal = null;
} }
@@ -238,54 +238,40 @@ public class DigEffect extends SpellAbilityEffect {
if (sa.hasParam("RandomOrder")) { if (sa.hasParam("RandomOrder")) {
CardLists.shuffle(movedCards); CardLists.shuffle(movedCards);
} }
} } else {
else {
String prompt; String prompt;
if (sa.hasParam("PrimaryPrompt")) { if (sa.hasParam("PrimaryPrompt")) {
prompt = sa.getParam("PrimaryPrompt"); prompt = sa.getParam("PrimaryPrompt");
} else { } else {
prompt = "Choose a card to put into " + destZone1.name(); prompt = "Choose card(s) to put into " + destZone1.name();
if (destZone1.equals(ZoneType.Library)) { if (destZone1.equals(ZoneType.Library)) {
if (libraryPosition == -1) { if (libraryPosition == -1) {
prompt = "Choose a card to put on the bottom of {player's} library"; prompt = "Choose card(s) to put on the bottom of {player's} library";
} } else if (libraryPosition == 0) {
else if (libraryPosition == 0) { prompt = "Choose card(s) to put on top of {player's} library";
prompt = "Choose a card to put on top of {player's} library";
} }
} }
} }
movedCards = new CardCollection(); movedCards = new CardCollection();
for (int i = 0; i < destZone1ChangeNum || (anyNumber && i < numToDig); i++) { if (valid.isEmpty()) {
// let user get choice
Card chosen = null;
if (!valid.isEmpty()) {
// If we're choosing multiple cards, only need to show the reveal dialog the first time through.
boolean shouldReveal = (i == 0);
chosen = chooser.getController().chooseSingleEntityForEffect(valid, shouldReveal ? delayedReveal : null, sa, prompt, anyNumber || optional, p);
}
else {
if (i == 0) {
chooser.getController().notifyOfValue(sa, null, "No valid cards"); chooser.getController().notifyOfValue(sa, null, "No valid cards");
} else {
if ( p == chooser ) { // the digger can still see all the dug cards when choosing
chooser.getController().tempShowCards(top);
} }
} List<Card> chosen;
if (chosen == null) {
break;
}
movedCards.add(chosen);
valid.remove(chosen);
if (!andOrValid.equals("")) { if (!andOrValid.equals("")) {
andOrCards.remove(chosen); valid.removeAll(andOrCards); //pfps remove andOr cards to get two two choices set up correctly
if (!chosen.isValid(andOrValid.split(","), host.getController(), host, sa)) { chosen = chooser.getController().chooseFromTwoListsForEffect(valid, andOrCards, optional, delayedReveal, sa, prompt, p);
valid = new CardCollection(andOrCards); } else {
} int min = (anyNumber || optional) ? 0 : numToDig;
else if (!chosen.isValid(changeValid.split(","), host.getController(), host, sa)) { int max = Math.max(destZone1ChangeNum, anyNumber ? valid.size() : 0);
valid.removeAll((Collection<?>)andOrCards); chosen = chooser.getController().chooseEntitiesForEffect(valid, min, max, delayedReveal, sa, prompt, p);
}
} }
chooser.getController().endTempShowCards();
movedCards.addAll(chosen);
} }
if (!changeValid.isEmpty() && !sa.hasParam("ExileFaceDown") && !sa.hasParam("NoReveal")) { if (!changeValid.isEmpty() && !sa.hasParam("ExileFaceDown") && !sa.hasParam("NoReveal")) {

View File

@@ -81,6 +81,9 @@ public abstract class PlayerController {
public Player getPlayer() { return player; } public Player getPlayer() { return player; }
public LobbyPlayer getLobbyPlayer() { return lobbyPlayer; } public LobbyPlayer getLobbyPlayer() { return lobbyPlayer; }
public void tempShowCards(final Iterable<Card> cards) { } // show cards in UI until ended
public void endTempShowCards() { }
public final SpellAbility getAbilityToPlay(final Card hostCard, final List<SpellAbility> abilities) { return getAbilityToPlay(hostCard, abilities, null); } public final SpellAbility getAbilityToPlay(final Card hostCard, final List<SpellAbility> abilities) { return getAbilityToPlay(hostCard, abilities, null); }
public abstract SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent); public abstract SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent);
@@ -112,6 +115,7 @@ public abstract class PlayerController {
Map<String, Object> params); Map<String, Object> params);
public abstract <T extends GameEntity> List<T> chooseEntitiesForEffect(FCollectionView<T> optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer); public abstract <T extends GameEntity> List<T> chooseEntitiesForEffect(FCollectionView<T> optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer);
public abstract <T extends GameEntity> List<T> chooseFromTwoListsForEffect(FCollectionView<T> optionList1, FCollectionView<T> optionList2, boolean optional, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer);
public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message); public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message);
public abstract boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife, String string, int bid, Player winner); public abstract boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife, String string, int bid, Player winner);

View File

@@ -271,18 +271,18 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
// Magenta outline for when card was chosen to pay // Magenta outline for when card was chosen to pay
if (matchUI.isUsedToPay(getCard())) { if (matchUI.isUsedToPay(getCard())) {
g2d.setColor(Color.magenta); g2d.setColor(Color.magenta);
final int n2 = Math.max(1, Math.round(2 * cardWidth * CardPanel.SELECTED_BORDER_SIZE)); final int n2 = Math.max(4, Math.round(2 * cardWidth * CardPanel.SELECTED_BORDER_SIZE));
g2d.fillRoundRect(cardXOffset - n2, (cardYOffset - n2) + offset, cardWidth + (n2 * 2), cardHeight + (n2 * 2), cornerSize + n2, cornerSize + n2); g2d.fillRoundRect(cardXOffset - n2, (cardYOffset - n2) + offset, cardWidth + (n2 * 2), cardHeight + (n2 * 2), cornerSize + n2, cornerSize + n2);
} else if (matchUI.isSelectable(getCard())) { // Cyan outline for selectable cards } else if (matchUI.isSelectable(getCard())) { // Cyan outline for selectable cards
g2d.setColor(Color.cyan); g2d.setColor(Color.cyan);
final int n2 = Math.max(1, Math.round(2 * cardWidth * CardPanel.SELECTED_BORDER_SIZE)); final int n2 = Math.max(4, Math.round(2 * cardWidth * CardPanel.SELECTED_BORDER_SIZE));
g2d.fillRoundRect(cardXOffset - n2, (cardYOffset - n2) + offset, cardWidth + (n2 * 2), cardHeight + (n2 * 2), cornerSize + n2, cornerSize + n2); g2d.fillRoundRect(cardXOffset - n2, (cardYOffset - n2) + offset, cardWidth + (n2 * 2), cardHeight + (n2 * 2), cornerSize + n2, cornerSize + n2);
} }
// Green outline for hover // Green outline for hover
if (isSelected) { if (isSelected) {
g2d.setColor(Color.green); g2d.setColor(Color.green);
final int n = Math.max(1, Math.round(cardWidth * CardPanel.SELECTED_BORDER_SIZE)); final int n = Math.max(4, Math.round(cardWidth * CardPanel.SELECTED_BORDER_SIZE));
g2d.fillRoundRect(cardXOffset - n, (cardYOffset - n) + offset, cardWidth + (n * 2), cardHeight + (n * 2), cornerSize + n , cornerSize + n); g2d.fillRoundRect(cardXOffset - n, (cardYOffset - n) + offset, cardWidth + (n * 2), cardHeight + (n * 2), cornerSize + n , cornerSize + n);
} }

View File

@@ -179,6 +179,12 @@ public class PlayerControllerForTests extends PlayerController {
return null; return null;
} }
@Override
public <T extends GameEntity> List<T> chooseFromTwoListsForEffect(FCollectionView<T> optionList1, FCollectionView<T> optionList2, boolean optional, DelayedReveal delayedReveal, SpellAbility sa, String title, Player targetedPlayer) {
// this isn't used
return null;
}
@Override @Override
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) { public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return true; return true;

View File

@@ -517,7 +517,9 @@ public class MatchController extends AbstractGuiGame {
@Override @Override
public List<GameEntityView> chooseEntitiesForEffect(String title, List<? extends GameEntityView> optionList, int min, int max, DelayedReveal delayedReveal) { public List<GameEntityView> chooseEntitiesForEffect(String title, List<? extends GameEntityView> optionList, int min, int max, DelayedReveal delayedReveal) {
return SGuiChoose.order(title, "Selected", min, max, (List<GameEntityView>) optionList, null); final int m1 = max >= 0 ? optionList.size() - max : -1;
final int m2 = min >= 0 ? optionList.size() - min : -1;
return SGuiChoose.order(title, "Selected", m1, m2, (List<GameEntityView>) optionList, null);
} }
@Override @Override

View File

@@ -244,8 +244,8 @@ public class GuiChoose {
} }
public static <T> void many(final String title, final String topCaption, int min, int max, final List<T> sourceChoices, CardView referenceCard, final Callback<List<T>> callback) { public static <T> void many(final String title, final String topCaption, int min, int max, final List<T> sourceChoices, CardView referenceCard, final Callback<List<T>> callback) {
int m2 = min >= 0 ? sourceChoices.size() - min : -1;
int m1 = max >= 0 ? sourceChoices.size() - max : -1; int m1 = max >= 0 ? sourceChoices.size() - max : -1;
int m2 = min >= 0 ? sourceChoices.size() - min : -1;
order(title, topCaption, m1, m2, sourceChoices, null, referenceCard, callback); order(title, topCaption, m1, m2, sourceChoices, null, referenceCard, callback);
} }

View File

@@ -1,3 +1,10 @@
- Desktop GUI -
The Desktop GUI can pop up zones (Library, Graveyard, etc.) allow players to select cards from them when the option UI_SELECT_FROM_CARD_DISPLAYS is set.
The Desktop GUI outlines the selectable cards in many situations. This is not done when playing mana costs.
- Digging -
Multi-card digging (e.g., for Genesis Wave) is done as a single multiple-card selection instead of a sequence of single-card selections.
- Game Night - - Game Night -
Support was added for the Game Night box set, including all 10 exclusive cards. Support was added for the Game Night box set, including all 10 exclusive cards.

View File

@@ -42,7 +42,7 @@ public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSele
vCards.add(((Card)c).getView()) ; vCards.add(((Card)c).getView()) ;
} }
} }
controller.getGui().setSelectables(vCards); getController().getGui().setSelectables(vCards);
final PlayerZoneUpdates zonesToUpdate = new PlayerZoneUpdates(); final PlayerZoneUpdates zonesToUpdate = new PlayerZoneUpdates();
for (final GameEntity c : validChoices) { for (final GameEntity c : validChoices) {
final Zone cz = (c instanceof Card) ? ((Card) c).getZone() : null ; final Zone cz = (c instanceof Card) ? ((Card) c).getZone() : null ;
@@ -52,8 +52,8 @@ public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSele
} }
FThreads.invokeInEdtNowOrLater(new Runnable() { FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public void run() { @Override public void run() {
controller.getGui().updateZones(zonesToUpdate); getController().getGui().updateZones(zonesToUpdate);
zonesShown = controller.getGui().tempShowZones(controller.getPlayer().getView(),zonesToUpdate); zonesShown = getController().getGui().tempShowZones(controller.getPlayer().getView(),zonesToUpdate);
} }
}); });
} }

View File

@@ -0,0 +1,152 @@
package forge.match.input;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import forge.game.GameEntity;
import forge.game.card.Card;
import forge.game.card.CardView;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.player.PlayerControllerHuman;
import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView;
import forge.util.ITriggerEvent;
import forge.player.PlayerZoneUpdate;
import forge.player.PlayerZoneUpdates;
import forge.game.zone.Zone;
import forge.FThreads;
public class InputSelectFromTwoLists<T extends GameEntity> extends InputSelectManyBase<T> {
private final FCollectionView<T> valid1, valid2;
private final FCollection<T> validBoth;
private FCollectionView<T> validChoices;
protected final FCollection<T> selected = new FCollection<T>();
protected final PlayerZoneUpdates zonesToUpdate = new PlayerZoneUpdates();
protected Iterable<PlayerZoneUpdate> zonesShown; // want to hide these zones when input done
public InputSelectFromTwoLists(final PlayerControllerHuman controller, final boolean optional,
final FCollectionView<T> list1, final FCollectionView<T> list2, final SpellAbility sa0) {
super(controller, optional?0:1, 2, sa0);
valid1 = list1;
valid2 = list2;
validBoth = new FCollection<T>(valid1);
for ( T v : valid2 ) { validBoth.add(v); }
validChoices = validBoth;
setSelectables();
for (final GameEntity c : validChoices) {
final Zone cz = (c instanceof Card) ? ((Card) c).getZone() : null ;
if ( cz != null ) {
zonesToUpdate.add(new PlayerZoneUpdate(cz.getPlayer().getView(),cz.getZoneType()));
}
}
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public void run() {
controller.getGui().updateZones(zonesToUpdate);
zonesShown = controller.getGui().tempShowZones(controller.getPlayer().getView(),zonesToUpdate);
}
});
}
private void setSelectables() {
ArrayList<CardView> vCards = new ArrayList<CardView>();
getController().getGui().clearSelectables();
for ( T c : validChoices ) {
if ( c instanceof Card ) {
vCards.add(((Card)c).getView()) ;
}
}
getController().getGui().setSelectables(vCards);
}
private void setValid() {
boolean selected1 = false, selected2 = false;
for ( T s : selected ) {
if ( valid1.contains(s) ) { selected1 = true; }
if ( valid2.contains(s) ) { selected2 = true; }
}
validChoices = selected1 ? ( selected2 ? FCollection.getEmpty() : valid2 ) : ( selected2 ? valid1 : validBoth );
setSelectables();
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public void run() {
getController().getGui().updateZones(zonesToUpdate);
}
});
}
@Override
protected boolean onCardSelected(final Card c, final List<Card> otherCardsToSelect, final ITriggerEvent triggerEvent) {
if (!selectEntity(c)) {
return false;
}
refresh();
return true;
}
@Override
public String getActivateAction(final Card card) {
if (validChoices.contains(card)) {
if (selected.contains(card)) {
return "unselect card";
}
return "select card";
}
return null;
}
@Override
protected void onPlayerSelected(final Player p, final ITriggerEvent triggerEvent) {
if (!selectEntity(p)) {
return;
}
refresh();
}
@Override
public final Collection<T> getSelected() {
return selected;
}
@SuppressWarnings("unchecked")
protected boolean selectEntity(final GameEntity c) {
if (!validChoices.contains(c) && !selected.contains(c)) {
return false;
}
final boolean entityWasSelected = selected.contains(c);
if (entityWasSelected) {
selected.remove(c);
}
else {
selected.add((T)c);
}
setValid();
onSelectStateChanged(c, !entityWasSelected);
return true;
}
// might re-define later
@Override
protected boolean hasEnoughTargets() { return selected.size() >= min; }
@Override
protected boolean hasAllTargets() { return selected.size() >= max; }
@Override
protected String getMessage() {
return max == Integer.MAX_VALUE
? String.format(message, selected.size())
: String.format(message, max - selected.size());
}
@Override
protected void onStop() {
getController().getGui().hideZones(getController().getPlayer().getView(),zonesShown);
getController().getGui().clearSelectables();
super.onStop();
}
}

View File

@@ -156,7 +156,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
c.setMayLookAt(player, true, true); c.setMayLookAt(player, true, true);
} }
private void tempShowCards(final Iterable<Card> cards) { @Override
public void tempShowCards(final Iterable<Card> cards) {
if (mayLookAtAllCards) { if (mayLookAtAllCards) {
return; return;
} // no needed if this is set } // no needed if this is set
@@ -166,7 +167,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
} }
} }
private void endTempShowCards() { @Override
public void endTempShowCards() {
if (tempShownCards.isEmpty()) { if (tempShownCards.isEmpty()) {
return; return;
} }
@@ -405,6 +407,15 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return choices; return choices;
} }
// pfps there should be a better way
private GameEntity convertToEntity(final GameEntityView view) {
if (view instanceof CardView) {
return game.getCard((CardView) view);
} else if (view instanceof PlayerView) {
return game.getPlayer((PlayerView) view);
} else return null;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T extends GameEntity> T chooseSingleEntityForEffect(final FCollectionView<T> optionList, public <T extends GameEntity> T chooseSingleEntityForEffect(final FCollectionView<T> optionList,
@@ -427,12 +438,11 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return Iterables.getFirst(optionList, null); return Iterables.getFirst(optionList, null);
} }
if (useSelectCardsInput(optionList)) {
if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(),
delayedReveal.getMessagePrefix());
}
tempShow(optionList); tempShow(optionList);
if (delayedReveal != null) {
tempShow(delayedReveal.getCards());
}
if (useSelectCardsInput(optionList)) {
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, isOptional ? 0 : 1, 1, final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, isOptional ? 0 : 1, 1,
optionList, sa); optionList, sa);
input.setCancelAllowed(isOptional); input.setCancelAllowed(isOptional);
@@ -442,21 +452,10 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return Iterables.getFirst(input.getSelected(), null); return Iterables.getFirst(input.getSelected(), null);
} }
tempShow(optionList);
if (delayedReveal != null) {
tempShow(delayedReveal.getCards());
}
final GameEntityView result = getGui().chooseSingleEntityForEffect(title, final GameEntityView result = getGui().chooseSingleEntityForEffect(title,
GameEntityView.getEntityCollection(optionList), delayedReveal, isOptional); GameEntityView.getEntityCollection(optionList), delayedReveal, isOptional);
endTempShowCards(); endTempShowCards();
return (T) convertToEntity(result);
if (result instanceof CardView) {
return (T) game.getCard((CardView) result);
}
if (result instanceof PlayerView) {
return (T) game.getPlayer((PlayerView) result);
}
return null;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -468,8 +467,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
Sentry.getContext().addExtra("Card", sa.getCardView().toString()); Sentry.getContext().addExtra("Card", sa.getCardView().toString());
Sentry.getContext().addExtra("SpellAbility", sa.toString()); Sentry.getContext().addExtra("SpellAbility", sa.toString());
// Human is supposed to read the message and understand from it what to // Human is supposed to read the message and understand from it what to // choose
// choose
if (optionList.isEmpty()) { if (optionList.isEmpty()) {
if (delayedReveal != null) { if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(),
@@ -478,12 +476,12 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return null; return null;
} }
if (useSelectCardsInput(optionList)) {
if (delayedReveal != null) { if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), tempShow(delayedReveal.getCards());
delayedReveal.getMessagePrefix());
} }
tempShow(optionList); tempShow(optionList);
if (useSelectCardsInput(optionList)) {
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, min, max, final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, min, max,
optionList, sa); optionList, sa);
input.setCancelAllowed(true); input.setCancelAllowed(true);
@@ -492,16 +490,11 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
endTempShowCards(); endTempShowCards();
return (List<T>) input.getSelected(); return (List<T>) input.getSelected();
} }
tempShow(optionList);
if (delayedReveal != null) {
tempShow(delayedReveal.getCards());
}
final List<GameEntityView> chosen = getGui().chooseEntitiesForEffect(title, final List<GameEntityView> chosen = getGui().chooseEntitiesForEffect(title,
GameEntityView.getEntityCollection(optionList), min, max, delayedReveal); GameEntityView.getEntityCollection(optionList), min, max, delayedReveal);
endTempShowCards(); endTempShowCards();
List<T> results = new ArrayList<>(); List<T> results = new ArrayList<>(); //pfps I'm not sure that the chosens should be modified this way
if (chosen instanceof List && chosen.size() > 0) { if (chosen instanceof List && chosen.size() > 0) {
for (GameEntityView entry: chosen) { for (GameEntityView entry: chosen) {
if (entry instanceof CardView) { if (entry instanceof CardView) {
@@ -515,6 +508,41 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return results; return results;
} }
@Override
public <T extends GameEntity> List<T> chooseFromTwoListsForEffect(final FCollectionView<T> optionList1, final FCollectionView<T> optionList2,
boolean optional, final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer) {
// Human is supposed to read the message and understand from it what to choose
// useful details for debugging problems with the mass select logic
Sentry.getContext().addExtra("Card", sa.getCardView().toString());
Sentry.getContext().addExtra("SpellAbility", sa.toString());
if (delayedReveal != null) {
tempShow(delayedReveal.getCards());
}
tempShow(optionList1);
tempShow(optionList2);
if (useSelectCardsInput(optionList1) && useSelectCardsInput(optionList2)) {
final InputSelectFromTwoLists<T> input = new InputSelectFromTwoLists<T>(this, optional, optionList1, optionList2, sa);
input.setCancelAllowed(optional);
input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer));
input.showAndWait();
endTempShowCards();
return (List<T>) input.getSelected();
}
final GameEntityView result1 = getGui().chooseSingleEntityForEffect(title, GameEntityView.getEntityCollection(optionList1), null, optional);
final GameEntityView result2 = getGui().chooseSingleEntityForEffect(title, GameEntityView.getEntityCollection(optionList2), null, (result1==null)?optional:true);
endTempShowCards();
List<T> results = new ArrayList<>();
GameEntity entity1 = convertToEntity(result1);
if (entity1!=null) { results.add((T) entity1); }
GameEntity entity2 = convertToEntity(result2);
if (entity2!=null) { results.add((T) entity2); }
return results;
}
@Override @Override
public int chooseNumber(final SpellAbility sa, final String title, final int min, final int max) { public int chooseNumber(final SpellAbility sa, final String title, final int min, final int max) {
if (min >= max) { if (min >= max) {

View File

@@ -163,8 +163,8 @@ public class SGuiChoose {
} }
public static <T> List<T> many(final String title, final String topCaption, final int min, final int max, final List<T> sourceChoices) { public static <T> List<T> many(final String title, final String topCaption, final int min, final int max, final List<T> sourceChoices) {
final int m2 = min >= 0 ? sourceChoices.size() - min : -1;
final int m1 = max >= 0 ? sourceChoices.size() - max : -1; final int m1 = max >= 0 ? sourceChoices.size() - max : -1;
final int m2 = min >= 0 ? sourceChoices.size() - min : -1;
return order(title, topCaption, m1, m2, sourceChoices, null); return order(title, topCaption, m1, m2, sourceChoices, null);
} }