diff --git a/forge-core/src/main/java/forge/card/CardType.java b/forge-core/src/main/java/forge/card/CardType.java index 6082b5f8000..a801cca9d1e 100644 --- a/forge-core/src/main/java/forge/card/CardType.java +++ b/forge-core/src/main/java/forge/card/CardType.java @@ -17,13 +17,7 @@ */ package forge.card; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.NotImplementedException; @@ -74,6 +68,15 @@ public final class CardType implements Comparable, CardTypeView { private static Map stringToCoreType = EnumUtils.getEnumMap(CoreType.class); private static final Set allCoreTypeNames = stringToCoreType.keySet(); public static final Set spellTypes = ImmutableSet.of(Instant, Sorcery); + public static final Set permanentTypeNames() { + Set permanentTypes = new HashSet<>(); + for (CoreType c : CoreType.values()) { + if (c.isPermanent) { + permanentTypes.add(c.name()); + } + } + return permanentTypes; + } public static CoreType getEnum(String name) { return stringToCoreType.get(name); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java index ef0f8db6827..f10b24b2e20 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java @@ -224,9 +224,17 @@ public class ChooseCardEffect extends SpellAbilityEffect { dontRevealToOwner = false; } else { String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " "; - if (sa.hasParam ("ChoiceTitleAppendDefined")) { - String defined = AbilityUtils.getDefinedPlayers(host, sa.getParam("ChoiceTitleAppendDefined"), sa).toString(); - title = title + " " + defined; + if (sa.hasParam ("ChoiceTitleAppend")) { + String tag = ""; + String value = sa.getParam("ChoiceTitleAppend"); + if (value.startsWith("Defined ")) { + tag = AbilityUtils.getDefinedPlayers(host, value.substring(8), sa).toString(); + } else if (value.equals("ChosenType")) { + tag = host.getChosenType(); + } + if (!tag.equals("")) { + title = title + " (" + tag +")"; + } } if (sa.hasParam("QuasiLibrarySearch")) { final Player searched = AbilityUtils.getDefinedPlayers(host, diff --git a/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java index 33c16955a25..59e0299af37 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java @@ -136,26 +136,41 @@ public class RepeatEachEffect extends SpellAbilityEffect { } } - if (sa.hasParam("RepeatTypesFromDefined")) { - final String def = sa.getParam("RepeatTypesFromDefined"); + if (sa.hasParam("RepeatTypes") || sa.hasParam("RepeatTypesFrom")) { final Set validTypes = new HashSet<>(); - final List res; - if (def.startsWith("ThisTurnCast")) { - final String[] workingCopy = def.split("_"); - final String validFilter = workingCopy[1]; - res = CardUtil.getThisTurnCast(validFilter, source, sa); - } else { - res = AbilityUtils.getDefinedCards(source, def, sa); - } - for (final Card c : res) { - for (CardType.CoreType type : c.getType().getCoreTypes()) { - validTypes.add(type.name()); + if (sa.hasParam("RepeatTypes")) { + final String def = sa.getParam("RepeatTypes"); + if (def.equals("Permanent")) { + validTypes.addAll(CardType.CoreType.permanentTypeNames()); + } else { + validTypes.addAll(Arrays.asList(sa.getParam("RepeatTypes").split(","))); + } + } else if (sa.hasParam("RepeatTypesFrom")) { + final String def = sa.getParam("RepeatTypesFrom"); + final List res; + if (def.startsWith("ThisTurnCast")) { + final String[] workingCopy = def.split("_"); + final String validFilter = workingCopy[1]; + res = CardUtil.getThisTurnCast(validFilter, source, sa); + } else if (def.startsWith("Defined ")) { + res = AbilityUtils.getDefinedCards(source, def.substring(8), sa); + } else { + res = CardLists.getValidCards(game.getCardsInGame(), def, source.getController(), source, sa); + } + for (final Card c : res) { + for (CardType.CoreType type : c.getType().getCoreTypes()) { + validTypes.add(type.name()); + } } } final String storedType = source.getChosenType(); + Player chooser = player; + if (sa.hasParam("ChooseOrder") && !sa.getParam("ChooseOrder").equals("True")) { + chooser = AbilityUtils.getDefinedPlayers(source, sa.getParam("ChooseOrder"), sa).get(0); + } while (validTypes.size() > 0) { - String chosenT = player.getController().chooseSomeType("card", sa, validTypes, null); + String chosenT = chooser.getController().chooseSomeType("card", sa, validTypes, null); source.setChosenType(chosenT); AbilityUtils.resolve(repeat); validTypes.remove(chosenT); diff --git a/forge-gui/res/cardsfolder/g/grime_gorger.txt b/forge-gui/res/cardsfolder/g/grime_gorger.txt index c4b68d7c788..8ef3f477c45 100644 --- a/forge-gui/res/cardsfolder/g/grime_gorger.txt +++ b/forge-gui/res/cardsfolder/g/grime_gorger.txt @@ -3,17 +3,12 @@ ManaCost:2 B G Types:Creature Horror PT:3/3 K:Menace -T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigExile | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, exile up to one card of each card type from defending player's graveyard. Put a +1/+1 counter on CARDNAME for each card exiled this way. -SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | ChangeType$ Land.OwnedBy TriggeredDefendingPlayer | RememberChanged$ True | SubAbility$ ExileCreature -SVar:ExileCreature:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | ChangeType$ Creature.OwnedBy TriggeredDefendingPlayer | RememberChanged$ True | SubAbility$ ExilePlaneswalker -SVar:ExilePlaneswalker:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | ChangeType$ Planeswalker.OwnedBy TriggeredDefendingPlayer | RememberChanged$ True | SubAbility$ ExileArtifact -SVar:ExileArtifact:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | ChangeType$ Artifact.OwnedBy TriggeredDefendingPlayer | RememberChanged$ True | SubAbility$ ExileEnchantment -SVar:ExileEnchantment:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | ChangeType$ Enchantment.OwnedBy TriggeredDefendingPlayer | RememberChanged$ True | SubAbility$ ExileInstant -SVar:ExileInstant:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | ChangeType$ Instant.OwnedBy TriggeredDefendingPlayer | RememberChanged$ True | SubAbility$ ExileSorcery -SVar:ExileSorcery:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | ChangeType$ Sorcery.OwnedBy TriggeredDefendingPlayer | RememberChanged$ True | SubAbility$ ExileTribal -SVar:ExileTribal:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | ChangeType$ Tribal.OwnedBy TriggeredDefendingPlayer | RememberChanged$ True | SubAbility$ DBPutCounter +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigRepeatTypes | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, exile up to one card of each card type from defending player's graveyard. Put a +1/+1 counter on CARDNAME for each card exiled this way. +SVar:TrigRepeatTypes:DB$ RepeatEach | RepeatTypesFrom$ Card.inZoneGraveyard+OwnedBy TriggeredDefendingPlayer | RepeatSubAbility$ ChooseCard | SubAbility$ DBPutCounter +SVar:ChooseCard:DB$ ChooseCard | ChoiceZone$ Graveyard | Choices$ Card.ChosenType+OwnedBy TriggeredDefendingPlayer | ChoiceTitle$ You may choose a card of this type from defending player's graveyard to exile | ChoiceTitleAppend$ ChosenType | AILogic$ BestCard | SubAbility$ DBExile +SVar:DBExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Defined$ ChosenCard | RememberChanged$ True SVar:DBPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ X | SubAbility$ DBCleanup -SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True SVar:X:Remembered$Amount SVar:HasAttackEffect:TRUE DeckHas:Ability$Counters diff --git a/forge-gui/res/cardsfolder/l/liliana_dreadhorde_general.txt b/forge-gui/res/cardsfolder/l/liliana_dreadhorde_general.txt index 33b1fa6fc0e..8baf6511313 100644 --- a/forge-gui/res/cardsfolder/l/liliana_dreadhorde_general.txt +++ b/forge-gui/res/cardsfolder/l/liliana_dreadhorde_general.txt @@ -3,17 +3,14 @@ ManaCost:4 B B Types:Legendary Planeswalker Liliana Loyalty:6 T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever a creature you control dies, draw a card. -SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1 -A:AB$ Token | Cost$ AddCounter<1/LOYALTY> | TokenAmount$ 1 | TokenScript$ b_2_2_zombie | TokenOwner$ You | Planeswalker$ True | SpellDescription$ Create a 2/2 black Zombie creature token. -A:AB$ Sacrifice | Cost$ SubCounter<4/LOYALTY> | Amount$ 2 | SacValid$ Creature | Defined$ Player | Planeswalker$ True | SpellDescription$ Each player sacrifices two creatures. -A:AB$ RepeatEach | Cost$ SubCounter<9/LOYALTY> | Planeswalker$ True | Ultimate$ True | RepeatPlayers$ Opponent | RepeatSubAbility$ ChooseArtf | SubAbility$ SacAllOthers | SpellDescription$ Each opponent chooses a permanent they control of each permanent type and sacrifices the rest. -SVar:ChooseArtf:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Artifact.RememberedPlayerCtrl | ChoiceTitle$ Choose an artifact to keep | SubAbility$ ChooseCrtr | RememberChosen$ True | Mandatory$ True -SVar:ChooseCrtr:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Creature.RememberedPlayerCtrl | ChoiceTitle$ Choose a creature to keep | SubAbility$ ChooseEnch | RememberChosen$ True | Mandatory$ True -SVar:ChooseEnch:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Enchantment.RememberedPlayerCtrl | ChoiceTitle$ Choose an enchantment to keep | SubAbility$ ChooseLand | RememberChosen$ True | Mandatory$ True -SVar:ChooseLand:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Land.RememberedPlayerCtrl | ChoiceTitle$ Choose a land to keep | SubAbility$ ChoosePW | RememberChosen$ True | Mandatory$ True -SVar:ChoosePW:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Planeswalker.RememberedPlayerCtrl | ChoiceTitle$ Choose a planeswalker to keep | RememberChosen$ True | Mandatory$ True -SVar:SacAllOthers:DB$ SacrificeAll | ValidCards$ Permanent.IsNotRemembered+OppCtrl | SubAbility$ DBCleanup +SVar:TrigDraw:DB$ Draw +A:AB$ Token | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | TokenScript$ b_2_2_zombie | SpellDescription$ Create a 2/2 black Zombie creature token. +A:AB$ Sacrifice | Cost$ SubCounter<4/LOYALTY> | Planeswalker$ True | Amount$ 2 | SacValid$ Creature | Defined$ Player | SpellDescription$ Each player sacrifices two creatures. +A:AB$ RepeatEach | Cost$ SubCounter<9/LOYALTY> | Planeswalker$ True | Ultimate$ True | RepeatPlayers$ Opponent | RepeatSubAbility$ ChoosePerms | SubAbility$ SacAllOthers | SpellDescription$ Each opponent chooses a permanent they control of each permanent type and sacrifices the rest. +SVar:ChoosePerms:DB$ RepeatEach | RepeatTypes$ Permanent | ChooseOrder$ RememberedPlayer | RepeatSubAbility$ ChooseCard +SVar:ChooseCard:DB$ ChooseCard | Defined$ RememberedPlayer | Choices$ Card.ChosenType+RememberedPlayerCtrl | ChoiceTitle$ Choose a card of this type to keep | ChoiceTitleAppend$ ChosenType | AILogic$ BestCard | RememberChosen$ True | Mandatory$ True +SVar:SacAllOthers:DB$ SacrificeAll | ValidCards$ Permanent.IsNotRemembered+OppCtrl | SubAbility$ DBCleanup | StackDescription$ None SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -DeckHas:Ability$Token|Sacrifice +DeckHas:Ability$Token|Sacrifice & Type$Zombie SVar:PlayMain1:TRUE Oracle:Whenever a creature you control dies, draw a card.\n[+1]: Create a 2/2 black Zombie creature token.\n[-4]: Each player sacrifices two creatures.\n[-9]: Each opponent chooses a permanent they control of each permanent type and sacrifices the rest. diff --git a/forge-gui/res/cardsfolder/n/nihiloor.txt b/forge-gui/res/cardsfolder/n/nihiloor.txt index 8e3bcc3b93f..14e3013e947 100644 --- a/forge-gui/res/cardsfolder/n/nihiloor.txt +++ b/forge-gui/res/cardsfolder/n/nihiloor.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Horror PT:3/5 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ DBRepeat | TriggerDescription$ When CARDNAME enters the battlefield, for each opponent, tap up to one untapped creature you control. When you do, gain control of target creature that player controls with power less than or equal to the tapped creature's power for as long as you control CARDNAME. SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | RepeatSubAbility$ DBChoose | SubAbility$ DBCleanup -SVar:DBChoose:DB$ ChooseCard | Defined$ You | MinAmount$ 0 | Amount$ 1 | Choices$ Creature.untapped+YouCtrl | ChoiceTitle$ Choose up to one untapped creature you control to tap | ChoiceTitleAppendDefined$ Player.IsRemembered | ChoiceZone$ Battlefield | SubAbility$ DBTap +SVar:DBChoose:DB$ ChooseCard | Defined$ You | MinAmount$ 0 | Amount$ 1 | Choices$ Creature.untapped+YouCtrl | ChoiceTitle$ Choose up to one untapped creature you control to tap | ChoiceTitleAppend$ Defined Player.IsRemembered | ChoiceZone$ Battlefield | SubAbility$ DBTap SVar:DBTap:DB$ Tap | Defined$ ChosenCard | SubAbility$ DBImmediateTrigger SVar:DBImmediateTrigger:DB$ ImmediateTrigger | RememberObjects$ ChosenCard,Player.IsRemembered | ConditionDefined$ ChosenCard | ConditionPresent$ Card | ConditionCompare$ GE1 | Execute$ TrigGainControl | TrigDescReminderDefined$ Player.IsRemembered | TriggerDescription$ When you do, gain control of target creature that player controls with power less than or equal to the tapped creature's power for as long as you control CARDNAME. SVar:TrigGainControl:DB$ GainControl | ValidTgts$ Creature.powerLEX+ControlledBy DelayTriggerRemembered | LoseControl$ LeavesPlay,LoseControl | TgtPrompt$ Select target creature that opponent controls diff --git a/forge-gui/res/cardsfolder/upcoming/hurkyl_master_wizard.txt b/forge-gui/res/cardsfolder/upcoming/hurkyl_master_wizard.txt index 8fc9df1d0fd..128008a8f28 100644 --- a/forge-gui/res/cardsfolder/upcoming/hurkyl_master_wizard.txt +++ b/forge-gui/res/cardsfolder/upcoming/hurkyl_master_wizard.txt @@ -4,8 +4,8 @@ Types:Legendary Creature Human Wizard Advisor PT:2/4 T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE1 | Execute$ TrigDig | TriggerDescription$ At the beginning of your end step, if you've cast a noncreature spell this turn, reveal the top five cards of your library. For each card type among noncreature spells you've cast this turn, you may put a card of that type from among the revealed cards into your hand. Put the rest on the bottom of your library in a random order. SVar:TrigDig:DB$ Dig | DigNum$ 5 | Reveal$ True | NoMove$ True | RememberRevealed$ True | SubAbility$ DBRepeatEach -SVar:DBRepeatEach:DB$ RepeatEach | RepeatTypesFromDefined$ ThisTurnCast_Card.nonCreature+YouCtrl | RepeatSubAbility$ ChooseCard | SubAbility$ DBChangeZoneAll -SVar:ChooseCard:DB$ ChooseCard | Choices$ Card.IsRemembered+ChosenType | ImprintChosen$ True | ForgetChosen$ True | ChoiceTitle$ You may choose a card of this type to put into your hand | ChoiceZone$ Library | AILogic$ BestCard +SVar:DBRepeatEach:DB$ RepeatEach | RepeatTypesFrom$ ThisTurnCast_Card.nonCreature+YouCtrl | RepeatSubAbility$ ChooseCard | SubAbility$ DBChangeZoneAll +SVar:ChooseCard:DB$ ChooseCard | Choices$ Card.IsRemembered+ChosenType | ImprintChosen$ True | ForgetChosen$ True | ChoiceTitle$ You may choose a card of this type to put into your hand | ChoiceTitleAppend$ ChosenType | ChoiceZone$ Library | AILogic$ BestCard SVar:DBChangeZoneAll:DB$ ChangeZone | Defined$ Imprinted | Origin$ Library | Destination$ Hand | SubAbility$ DBRestRandomOrder SVar:DBRestRandomOrder:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Library | Destination$ Library | LibraryPosition$ -1 | RandomOrder$ True | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True | ClearChosenCard$ True