moved convoke cards selection code from ManaCostBeingPaid to dedicated input for human player

This commit is contained in:
Maxmtg
2014-01-20 07:32:12 +00:00
parent 6ced3d38a4
commit 89dcef5b67
7 changed files with 203 additions and 86 deletions

1
.gitattributes vendored
View File

@@ -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

View File

@@ -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 = "";

View File

@@ -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);
}

View File

@@ -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>();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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>();
}
}