diff --git a/.gitattributes b/.gitattributes index f1db706c8a8..1b3f633d1bc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10904,6 +10904,7 @@ res/cardsfolder/s/stronghold_assassin.txt svneol=native#text/plain res/cardsfolder/s/stronghold_biologist.txt svneol=native#text/plain res/cardsfolder/s/stronghold_discipline.txt svneol=native#text/plain res/cardsfolder/s/stronghold_furnace.txt -text +res/cardsfolder/s/stronghold_gambit.txt -text res/cardsfolder/s/stronghold_machinist.txt svneol=native#text/plain res/cardsfolder/s/stronghold_overseer.txt svneol=native#text/plain res/cardsfolder/s/stronghold_rats.txt svneol=native#text/plain diff --git a/res/cardsfolder/s/stronghold_gambit.txt b/res/cardsfolder/s/stronghold_gambit.txt new file mode 100644 index 00000000000..e3eb8dbd584 --- /dev/null +++ b/res/cardsfolder/s/stronghold_gambit.txt @@ -0,0 +1,13 @@ +Name:Stronghold Gambit +ManaCost:1 R +Types:Sorcery +A:SP$ RepeatEach | Cost$ 1 R | RepeatPlayers$ Player | RepeatSubAbility$ DBChooseCard | SubAbility$ DBReveal | SpellDescription$ Each player chooses a card in his or her hand. Then each player reveals his or her chosen card. The owner of each creature card revealed this way with the lowest converted mana cost puts it onto the battlefield. +SVar:DBChooseCard:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Card.RememberedPlayerCtrl | ChoiceZone$ Hand | AILogic$ LowestCMCCreature | RememberChosen$ True | Mandatory$ True +SVar:DBReveal:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBRevealCard | SubAbility$ FilterCreature +SVar:DBRevealCard:DB$ Reveal | Defined$ Player.IsRemembered | RevealDefined$ ValidHand Card.IsRemembered+RememberedPlayerCtrl +SVar:FilterCreature:DB$ Pump | ForgetObjects$ ValidHand Card.nonCreature+IsRemembered | SubAbility$ MoveToPlay +SVar:MoveToPlay:DB$ ChangeZoneAll | ChangeType$ Card.lowestRememberedCMC | Origin$ Hand | Destination$ Battlefield | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/stronghold_gambit.jpg +Oracle:Each player chooses a card in his or her hand. Then each player reveals his or her chosen card. The owner of each creature card revealed this way with the lowest converted mana cost puts it onto the battlefield. diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index 882e8603357..d529b3d94c0 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -6246,6 +6246,20 @@ public class Card extends GameEntity implements Comparable { if (!list.contains(this)) { return false; } + } else if (property.startsWith("lowestRememberedCMC")) { + List list = new ArrayList(); + for (final Object o : source.getRemembered()) { + if (o instanceof Card) { + list.add(game.getCardState((Card) o)); + } + } + if (!list.contains(this)) { + return false; + } + list = CardLists.getCardsWithLowestCMC(list); + if (!list.contains(this)) { + return false; + } } else if (property.startsWith("lowestCMC")) { final List list = game.getCardsIn(ZoneType.Battlefield); for (final Card crd : list) { diff --git a/src/main/java/forge/CardLists.java b/src/main/java/forge/CardLists.java index 7c7b906de8f..877cee04304 100644 --- a/src/main/java/forge/CardLists.java +++ b/src/main/java/forge/CardLists.java @@ -258,4 +258,27 @@ public class CardLists { } return tiedForHighest; } + + /** + * Given a List cardList, return a List that are tied for having the lowest CMC. + * + * @param cardList the Card List to be filtered. + * @return the list of Cards sharing the lowest CMC. + */ + public static List getCardsWithLowestCMC(Iterable cardList) { + final List tiedForLowest = new ArrayList(); + int lowest = 25; + for (final Card crd : cardList) { + int curCmc = crd.isSplitCard() ? Math.min(crd.getCMC(Card.SplitCMCMode.LeftSplitCMC), crd.getCMC(Card.SplitCMCMode.RightSplitCMC)) : crd.getCMC(); + + if (curCmc < lowest) { + lowest = curCmc; + tiedForLowest.clear(); + } + if (curCmc <= lowest) { + tiedForLowest.add(crd); + } + } + return tiedForLowest; + } } diff --git a/src/main/java/forge/card/ability/ai/ChooseCardAi.java b/src/main/java/forge/card/ability/ai/ChooseCardAi.java index 4218a7c3cbc..31cbb422d86 100644 --- a/src/main/java/forge/card/ability/ai/ChooseCardAi.java +++ b/src/main/java/forge/card/ability/ai/ChooseCardAi.java @@ -1,10 +1,10 @@ package forge.card.ability.ai; import java.util.Collection; +import java.util.Collections; import java.util.List; import com.google.common.base.Predicate; - import forge.Card; import forge.CardLists; import forge.CardPredicates.Presets; @@ -40,6 +40,7 @@ public class ChooseCardAi extends SpellAbilityAi { } if (sa.hasParam("AILogic")) { ZoneType choiceZone = ZoneType.Battlefield; + String logic = sa.getParam("AILogic"); if (sa.hasParam("ChoiceZone")) { choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone")); } @@ -50,22 +51,22 @@ public class ChooseCardAi extends SpellAbilityAi { if (sa.hasParam("TargetControls")) { choices = CardLists.filterControlledBy(choices, ai.getOpponent()); } - if (sa.getParam("AILogic").equals("AtLeast1") || sa.getParam("AILogic").equals("OppPreferred")) { + if (logic.equals("AtLeast1") || logic.equals("OppPreferred")) { if (choices.isEmpty()) { return false; } - } else if (sa.getParam("AILogic").equals("AtLeast2") || sa.getParam("AILogic").equals("BestBlocker")) { + } else if (logic.equals("AtLeast2") || logic.equals("BestBlocker")) { if (choices.size() < 2) { return false; } - } else if (sa.getParam("AILogic").equals("Clone")) { + } else if (logic.equals("Clone")) { choices = CardLists.getValidCards(choices, "Permanent.YouDontCtrl,Permanent.nonLegendary", host.getController(), host); if (choices.isEmpty()) { return false; } - } else if (sa.getParam("AILogic").equals("Never")) { + } else if (logic.equals("Never")) { return false; - } else if (sa.getParam("AILogic").equals("NeedsPrevention")) { + } else if (logic.equals("NeedsPrevention")) { if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) { return false; } @@ -148,6 +149,16 @@ public class ChooseCardAi extends SpellAbilityAi { List aiControlled = CardLists.filterControlledBy(options, ai); choice = ComputerUtilCard.getWorstAI(aiControlled); } + } else if ("LowestCMCCreature".equals(logic)) { + List creats = CardLists.filter(options, Presets.CREATURES); + creats = CardLists.filterToughness(creats, 1); + if (creats.isEmpty()) { + choice = ComputerUtilCard.getWorstAI(options); + } else { + CardLists.sortByCmcDesc(creats); + Collections.reverse(creats); + choice = creats.get(0); + } } else { choice = ComputerUtilCard.getBestAI(options); } diff --git a/src/main/java/forge/card/ability/effects/RevealEffect.java b/src/main/java/forge/card/ability/effects/RevealEffect.java index 4301ad939e9..70f7b6a0718 100644 --- a/src/main/java/forge/card/ability/effects/RevealEffect.java +++ b/src/main/java/forge/card/ability/effects/RevealEffect.java @@ -47,7 +47,7 @@ public class RevealEffect extends SpellAbilityEffect { } } else if (sa.hasParam("RevealDefined")) { - revealed.addAll(AbilityUtils.getDefinedCards(sa.getSourceCard(), sa.getParam("Defined"), sa)); + revealed.addAll(AbilityUtils.getDefinedCards(sa.getSourceCard(), sa.getParam("RevealDefined"), sa)); } else { List valid = new ArrayList(cardsInHand);