Merge pull request #263 from Northmoc/hiddenCZ

various getStackDescription improvements
This commit is contained in:
Anthony Calosa
2022-05-07 06:48:46 +08:00
committed by GitHub
11 changed files with 92 additions and 29 deletions

View File

@@ -206,8 +206,9 @@ public class AnimateEffect extends AnimateEffectBase {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final Card host = sa.getHostCard(); final Card host = sa.getHostCard();
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final List<Card> tgts = getCardsfromTargets(sa); final List<Card> tgts = getDefinedCardsOrTargeted(sa);
final boolean justOne = tgts.size() == 1; //possible to be building stack desc before Defined is populated... for now, 0 will default to singular
final boolean justOne = tgts.size() <= 1;
if (sa.hasParam("IfDesc")) { if (sa.hasParam("IfDesc")) {
if (sa.getParam("IfDesc").equals("True") && sa.hasParam("SpellDescription")) { if (sa.getParam("IfDesc").equals("True") && sa.hasParam("SpellDescription")) {
@@ -264,7 +265,7 @@ public class AnimateEffect extends AnimateEffectBase {
} else { } else {
sb.append("toughness ").append(toughness).append(" "); sb.append("toughness ").append(toughness).append(" ");
} }
} else { } else if (sb.length() > initial) {
sb.append(justOne ? "becomes " : "become "); sb.append(justOne ? "becomes " : "become ");
} }
@@ -291,7 +292,8 @@ public class AnimateEffect extends AnimateEffectBase {
} }
} }
if (keywords.size() > 0) { if (keywords.size() > 0) {
sb.append("and gains ").append(Lang.joinHomogenous(keywords).toLowerCase()).append(" "); sb.append(sb.length() > initial ? "and " : "").append(" gains ");
sb.append(Lang.joinHomogenous(keywords).toLowerCase()).append(" ");
} }
// sb.append(abilities) // sb.append(abilities)
// sb.append(triggers) // sb.append(triggers)
@@ -317,6 +319,20 @@ public class AnimateEffect extends AnimateEffectBase {
} }
sb.append("."); sb.append(".");
if (sa.hasParam("AtEOT")) {
sb.append(" ");
final String eot = sa.getParam("AtEOT");
final String pronoun = justOne ? "it" : "them";
if (eot.equals("Hand")) {
sb.append("Return ").append(pronoun).append(" to your hand");
} else if (eot.equals("SacrificeCtrl")) {
sb.append(justOne ? "Its controller sacrifices it" : "Their controllers sacrifice them");
} else { //Sacrifice,Exile
sb.append(eot).append(" ").append(pronoun);
}
sb.append(" at the beginning of the next end step.");
}
return sb.toString(); return sb.toString();
} }

View File

@@ -293,15 +293,36 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
// TODO Expand on this Description as more cards use it // TODO Expand on this Description as more cards use it
// for the non-targeted SAs when you choose what is returned on resolution // for the non-targeted SAs when you choose what is returned on resolution
sb.append("Return ").append(num).append(" ").append(type).append(" card(s) "); sb.append("Return ").append(num).append(" ").append(type).append(" card(s) ");
sb.append(" to your ").append(destination); sb.append(" to your ").append(destination).append(".");
} else if (origin.equals("Graveyard")) { } else if (origin.equals("Graveyard")) {
// for non-targeted SAs when you choose what is moved on resolution // for non-targeted SAs when you choose what is moved on resolution
// this will need expansion as more cards use it // this will need expansion as more cards use it
sb.append(chooserNames).append(" puts ");
final String cardTag = type.contains("card") ? "" : " card"; final String cardTag = type.contains("card") ? "" : " card";
sb.append(num != 0 ? Lang.nounWithNumeralExceptOne(num, type + cardTag) : final boolean changeNumDesc = sa.hasParam("ChangeNumDesc");
sa.getParamOrDefault("ChangeNumDesc", "") + " " + type + cardTag); final boolean mandatory = sa.hasParam("Mandatory");
sb.append(" into their ").append(destination.toLowerCase()).append("."); String changed;
if (changeNumDesc) {
changed = sa.getParam("ChangeNumDesc") + " " + type + cardTag;
} else if (!mandatory) {
changed = Lang.nounWithNumeral(num, type + cardTag);
} else {
changed = Lang.nounWithNumeralExceptOne(num, type + cardTag);
}
final boolean battlefield = destination.equals("Battlefield");
sb.append(chooserNames).append(" returns ").append(mandatory || changeNumDesc ? "" : "up to ");
sb.append(changed);
// so far, it seems non-targeted only lets you return from your own graveyard
sb.append(" from their graveyard").append(choosers.size() > 1 ? "s" : "");
sb.append(battlefield ? " to the " : " into their ").append(destination.toLowerCase());
if (sa.hasParam("WithCountersType")) {
final CounterType cType = CounterType.getType(sa.getParam("WithCountersType"));
if (cType != null) {
sb.append(" with an additional ").append(cType.getName()).append(" counter on it");
} else {
sb.append(" [ChangeZoneEffect WithCountersType error]");
}
}
sb.append(".");
} }
return sb.toString(); return sb.toString();

