From f5fe2bd133607bd24e0358463bf493a416565816 Mon Sep 17 00:00:00 2001 From: magenoxx Date: Tue, 18 Apr 2017 23:28:42 +0300 Subject: [PATCH] Issue#3148: added reproducing test --- .../cost/modification/FluctuatorTest.java | 112 +++++++++++++++++ .../mage/abilities/costs/WrapperCost.java | 41 ++++++ .../abilities/costs/common/CyclingCost.java | 119 ++++++++++++++++++ .../abilities/keyword/CyclingAbility.java | 75 +---------- 4 files changed, 273 insertions(+), 74 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/FluctuatorTest.java create mode 100644 Mage/src/main/java/mage/abilities/costs/WrapperCost.java create mode 100644 Mage/src/main/java/mage/abilities/costs/common/CyclingCost.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/FluctuatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/FluctuatorTest.java new file mode 100644 index 0000000000..197a7c5629 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/FluctuatorTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.cost.modification; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author noxx + */ +public class FluctuatorTest extends CardTestPlayerBase { + + /** + * Fluctuator makes 'Akroma's Vengeance' cyclic cost reduced to {1} + * Test it with one Plains on battlefield. + */ + @Test + public void testFluctuatorReducedBy2() { + + // Destroy all artifacts, creatures, and enchantments. + // Cycling ({3}, Discard this card: Draw a card.) + addCard(Zone.HAND, playerA, "Akroma's Vengeance"); + + // Cycling abilities you activate cost you up to {2} less to activate. + addCard(Zone.BATTLEFIELD, playerA, "Fluctuator"); + + // One mana should be enough + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Akroma's Vengeance", 1); + assertHandCount(playerA, 1); + } + + /** + * Fluctuator makes 'Akroma's Vengeance' cyclic cost reduced to {1} + * + * Make sure it wasn't reduced more than by two. + */ + @Test + public void testFluctuatorReducedNotBy3() { + + // Destroy all artifacts, creatures, and enchantments. + // Cycling ({3}, Discard this card: Draw a card.) + addCard(Zone.HAND, playerA, "Akroma's Vengeance"); + + // Cycling abilities you activate cost you up to {2} less to activate. + addCard(Zone.BATTLEFIELD, playerA, "Fluctuator"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Akroma's Vengeance", 0); + assertHandCount(playerA, 1); + } + + /** + * Test 2 Fluctuators reduce cycling cost up to 4. + * + */ + @Test + public void testTwoFluctuatorsReduceBy4() { + + // Destroy all artifacts, creatures, and enchantments. + // Cycling ({3}, Discard this card: Draw a card.) + addCard(Zone.HAND, playerA, "Akroma's Vengeance"); + + // Cycling abilities you activate cost you up to {2} less to activate. + addCard(Zone.BATTLEFIELD, playerA, "Fluctuator", 2); // 2 copies + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Akroma's Vengeance", 1); + assertHandCount(playerA, 1); + } +} diff --git a/Mage/src/main/java/mage/abilities/costs/WrapperCost.java b/Mage/src/main/java/mage/abilities/costs/WrapperCost.java new file mode 100644 index 0000000000..c9714a8acf --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/WrapperCost.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.costs; + +import java.io.Serializable; + +/** + * Some Cost act like wrappers hiding real costs inside + * + * @author noxx + */ +public interface WrapperCost extends Serializable { + + Cost getOriginalCost(); + +} diff --git a/Mage/src/main/java/mage/abilities/costs/common/CyclingCost.java b/Mage/src/main/java/mage/abilities/costs/common/CyclingCost.java new file mode 100644 index 0000000000..ebcbdfd00d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/common/CyclingCost.java @@ -0,0 +1,119 @@ +/* + * Copyright 2017 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.costs.common; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.WrapperCost; +import mage.game.Game; +import mage.game.events.CostEvent; +import mage.game.events.GameEvent; +import mage.target.Targets; + +import java.util.UUID; + +/** + * Cycling Cost to interact with cards like 'New Perspectives' + */ +public class CyclingCost implements Cost, WrapperCost { + + protected Cost cost; + + public CyclingCost(Cost cost) { + this.cost = cost; + } + + public CyclingCost(final CyclingCost cost) { + this.cost = cost.cost.copy(); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + return pay(ability, game, sourceId, controllerId, noMana, cost); + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + CostEvent costEvent = new CostEvent(GameEvent.EventType.CAN_PAY_CYCLE_COST, sourceId, sourceId, controllerId, cost); + game.replaceEvent(costEvent); + return cost.canPay(ability, sourceId, controllerId, game) || costEvent.getCost().canPay(ability, sourceId, controllerId, game); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + CostEvent costEvent = new CostEvent(GameEvent.EventType.PAY_CYCLE_COST, sourceId, sourceId, controllerId, cost); + game.replaceEvent(costEvent); + cost = costEvent.getCost(); + return cost.pay(ability, game, sourceId, controllerId, noMana, cost); + } + + @Override + public String getText() { + return cost.getText(); + } + + @Override + public void setText(String text) { + cost.setText(text); + } + + @Override + public Targets getTargets() { + return cost.getTargets(); + } + + @Override + public boolean isPaid() { + return cost.isPaid(); + } + + @Override + public void clearPaid() { + cost.clearPaid(); + } + + @Override + public void setPaid() { + cost.setPaid(); + } + + @Override + public UUID getId() { + return cost.getId(); + } + + @Override + public Cost copy() { + return new CyclingCost(this); + } + + @Override + public Cost getOriginalCost() { + return this.cost; + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/keyword/CyclingAbility.java b/Mage/src/main/java/mage/abilities/keyword/CyclingAbility.java index 09f1c72d45..dba43008be 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CyclingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CyclingAbility.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; +import mage.abilities.costs.common.CyclingCost; import mage.abilities.costs.common.DiscardSourceCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -90,77 +91,3 @@ public class CyclingAbility extends ActivatedAbilityImpl { } } - -class CyclingCost implements Cost { - - protected Cost cost; - - public CyclingCost(Cost cost) { - this.cost = cost; - } - - public CyclingCost(final CyclingCost cost) { - this.cost = cost.cost.copy(); - } - - @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { - return pay(ability, game, sourceId, controllerId, noMana, cost); - } - - @Override - public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { - CostEvent costEvent = new CostEvent(GameEvent.EventType.CAN_PAY_CYCLE_COST, sourceId, sourceId, controllerId, cost); - game.replaceEvent(costEvent); - return cost.canPay(ability, sourceId, controllerId, game) || costEvent.getCost().canPay(ability, sourceId, controllerId, game); - } - - @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { - CostEvent costEvent = new CostEvent(GameEvent.EventType.PAY_CYCLE_COST, sourceId, sourceId, controllerId, cost); - game.replaceEvent(costEvent); - cost = costEvent.getCost(); - return cost.pay(ability, game, sourceId, controllerId, noMana, cost); - } - - @Override - public String getText() { - return cost.getText(); - } - - @Override - public void setText(String text) { - cost.setText(text); - } - - @Override - public Targets getTargets() { - return cost.getTargets(); - } - - @Override - public boolean isPaid() { - return cost.isPaid(); - } - - @Override - public void clearPaid() { - cost.clearPaid(); - } - - @Override - public void setPaid() { - cost.setPaid(); - } - - @Override - public UUID getId() { - return cost.getId(); - } - - @Override - public Cost copy() { - return new CyclingCost(this); - } - -}