From 5a3c90a2950011bd60fa0034cd99a6b5f69114fd Mon Sep 17 00:00:00 2001 From: Nathaniel Brandes Date: Mon, 27 Apr 2015 02:25:20 -0700 Subject: [PATCH] Changed Kentaro, the Smiling Cat's ability to be an alternate cost instead of a set cost effect. Also cleaned up dash names to be "dash" instead of "evoke". --- .../KentaroTheSmilingCat.java | 120 +++++++++++------- .../costs/AlternativeCostSourceAbility.java | 57 +++++++-- .../src/mage/abilities/costs/DynamicCost.java | 12 ++ .../mage/abilities/keyword/DashAbility.java | 18 +-- 4 files changed, 138 insertions(+), 69 deletions(-) create mode 100644 Mage/src/mage/abilities/costs/DynamicCost.java diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/KentaroTheSmilingCat.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/KentaroTheSmilingCat.java index 8453f863634..5500eef9593 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/KentaroTheSmilingCat.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/KentaroTheSmilingCat.java @@ -27,22 +27,31 @@ */ package mage.sets.betrayersofkamigawa; -import mage.constants.*; +import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.condition.common.SourceIsSpellCondition; +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.DynamicCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.keyword.BushidoAbility; -import mage.abilities.keyword.FlashbackAbility; -import mage.abilities.keyword.RetraceAbility; -import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; -import java.util.UUID; - /** * @author LevelX2 */ @@ -62,7 +71,7 @@ public class KentaroTheSmilingCat extends CardImpl { this.addAbility(new BushidoAbility(1)); // You may pay {X} rather than pay the mana cost for Samurai spells you cast, where X is that spell's converted mana cost. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KentaroTheSmilingCatCostReductionEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KentaroTheSmilingCatCastingEffect())); } @@ -75,50 +84,63 @@ public class KentaroTheSmilingCat extends CardImpl { public KentaroTheSmilingCat copy() { return new KentaroTheSmilingCat(this); } +} - //TODO : change CostModification to AlternativCost - private class KentaroTheSmilingCatCostReductionEffect extends CostModificationEffectImpl { +class KentaroTheSmilingCatCastingEffect extends ContinuousEffectImpl { + + private static final FilterCard filterSamurai = new FilterCard(); + + static { + filterSamurai.add(new SubtypePredicate("Samurai")); + } + + static final AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility( + SourceIsSpellCondition.getInstance(), null, filterSamurai, true, new ColorlessConvertedManaCost()); + + public KentaroTheSmilingCatCastingEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "You may pay {X} rather than pay the mana cost for Samurai spells you cast, where X is that spell's converted mana cost"; + } + + public KentaroTheSmilingCatCastingEffect(final KentaroTheSmilingCatCastingEffect effect) { + super(effect); + } - private static final String effectText = "You may pay {X} rather than pay the mana cost for Samurai spells you cast, where X is that spell's converted mana cost"; + @Override + public KentaroTheSmilingCatCastingEffect copy() { + return new KentaroTheSmilingCatCastingEffect(this); + } - KentaroTheSmilingCatCostReductionEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.SET_COST); - staticText = effectText; - } - - KentaroTheSmilingCatCostReductionEffect(KentaroTheSmilingCatCostReductionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + controller.getAlternativeSourceCosts().add(alternativeCastingCostAbility); return true; } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) { - Ability spell = abilityToModify; - if (spell.getControllerId().equals(source.getControllerId())) { - Card sourceCard = game.getCard(spell.getSourceId()); - if (sourceCard != null && sourceCard.hasSubtype("Samurai")) { - String manaCostsString = "{" + sourceCard.getManaCost().convertedManaCost() + "}"; - Player player = game.getPlayer(spell.getControllerId()); - if (player != null && player.chooseUse(Outcome.Benefit, "Pay converted mana cost rather than pay the mana cost for Samurai creature?", game)) { - spell.getManaCostsToPay().clear(); - spell.getManaCostsToPay().load(manaCostsString); - return true; - } - } - } - } - return false; - } - - @Override - public KentaroTheSmilingCatCostReductionEffect copy() { - return new KentaroTheSmilingCatCostReductionEffect(this); - } - + return false; } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.RulesEffects; + } +} + +class ColorlessConvertedManaCost implements DynamicCost { + + @Override + public Cost getCost(Ability ability, Game game) { + return new GenericManaCost(ability.getManaCosts().convertedManaCost()); + } + + @Override + public String getText(Ability ability, Game game) { + return "Pay " + getCost(ability, game).getText() + " rather than " + ability.getManaCosts().getText() + " for Samurai?"; + } } \ No newline at end of file diff --git a/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java b/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java index cb0bb3a9277..a041c5cec2f 100644 --- a/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java +++ b/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java @@ -51,6 +51,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter protected String rule; protected FilterCard filter; protected boolean onlyMana; + protected DynamicCost dynamicCost; public AlternativeCostSourceAbility(Cost cost) { this(cost, null); @@ -78,13 +79,23 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter */ public AlternativeCostSourceAbility(Cost cost, Condition condition, String rule, FilterCard filter, boolean onlyMana) { super(Zone.ALL, null); - this.convertToAlternativeCostAndAdd(cost); + this.addCost(cost); this.setRuleAtTheTop(true); this.condition = condition; this.rule = rule; this.filter = filter; this.onlyMana = onlyMana; } + + public AlternativeCostSourceAbility(Condition condition, String rule, FilterCard filter, boolean onlyMana, DynamicCost dynamicCost) { + super(Zone.ALL, null); + this.setRuleAtTheTop(true); + this.condition = condition; + this.rule = rule; + this.filter = filter; + this.onlyMana = onlyMana; + this.dynamicCost = dynamicCost; + } public AlternativeCostSourceAbility(final AlternativeCostSourceAbility ability) { super(ability); @@ -93,18 +104,19 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter this.rule = ability.rule; this.filter = ability.filter; this.onlyMana = ability.onlyMana; + this.dynamicCost = ability.dynamicCost; } @Override public void addCost(Cost cost) { - this.convertToAlternativeCostAndAdd(cost); + AlternativeCost2 alternativeCost = convertToAlternativeCost(cost); + if(alternativeCost != null) { + this.alternateCosts.add(alternativeCost); + } } - private void convertToAlternativeCostAndAdd(Cost cost) { - if (cost != null) { - AlternativeCost2 alternativeCost = new AlternativeCost2Impl(null, null, cost); - this.alternateCosts.add(alternativeCost); - } + private AlternativeCost2 convertToAlternativeCost(Cost cost) { + return cost != null ? new AlternativeCost2Impl(null, cost.getText(), cost) : null; } @Override @@ -131,13 +143,29 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter } Player player = game.getPlayer(ability.getControllerId()); if (player != null) { - if (alternateCosts.canPay(ability, ability.getSourceId(), ability.getControllerId(), game) && - player.chooseUse(Outcome.Detriment, alternateCosts.isEmpty() ? "Cast without paying its mana cost?":"Pay alternative costs? (" + alternateCosts.getText() +")", game)) { + Costs alternativeCosts; + if(dynamicCost != null) { + alternativeCosts = new CostsImpl<>(); + alternativeCosts.add(convertToAlternativeCost(dynamicCost.getCost(ability, game))); + } else { + alternativeCosts = this.alternateCosts; + } + + String costChoiceText; + if(dynamicCost != null) { + costChoiceText = dynamicCost.getText(ability, game); + } else { + costChoiceText = alternativeCosts.isEmpty() ? "Cast without paying its mana cost?" : "Pay alternative costs? (" + alternativeCosts.getText() +")"; + } + + + if (alternativeCosts.canPay(ability, ability.getSourceId(), ability.getControllerId(), game) && + player.chooseUse(Outcome.Benefit, costChoiceText, game)) { ability.getManaCostsToPay().clear(); if(!onlyMana) { ability.getCosts().clear(); } - for (Cost cost : alternateCosts) { + for (Cost cost : alternativeCosts) { AlternativeCost2 alternateCost = (AlternativeCost2) cost; alternateCost.activate(); for (Iterator it = ((Costs) alternateCost).iterator(); it.hasNext();) { @@ -161,7 +189,14 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter @Override public boolean isActivated(Ability source, Game game) { - for (AlternativeCost2 cost : alternateCosts) { + Costs alternativeCosts; + if(dynamicCost != null) { + alternativeCosts = new CostsImpl<>(); + alternativeCosts.add(convertToAlternativeCost(dynamicCost.getCost(source, game))); + } else { + alternativeCosts = this.alternateCosts; + } + for (AlternativeCost2 cost : alternativeCosts) { if (cost.isActivated(game)) { return true; } diff --git a/Mage/src/mage/abilities/costs/DynamicCost.java b/Mage/src/mage/abilities/costs/DynamicCost.java new file mode 100644 index 00000000000..efb39245d38 --- /dev/null +++ b/Mage/src/mage/abilities/costs/DynamicCost.java @@ -0,0 +1,12 @@ +package mage.abilities.costs; + +import mage.abilities.Ability; +import mage.game.Game; + +public interface DynamicCost { + + Cost getCost(Ability ability, Game game); + + String getText(Ability ability, Game game); + +} diff --git a/Mage/src/mage/abilities/keyword/DashAbility.java b/Mage/src/mage/abilities/keyword/DashAbility.java index 8f7cdaa8056..dbb7ddbcbe4 100644 --- a/Mage/src/mage/abilities/keyword/DashAbility.java +++ b/Mage/src/mage/abilities/keyword/DashAbility.java @@ -131,13 +131,13 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts Player player = game.getPlayer(controllerId); if (player != null) { this.resetDash(); - for (AlternativeCost2 evokeCost: alternativeSourceCosts) { - if (evokeCost.canPay(ability, sourceId, controllerId, game) && - player.chooseUse(Outcome.Benefit, new StringBuilder(KEYWORD).append(" the creature for ").append(evokeCost.getText(true)).append(" ?").toString(), game)) { - activateDash(evokeCost, game); + for (AlternativeCost2 dashCost: alternativeSourceCosts) { + if (dashCost.canPay(ability, sourceId, controllerId, game) && + player.chooseUse(Outcome.Benefit, new StringBuilder(KEYWORD).append(" the creature for ").append(dashCost.getText(true)).append(" ?").toString(), game)) { + activateDash(dashCost, game); ability.getManaCostsToPay().clear(); ability.getCosts().clear(); - for (Iterator it = ((Costs) evokeCost).iterator(); it.hasNext();) { + for (Iterator it = ((Costs) dashCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); if (cost instanceof ManaCostsImpl) { ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); @@ -170,12 +170,12 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts StringBuilder sb = new StringBuilder(); int numberCosts = 0; String remarkText = ""; - for (AlternativeCost2 evokeCost: alternativeSourceCosts) { + for (AlternativeCost2 dashCost: alternativeSourceCosts) { if (numberCosts == 0) { - sb.append(evokeCost.getText(false)); - remarkText = evokeCost.getReminderText(); + sb.append(dashCost.getText(false)); + remarkText = dashCost.getReminderText(); } else { - sb.append(" and/or ").append(evokeCost.getText(true)); + sb.append(" and/or ").append(dashCost.getText(true)); } ++numberCosts; }