View File

@@ -11,6 +11,7 @@ import forge.game.card.Card;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
import forge.game.card.CardZoneTable; import forge.game.card.CardZoneTable;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Lang; import forge.util.Lang;
@@ -92,17 +93,40 @@ public class MillEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final int numCards = sa.hasParam("NumCards") ? AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa) : 1; final int numCards = sa.hasParam("NumCards") ? AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa) : 1;
final boolean optional = sa.hasParam("Optional");
final boolean eachP = sa.hasParam("Defined") && sa.getParam("Defined").equals("Player");
String each = "Each player";
final PlayerCollection tgtPs = getTargetPlayers(sa);
sb.append(Lang.joinHomogenous(getTargetPlayers(sa))).append(" "); if (sa.hasParam("IfDesc")) {
final String ifD = sa.getParam("IfDesc");
if (ifD.equals("True")) {
String ifDesc = sa.getDescription();
if (ifDesc.contains(",")) {
sb.append(ifDesc, 0, ifDesc.indexOf(",") + 1);
} else {
sb.append("[MillEffect IfDesc parsing error]");
}
} else {
sb.append(ifD);
}
sb.append(" ");
each = each.toLowerCase();
}
sb.append(eachP ? each : Lang.joinHomogenous(tgtPs));
sb.append(" ");
final ZoneType dest = ZoneType.smartValueOf(sa.getParam("Destination")); final ZoneType dest = ZoneType.smartValueOf(sa.getParam("Destination"));
sb.append(optional ? "may " : "");
if ((dest == null) || dest.equals(ZoneType.Graveyard)) { if ((dest == null) || dest.equals(ZoneType.Graveyard)) {
sb.append("mills "); sb.append("mill");
} else if (dest.equals(ZoneType.Exile)) { } else if (dest.equals(ZoneType.Exile)) {
sb.append("exiles "); sb.append("exile");
} else if (dest.equals(ZoneType.Ante)) { } else if (dest.equals(ZoneType.Ante)) {
sb.append("antes "); sb.append("ante");
} }
sb.append((optional || tgtPs.size() > 1) && !eachP ? " " : "s ");
sb.append(Lang.nounWithNumeralExceptOne(numCards, "card")).append("."); sb.append(Lang.nounWithNumeralExceptOne(numCards, "card")).append(".");

View File

@@ -1,8 +1,8 @@
Name:Blood for Bones Name:Blood for Bones
ManaCost:3 B ManaCost:3 B
Types:Sorcery Types:Sorcery
A:SP$ ChangeZone | Cost$ 3 B Sac<1/Creature> | Origin$ Graveyard | Destination$ Battlefield | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn | RememberChanged$ True | SubAbility$ DBChangeZone | SpellDescription$ Return a creature card from your graveyard to the battlefield, then return another creature card from your graveyard to your hand. A:SP$ ChangeZone | Cost$ 3 B Sac<1/Creature> | Origin$ Graveyard | Destination$ Battlefield | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn | PrimaryPrompt$ Choose a creature card to return to the battlefield | ChangeTypeDesc$ creature | RememberChanged$ True | SubAbility$ DBChangeZone | SpellDescription$ Return a creature card from your graveyard to the battlefield, then return another creature card from your graveyard to your hand.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn+IsNotRemembered | SubAbility$ DBCleanup SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn+IsNotRemembered | PrimaryPrompt$ Choose another creature card to return to your hand | ChangeNumDesc$ another | ChangeTypeDesc$ creature | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:Random AI:RemoveDeck:Random
Oracle:As an additional cost to cast this spell, sacrifice a creature.\nReturn a creature card from your graveyard to the battlefield, then return another creature card from your graveyard to your hand. Oracle:As an additional cost to cast this spell, sacrifice a creature.\nReturn a creature card from your graveyard to the battlefield, then return another creature card from your graveyard to your hand.

