diff --git a/Mage.Sets/src/mage/cards/n/NewPerspectives.java b/Mage.Sets/src/mage/cards/n/NewPerspectives.java new file mode 100644 index 0000000000..fdd28604a6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NewPerspectives.java @@ -0,0 +1,127 @@ +/* + * 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 mage.cards.n; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalReplacementEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.CostEvent; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class NewPerspectives extends CardImpl { + + public NewPerspectives(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{U}"); + + // When New Perspectives enters the battlefield, draw three cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(3), false)); + + // As long as you have seven or more cards in hand, you may pay {0} rather than pay cycling costs. + Condition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 6); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalReplacementEffect( + new PerspectivesReplaceCylcingCosts(), condition)); + this.addAbility(ability); + } + + public NewPerspectives(final NewPerspectives card) { + super(card); + } + + @Override + public NewPerspectives copy() { + return new NewPerspectives(this); + } +} + +class PerspectivesReplaceCylcingCosts extends ReplacementEffectImpl { + + public PerspectivesReplaceCylcingCosts() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "As long as you have seven or more cards in hand, you may pay {0} rather than pay cycling costs"; + } + + public PerspectivesReplaceCylcingCosts(final PerspectivesReplaceCylcingCosts effect) { + super(effect); + } + + @Override + public PerspectivesReplaceCylcingCosts copy() { + return new PerspectivesReplaceCylcingCosts(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + if (event.getType() == EventType.CAN_PAY_CYCLE_COST) { + ((CostEvent) event).setCost(new ManaCostsImpl<>("{0}")); + return false; + } + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && controller.chooseUse(outcome, "Pay {0} rather than normal cycling costs?", source, game)) { + ((CostEvent) event).setCost(new ManaCostsImpl<>("{0}")); + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.PAY_CYCLE_COST || event.getType() == EventType.CAN_PAY_CYCLE_COST; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getPlayerId().equals(source.getControllerId()); + } + +} diff --git a/Mage.Sets/src/mage/sets/Amonkhet.java b/Mage.Sets/src/mage/sets/Amonkhet.java index e73ff91a51..58030e1113 100644 --- a/Mage.Sets/src/mage/sets/Amonkhet.java +++ b/Mage.Sets/src/mage/sets/Amonkhet.java @@ -234,6 +234,7 @@ public class Amonkhet extends ExpansionSet { cards.add(new SetCardInfo("Neheb, the Worthy", 203, Rarity.RARE, mage.cards.n.NehebTheWorthy.class)); cards.add(new SetCardInfo("Nest of Scarabs", 101, Rarity.UNCOMMON, mage.cards.n.NestOfScarabs.class)); cards.add(new SetCardInfo("Never // Return", 212, Rarity.RARE, mage.cards.n.NeverReturn.class)); + cards.add(new SetCardInfo("New Perspectives", 63, Rarity.RARE, mage.cards.n.NewPerspectives.class)); cards.add(new SetCardInfo("Nimble-Blade Khenra", 145, Rarity.COMMON, mage.cards.n.NimbleBladeKhenra.class)); cards.add(new SetCardInfo("Nissa, Steward of Elements", 204, Rarity.MYTHIC, mage.cards.n.NissaStewardOfElements.class)); cards.add(new SetCardInfo("Oashra Cultivator", 177, Rarity.COMMON, mage.cards.o.OashraCultivator.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/CyclingAbility.java b/Mage/src/main/java/mage/abilities/keyword/CyclingAbility.java index 3f9cc3700e..09f1c72d45 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CyclingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CyclingAbility.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,25 +20,29 @@ * 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.keyword; -import mage.constants.Zone; +import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; import mage.abilities.costs.common.DiscardSourceCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.constants.Zone; import mage.filter.FilterCard; +import mage.game.Game; +import mage.game.events.CostEvent; +import mage.game.events.GameEvent; +import mage.target.Targets; import mage.target.common.TargetCardInLibrary; - /** * * @author BetaSteward_at_googlemail.com @@ -47,16 +51,16 @@ public class CyclingAbility extends ActivatedAbilityImpl { private final Cost cost; private final String text; - + public CyclingAbility(Cost cost) { - super(Zone.HAND, new DrawCardSourceControllerEffect(1), cost); + super(Zone.HAND, new DrawCardSourceControllerEffect(1), new CyclingCost(cost)); this.addCost(new DiscardSourceCost()); this.cost = cost; this.text = "Cycling"; } - - public CyclingAbility(Cost cost, FilterCard filter, String text){ - super(Zone.HAND, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true), cost); + + public CyclingAbility(Cost cost, FilterCard filter, String text) { + super(Zone.HAND, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true), new CyclingCost(cost)); this.addCost(new DiscardSourceCost()); this.cost = cost; this.text = text; @@ -76,14 +80,87 @@ public class CyclingAbility extends ActivatedAbilityImpl { @Override public String getRule() { StringBuilder rule = new StringBuilder(this.text); - if(cost instanceof ManaCost){ + if (cost instanceof ManaCost) { rule.append(' '); - } - else{ - rule.append("—"); + } else { + rule.append("—"); } rule.append(cost.getText()).append(" (").append(super.getRule(true)).append(")"); return rule.toString(); } } + +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); + } + +} diff --git a/Mage/src/main/java/mage/game/events/CostEvent.java b/Mage/src/main/java/mage/game/events/CostEvent.java new file mode 100644 index 0000000000..21e65fa592 --- /dev/null +++ b/Mage/src/main/java/mage/game/events/CostEvent.java @@ -0,0 +1,54 @@ +/* + * 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 mage.game.events; + +import java.util.UUID; +import mage.abilities.costs.Cost; + +/** + * + * @author LevelX2 + */ +public class CostEvent extends GameEvent { + + protected Cost cost; + + public CostEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, Cost cost) { + super(type, targetId, sourceId, playerId); + this.cost = cost; + } + + public Cost getCost() { + return cost; + } + + public void setCost(Cost cost) { + this.cost = cost; + } + +} diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index b6c8871fd3..06dfa59f1c 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -94,7 +94,8 @@ public class GameEvent implements Serializable { INVESTIGATED, DISCARD_CARD, DISCARDED_CARD, - CYCLE_CARD, CYCLED_CARD, + // CYCLE_CARD, CYCLED_CARD, + PAY_CYCLE_COST, CAN_PAY_CYCLE_COST, CLASH, CLASHED, DAMAGE_PLAYER, /* DAMAGED_PLAYER