removing more player type checks from discard

This commit is contained in:
Maxmtg
2013-02-25 20:19:36 +00:00
parent 5147a891c9
commit ebd38fd02a
5 changed files with 132 additions and 113 deletions

View File

@@ -5,6 +5,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@@ -18,7 +19,6 @@ import forge.game.player.AIPlayer;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose; import forge.gui.GuiChoose;
import forge.gui.GuiDialog;
import forge.util.Aggregates; import forge.util.Aggregates;
public class DiscardEffect extends RevealEffectBase { public class DiscardEffect extends RevealEffectBase {
@@ -86,34 +86,6 @@ public class DiscardEffect extends RevealEffectBase {
return sb.toString(); return sb.toString();
} // discardStackDescription() } // discardStackDescription()
private List<Card> discardComputerChooses(SpellAbility sa, Player victim, Player chooser, int numCards, String[] dValid, boolean isReveal) {
final Card source = sa.getSourceCard();
List<Card> dPChHand = new ArrayList<Card>(victim.getCardsIn(ZoneType.Hand));
dPChHand = CardLists.getValidCards(dPChHand, dValid, source.getController(), source);
final List<Card> toDiscard = new ArrayList<Card>();
int max = Math.min(dPChHand.size(), numCards);
List<Card> list = new ArrayList<Card>();
if (!victim.isOpponentOf(chooser) && victim instanceof AIPlayer) { // discard AI cards
list = ((AIPlayer) victim).getAi().getCardsToDiscard(max, dValid, sa);
} else {
// discard hostile or human opponent
for (int i = 0; i < max; i++) {
Card dC = chooseCardToDiscardFromOpponent(sa, dPChHand);
dPChHand.remove(dC);
list.add(dC);
}
}
if (isReveal) {
GuiChoose.oneOrNone("Computer has chosen", list);
}
return toDiscard;
}
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @param sa * @param sa
@@ -207,19 +179,9 @@ public class DiscardEffect extends RevealEffectBase {
} }
if (mode.equals("Random")) { if (mode.equals("Random")) {
boolean runDiscard = true; String message = "Would you like to discard " + numCards + " random card(s)?";
if (sa.hasParam("Optional")) { boolean runDiscard = !sa.hasParam("Optional") || p.getController().confirmAction(sa, mode, message);
if (p.isHuman()) {
// TODO Ask if Human would like to discard a card at Random
StringBuilder sb = new StringBuilder("Would you like to discard ");
sb.append(numCards).append(" random card(s)?");
runDiscard = GuiDialog.confirm(source, sb.toString());
}
else {
// TODO For now AI will always discard Random used currently with:
// Balduvian Horde and similar cards
}
}
if (runDiscard) { if (runDiscard) {
final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card"; final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card";
@@ -253,68 +215,88 @@ public class DiscardEffect extends RevealEffectBase {
// Is Reveal you choose right? I think the wrong player is // Is Reveal you choose right? I think the wrong player is
// being used? // being used?
List<Card> dPHand = new ArrayList<Card>(p.getCardsIn(ZoneType.Hand)); List<Card> dPHand = new ArrayList<Card>(p.getCardsIn(ZoneType.Hand));
if (dPHand.size() != 0) { if (dPHand.isEmpty())
if (sa.hasParam("RevealNumber")) { continue; // for loop over players
String amountString = sa.getParam("RevealNumber");
int amount = amountString.matches("[0-9][0-9]?") ? Integer.parseInt(amountString)
: CardFactoryUtil.xCount(source, source.getSVar(amountString));
dPHand = getRevealedList(p, dPHand, amount, false);
}
List<Card> dPChHand = new ArrayList<Card>(dPHand);
final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card";
String[] dValid = ArrayUtils.EMPTY_STRING_ARRAY;
dValid = valid.split(",");
dPChHand = CardLists.getValidCards(dPHand, dValid, source.getController(), source);
Player chooser = p; if (sa.hasParam("RevealNumber")) {
if (mode.equals("RevealYouChoose")) { String amountString = sa.getParam("RevealNumber");
chooser = source.getController(); int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString));
} else if (mode.equals("RevealOppChoose")) { dPHand = getRevealedList(p, dPHand, amount, false);
chooser = source.getController().getOpponent(); }
} List<Card> dPChHand = new ArrayList<Card>(dPHand);
final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card";
String[] dValid = ArrayUtils.EMPTY_STRING_ARRAY;
dValid = valid.split(",");
dPChHand = CardLists.getValidCards(dPHand, dValid, source.getController(), source);
List<Card> toBeDiscarded = new ArrayList<Card>(); Player chooser = p;
if (chooser.isComputer()) { if (mode.equals("RevealYouChoose")) {
toBeDiscarded = discardComputerChooses(sa, p, chooser, numCards, dValid, mode.startsWith("Reveal")); chooser = source.getController();
} else if (mode.equals("RevealOppChoose")) {
chooser = source.getController().getOpponent();
}
List<Card> toBeDiscarded = new ArrayList<Card>();
if (chooser.isComputer()) {
List<Card> dPChHand1 = new ArrayList<Card>(p.getCardsIn(ZoneType.Hand));
dPChHand1 = CardLists.getValidCards(dPChHand1, dValid, source.getController(), source);
int max = Math.min(dPChHand1.size(), numCards);
List<Card> list = new ArrayList<Card>();
if (!p.isOpponentOf(chooser) && p instanceof AIPlayer) { // discard AI cards
toBeDiscarded = ((AIPlayer) p).getAi().getCardsToDiscard(max, dValid, sa);
} else { } else {
// human // discard hostile or human opponent
if (mode.startsWith("Reveal")) { for (int i = 0; i < max; i++) {
GuiChoose.oneOrNone("Revealed " + p + " hand", dPHand); Card dC = chooseCardToDiscardFromOpponent(sa, dPChHand1);
} dPChHand1.remove(dC);
toBeDiscarded.add(dC);
if (sa.hasParam("AnyNumber")) {
List<Card> chosen = getDiscardedList(p, dPChHand, dPChHand.size(), true);
for (Card c : chosen) {
dPChHand.remove(chosen);
toBeDiscarded.add(c);
}
} else
for (int i = 0; i < numCards; i++) {
if (dPChHand.isEmpty()) {
break;
}
Card dC = null;
if (sa.hasParam("Optional")) {
dC = GuiChoose.oneOrNone("Choose a card to be discarded", dPChHand);
} else {
dC = GuiChoose.one("Choose a card to be discarded", dPChHand);
}
if (dC != null) {
dPChHand.remove(dC);
toBeDiscarded.add(dC);
}
else break;
} }
} }
if (mode.startsWith("Reveal")) {
GuiChoose.oneOrNone("Computer has chosen", list);
}
if (toBeDiscarded != null) { } else {
for (Card card : toBeDiscarded) { // human
if ( null == card ) continue; if (mode.startsWith("Reveal")) {
p.discard(card, sa); GuiChoose.oneOrNone("Revealed " + p + " hand", dPHand);
discarded.add(card); }
if (sa.hasParam("AnyNumber")) {
List<Card> chosen = getDiscardedList(p, dPChHand);
for (Card c : chosen) {
dPChHand.remove(chosen);
toBeDiscarded.add(c);
} }
} else
for (int i = 0; i < numCards; i++) {
if (dPChHand.isEmpty()) {
break;
}
Card dC = null;
if (sa.hasParam("Optional")) {
dC = GuiChoose.oneOrNone("Choose a card to be discarded", dPChHand);
} else {
dC = GuiChoose.one("Choose a card to be discarded", dPChHand);
}
if (dC != null) {
dPChHand.remove(dC);
toBeDiscarded.add(dC);
}
else break;
}
}
if (toBeDiscarded != null) {
for (Card card : toBeDiscarded) {
if ( null == card ) continue;
p.discard(card, sa);
discarded.add(card);
} }
} }
} }
@@ -329,11 +311,11 @@ public class DiscardEffect extends RevealEffectBase {
} // discardResolve() } // discardResolve()
public static List<Card> getDiscardedList(final Player player, final List<Card> valid, final int max, boolean anyNumber) { public static List<Card> getDiscardedList(final Player player, final List<Card> valid) {
final List<Card> chosen = new ArrayList<Card>(); final List<Card> chosen = new ArrayList<Card>();
final int validamount = Math.min(valid.size(), max); final int validamount = Math.min(valid.size(), valid.size());
if (anyNumber && player.isHuman() && validamount > 0) { if (player.isHuman() && validamount > 0) {
final List<Card> selection = GuiChoose.order("Choose Which Cards to Discard", "Discarded", -1, valid, null, null); final List<Card> selection = GuiChoose.order("Choose Which Cards to Discard", "Discarded", -1, valid, null, null);
for (final Object o : selection) { for (final Object o : selection) {
if (o != null && o instanceof Card) { if (o != null && o instanceof Card) {

View File

@@ -17,6 +17,7 @@
*/ */
package forge.game.ai; package forge.game.ai;
import java.security.InvalidParameterException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@@ -545,7 +546,7 @@ public class AiController {
// look for good discards // look for good discards
while (count < numDiscard) { while (count < numDiscard) {
Card prefCard = null; Card prefCard = null;
if (sa != null && sa.getActivatingPlayer() != null && sa.getActivatingPlayer().isHuman()) { if (sa != null && sa.getActivatingPlayer() != null && sa.getActivatingPlayer().isOpponentOf(player)) {
for (Card c : hand) { for (Card c : hand) {
if (c.hasKeyword("If a spell or ability an opponent controls causes you to discard CARDNAME," if (c.hasKeyword("If a spell or ability an opponent controls causes you to discard CARDNAME,"
+ " put it onto the battlefield instead of putting it into your graveyard.")) { + " put it onto the battlefield instead of putting it into your graveyard.")) {
@@ -604,5 +605,38 @@ public class AiController {
return discardList; return discardList;
} }
public Card chooseSingleCardForEffect(List<Card> options, SpellAbility sa, String title, boolean isOptional) {
ApiType api = sa.getApi();
if ( null == api ) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet");
}
switch(api) {
case Bond: return CardFactoryUtil.getBestCreatureAI(options);
default: throw new InvalidParameterException("AI chooseSingleCard does not know how to choose card for " + api);
}
}
public boolean confirmAction(SpellAbility sa, String mode, String message) {
ApiType api = sa.getApi();
if ( null == api ) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet");
}
switch(api) {
case Discard:
if ( mode.equals("Random") ) { //
// TODO For now AI will always discard Random used currently with: Balduvian Horde and similar cards
return true;
}
break;
default:
}
String exMsg = String.format("AI confirmAction does not know what to decide about %s with %s mode.", api, mode);
throw new InvalidParameterException(exMsg);
}
} }

View File

@@ -94,4 +94,5 @@ public abstract class PlayerController {
public Card chooseSingleCardForEffect(List<Card> sourceList, SpellAbility sa, String title) { return chooseSingleCardForEffect(sourceList, sa, title); } public Card chooseSingleCardForEffect(List<Card> sourceList, SpellAbility sa, String title) { return chooseSingleCardForEffect(sourceList, sa, title); }
public abstract Card chooseSingleCardForEffect(List<Card> sourceList, SpellAbility sa, String title, boolean isOptional); public abstract Card chooseSingleCardForEffect(List<Card> sourceList, SpellAbility sa, String title, boolean isOptional);
public abstract boolean confirmAction(SpellAbility sa, String mode, String message);
} }

View File

@@ -1,13 +1,10 @@
package forge.game.player; package forge.game.player;
import java.security.InvalidParameterException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import forge.Card; import forge.Card;
import forge.GameEntity; import forge.GameEntity;
import forge.card.ability.ApiType;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.Spell; import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.control.input.Input; import forge.control.input.Input;
@@ -193,15 +190,12 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public Card chooseSingleCardForEffect(List<Card> options, SpellAbility sa, String title, boolean isOptional) { public Card chooseSingleCardForEffect(List<Card> options, SpellAbility sa, String title, boolean isOptional) {
ApiType api = sa.getApi(); return brains.chooseSingleCardForEffect(options, sa, title, isOptional);
if ( null == api ) { }
throw new InvalidParameterException("SA is not api-based, this is not supported yet");
} @Override
public boolean confirmAction(SpellAbility sa, String mode, String message) {
switch(api) { return brains.confirmAction(sa, mode, message);
case Bond: return CardFactoryUtil.getBestCreatureAI(options);
default: throw new InvalidParameterException("AI chooseSingleCard does not know how to choose card for " + api);
}
} }
} }

View File

@@ -237,5 +237,13 @@ public class PlayerControllerHuman extends PlayerController {
return GuiChoose.one(title, options); return GuiChoose.one(title, options);
} }
/* (non-Javadoc)
* @see forge.game.player.PlayerController#confirmAction(forge.card.spellability.SpellAbility, java.lang.String, java.lang.String)
*/
@Override
public boolean confirmAction(SpellAbility sa, String mode, String message) {
return GuiDialog.confirm(sa.getSourceCard(), message);
}
} }