View File

@@ -4,7 +4,7 @@ Types:Snow Sorcery
A:SP$ Charm | Cost$ 4 B B | Choices$ DestroyCtrs,DestroyPWs | CharmNum$ 1 | SpellDescription$ Then return a creature or planeswalker card with mana value X or less from your graveyard to the battlefield, where X is the amount of {S} spent to cast this spell. ({S} is mana from a snow source.) A:SP$ Charm | Cost$ 4 B B | Choices$ DestroyCtrs,DestroyPWs | CharmNum$ 1 | SpellDescription$ Then return a creature or planeswalker card with mana value X or less from your graveyard to the battlefield, where X is the amount of {S} spent to cast this spell. ({S} is mana from a snow source.)
SVar:DestroyCtrs:DB$ DestroyAll | ValidCards$ Creature | SubAbility$ DBReturn | SpellDescription$ Destroy all creatures. SVar:DestroyCtrs:DB$ DestroyAll | ValidCards$ Creature | SubAbility$ DBReturn | SpellDescription$ Destroy all creatures.
SVar:DestroyPWs:DB$ DestroyAll | ValidCards$ Planeswalker | SubAbility$ DBReturn | SpellDescription$ Destroy all planeswalkers. SVar:DestroyPWs:DB$ DestroyAll | ValidCards$ Planeswalker | SubAbility$ DBReturn | SpellDescription$ Destroy all planeswalkers.
SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn+cmcLEX,Planeswalker.YouOwn+cmcLEX | SpellDescription$ Then return a creature or planeswalker card with mana value X or less from your graveyard to the battlefield, where X is the amount of {S} spent to cast this spell. ({S} is mana from a snow source.) SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Hidden$ True | Mandatory$ True | ChangeType$ Creature.YouOwn+cmcLEX,Planeswalker.YouOwn+cmcLEX | ChangeTypeDesc$ creature or planeswalker card with mana value X or less | SpellDescription$ Then return a creature or planeswalker card with mana value X or less from your graveyard to the battlefield, where X is the amount of {S} spent to cast this spell. ({S} is mana from a snow source.)
SVar:X:Count$CastTotalManaSpent Snow SVar:X:Count$CastTotalManaSpent Snow
SVar:AIPreference:ManaFrom$Snow SVar:AIPreference:ManaFrom$Snow
AI:RemoveDeck:Random AI:RemoveDeck:Random

View File

@@ -1,8 +1,8 @@
Name:Bond of Insight Name:Bond of Insight
ManaCost:3 U ManaCost:3 U
Types:Sorcery Types:Sorcery
A:SP$ Mill | Cost$ 3 U | NumCards$ 4 | Defined$ Player | SubAbility$ DBChangeZone | StackDescription$ Each player mills four cards. | SpellDescription$ Each player mills four cards. Return up to two instant and/or sorcery cards from your graveyard to your hand. Exile CARDNAME. A:SP$ Mill | NumCards$ 4 | Defined$ Player | SubAbility$ DBChangeZone | SpellDescription$ Each player mills four cards. Return up to two instant and/or sorcery cards from your graveyard to your hand. Exile CARDNAME.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ChangeNum$ 2 | ChangeType$ Instant.YouOwn,Sorcery.YouOwn | SelectPrompt$ Select up to two instant and/or sorcery cards from your graveyard to return to your hand | Hidden$ True | SubAbility$ DBExile | StackDescription$ {p:You} returns up to two instant and/or sorcery cards from their graveyard to their hand. SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ChangeNum$ 2 | ChangeType$ Instant.YouOwn,Sorcery.YouOwn | ChangeTypeDesc$ instant and/or sorcery | SelectPrompt$ Select up to two instant and/or sorcery cards from your graveyard to return to your hand | Hidden$ True | SubAbility$ DBExile | StackDescription$ {p:You} returns up to two instant and/or sorcery cards from their graveyard to their hand.
SVar:DBExile:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | StackDescription$ Exile CARDNAME. SVar:DBExile:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | StackDescription$ Exile CARDNAME.
DeckHas:Ability$Graveyard|Mill DeckHas:Ability$Graveyard|Mill
DeckHints:Type$Instant|Sorcery DeckHints:Type$Instant|Sorcery

