Skip to content

Commit

Permalink
WHO: the_five_doctors.txt and support (ChangeZoneEffect refactors)
Browse files Browse the repository at this point in the history
  • Loading branch information
Northmoc committed Nov 27, 2023
1 parent 1bfa22e commit de207f9
Show file tree
Hide file tree
Showing 75 changed files with 216 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,11 @@ public final String getStackDescriptionWithSubs(final Map<String, String> params
}
// by typing "SpellDescription" they want to bypass the Effect's string builder
if ("SpellDescription".equalsIgnoreCase(stackDesc)) {
String rawSDesc = params.get("SpellDescription");
if (rawSDesc.contains(",,,,,,")) rawSDesc = rawSDesc.replaceAll(",,,,,,", " ");
if (rawSDesc.contains(",,,")) rawSDesc = rawSDesc.replaceAll(",,,", " ");
if (params.containsKey("SpellDescription")) {
String spellDesc = CardTranslation.translateSingleDescriptionText(params.get("SpellDescription"),
String spellDesc = CardTranslation.translateSingleDescriptionText(rawSDesc,
sa.getHostCard().getName());

int idx = spellDesc.indexOf("(");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;

import java.util.List;
import java.util.Map;
import java.util.*;

public class ChangeZoneEffect extends SpellAbilityEffect {

Expand Down Expand Up @@ -460,19 +460,12 @@ private void changeKnownOriginResolve(final SpellAbility sa) {
origin.addAll(ZoneType.listValueOf(sa.getParam("Origin")));
}

boolean altDest = false;
int libraryPosition = sa.hasParam("LibraryPosition") ?
AbilityUtils.calculateAmount(hostCard, sa.getParam("LibraryPosition"), sa) : 0;
if (sa.hasParam("DestinationAlternative")) {
final StringBuilder sb = new StringBuilder();
sb.append(sa.getParam("AlternativeDestinationMessage"));
Player alterDecider = player;
if (sa.hasParam("AlternativeDecider")) {
PlayerCollection deciders = AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("AlternativeDecider"), sa);
alterDecider = deciders.isEmpty() ? null : deciders.get(0);
}
if (alterDecider != null && !alterDecider.getController().confirmAction(sa, PlayerActionConfirmMode.ChangeZoneToAltDestination, sb.toString(), null)) {
destination = ZoneType.smartValueOf(sa.getParam("DestinationAlternative"));
altDest = true;
}
Pair<ZoneType, Integer> pair = handleAltDest(sa, hostCard, destination, libraryPosition, player);
destination = pair.getKey();
libraryPosition = pair.getValue();
}

final CardZoneTable triggerList = new CardZoneTable();
Expand Down Expand Up @@ -555,14 +548,6 @@ private void changeKnownOriginResolve(final SpellAbility sa) {
Card movedCard = null;

if (destination.equals(ZoneType.Library)) {
// library position is zero indexed
int libraryPosition = 0;
if (altDest) {
libraryPosition = sa.hasParam("LibraryPositionAlternative") ? Integer.parseInt(sa.getParam("LibraryPositionAlternative")) : 0;
} else {
libraryPosition = sa.hasParam("LibraryPosition") ? AbilityUtils.calculateAmount(hostCard, sa.getParam("LibraryPosition"), sa) : 0;
}

// If a card is moved to library from the stack, remove its spells from the stack
if (sa.hasParam("Fizzle")) {
// TODO only AI still targets as card, try to remove it
Expand Down Expand Up @@ -946,8 +931,8 @@ private void changeZonePlayerInvariant(Player chooser, SpellAbility sa, List<Pla
CardCollectionView altFetchList = AbilityUtils.filterListByType(player.getCardsIn(alt), sa.getParam("ChangeType"), sa);

final StringBuilder sb = new StringBuilder();
sb.append(sa.getParam("AlternativeMessage")).append(" ");
sb.append(altFetchList.size()).append(" " + Localizer.getInstance().getMessage("lblCardMatchSearchingTypeInAlternateZones"));
sb.append(Localizer.getInstance().getMessage("lblSearchLibrary")).append(" ");
sb.append(altFetchList.size()).append(" ").append(Localizer.getInstance().getMessage("lblCardMatchSearchingTypeInAlternateZones"));

if (!decider.getController().confirmAction(sa, PlayerActionConfirmMode.ChangeZoneFromAltSource, sb.toString(), null)) {
origin.clear();
Expand Down Expand Up @@ -975,16 +960,6 @@ private void changeZonePlayerInvariant(Player chooser, SpellAbility sa, List<Pla
// this needs to be zero indexed. Top = 0, Third = 2
int libraryPos = sa.hasParam("LibraryPosition") ? AbilityUtils.calculateAmount(source, sa.getParam("LibraryPosition"), sa) : 0;

if (sa.hasParam("DestinationAlternative")) {
final StringBuilder sb = new StringBuilder();
sb.append(sa.getParam("AlternativeDestinationMessage"));

if (!decider.getController().confirmAction(sa, PlayerActionConfirmMode.ChangeZoneToAltDestination, sb.toString(), null)) {
destination = ZoneType.smartValueOf(sa.getParam("DestinationAlternative"));
libraryPos = sa.hasParam("LibraryPositionAlternative") ? Integer.parseInt(sa.getParam("LibraryPositionAlternative")) : 0;
}
}

int changeNum = sa.hasParam("ChangeNum") ? AbilityUtils.calculateAmount(source, sa.getParam("ChangeNum"), sa) : 1;

if (sa.hasParam("Optional")) {
Expand Down Expand Up @@ -1248,6 +1223,13 @@ else if (origin.contains(ZoneType.Hand) && player.isOpponentOf(decider)) {
if (sa.hasParam("ShuffleChangedPile")) {
CardLists.shuffle(chosenCards);
}

if (sa.hasParam("DestinationAlternative")) {
Pair<ZoneType, Integer> pair = handleAltDest(sa, source, destination, libraryPos, decider);
destination = pair.getKey();
libraryPos = pair.getValue();
}

// do not shuffle the library once we have placed a fetched card on top.
if (origin.contains(ZoneType.Library) && destination == ZoneType.Library && shuffleMandatory) {
player.shuffle(sa);
Expand Down Expand Up @@ -1630,4 +1612,50 @@ private void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA,
}
}
}

private Pair<ZoneType, Integer> handleAltDest(final SpellAbility sa, final Card host, final ZoneType dest1,
final int libPos1, final Player p) {
boolean allowAltDest = true;
boolean altDestOpt = true;

if (sa.hasParam("DestAltSVar")) {
allowAltDest = false;
String sVar = sa.getParam("DestAltSVar");
if (sVar.startsWith("MANDATORY ")) {
altDestOpt = false;
sVar = sVar.replace("MANDATORY ", "");
}
final String comparator = sa.getParamOrDefault("DestAltSVarCompare", "GE1");
final String compareTo = comparator.substring(2);
final int x = AbilityUtils.calculateAmount(host, sVar, sa);
if (Expressions.compare(x, comparator, AbilityUtils.calculateAmount(host, compareTo, sa))) {
allowAltDest = true;
}
}

final ZoneType dest2 = ZoneType.smartValueOf(sa.getParam("DestinationAlternative"));
final Pair<ZoneType, Integer> alt = Pair.of(dest2,
Integer.parseInt(sa.getParamOrDefault("LibraryPositionAlternative", "0")));

if (allowAltDest && !altDestOpt) return alt;
else if (allowAltDest) {
final boolean topBot = dest1.equals(ZoneType.Library) && dest2.equals(ZoneType.Library);
final String prompt = Localizer.getInstance().getMessage(topBot ? "lblChooseLibraryPosition" :
"lblChooseDestination");
final List<String> options = topBot ? Arrays.asList(Localizer.getInstance().getMessage("lblTop") +
(libPos1 == 0 ? "" : " (" + Lang.getInstance().getOrdinal(libPos1 + 1) + ")"),
Localizer.getInstance().getMessage("lblBottom")) :
Arrays.asList(StringUtils.capitalize(dest1.getTranslatedName()),
StringUtils.capitalize(dest2.getTranslatedName()));
Player decider = p;
if (sa.hasParam("AlternativeDecider")) {
PlayerCollection c = AbilityUtils.getDefinedPlayers(host, sa.getParam("AlternativeDecider"), sa);
decider = c.isEmpty() ? null : c.get(0);
}
if (decider != null && !decider.getController().confirmAction(sa,
PlayerActionConfirmMode.ChangeZoneToAltDestination, prompt, options, null, null))
return alt;
}
return Pair.of(dest1, libPos1);
}
}
3 changes: 2 additions & 1 deletion forge-gui/res/cardsfolder/a/aether_gust.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Name:Aether Gust
ManaCost:1 U
Types:Instant
A:SP$ ChangeZone | Cost$ 1 U | ValidTgts$ Card.inZoneStack+Red,Card.inZoneStack+Green,Permanent.Red,Permanent.Green | TgtZone$ Battlefield,Stack | TgtPrompt$ Select target spell or permanent that's red or green | AlternativeDecider$ TargetedOwner | Origin$ Battlefield,Stack | Fizzle$ True | Destination$ Library | LibraryPosition$ 0 | DestinationAlternative$ Library | LibraryPositionAlternative$ -1 | AlternativeDestinationMessage$ Would you like to put the card on the top of your library (and not on the bottom)? | SpellDescription$ Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
A:SP$ ChangeZone | ValidTgts$ Card.inZoneStack+Red,Card.inZoneStack+Green,Permanent.Red,Permanent.Green | TgtZone$ Battlefield,Stack | TgtPrompt$ Select target spell or permanent that's red or green | AlternativeDecider$ TargetedOwner | Origin$ Battlefield,Stack | Fizzle$ True | Destination$ Library | DestinationAlternative$ Library | LibraryPositionAlternative$ -1 | StackDescription$ {c:TargetedOwner} puts {c:Targeted} on the top or bottom of their library. | SpellDescription$ Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
AI:RemoveDeck:Random
Oracle:Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
3 changes: 2 additions & 1 deletion forge-gui/res/cardsfolder/a/ajanis_aid.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ Name:Ajani's Aid
ManaCost:2 G W
Types:Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearch | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library and/or graveyard for a card named Ajani, Valiant Protector, reveal it, and put it into your hand. If you search your library this way, shuffle.
SVar:TrigSearch:DB$ ChangeZone | Origin$ Library | OriginAlternative$ Graveyard | AlternativeMessage$ Would you like to search your library with this ability? If you do, your library will be shuffled. | Destination$ Hand | ChangeType$ Card.YouOwn+namedAjani; Valiant Protector | Optional$ True
SVar:TrigSearch:DB$ ChangeZone | Origin$ Library | OriginAlternative$ Graveyard | Destination$ Hand | ChangeType$ Card.YouOwn+namedAjani; Valiant Protector | Optional$ True
A:AB$ ChooseCard | Cost$ Sac<1/CARDNAME> | Choices$ Creature | Mandatory$ True | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SpellDescription$ Prevent all combat damage a creature of your choice would deal this turn.
SVar:DBEffect:DB$ Effect | ReplacementEffects$ RPreventNextFromSource | RememberObjects$ ChosenCard | ExileOnMoved$ Battlefield
SVar:RPreventNextFromSource:Event$ DamageDone | IsCombat$ True | ValidSource$ Card.IsRemembered | Prevent$ True | Description$ Prevent all combat damage a creature of your choice would deal this turn.
DeckHints:Name$Ajani, Valiant Protector
DeckHas:Ability$Sacrifice
Oracle:When Ajani's Aid enters the battlefield, you may search your library and/or graveyard for a card named Ajani, Valiant Protector, reveal it, and put it into your hand. If you search your library this way, shuffle.\nSacrifice Ajani's Aid: Prevent all combat damage a creature of your choice would deal this turn.
4 changes: 2 additions & 2 deletions forge-gui/res/cardsfolder/a/angraths_fury.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Name:Angrath's Fury
ManaCost:3 B R
Types:Sorcery
A:SP$ Destroy | Cost$ 3 B R | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBDealDamage | SpellDescription$ Destroy target creature. CARDNAME deals 3 damage to target player or planeswalker. You may search your library and/or graveyard for a card named Angrath, Minotaur Pirate, reveal it, and put it into your hand. If you search your library this way, shuffle.
A:SP$ Destroy | ValidTgts$ Creature | SubAbility$ DBDealDamage | SpellDescription$ Destroy target creature. CARDNAME deals 3 damage to target player or planeswalker. You may search your library and/or graveyard for a card named Angrath, Minotaur Pirate, reveal it, and put it into your hand. If you search your library this way, shuffle.
SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 3 | SubAbility$ DBSearch
SVar:DBSearch:DB$ ChangeZone | Origin$ Library | OriginAlternative$ Graveyard | AlternativeMessage$ Would you like to search your library with this ability? If you do, your library will be shuffled. | Destination$ Hand | ChangeType$ Card.YouOwn+namedAngrath; Minotaur Pirate | Optional$ True
SVar:DBSearch:DB$ ChangeZone | Origin$ Library | OriginAlternative$ Graveyard | Destination$ Hand | ChangeType$ Card.YouOwn+namedAngrath; Minotaur Pirate | Optional$ True
DeckNeeds:Name$Angrath, Minotaur Pirate
Oracle:Destroy target creature. Angrath's Fury deals 3 damage to target player or planeswalker. You may search your library and/or graveyard for a card named Angrath, Minotaur Pirate, reveal it, and put it into your hand. If you search your library this way, shuffle.
4 changes: 2 additions & 2 deletions forge-gui/res/cardsfolder/a/arachnus_spinner.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ ManaCost:5 G
Types:Creature Spider
PT:5/7
K:Reach
A:AB$ ChangeZone | Cost$ tapXType<1/Spider> | Hidden$ True | Origin$ Library | OriginAlternative$ Graveyard | AlternativeMessage$ Would you like to search your library with this ability? If you do, your library will be shuffled. | Destination$ Battlefield | ChangeType$ Card.YouOwn+namedArachnus Web | SpellDescription$ Search your graveyard and/or library for a card named Arachnus Web and put it onto the battlefield attached to target creature. If you search your library this way, shuffle.
DeckHints:Name$Arachnus Web
A:AB$ ChangeZone | Cost$ tapXType<1/Spider> | Hidden$ True | Origin$ Library | OriginAlternative$ Graveyard | Destination$ Battlefield | ChangeType$ Card.YouOwn+namedArachnus Web | SpellDescription$ Search your graveyard and/or library for a card named Arachnus Web and put it onto the battlefield attached to target creature. If you search your library this way, shuffle.
DeckHints:Name$Arachnus Web & Type$Spider
Oracle:Reach\nTap an untapped Spider you control: Search your graveyard and/or library for a card named Arachnus Web and put it onto the battlefield attached to target creature. If you search your library this way, shuffle.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/a/arashin_sovereign.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ Types:Creature Dragon
PT:6/6
K:Flying
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | OptionalDecider$ TriggeredCardController | Execute$ TrigChange | TriggerDescription$ When CARDNAME dies, you may put it on the top or bottom of its owner's library.
SVar:TrigChange:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Library | LibraryPosition$ 0 | DestinationAlternative$ Library | LibraryPositionAlternative$ -1 | AlternativeDestinationMessage$ Would you like to put the card on the top of the library (and not on the bottom)?
SVar:TrigChange:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Library | DestinationAlternative$ Library | LibraryPositionAlternative$ -1
Oracle:Flying\nWhen Arashin Sovereign dies, you may put it on the top or bottom of its owner's library.
4 changes: 2 additions & 2 deletions forge-gui/res/cardsfolder/a/ashioks_forerunner.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ Types:Creature Human Wizard
PT:3/3
K:Flash
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearch | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library and/or graveyard for a card named Ashiok, Sculptor of Fears, reveal it, and put it into your hand. If you search your library this way, shuffle.
SVar:TrigSearch:DB$ ChangeZone | Origin$ Library | OriginAlternative$ Graveyard | AlternativeMessage$ Would you like to search your library with this ability? If you do, your library will be shuffled. | Destination$ Hand | ChangeType$ Card.YouOwn+namedAshiok; Sculptor of Fears | Optional$ True
DeckHints:Name$Ashiok, Sculptor of Fears
SVar:TrigSearch:DB$ ChangeZone | Origin$ Library | OriginAlternative$ Graveyard | Destination$ Hand | ChangeType$ Card.YouOwn+namedAshiok; Sculptor of Fears | Optional$ True
DeckNeeds:Name$Ashiok, Sculptor of Fears
Oracle:Flash\nWhen Ashiok's Forerunner enters the battlefield, you may search your library and/or graveyard for a card named Ashiok, Sculptor of Fears, reveal it, and put it into your hand. If you search your library this way, shuffle.
4 changes: 2 additions & 2 deletions forge-gui/res/cardsfolder/b/basris_aegis.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Name:Basri's Aegis
ManaCost:2 W W
Types:Sorcery
A:SP$ PutCounter | CounterType$ P1P1 | TargetMin$ 0 | TargetMax$ 2 | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBSearch | SpellDescription$ Put a +1/+1 counter on each of up to two target creatures. You may search your library and/or graveyard for a card named Basri, Devoted Paladin, reveal it, and put it into your hand. If you search your library this way, shuffle.
SVar:DBSearch:DB$ ChangeZone | Optional$ True | Origin$ Library | OriginAlternative$ Graveyard | AlternativeMessage$ Would you like to search your library with this ability? If you do, your library will be shuffled. | Destination$ Hand | ChangeType$ Card.YouOwn+namedBasri; Devoted Paladin | ChangeTypeDesc$ card named Basri, Devoted Paladin | ChangeNum$ 1
A:SP$ PutCounter | CounterType$ P1P1 | TargetMin$ 0 | TargetMax$ 2 | ValidTgts$ Creature | TgtPrompt$ Select up to two target creatures | SubAbility$ DBSearch | SpellDescription$ Put a +1/+1 counter on each of up to two target creatures. You may search your library and/or graveyard for a card named Basri, Devoted Paladin, reveal it, and put it into your hand. If you search your library this way, shuffle.
SVar:DBSearch:DB$ ChangeZone | Optional$ True | Origin$ Library | OriginAlternative$ Graveyard | Destination$ Hand | ChangeType$ Card.YouOwn+namedBasri; Devoted Paladin | ChangeTypeDesc$ card named Basri, Devoted Paladin | ChangeNum$ 1
DeckHints:Name$Basri, Devoted Paladin
DeckHas:Ability$Counters
Oracle:Put a +1/+1 counter on each of up to two target creatures. You may search your library and/or graveyard for a card named Basri, Devoted Paladin, reveal it, and put it into your hand. If you search your library this way, shuffle.
Loading

0 comments on commit de207f9

Please sign in to comment.