diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 56b905e9010..e256daefb66 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -2378,8 +2378,9 @@ public class ComputerUtil { chosen = ComputerUtilCard.getMostProminentType(list, valid); } } - else if (logic.equals("MostProminentInComputerDeck")) { - chosen = ComputerUtilCard.getMostProminentType(ai.getAllCards(), valid); + else if (logic.startsWith("MostProminentInComputerDeck")) { + boolean includeTokens = !logic.endsWith("NonToken"); + chosen = ComputerUtilCard.getMostProminentType(ai.getAllCards(), valid, includeTokens); } else if (logic.equals("MostProminentInComputerGraveyard")) { chosen = ComputerUtilCard.getMostProminentType(ai.getCardsIn(ZoneType.Graveyard), valid); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index 3f0e6ef9e41..3e51f47f0e1 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -762,30 +762,21 @@ public class ComputerUtilCard { return maxName; } - public static String getMostProminentBasicLandType(final CardCollectionView list) { - return getMostProminentType(list, CardType.getBasicTypes()); + public static String getMostProminentType(final CardCollectionView list, final Collection valid) { + return getMostProminentType(list, valid, true); } - /** - *

- * getMostProminentCreatureType. - *

- * - * @param list - * @return a {@link java.lang.String} object. - */ - public static String getMostProminentCreatureType(final CardCollectionView list) { - return getMostProminentType(list, CardType.getAllCreatureTypes()); - } - public static String getMostProminentType(final CardCollectionView list, final Collection valid) { + public static String getMostProminentType(final CardCollectionView list, final Collection valid, boolean includeTokens) { if (list.size() == 0) { return ""; } final Map typesInDeck = Maps.newHashMap(); - // TODO JAVA 8 use getOrDefault for (final Card c : list) { + if (!includeTokens && c.isToken()) { + continue; + } // Changeling are all creature types, they are not interesting for // counting creature types if (c.hasStartOfKeyword(Keyword.CHANGELING.toString())) { @@ -803,58 +794,55 @@ public class ComputerUtilCard { continue; } + // Cards in hand and commanders are worth double, as they are more likely to be played. + int weight = 1; + if (c.isInZone(ZoneType.Hand) || c.isRealCommander()) { + weight = 2; + } + Set cardCreatureTypes = c.getType().getCreatureTypes(); for (String type : cardCreatureTypes) { - Integer count = typesInDeck.get(type); - if (count == null) { - count = 0; - } - typesInDeck.put(type, count + 1); + Integer count = typesInDeck.getOrDefault(type, 0); + typesInDeck.put(type, count + weight); } + //also take into account abilities that generate tokens - for (SpellAbility sa : c.getAllSpellAbilities()) { - if (sa.getApi() != ApiType.Token) { - continue; - } - if (sa.hasParam("TokenTypes")) { - for (String var : sa.getParam("TokenTypes").split(",")) { - if (!CardType.isACreatureType(var)) { - continue; - } - Integer count = typesInDeck.get(var); - if (count == null) { - count = 0; - } - typesInDeck.put(var, count + 1); - } - } - } - // same for Trigger that does make Tokens - for (Trigger t :c .getTriggers()) { - SpellAbility sa = t.ensureAbility(); - if (sa != null) { - if (sa.getApi() != ApiType.Token || !sa.hasParam("TokenTypes")) { + if (includeTokens) { + for (SpellAbility sa : c.getAllSpellAbilities()) { + if (sa.getApi() != ApiType.Token) { continue; } - for (String var : sa.getParam("TokenTypes").split(",")) { - if (!CardType.isACreatureType(var)) { - continue; + if (sa.hasParam("TokenTypes")) { + for (String var : sa.getParam("TokenTypes").split(",")) { + if (!CardType.isACreatureType(var)) { + continue; + } + Integer count = typesInDeck.getOrDefault(var, 0); + typesInDeck.put(var, count + weight); } - Integer count = typesInDeck.get(var); - if (count == null) { - count = 0; - } - typesInDeck.put(var, count + 1); } } - } - // special rule for Fabricate and Servo - if (c.hasStartOfKeyword(Keyword.FABRICATE.toString())) { - Integer count = typesInDeck.get("Servo"); - if (count == null) { - count = 0; + // same for Trigger that does make Tokens + for (Trigger t : c.getTriggers()) { + SpellAbility sa = t.ensureAbility(); + if (sa != null) { + if (sa.getApi() != ApiType.Token || !sa.hasParam("TokenTypes")) { + continue; + } + for (String var : sa.getParam("TokenTypes").split(",")) { + if (!CardType.isACreatureType(var)) { + continue; + } + Integer count = typesInDeck.getOrDefault(var, 0); + typesInDeck.put(var, count + weight); + } + } + } + // special rule for Fabricate and Servo + if (c.hasStartOfKeyword(Keyword.FABRICATE.toString())) { + Integer count = typesInDeck.getOrDefault("Servo", 0); + typesInDeck.put("Servo", count + weight); } - typesInDeck.put("Servo", count + 1); } } // for diff --git a/forge-gui/res/cardsfolder/b/belbes_portal.txt b/forge-gui/res/cardsfolder/b/belbes_portal.txt index 6ff51947838..4c4bc9baa7a 100644 --- a/forge-gui/res/cardsfolder/b/belbes_portal.txt +++ b/forge-gui/res/cardsfolder/b/belbes_portal.txt @@ -2,6 +2,6 @@ Name:Belbe's Portal ManaCost:5 Types:Artifact K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeck +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeckNonToken A:AB$ ChangeZone | Cost$ 3 T | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature.ChosenType | ChangeNum$ 1 | SpellDescription$ You may put a creature card of the chosen type from your hand onto the battlefield. Oracle:As Belbe's Portal enters the battlefield, choose a creature type.\n{3}, {T}: You may put a creature card of the chosen type from your hand onto the battlefield. diff --git a/forge-gui/res/cardsfolder/b/bloodline_shaman.txt b/forge-gui/res/cardsfolder/b/bloodline_shaman.txt index a567d77e63f..026522e8265 100644 --- a/forge-gui/res/cardsfolder/b/bloodline_shaman.txt +++ b/forge-gui/res/cardsfolder/b/bloodline_shaman.txt @@ -2,7 +2,7 @@ Name:Bloodline Shaman ManaCost:1 G Types:Creature Elf Wizard Shaman PT:1/1 -A:AB$ ChooseType | Cost$ T | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SubAbility$ ShamanDig | SpellDescription$ Choose a creature type. Reveal the top card of your library. If that card is a creature card of the chosen type, put it into your hand. Otherwise, put it into your graveyard. +A:AB$ ChooseType | Cost$ T | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeckNonToken | SubAbility$ ShamanDig | SpellDescription$ Choose a creature type. Reveal the top card of your library. If that card is a creature card of the chosen type, put it into your hand. Otherwise, put it into your graveyard. SVar:ShamanDig:DB$ Dig | DigNum$ 1 | Reveal$ True | ChangeNum$ All | ChangeValid$ Creature.ChosenType | DestinationZone$ Hand | DestinationZone2$ Graveyard AI:RemoveDeck:Random Oracle:{T}: Choose a creature type. Reveal the top card of your library. If that card is a creature card of the chosen type, put it into your hand. Otherwise, put it into your graveyard. diff --git a/forge-gui/res/cardsfolder/b/brass_herald.txt b/forge-gui/res/cardsfolder/b/brass_herald.txt index 2720f462c9f..3ec82e8e363 100644 --- a/forge-gui/res/cardsfolder/b/brass_herald.txt +++ b/forge-gui/res/cardsfolder/b/brass_herald.txt @@ -4,7 +4,7 @@ Types:Artifact Creature Golem PT:2/2 S:Mode$ Continuous | Affected$ Creature.ChosenType | AddPower$ 1 | AddToughness$ 1 | Description$ Creatures of the chosen type get +1/+1. K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeck +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeckNonToken T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigDig | TriggerDescription$ When CARDNAME enters the battlefield, reveal the top four cards of your library. Put all creature cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order. SVar:TrigDig:DB$ Dig | DigNum$ 4 | Reveal$ True | ChangeNum$ All | ChangeValid$ Creature.ChosenType SVar:PlayMain1:TRUE diff --git a/forge-gui/res/cardsfolder/c/cavern_of_souls.txt b/forge-gui/res/cardsfolder/c/cavern_of_souls.txt index 34774696cd6..39b4212a905 100644 --- a/forge-gui/res/cardsfolder/c/cavern_of_souls.txt +++ b/forge-gui/res/cardsfolder/c/cavern_of_souls.txt @@ -2,7 +2,7 @@ Name:Cavern of Souls ManaCost:no cost Types:Land K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeck +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeckNonToken A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. A:AB$ Mana | Cost$ T | Produced$ Any | RestrictValid$ Spell.Creature+ChosenType | AddsNoCounter$ True | SpellDescription$ Add one mana of any color. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered. Oracle:As Cavern of Souls enters the battlefield, choose a creature type.\n{T}: Add {C}.\n{T}: Add one mana of any color. Spend this mana only to cast a creature spell of the chosen type, and that spell can't be countered. diff --git a/forge-gui/res/cardsfolder/h/heralds_horn.txt b/forge-gui/res/cardsfolder/h/heralds_horn.txt index e2ae939311b..1c07d7af5c2 100644 --- a/forge-gui/res/cardsfolder/h/heralds_horn.txt +++ b/forge-gui/res/cardsfolder/h/heralds_horn.txt @@ -2,7 +2,7 @@ Name:Herald's Horn ManaCost:3 Types:Artifact K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeck +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeckNonToken S:Mode$ ReduceCost | ValidCard$ Creature.ChosenType | Type$ Spell | Activator$ You | Amount$ 1 | Description$ Creature spells you cast of the chosen type cost {1} less to cast. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigPeek | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, look at the top card of your library. If it's a creature card of the chosen type, you may reveal it and put it into your hand. SVar:TrigPeek:DB$ PeekAndReveal | PeekAmount$ 1 | RevealValid$ Creature.ChosenType | RevealOptional$ True | RememberRevealed$ True | SubAbility$ DBChangeZone diff --git a/forge-gui/res/cardsfolder/k/kolvori_god_of_kinship_the_ringhart_crest.txt b/forge-gui/res/cardsfolder/k/kolvori_god_of_kinship_the_ringhart_crest.txt index a6a06b166ef..9c3461a6eab 100644 --- a/forge-gui/res/cardsfolder/k/kolvori_god_of_kinship_the_ringhart_crest.txt +++ b/forge-gui/res/cardsfolder/k/kolvori_god_of_kinship_the_ringhart_crest.txt @@ -13,6 +13,6 @@ Name:The Ringhart Crest ManaCost:1 G Types:Legendary Artifact K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeckNonToken | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. A:AB$ Mana | Cost$ T | Produced$ G | RestrictValid$ Spell.Creature+ChosenType,Spell.Creature+Legendary | SpellDescription$ Add {G}. Spend this mana only to cast a creature spell of the chosen type or a legendary creature spell. Oracle:As The Ringhart Crest enters the battlefield, choose a creature type.\n{T}: Add {G}. Spend this mana only to cast a creature spell of the chosen type or a legendary creature spell. diff --git a/forge-gui/res/cardsfolder/m/molten_echoes.txt b/forge-gui/res/cardsfolder/m/molten_echoes.txt index 1df0b6269d5..d7f8472de79 100644 --- a/forge-gui/res/cardsfolder/m/molten_echoes.txt +++ b/forge-gui/res/cardsfolder/m/molten_echoes.txt @@ -2,7 +2,7 @@ Name:Molten Echoes ManaCost:2 R R Types:Enchantment K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeckNonToken | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. T:Mode$ ChangesZone | ValidCard$ Creature.nonToken+ChosenType+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigCopyPermanent | TriggerZones$ Battlefield | TriggerDescription$ Whenever a nontoken creature of the chosen type enters the battlefield under your control, create a token that's a copy of that creature. That token gains haste. Exile it at the beginning of the next end step. SVar:TrigCopyPermanent:DB$ CopyPermanent | Defined$ TriggeredCard | NumCopies$ 1 | PumpKeywords$ Haste | AtEOT$ Exile Oracle:As Molten Echoes enters the battlefield, choose a creature type.\nWhenever a nontoken creature of the chosen type enters the battlefield under your control, create a token that's a copy of that creature. That token gains haste. Exile it at the beginning of the next end step. diff --git a/forge-gui/res/cardsfolder/r/realmwalker.txt b/forge-gui/res/cardsfolder/r/realmwalker.txt index 49fa31818ce..85e431d8014 100644 --- a/forge-gui/res/cardsfolder/r/realmwalker.txt +++ b/forge-gui/res/cardsfolder/r/realmwalker.txt @@ -4,7 +4,7 @@ Types:Creature Shapeshifter PT:2/3 K:Changeling K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeckNonToken | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ You | Description$ You may look at the top card of your library any time. S:Mode$ Continuous | Affected$ Creature.ChosenType+TopLibrary+YouCtrl+nonLand | AffectedZone$ Library | MayPlay$ True | Description$ You may cast creature spells of the chosen type from the top of your library. Oracle:Changeling (This card is every creature type.)\nAs Realmwalker enters the battlefield, choose a creature type.\nYou may look at the top card of your library any time.\nYou may cast creature spells of the chosen type from the top of your library. diff --git a/forge-gui/res/cardsfolder/r/reflections_of_littjara.txt b/forge-gui/res/cardsfolder/r/reflections_of_littjara.txt index 5e7652ddedd..2e809e5b8a7 100644 --- a/forge-gui/res/cardsfolder/r/reflections_of_littjara.txt +++ b/forge-gui/res/cardsfolder/r/reflections_of_littjara.txt @@ -2,7 +2,7 @@ Name:Reflections of Littjara ManaCost:4 U Types:Enchantment K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | StackDescription$ SpellDescription +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeckNonToken | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | StackDescription$ SpellDescription T:Mode$ SpellCast | ValidCard$ Card.ChosenType | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigCopy | TriggerDescription$ Whenever you cast a spell of the chosen type, copy that spell. (A copy of a permanent spell becomes a token.) SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always | MayChooseTarget$ True DeckHas:Ability$Token diff --git a/forge-gui/res/cardsfolder/u/unclaimed_territory.txt b/forge-gui/res/cardsfolder/u/unclaimed_territory.txt index 4cd2e8cc124..6004cba3249 100644 --- a/forge-gui/res/cardsfolder/u/unclaimed_territory.txt +++ b/forge-gui/res/cardsfolder/u/unclaimed_territory.txt @@ -2,7 +2,7 @@ Name:Unclaimed Territory ManaCost:no cost Types:Land K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeck +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | AILogic$ MostProminentInComputerDeckNonToken A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. A:AB$ Mana | Cost$ T | Produced$ Any | RestrictValid$ Spell.Creature+ChosenType | SpellDescription$ Add one mana of any color. Spend this mana only to cast a creature spell of the chosen type. Oracle:As Unclaimed Territory enters the battlefield, choose a creature type.\n{T}: Add {C}.\n{T}: Add one mana of any color. Spend this mana only to cast a creature spell of the chosen type. diff --git a/forge-gui/res/cardsfolder/u/urzas_incubator.txt b/forge-gui/res/cardsfolder/u/urzas_incubator.txt index 7e6471c1acb..c40b7a2b2aa 100644 --- a/forge-gui/res/cardsfolder/u/urzas_incubator.txt +++ b/forge-gui/res/cardsfolder/u/urzas_incubator.txt @@ -2,7 +2,7 @@ Name:Urza's Incubator ManaCost:3 Types:Artifact K:ETBReplacement:Other:ChooseCT -SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeckNonToken | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. S:Mode$ ReduceCost | ValidCard$ Creature.ChosenType | Type$ Spell | Amount$ 2 | Description$ Creature spells of the chosen type cost {2} less to cast. AI:RemoveDeck:Random Oracle:As Urza's Incubator enters the battlefield, choose a creature type.\nCreature spells of the chosen type cost {2} less to cast. diff --git a/forge-gui/res/cardsfolder/v/vexing_arcanix.txt b/forge-gui/res/cardsfolder/v/vexing_arcanix.txt index 949244cd3f6..a7aa6890bf7 100644 --- a/forge-gui/res/cardsfolder/v/vexing_arcanix.txt +++ b/forge-gui/res/cardsfolder/v/vexing_arcanix.txt @@ -1,7 +1,7 @@ Name:Vexing Arcanix ManaCost:4 Types:Artifact -A:AB$ NameCard | Cost$ 3 T | ValidTgts$ Player | TgtPrompt$ Select target player | SubAbility$ DBDig | AILogic$ MostProminentInComputerDeck | SpellDescription$ Target player chooses a card name, then reveals the top card of their library. If that card has the chosen name, the player puts it into their hand. Otherwise, the player puts it into their graveyard and CARDNAME deals 2 damage to them. +A:AB$ NameCard | Cost$ 3 T | ValidTgts$ Player | TgtPrompt$ Select target player | SubAbility$ DBDig | AILogic$ MostProminentInComputerDeckNonToken | SpellDescription$ Target player chooses a card name, then reveals the top card of their library. If that card has the chosen name, the player puts it into their hand. Otherwise, the player puts it into their graveyard and CARDNAME deals 2 damage to them. SVar:DBDig:DB$ Dig | DigNum$ 1 | Defined$ Targeted | ChangeNum$ All | ChangeValid$ Card.NamedCard | DestinationZone2$ Graveyard | Reveal$ True | RememberChanged$ True | SubAbility$ DBDamage SVar:DBDamage:DB$ DealDamage | NumDmg$ 2 | Defined$ Targeted | ConditionDefined$ Remembered | ConditionPresent$ Card.NamedCard | ConditionCompare$ EQ0 | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True