View File

@@ -1,8 +1,8 @@
Name:Cauldron's Gift Name:Cauldron's Gift
ManaCost:4 B ManaCost:4 B
Types:Sorcery Types:Sorcery
A:SP$ Mill | Cost$ 4 B | NumCards$ 4 | Defined$ You | SubAbility$ DBChangeZone | ConditionCheckSVar$ X | AIManaPref$ B | SpellDescription$ Adamant — If at least three black mana was spent to cast this spell, mill four cards. You may choose a creature card in your graveyard. If you do, return it to the battlefield with an additional +1/+1 counter on it. A:SP$ Mill | NumCards$ 4 | SubAbility$ DBChangeZone | ConditionCheckSVar$ X | AIManaPref$ B | IfDesc$ True | SpellDescription$ Adamant — If at least three black mana was spent to cast this spell, mill four cards. You may choose a creature card in your graveyard. If you do, return it to the battlefield with an additional +1/+1 counter on it.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouOwn | Hidden$ True | ChangeNum$ 1 | WithCountersType$ P1P1 SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouOwn | ChangeTypeDesc$ creature | Hidden$ True | ChangeNum$ 1 | WithCountersType$ P1P1
SVar:X:Count$Adamant.Black.1.0 SVar:X:Count$Adamant.Black.1.0
DeckHas:Ability$Counters|Graveyard DeckHas:Ability$Counters|Graveyard|Mill
Oracle:Adamant — If at least three black mana was spent to cast this spell, mill four cards.\nYou may choose a creature card in your graveyard. If you do, return it to the battlefield with an additional +1/+1 counter on it. Oracle:Adamant — If at least three black mana was spent to cast this spell, mill four cards.\nYou may choose a creature card in your graveyard. If you do, return it to the battlefield with an additional +1/+1 counter on it.

View File

@@ -1,7 +1,7 @@
Name:Connive Name:Connive
ManaCost:2 U/B U/B ManaCost:2 U/B U/B
Types:Sorcery Types:Sorcery
A:SP$ GainControl | Cost$ 2 U/B U/B | ValidTgts$ Creature.powerLE2 | TgtPrompt$ Select target creature with power 2 or less. | SpellDescription$ Gain control of target creature with power 2 or less. A:SP$ GainControl | ValidTgts$ Creature.powerLE2 | TgtPrompt$ Select target creature with power 2 or less | SpellDescription$ Gain control of target creature with power 2 or less.
AlternateMode:Split AlternateMode:Split
Oracle:Gain control of target creature with power 2 or less. Oracle:Gain control of target creature with power 2 or less.
@@ -10,7 +10,7 @@ ALTERNATE
Name:Concoct Name:Concoct
ManaCost:3 U B ManaCost:3 U B
Types:Sorcery Types:Sorcery
A:SP$ Surveil | Cost$ 3 U B | Amount$ 3 | SubAbility$ DBReturn | SpellDescription$ Surveil 3, then return a creature card from your graveyard to the battlefield. A:SP$ Surveil | Amount$ 3 | SubAbility$ DBReturn | SpellDescription$ Surveil 3, then return a creature card from your graveyard to the battlefield.
SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouCtrl | ChangeNum$ 1 | Hidden$ True SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouOwn | ChangeTypeDesc$ creature | ChangeNum$ 1 | Hidden$ True | Mandatory$ True
DeckHas:Ability$Surveil|Graveyard DeckHas:Ability$Surveil|Graveyard
Oracle:Surveil 3, then return a creature card from your graveyard to the battlefield. Oracle:Surveil 3, then return a creature card from your graveyard to the battlefield.

