mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
moved convoke cards selection code from ManaCostBeingPaid to dedicated input for human player
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -15387,6 +15387,7 @@ forge-gui/src/main/java/forge/gui/input/InputPayManaSimple.java svneol=native#te
|
||||
forge-gui/src/main/java/forge/gui/input/InputPayManaX.java -text
|
||||
forge-gui/src/main/java/forge/gui/input/InputPlaybackControl.java -text
|
||||
forge-gui/src/main/java/forge/gui/input/InputProliferate.java -text
|
||||
forge-gui/src/main/java/forge/gui/input/InputSelectCardsForConvoke.java -text
|
||||
forge-gui/src/main/java/forge/gui/input/InputSelectCardsFromList.java -text
|
||||
forge-gui/src/main/java/forge/gui/input/InputSelectEntitiesFromList.java -text
|
||||
forge-gui/src/main/java/forge/gui/input/InputSelectManyBase.java -text
|
||||
|
||||
@@ -20,10 +20,10 @@ package forge.game.mana;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -38,12 +38,10 @@ import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.maps.EnumMapToAmount;
|
||||
import forge.util.maps.MapToAmount;
|
||||
@@ -569,7 +567,7 @@ public class ManaCostBeingPaid {
|
||||
}
|
||||
}
|
||||
else if (spell.getSourceCard().hasKeyword("Convoke")) {
|
||||
adjustCostByConvoke(sa, spell);
|
||||
adjustCostByConvoke(sa);
|
||||
}
|
||||
} // isSpell
|
||||
|
||||
@@ -617,82 +615,23 @@ public class ManaCostBeingPaid {
|
||||
}
|
||||
} // GetSpellCostChange
|
||||
|
||||
private void adjustCostByConvoke(final SpellAbility sa, final SpellAbility spell) {
|
||||
private void adjustCostByConvoke(final SpellAbility sa) {
|
||||
|
||||
List<Card> untappedCreats = CardLists.filter(spell.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES);
|
||||
List<Card> untappedCreats = CardLists.filter(sa.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES);
|
||||
untappedCreats = CardLists.filter(untappedCreats, CardPredicates.Presets.UNTAPPED);
|
||||
|
||||
while (!untappedCreats.isEmpty() && getConvertedManaCost() > 0) {
|
||||
Card workingCard = null;
|
||||
String chosenColor = null;
|
||||
if (sa.getActivatingPlayer().isHuman()) {
|
||||
workingCard = GuiChoose.oneOrNone("Tap for Convoke? " + toString(), untappedCreats);
|
||||
if (null == workingCard) {
|
||||
break; // that means "I'm done"
|
||||
}
|
||||
Map<Card, ManaCostShard> convokedCards = sa.getActivatingPlayer().getController().chooseCardsForConvoke(sa, this.toManaCost(), untappedCreats);
|
||||
|
||||
List<String> usableColors = getConvokableColors(workingCard);
|
||||
if (!usableColors.isEmpty()) {
|
||||
chosenColor = usableColors.size() == 1 ? usableColors.get(0) : GuiChoose.one("Convoke for which color?", usableColors);
|
||||
// Convoked creats are tapped here with triggers suppressed,
|
||||
// Then again when payment is done(In InputPayManaCost.done()) with suppression cleared.
|
||||
// This is to make sure that triggers go off at the right time
|
||||
// AND that you can't use mana tapabilities of convoked creatures to pay the convoked cost.
|
||||
for (final Entry<Card, ManaCostShard> conv : convokedCards.entrySet()) {
|
||||
sa.addTappedForConvoke(conv.getKey());
|
||||
this.decreaseShard(conv.getValue(), 1);
|
||||
conv.getKey().setTapped(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: AI to choose a creature to tap would go here
|
||||
// Probably along with deciding how many creatures to tap
|
||||
break;
|
||||
}
|
||||
untappedCreats.remove(workingCard);
|
||||
|
||||
if (null == chosenColor) {
|
||||
continue;
|
||||
}
|
||||
else if (chosenColor.equals("colorless")) {
|
||||
decreaseColorlessMana(1);
|
||||
}
|
||||
else {
|
||||
decreaseShard(ManaCostShard.valueOf(MagicColor.fromName(chosenColor)), 1);
|
||||
}
|
||||
|
||||
sa.addTappedForConvoke(workingCard);
|
||||
}
|
||||
|
||||
// Convoked creats are tapped here with triggers
|
||||
// suppressed,
|
||||
// Then again when payment is done(In
|
||||
// InputPayManaCost.done()) with suppression cleared.
|
||||
// This is to make sure that triggers go off at the
|
||||
// right time
|
||||
// AND that you can't use mana tapabilities of convoked
|
||||
// creatures
|
||||
// to pay the convoked cost.
|
||||
for (final Card c : sa.getTappedForConvoke()) {
|
||||
c.setTapped(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the convokable colors.
|
||||
*
|
||||
* @param cardToConvoke
|
||||
* the card to convoke
|
||||
* @param cost
|
||||
* the cost
|
||||
* @return the convokable colors
|
||||
*/
|
||||
private List<String> getConvokableColors(final Card cardToConvoke) {
|
||||
final ArrayList<String> usableColors = new ArrayList<String>();
|
||||
|
||||
if (getColorlessManaAmount() > 0) {
|
||||
usableColors.add("colorless");
|
||||
}
|
||||
ColorSet cs = CardUtil.getColors(cardToConvoke);
|
||||
for (byte color : MagicColor.WUBRG) {
|
||||
if (cs.hasAnyColor(color)) {
|
||||
usableColors.add(MagicColor.toLongString(color));
|
||||
}
|
||||
}
|
||||
return usableColors;
|
||||
}
|
||||
|
||||
private void adjustCostByOffering(final SpellAbility sa, final SpellAbility spell) {
|
||||
String offeringType = "";
|
||||
|
||||
@@ -13,6 +13,8 @@ import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
@@ -195,6 +197,7 @@ public abstract class PlayerController {
|
||||
public abstract List<AbilitySub> chooseModeForAbility(SpellAbility sa, int min, int num);
|
||||
|
||||
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 List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options);
|
||||
@@ -221,4 +224,9 @@ public abstract class PlayerController {
|
||||
public Collection<? extends PaperCard> complainCardsCantPlayWell(Deck myDeck) { return null; }
|
||||
|
||||
public abstract boolean payManaCost(CostPartMana costPartMana, PaymentDecision pd, SpellAbility sa);
|
||||
|
||||
public abstract Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost, List<Card> untappedCreats);
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import forge.ai.ComputerUtilMana;
|
||||
import forge.ai.ability.CharmAi;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
@@ -535,6 +537,18 @@ public class PlayerControllerAi extends PlayerController {
|
||||
return new ImmutablePair<CounterType,String>(countersOnCard.get(random),"Remove");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) {
|
||||
final String c = ComputerUtilCard.getMostProminentColor(player.getCardsIn(ZoneType.Hand));
|
||||
byte chosenColorMask = MagicColor.fromName(c);
|
||||
if ((colors.getColor() & chosenColorMask) != 0) {
|
||||
return chosenColorMask;
|
||||
} else {
|
||||
return Iterables.getFirst(colors, (byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte chooseColor(String message, SpellAbility sa, ColorSet colors) {
|
||||
final String c = ComputerUtilCard.getMostProminentColor(player.getCardsIn(ZoneType.Hand));
|
||||
@@ -713,4 +727,12 @@ public class PlayerControllerAi extends PlayerController {
|
||||
return ComputerUtilMana.payManaCost(player, sa);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost,
|
||||
List<Card> untappedCreats) {
|
||||
// TODO: AI to choose a creature to tap would go here
|
||||
// Probably along with deciding how many creatures to tap
|
||||
return new HashMap<Card, ManaCostShard>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package forge.gui.input;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.mana.ManaCostBeingPaid;
|
||||
import forge.game.player.Player;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public final class InputSelectCardsForConvoke extends InputSelectManyBase<Card> {
|
||||
private static final long serialVersionUID = -1779224307654698954L;
|
||||
private final Map<Card, ImmutablePair<Byte, ManaCostShard>> chosenCards = new HashMap<Card, ImmutablePair<Byte, ManaCostShard>>();
|
||||
private final ManaCostBeingPaid remainingCost;
|
||||
private final Player player;
|
||||
|
||||
public InputSelectCardsForConvoke(Player p, ManaCost cost, List<Card> untapped) {
|
||||
super(1, Math.min(cost.getCMC(), untapped.size()));
|
||||
remainingCost = new ManaCostBeingPaid(cost);
|
||||
player = p;
|
||||
allowUnselect = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected String getMessage() {
|
||||
return "Choose creatures to tap for convoke.\nRemaining mana cost is " + remainingCost.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardSelected(final Card card, final MouseEvent triggerEvent) {
|
||||
|
||||
boolean entityWasSelected = chosenCards.containsKey(card);
|
||||
if (entityWasSelected) {
|
||||
ImmutablePair<Byte, ManaCostShard> color = this.chosenCards.remove(card);
|
||||
remainingCost.increaseShard(color.right, 1);
|
||||
onSelectStateChanged(card, false);
|
||||
}
|
||||
else {
|
||||
|
||||
byte chosenColor = player.getController().chooseColorAllowColorless("Convoke " + card.toString() + " for which color?", card, CardUtil.getColors(card));
|
||||
|
||||
if (remainingCost.getColorlessManaAmount() > 0 && (chosenColor == 0 || !remainingCost.needsColor(chosenColor))) {
|
||||
registerConvoked(card, ManaCostShard.COLORLESS, chosenColor);
|
||||
} else {
|
||||
for (ManaCostShard shard : remainingCost.getDistinctShards()) {
|
||||
if (shard.canBePaidWithManaOfColor(chosenColor)) {
|
||||
registerConvoked(card, shard, chosenColor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
showMessage("The colors provided by " + card.toString() + " you've chosen cannot be used to decrease the manacost of " + remainingCost.toString());
|
||||
flashIncorrectAction();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
private void registerConvoked(Card card, ManaCostShard shard, byte chosenColor) {
|
||||
remainingCost.decreaseShard(shard, 1);
|
||||
chosenCards.put(card, ImmutablePair.of(chosenColor, shard));
|
||||
onSelectStateChanged(card, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected final void onPlayerSelected(Player player, final MouseEvent triggerEvent) {
|
||||
}
|
||||
|
||||
public Map<Card, ManaCostShard> getConvokeMap() {
|
||||
Map<Card, ManaCostShard> result = new HashMap<Card, ManaCostShard>();
|
||||
if( !hasCancelled() )
|
||||
for(Entry<Card, ImmutablePair<Byte, ManaCostShard>> c : chosenCards.entrySet())
|
||||
result.put(c.getKey(), c.getValue().right);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean hasEnoughTargets() { return true; }
|
||||
|
||||
@Override
|
||||
protected boolean hasAllTargets() { return false; }
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<Card> getSelected() {
|
||||
// TODO Auto-generated method stub
|
||||
return chosenCards.keySet();
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import com.google.common.collect.Multimap;
|
||||
import forge.Singletons;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
@@ -69,6 +71,7 @@ import forge.gui.input.InputBlock;
|
||||
import forge.gui.input.InputConfirmMulligan;
|
||||
import forge.gui.input.InputPassPriority;
|
||||
import forge.gui.input.InputProliferate;
|
||||
import forge.gui.input.InputSelectCardsForConvoke;
|
||||
import forge.gui.input.InputSelectCardsFromList;
|
||||
import forge.gui.input.InputConfirm;
|
||||
import forge.gui.input.InputSelectEntitiesFromList;
|
||||
@@ -898,19 +901,35 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
switch (cntColors) {
|
||||
case 0: return 0;
|
||||
case 1: return colors.getColor();
|
||||
default:
|
||||
default: return chooseColorCommon(message, sa == null ? null : sa.getSourceCard(), colors, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte chooseColorAllowColorless(String message, Card c, ColorSet colors) {
|
||||
int cntColors = 1 + colors.countColors();
|
||||
switch (cntColors) {
|
||||
case 1: return 0;
|
||||
default: return chooseColorCommon(message, c, colors, true);
|
||||
}
|
||||
}
|
||||
|
||||
private byte chooseColorCommon(String message, Card c, ColorSet colors, boolean withColorless) {
|
||||
int cntColors = colors.countColors();
|
||||
if( withColorless ) cntColors++;
|
||||
String[] colorNames = new String[cntColors];
|
||||
int i = 0;
|
||||
if(withColorless)
|
||||
colorNames[i++] = MagicColor.toLongString((byte)0);
|
||||
for (byte b : colors) {
|
||||
colorNames[i++] = MagicColor.toLongString(b);
|
||||
}
|
||||
if (colorNames.length > 2) {
|
||||
return MagicColor.fromName(GuiChoose.one(message, colorNames));
|
||||
}
|
||||
int idxChosen = GuiDialog.confirm(sa.getSourceCard(), message, colorNames) ? 0 : 1;
|
||||
int idxChosen = GuiDialog.confirm(c, message, colorNames) ? 0 : 1;
|
||||
return MagicColor.fromName(colorNames[idxChosen]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate<PaperCard> cpp, String name) {
|
||||
@@ -1059,4 +1078,11 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
// TODO Auto-generated method stub
|
||||
return HumanPlay.payManaCost(costPartMana, sa, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost, List<Card> untappedCreats) {
|
||||
InputSelectCardsForConvoke inp = new InputSelectCardsForConvoke(player, manaCost, untappedCreats);
|
||||
inp.showAndWait();
|
||||
return inp.getConvokeMap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import forge.ai.ability.DrawAi;
|
||||
import forge.ai.ability.GameWinAi;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
@@ -421,6 +423,12 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
return Iterables.getFirst(colors, MagicColor.WHITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) {
|
||||
return Iterables.getFirst(colors, (byte)0);
|
||||
}
|
||||
|
||||
|
||||
private <T> List<T> chooseItems(Collection<T> items, int amount) {
|
||||
if (items == null || items.isEmpty()) {
|
||||
return new ArrayList<T>(items);
|
||||
@@ -571,4 +579,12 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
// TODO Auto-generated method stub
|
||||
return ComputerUtilMana.payManaCost(player, sa);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost,
|
||||
List<Card> untappedCreats) {
|
||||
// TODO: AI to choose a creature to tap would go here
|
||||
// Probably along with deciding how many creatures to tap
|
||||
return new HashMap<Card, ManaCostShard>();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user