diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java index dc4f99abfe..f30c624167 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java @@ -12,6 +12,7 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.util.CardUtil; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -750,6 +751,40 @@ public class CopySpellTest extends CardTestPlayerBase { //cardsMustHaveSameZoneAndZCC(originalCard.getRightHalfCard(), copiedCard.getRightHalfCard(), "right"); } + /** + * Reported bug: https://github.com/magefree/mage/issues/7655 + * Thieving Skydiver is kicked and then copied, but the copied version does not let you gain control of anything. + */ + @Test + @Ignore + public void copySpellWithKicker() { + // When Thieving Skydiver enters the battlefield, if it was kicked, gain control of target artifact with mana value X or less. + // If that artifact is an Equipment, attach it to Thieving Skydiver. + addCard(Zone.HAND, playerA, "Thieving Skydiver"); + // Copy target creature spell you control, except it isn’t legendary if the spell is legendary. + addCard(Zone.HAND, playerA, "Double Major"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); // Original price, + 1 kicker, + 1 for Double Major + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + + addCard(Zone.BATTLEFIELD, playerB, "Sol Ring", 2); + setStrictChooseMode(true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thieving Skydiver"); + setChoice(playerA, "Yes"); + setChoice(playerA, "X=1"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", "Thieving Skydiver", "Thieving Skydiver"); + addTarget(playerA, "Sol Ring"); // Choice for copy + addTarget(playerA, "Sol Ring"); // Choice for original + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Sol Ring", 2); // 1 taken by original, one by copy + assertPermanentCount(playerB, "Sol Ring", 0); + } + private void abilitySourceMustBeSame(Card card, String infoPrefix) { Set partIds = CardUtil.getObjectParts(card); diff --git a/Mage/src/main/java/mage/abilities/keyword/KickerAbility.java b/Mage/src/main/java/mage/abilities/keyword/KickerAbility.java index 37c90cc066..967dcaca63 100644 --- a/Mage/src/main/java/mage/abilities/keyword/KickerAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/KickerAbility.java @@ -231,46 +231,48 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo @Override public void addOptionalAdditionalCosts(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - Player player = game.getPlayer(ability.getControllerId()); - if (player != null) { - this.resetKicker(); - for (OptionalAdditionalCost kickerCost : kickerCosts) { - boolean again = true; - while (player.canRespond() && again) { - String times = ""; - if (kickerCost.isRepeatable()) { - int activatedCount = getKickedCounterStrict(game, ability, kickerCost.getText(true)); - times = (activatedCount + 1) + (activatedCount == 0 ? " time " : " times "); - } - // TODO: add AI support to find max number of possible activations (from available mana) - // canPay checks only single mana available, not total mana usage - if (kickerCost.canPay(ability, this, ability.getControllerId(), game) - && player.chooseUse(/*Outcome.Benefit*/Outcome.AIDontUseIt, - "Pay " + times + kickerCost.getText(false) + " ?", ability, game)) { - this.activateKicker(kickerCost, ability, game); - if (kickerCost instanceof Costs) { - // as multiple costs - for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext(); ) { - Object kickerCostObject = itKickerCost.next(); - if ((kickerCostObject instanceof Costs)) { - for (@SuppressWarnings("unchecked") Iterator itDetails - = ((Costs) kickerCostObject).iterator(); itDetails.hasNext(); ) { - addKickerCostsToAbility(itDetails.next(), ability, game); - } - } else { - addKickerCostsToAbility((Cost) kickerCostObject, ability, game); - } + if (!(ability instanceof SpellAbility)) { + return; + } + Player player = game.getPlayer(ability.getControllerId()); + if (player == null) { + return; + } + this.resetKicker(); + for (OptionalAdditionalCost kickerCost : kickerCosts) { + boolean again = true; + while (player.canRespond() && again) { + String times = ""; + if (kickerCost.isRepeatable()) { + int activatedCount = getKickedCounterStrict(game, ability, kickerCost.getText(true)); + times = (activatedCount + 1) + (activatedCount == 0 ? " time " : " times "); + } + // TODO: add AI support to find max number of possible activations (from available mana) + // canPay checks only single mana available, not total mana usage + if (kickerCost.canPay(ability, this, ability.getControllerId(), game) + && player.chooseUse(/*Outcome.Benefit*/Outcome.AIDontUseIt, + "Pay " + times + kickerCost.getText(false) + " ?", ability, game)) { + this.activateKicker(kickerCost, ability, game); + if (kickerCost instanceof Costs) { + // as multiple costs + for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext(); ) { + Object kickerCostObject = itKickerCost.next(); + if ((kickerCostObject instanceof Costs)) { + for (@SuppressWarnings("unchecked") Iterator itDetails + = ((Costs) kickerCostObject).iterator(); itDetails.hasNext(); ) { + addKickerCostsToAbility(itDetails.next(), ability, game); } } else { - // as single cost - addKickerCostsToAbility(kickerCost, ability, game); + addKickerCostsToAbility((Cost) kickerCostObject, ability, game); } - again = kickerCost.isRepeatable(); - } else { - again = false; } + } else { + // as single cost + addKickerCostsToAbility(kickerCost, ability, game); } + again = kickerCost.isRepeatable(); + } else { + again = false; } } }