View File

@@ -2,8 +2,9 @@ Name:Corpse Dance
ManaCost:2 B ManaCost:2 B
Types:Instant Types:Instant
K:Buyback:2 K:Buyback:2
A:SP$ ChangeZone | Cost$ 2 B | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.TopGraveyardCreature+YouCtrl | Hidden$ True | Mandatory$ True | RememberChanged$ True | SubAbility$ DBPump | SpellDescription$ Return the top creature card of your graveyard to the battlefield. That creature gains haste until end of turn. Exile it at the beginning of the next end step. A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.TopGraveyardCreature+YouOwn | Hidden$ True | Mandatory$ True | RememberChanged$ True | SubAbility$ DBPump | StackDescription$ {p:You} returns the top creature card of their graveyard to the battlefield. | SpellDescription$ Return the top creature card of your graveyard to the battlefield.
SVar:DBPump:DB$ Animate | Keywords$ Haste | Defined$ Remembered | AtEOT$ Exile | SubAbility$ DBCleanup SVar:DBPump:DB$ Animate | Keywords$ Haste | Defined$ Remembered | AtEOT$ Exile | SubAbility$ DBCleanup | DefinedDesc$ That creature | SpellDescription$ That creature gains haste until end of turn. Exile it at the beginning of the next end step.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:NeedsOrderedGraveyard:TRUE SVar:NeedsOrderedGraveyard:TRUE
DeckHas:Ability$Graveyard
Oracle:Buyback {2} (You may pay an additional {2} as you cast this spell. If you do, put this card into your hand as it resolves.)\nReturn the top creature card of your graveyard to the battlefield. That creature gains haste until end of turn. Exile it at the beginning of the next end step. Oracle:Buyback {2} (You may pay an additional {2} as you cast this spell. If you do, put this card into your hand as it resolves.)\nReturn the top creature card of your graveyard to the battlefield. That creature gains haste until end of turn. Exile it at the beginning of the next end step.

View File

@@ -1,7 +1,8 @@
Name:Eerie Ultimatum Name:Eerie Ultimatum
ManaCost:W W B B B G G ManaCost:W W B B B G G
Types:Sorcery Types:Sorcery
A:SP$ ChangeZone | Cost$ W W B B B G G | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Permanent.YouOwn | DifferentNames$ True | ChangeNum$ X | Hidden$ True | StackDescription$ SpellDescription | SpellDescription$ Return any number of permanent cards with different names from your graveyard to the battlefield. A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Permanent.YouOwn | ChangeNumDesc$ any number of | ChangeTypeDesc$ permanent cards with different names | DifferentNames$ True | ChangeNum$ X | Hidden$ True | SpellDescription$ Return any number of permanent cards with different names from your graveyard to the battlefield.
SVar:X:Count$DifferentCardNames_Permanent.YouOwn+inZoneGraveyard SVar:X:Count$DifferentCardNames_Permanent.YouOwn+inZoneGraveyard
SVar:IsReanimatorCard:TRUE SVar:IsReanimatorCard:TRUE
DeckHas:Ability$Graveyard
Oracle:Return any number of permanent cards with different names from your graveyard to the battlefield. Oracle:Return any number of permanent cards with different names from your graveyard to the battlefield.

View File

@@ -1,6 +1,6 @@
Name:Forbidden Friendship Name:Forbidden Friendship
ManaCost:1 R ManaCost:1 R
Types:Sorcery Types:Sorcery
A:SP$ Token | Cost$ 1 R | TokenAmount$ 1 | TokenScript$ r_1_1_dinosaur_haste,w_1_1_human_soldier | TokenOwner$ You | SpellDescription$ Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token. A:SP$ Token | TokenScript$ r_1_1_dinosaur_haste,w_1_1_human_soldier | SpellDescription$ Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token.
DeckHas:Ability$Token DeckHas:Ability$Token & Type$Dinosaur|Human|Soldier
Oracle:Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token. Oracle:Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token.