Fix Unbound Flourishing triggering for additional X costs (#1581)

* Fix Unbound Flourishing triggering for additional X costs
This commit is contained in:
tool4ever
2022-09-25 21:28:10 +02:00
committed by GitHub
parent 20827bb7f3
commit 29fc28be3b
12 changed files with 23 additions and 21 deletions

View File

@@ -258,7 +258,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
// intervening if check, make sure to use right controller // intervening if check, make sure to use right controller
if (game.getStack().isResolving(getHostCard())) { if (game.getStack().isResolving(getHostCard())) {
SpellAbility sa = game.getStack().peekAbility(); SpellAbility sa = game.getStack().peek().getSpellAbility(false);
if (sa.isTrigger()) { if (sa.isTrigger()) {
hostController = sa.getActivatingPlayer(); hostController = sa.getActivatingPlayer();
} }

View File

@@ -1723,12 +1723,12 @@ public class AbilityUtils {
&& ZoneType.Battlefield.name().equals(t.getParam("Destination"))) { && ZoneType.Battlefield.name().equals(t.getParam("Destination"))) {
return doXMath(c.getXManaCostPaid(), expr, c, ctb); return doXMath(c.getXManaCostPaid(), expr, c, ctb);
} else if (TriggerType.SpellCast.equals(t.getMode())) { } else if (TriggerType.SpellCast.equals(t.getMode())) {
// Cast Trigger like Hydroid Krasis // Cast Trigger like Hydroid Krasis, use SI because Unbound Flourishing might change X
SpellAbility castSA = (SpellAbility) root.getTriggeringObject(AbilityKey.SpellAbility); SpellAbilityStackInstance castSI = (SpellAbilityStackInstance) root.getTriggeringObject(AbilityKey.StackInstance);
if (castSA == null || castSA.getXManaCostPaid() == null) { if (castSI == null) {
return doXMath(0, expr, c, ctb); return doXMath(0, expr, c, ctb);
} }
return doXMath(castSA.getXManaCostPaid(), expr, c, ctb); return doXMath(castSI.getXManaPaid(), expr, c, ctb);
} else if (TriggerType.Cycled.equals(t.getMode())) { } else if (TriggerType.Cycled.equals(t.getMode())) {
SpellAbility cycleSA = (SpellAbility) sa.getTriggeringObject(AbilityKey.Cause); SpellAbility cycleSA = (SpellAbility) sa.getTriggeringObject(AbilityKey.Cause);
if (cycleSA == null || cycleSA.getXManaCostPaid() == null) { if (cycleSA == null || cycleSA.getXManaCostPaid() == null) {

View File

@@ -25,7 +25,7 @@ public class ChangeXEffect extends SpellAbilityEffect {
for (final SpellAbility tgtSA : sas) { for (final SpellAbility tgtSA : sas) {
// for Unbound Flourishing, can't go over SpellAbilityStackInstances because the x is in cast SA copy // for Unbound Flourishing, can't go over SpellAbilityStackInstances because the x is in cast SA copy
SpellAbility castSA = tgtSA.getHostCard().getCastSA(); SpellAbility castSA = tgtSA.getHostCard().getCastSA();
if (castSA != null && tgtSA.equals(castSA)) { if (castSA != null && tgtSA.equals(castSA) && castSA.getXManaCostPaid() != null) {
castSA.setXManaCostPaid(castSA.getXManaCostPaid() * 2); castSA.setXManaCostPaid(castSA.getXManaCostPaid() * 2);
} }
// fall back to other potential cards // fall back to other potential cards

View File

@@ -269,6 +269,7 @@ public final class CardUtil {
} }
newCopy.addRemembered(in.getRemembered()); newCopy.addRemembered(in.getRemembered());
newCopy.addImprintedCards(in.getImprintedCards()); newCopy.addImprintedCards(in.getImprintedCards());
newCopy.setChosenCards(new CardCollection(in.getChosenCards()));
for (Table.Cell<Player, CounterType, Integer> cl : in.getEtbCounters()) { for (Table.Cell<Player, CounterType, Integer> cl : in.getEtbCounters()) {
newCopy.addEtbCounter(cl.getColumnKey(), cl.getValue(), cl.getRowKey()); newCopy.addEtbCounter(cl.getColumnKey(), cl.getValue(), cl.getRowKey());

View File

@@ -212,7 +212,7 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView {
} }
public final int getXManaPaid() { public final int getXManaPaid() {
return xManaPaid; return xManaPaid == null ? 0 : xManaPaid;
} }
public final void setXManaPaid(int x) { public final void setXManaPaid(int x) {
xManaPaid = x; xManaPaid = x;

View File

@@ -192,11 +192,13 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
} }
if (hasParam("HasXManaCost")) { if (hasParam("HasXManaCost")) {
final Cost cost = (Cost) (runParams.get(AbilityKey.Cost)); final int numX;
if (cost.hasNoManaCost()) { if (spellAbility.isActivatedAbility()) {
return false; numX = spellAbility.getPayCosts().hasManaCost() ? spellAbility.getPayCosts().getCostMana().getAmountOfX() : 0;
} else {
numX = cast.getManaCost().countX();
} }
if (cost.getCostMana().getAmountOfX() <= 0) { if (numX == 0) {
return false; return false;
} }
} }

View File

@@ -7,7 +7,7 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
SVar:TrigChange:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | NextTurnForEachPlayer$ True | RepeatSubAbility$ DBEffect | SpellDescription$ Each opponent can't cast instant or sorcery spells during that player's next turn. SVar:TrigChange:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | NextTurnForEachPlayer$ True | RepeatSubAbility$ DBEffect | SpellDescription$ Each opponent can't cast instant or sorcery spells during that player's next turn.
SVar:DBEffect:DB$ Effect | Name$ Azor, the Lawbringer's Effect | StaticAbilities$ STCantBeCast | EffectOwner$ Remembered SVar:DBEffect:DB$ Effect | Name$ Azor, the Lawbringer's Effect | StaticAbilities$ STCantBeCast | EffectOwner$ Remembered
SVar:STCantBeCast:Mode$ CantBeCast | ValidCard$ Instant,Sorcery | Caster$ You | EffectZone$ Command | Description$ You can't cast instant or sorcery spells. SVar:STCantBeCast:Mode$ CantBeCast | ValidCard$ Instant,Sorcery | Caster$ You | EffectZone$ Command | Description$ You can't cast instant or sorcery spells.
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ Whenever Azor attacks, you may pay {X}{W}{U}{U}. If you do, you gain X life and draw X cards. T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ Whenever NICKNAME attacks, you may pay {X}{W}{U}{U}. If you do, you gain X life and draw X cards.
SVar:TrigDraw:AB$ GainLife | Cost$ X W U U | Defined$ You | LifeAmount$ X | SubAbility$ DBDraw | SpellDescription$ You gain X life and draw X cards. SVar:TrigDraw:AB$ GainLife | Cost$ X W U U | Defined$ You | LifeAmount$ X | SubAbility$ DBDraw | SpellDescription$ You gain X life and draw X cards.
SVar:DBDraw:DB$ Draw | NumCards$ X SVar:DBDraw:DB$ Draw | NumCards$ X
SVar:X:Count$xPaid SVar:X:Count$xPaid

View File

@@ -4,7 +4,7 @@ Types:Sorcery
A:SP$ ChangeZoneAll | Cost$ 5 W W | ChangeType$ Permanent | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile all permanents. For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield. A:SP$ ChangeZoneAll | Cost$ 5 W W | ChangeType$ Permanent | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile all permanents. For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield.
SVar:DBEffect:DB$ Effect | Triggers$ TrigUpkeep | RememberObjects$ Remembered | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup SVar:DBEffect:DB$ Effect | Triggers$ TrigUpkeep | RememberObjects$ Remembered | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:TrigUpkeep:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ BreachReturn | TriggerZones$ Command | TriggerController$ TriggeredPlayer | CheckSVar$ BreachX | SVarCompare$ GE1 | TriggerDescription$ At the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield. SVar:TrigUpkeep:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ BreachReturn | TriggerZones$ Command | TriggerController$ TriggeredPlayer | TriggerDescription$ At the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield.
SVar:BreachReturn:DB$ ChooseCard | Defined$ TriggeredPlayer | Amount$ 1 | Mandatory$ True | ChoiceTitle$ Choose a card to return to the battlefield | Choices$ Card.IsRemembered+ActivePlayerCtrl | ChoiceZone$ Exile | SubAbility$ MoveChosen SVar:BreachReturn:DB$ ChooseCard | Defined$ TriggeredPlayer | Amount$ 1 | Mandatory$ True | ChoiceTitle$ Choose a card to return to the battlefield | Choices$ Card.IsRemembered+ActivePlayerCtrl | ChoiceZone$ Exile | SubAbility$ MoveChosen
SVar:MoveChosen:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ ChosenCard | ForgetChanged$ True SVar:MoveChosen:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ ChosenCard | ForgetChanged$ True
Oracle:Exile all permanents. For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield. Oracle:Exile all permanents. For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards they own to the battlefield.

View File

@@ -3,6 +3,6 @@ ManaCost:1 B G U
Types:Enchantment Types:Enchantment
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDig | TriggerDescription$ At the beginning of your upkeep, look at the top card of your library. You may put that card into your graveyard. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDig | TriggerDescription$ At the beginning of your upkeep, look at the top card of your library. You may put that card into your graveyard.
SVar:TrigDig:DB$ Dig | DigNum$ 1 | ChangeNum$ 1 | DestinationZone$ Graveyard | Optional$ True | LibraryPosition2$ 0 SVar:TrigDig:DB$ Dig | DigNum$ 1 | ChangeNum$ 1 | DestinationZone$ Graveyard | Optional$ True | LibraryPosition2$ 0
A:AB$ Mana | Cost$ ExileFromGrave<1/Card> | Produced$ C | RestrictValid$ Spell.nonColorless+withoutXCost | SpellDescription$ Add {C}. Spend this mana only to cast a spell that's one or more colors without {X} in its mana cost. A:AB$ Mana | Cost$ ExileFromGrave<1/Card> | Produced$ C | RestrictValid$ Spell.nonColorless+!hasXCost | SpellDescription$ Add {C}. Spend this mana only to cast a spell that's one or more colors without {X} in its mana cost.
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:At the beginning of your upkeep, look at the top card of your library. You may put that card into your graveyard.\nExile a card from your graveyard: Add {C}. Spend this mana only to cast a spell that's one or more colors without {X} in its mana cost. Oracle:At the beginning of your upkeep, look at the top card of your library. You may put that card into your graveyard.\nExile a card from your graveyard: Add {C}. Spend this mana only to cast a spell that's one or more colors without {X} in its mana cost.

View File

@@ -4,7 +4,7 @@ Types:Legendary Creature Human Warrior
PT:3/4 PT:3/4
K:Flying K:Flying
K:Lifelink K:Lifelink
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigReturn | TriggerDescription$ Healing Tears — At the beginning of your end step, return target creature card with mana value X or less from your graveyard to the battlefield, where X is the amount of life you gained this turn. T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigReturn | TriggerZones$ Battlefield | TriggerDescription$ Healing Tears — At the beginning of your end step, return target creature card with mana value X or less from your graveyard to the battlefield, where X is the amount of life you gained this turn.
SVar:TrigReturn:DB$ ChangeZone | ValidTgts$ Creature.cmcLEX+YouOwn | TgtPrompt$ Select target creature card with mana value X or less | Origin$ Graveyard | Destination$ Battlefield SVar:TrigReturn:DB$ ChangeZone | ValidTgts$ Creature.cmcLEX+YouOwn | TgtPrompt$ Select target creature card with mana value X or less | Origin$ Graveyard | Destination$ Battlefield
SVar:X:Count$LifeYouGainedThisTurn SVar:X:Count$LifeYouGainedThisTurn
DeckHas:Ability$LifeGain|Graveyard DeckHas:Ability$LifeGain|Graveyard

View File

@@ -3,7 +3,7 @@ ManaCost:2 W U
Types:Creature Astartes Wizard Types:Creature Astartes Wizard
PT:3/4 PT:3/4
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCast | TriggerDescription$ Veil of Time — Whenever CARDNAME attacks, you may cast a spell with mana value X or less from your hand without paying its mana cost, where X is the number of attacking creatures. T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCast | TriggerDescription$ Veil of Time — Whenever CARDNAME attacks, you may cast a spell with mana value X or less from your hand without paying its mana cost, where X is the number of attacking creatures.
SVar:TrigCast:DB$ Play | ValidZone$ Hand | Valid$ Card.cmcLEX+YouOwn | ValidSA$ Spell | Optional$ True | WithoutManaCost$ True | SVar:TrigCast:DB$ Play | ValidZone$ Hand | Valid$ Card.cmcLEX+YouOwn | ValidSA$ Spell | Optional$ True | WithoutManaCost$ True
SVar:Z:Count$Valid Creature.attacking+YouCtrl SVar:X:Count$Valid Creature.attacking+YouCtrl
SVar:HasAttackEffect:TRUE SVar:HasAttackEffect:TRUE
Oracle:Veil of Time — Whenever Epistolary Librarian attacks, you may cast a spell with mana value X or less from your hand without paying its mana cost, where X is the number of attacking creatures. Oracle:Veil of Time — Whenever Epistolary Librarian attacks, you may cast a spell with mana value X or less from your hand without paying its mana cost, where X is the number of attacking creatures.

View File

@@ -5,10 +5,9 @@ PT:6/6
K:Flying K:Flying
K:Trample K:Trample
K:ETBReplacement:Other:DBChoose K:ETBReplacement:Other:DBChoose
SVar:DBChoose:DB$ ChooseCard | Choices$ Creature.Other+YouCtrl |TgtPrompt$ Select another target creature you control | Description$ As CARDNAME enters the battlefield, choose another creature you control. SVar:DBChoose:DB$ ChooseCard | Choices$ Creature.Other+YouCtrl | Mandatory$ True | SpellDescription$ As CARDNAME enters the battlefield, choose another creature you control.
S:Mode$ Continuous | Affected$ Card.ChosenCardStrict | AddKeyword$ Flying | AddToughness$ 3 | AddPower$ 3 | SpellDescription$ The chosen creature gets +3/+3 and has flying. S:Mode$ Continuous | Affected$ Card.ChosenCardStrict | AddKeyword$ Flying | AddToughness$ 3 | AddPower$ 3 | SpellDescription$ The chosen creature gets +3/+3 and has flying.
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigSacrifice | SubAbility$ DBCleanup | SpellDescription$ When CARDNAME leaves the battlefield, sacrifice the chosen creature. T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigSacrifice | SubAbility$ TrigSacrifice | TriggerDescription$ When CARDNAME leaves the battlefield, sacrifice the chosen creature.
SVar:TrigSacrifice:DB$ SacrificeAll | Defined$ ChosenCard SVar:TrigSacrifice:DB$ SacrificeAll | ValidCards$ Card.ChosenCardStrict
SVar:DBCleanup:DB$ Cleanup | ClearChosen$ True
DeckHas:Ability$Sacrifice DeckHas:Ability$Sacrifice
Oracle:Flying, trample\nAs Tyrannical Pitlord enters the battlefield, choose another creature you control.\nThe chosen creature gets +3/+3 and has flying.\nWhen Tyrannical Pitlord leaves the battlefield, sacrifice the chosen creature. Oracle:Flying, trample\nAs Tyrannical Pitlord enters the battlefield, choose another creature you control.\nThe chosen creature gets +3/+3 and has flying.\nWhen Tyrannical Pitlord leaves the battlefield, sacrifice the chosen creature.