diff --git a/Mage.Sets/src/mage/cards/t/TwinningGlass.java b/Mage.Sets/src/mage/cards/t/TwinningGlass.java index dc32723cf1..b4ec11930c 100644 --- a/Mage.Sets/src/mage/cards/t/TwinningGlass.java +++ b/Mage.Sets/src/mage/cards/t/TwinningGlass.java @@ -36,8 +36,7 @@ public final class TwinningGlass extends CardImpl { public TwinningGlass(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); - // {1}, {tap}: You may cast a nonland card from your hand without paying - // its mana cost if it has the same name as a spell that was cast this turn. + // {1}, {T}: You may cast a nonland card from your hand without paying its mana cost if it has the same name as a spell that was cast this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TwinningGlassEffect(), new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); @@ -104,17 +103,15 @@ class TwinningGlassEffect extends OneShotEffect { FilterNonlandCard filterCard = new FilterNonlandCard("nonland card that was cast this turn"); filterCard.add(Predicates.or(predicates)); TargetCard target = new TargetCard(0, 1, Zone.HAND, filterCard); + target.withChooseHint("free cast"); if (controller.choose(Outcome.PlayForFree, controller.getHand(), target, game)) { Card chosenCard = game.getCard(target.getFirstTarget()); if (chosenCard != null) { - if (controller.chooseUse(Outcome.PlayForFree, "Cast " - + chosenCard.getName() + " without paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(chosenCard, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null); - return cardWasCast; - } + game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE); + Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(chosenCard, game, true), + game, true, new ApprovingObject(source, game)); + game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null); + return cardWasCast; } } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BuybackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BuybackTest.java index fa4209a867..fc6f4b7629 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BuybackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BuybackTest.java @@ -110,4 +110,51 @@ public class BuybackTest extends CardTestPlayerBase { assertHandCount(playerA, "Elvish Fury", 0); assertGraveyardCount(playerA, "Elvish Fury", 1); } + + @Test + public void test_FreeCast() { + // bug: buyback doesn't work on free cast (no mana) + // https://github.com/magefree/mage/issues/4721 + + // {1}, {T}: You may cast a nonland card from your hand without paying its mana cost if it has + // the same name as a spell that was cast this turn. + addCard(Zone.BATTLEFIELD, playerA, "Twinning Glass", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + // + // Buyback {3} (You may pay an additional 3 as you cast this spell. If you do, put this card into your hand as it resolves.) + // Copy target instant or sorcery spell. You may choose new targets for the copy. + addCard(Zone.HAND, playerA, "Reiterate", 1); // Instant {1}{R}{R} + addCard(Zone.BATTLEFIELD, playerA, "Mountain", (3 + 3) * 3); + // + // Lightning Bolt deals 3 damage to any target. + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); // {R} + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + + // bolt 1 - cast (R) and copy (RRR), return reiterate with buyback (RRR) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reiterate", "Lightning Bolt"); + setChoice(playerA, true); // use buyback + setChoice(playerA, false); // same bolt's target + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkLife("bolt 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 20 - 3 * 2); + checkHandCardCount("bolt 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reiterate", 1); + checkPermanentTapped("bolt 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain", true, 1 + 3 + 3); + + // bolt 2 - cast (R) and copy as free cast (R), return reiterate with buyback (RRR) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, {T}:"); + setChoice(playerA, "Reiterate"); // free cast + setChoice(playerA, true); // use buyback + addTarget(playerA, "Lightning Bolt"); // copy target + setChoice(playerA, false); // same bolt's target + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkLife("bolt 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 20 - 3 * 2 - 3 * 2); + checkHandCardCount("bolt 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reiterate", 1); + checkPermanentTapped("bolt 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain", true, (1 + 3 + 3) + (1 + 1 + 3)); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } }