diff --git a/Mage.Sets/src/mage/cards/v/VolcanoHellion.java b/Mage.Sets/src/mage/cards/v/VolcanoHellion.java new file mode 100644 index 00000000000..d8d9dffdd51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VolcanoHellion.java @@ -0,0 +1,111 @@ +/* + * 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.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.EchoAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public class VolcanoHellion extends CardImpl { + + public VolcanoHellion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add("Hellion"); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + + // Volcano Hellion has echo {X}, where X is your life total. + this.addAbility(new EchoAbility(new ControllerLifeCount(), "{this} has echo {X}, where X is your life total.")); + + // When Volcano Hellion enters the battlefield, it deals an amount of damage of your choice to you and target creature. The damage can't be prevented. + Ability ability = new EntersBattlefieldTriggeredAbility(new VolcanoHellionEffect(), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + } + + public VolcanoHellion(final VolcanoHellion card) { + super(card); + } + + @Override + public VolcanoHellion copy() { + return new VolcanoHellion(this); + } +} + +class VolcanoHellionEffect extends OneShotEffect { + + public VolcanoHellionEffect() { + super(Outcome.AIDontUseIt); + this.staticText = "it deals an amount of damage of your choice to you and target creature. The damage can't be prevented"; + } + + public VolcanoHellionEffect(final VolcanoHellionEffect effect) { + super(effect); + } + + @Override + public VolcanoHellionEffect copy() { + return new VolcanoHellionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (controller != null) { + int amount = controller.getAmount(0, Integer.MAX_VALUE, "Choose the amount of damage to deliver to you and a target creature. The damage can't be prevented.", game); + if (amount > 0) { + controller.damage(amount, source.getSourceId(), game, false, false); + if (permanent != null) { + permanent.damage(amount, source.getSourceId(), game, false, false); + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/PlanarChaos.java b/Mage.Sets/src/mage/sets/PlanarChaos.java index f6622a868b1..8c99068372d 100644 --- a/Mage.Sets/src/mage/sets/PlanarChaos.java +++ b/Mage.Sets/src/mage/sets/PlanarChaos.java @@ -204,6 +204,7 @@ public class PlanarChaos extends ExpansionSet { cards.add(new SetCardInfo("Venarian Glimmer", 52, Rarity.UNCOMMON, mage.cards.v.VenarianGlimmer.class)); cards.add(new SetCardInfo("Vitaspore Thallid", 143, Rarity.COMMON, mage.cards.v.VitasporeThallid.class)); cards.add(new SetCardInfo("Voidstone Gargoyle", 21, Rarity.RARE, mage.cards.v.VoidstoneGargoyle.class)); + cards.add(new SetCardInfo("Volcano Hellion", 111, Rarity.RARE, mage.cards.v.VolcanoHellion.class)); cards.add(new SetCardInfo("Vorosh, the Hunter", 164, Rarity.RARE, mage.cards.v.VoroshTheHunter.class)); cards.add(new SetCardInfo("Waning Wurm", 83, Rarity.UNCOMMON, mage.cards.w.WaningWurm.class)); cards.add(new SetCardInfo("Whitemane Lion", 22, Rarity.COMMON, mage.cards.w.WhitemaneLion.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java b/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java index 6fd2119c17c..afe35d923f2 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java @@ -24,8 +24,7 @@ * 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 java.util.UUID; @@ -36,6 +35,7 @@ import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.CostsImpl; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.constants.Zone; @@ -54,12 +54,25 @@ public class EchoAbility extends TriggeredAbilityImpl { protected boolean echoPaid; protected Costs echoCosts = new CostsImpl<>(); private boolean manaEcho = true; + private DynamicValue amount; + private String rule; public EchoAbility(String manaString) { super(Zone.BATTLEFIELD, new EchoEffect(new ManaCostsImpl(manaString)), false); this.echoPaid = false; this.echoCosts.add(new ManaCostsImpl(manaString)); this.lastController = null; + this.rule = null; + } + + public EchoAbility(DynamicValue amount, String rule) { + super(Zone.BATTLEFIELD, new EchoEffect(amount), false); + this.amount = amount; + this.echoPaid = false; + this.echoCosts.add(costs); + this.lastController = null; + this.manaEcho = true; + this.rule = rule; } public EchoAbility(Cost echoCost) { @@ -68,6 +81,7 @@ public class EchoAbility extends TriggeredAbilityImpl { this.echoCosts.add(echoCost); this.manaEcho = false; this.lastController = null; + this.rule = null; } public EchoAbility(final EchoAbility ability) { @@ -76,6 +90,8 @@ public class EchoAbility extends TriggeredAbilityImpl { this.echoCosts = ability.echoCosts.copy(); this.manaEcho = ability.manaEcho; this.lastController = ability.lastController; + this.amount = ability.amount; + this.rule = ability.rule; } @Override @@ -85,7 +101,8 @@ public class EchoAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD || event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD + || event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; } @Override @@ -93,20 +110,21 @@ public class EchoAbility extends TriggeredAbilityImpl { // reset the echo paid state back, if creature enteres the battlefield if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId())) { - + this.echoPaid = false; } if (event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE) { - if(lastController != null){ - if(!lastController.equals(this.controllerId)){ + if (lastController != null) { + if (!lastController.equals(this.controllerId)) { this.echoPaid = false; } } // remember the last controller lastController = this.getControllerId(); // if echo not paid yet, controller has to pay - if (event.getPlayerId().equals(this.controllerId) && - lastController.equals(this.controllerId) && !this.echoPaid){ + if (event.getPlayerId().equals(this.controllerId) + && lastController.equals(this.controllerId) + && !this.echoPaid) { this.echoPaid = true; return true; } @@ -116,45 +134,66 @@ public class EchoAbility extends TriggeredAbilityImpl { @Override public String getRule() { - StringBuilder sb = new StringBuilder("Echo"); - if (manaEcho) { - sb.append(' '); + StringBuilder sb = new StringBuilder(); + if (rule != null) { + sb.append(rule); } else { - sb.append("—"); + sb = new StringBuilder("Echo"); + if (manaEcho) { + sb.append(' '); + } else { + sb.append("—"); + } + if (echoCosts != null) { + sb.append(echoCosts.getText()); + } } - sb.append(echoCosts.getText()); sb.append(" (At the beginning of your upkeep, if this came under your control since the beginning of your last upkeep, sacrifice it unless you pay its echo cost.)"); return sb.toString(); } } class EchoEffect extends OneShotEffect { + protected Cost cost; + protected DynamicValue amount; public EchoEffect(Cost costs) { super(Outcome.Sacrifice); this.cost = costs; - } + this.amount = null; + } + + public EchoEffect(DynamicValue amount) { + super(Outcome.Sacrifice); + this.amount = amount; + this.cost = null; + } public EchoEffect(final EchoEffect effect) { super(effect); this.cost = effect.cost; + this.amount = effect.amount; } @Override public boolean apply(Game game, Ability source) { + if (amount != null) { + cost = new ManaCostsImpl(Integer.toString(amount.calculate(game, source, this))); + } Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && source.getSourceObjectIfItStillExists(game) != null) { - if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() /* + " or sacrifice " + permanent.getName() */ + '?', source, game)) { - cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { - return true; - } - } - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.sacrifice(source.getSourceId(), game); + if (controller != null + && source.getSourceObjectIfItStillExists(game) != null) { + if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + '?', source, game)) { + cost.clearPaid(); + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { + return true; } + } + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + } return true; } return false; @@ -167,17 +206,16 @@ class EchoEffect extends OneShotEffect { @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder("sacrifice {this} unless you "); - String costText = cost.getText(); - if (costText.toLowerCase().startsWith("discard")) { - sb.append(costText.substring(0, 1).toLowerCase()); - sb.append(costText.substring(1)); - } - else { - sb.append("pay ").append(costText); - } + StringBuilder sb = new StringBuilder("sacrifice {this} unless you "); + String costText = cost.getText(); + if (costText.toLowerCase().startsWith("discard")) { + sb.append(costText.substring(0, 1).toLowerCase()); + sb.append(costText.substring(1)); + } else { + sb.append("pay ").append(costText); + } - return sb.toString(); + return sb.toString(); } }