diff --git a/Mage.Sets/src/mage/sets/darkascension/IncreasingVengeance.java b/Mage.Sets/src/mage/sets/darkascension/IncreasingVengeance.java index aa280e446b..927823ef3a 100644 --- a/Mage.Sets/src/mage/sets/darkascension/IncreasingVengeance.java +++ b/Mage.Sets/src/mage/sets/darkascension/IncreasingVengeance.java @@ -41,6 +41,8 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.Target; import mage.target.TargetSpell; /** @@ -66,7 +68,9 @@ public class IncreasingVengeance extends CardImpl { // Copy target instant or sorcery spell you control. If Increasing Vengeance was cast from a graveyard, copy that spell twice instead. You may choose new targets for the copies. this.getSpellAbility().addEffect(new IncreasingVengeanceEffect()); - this.getSpellAbility().addTarget(new TargetSpell(filter)); + Target target = new TargetSpell(filter); + target.setRequired(true); + this.getSpellAbility().addTarget(target); // Flashback {3}{R}{R} this.addAbility(new FlashbackAbility(new ManaCostsImpl("{3}{R}{R}"), TimingRule.INSTANT)); @@ -95,24 +99,29 @@ class IncreasingVengeanceEffect extends OneShotEffect @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); - if (spell != null) { - Spell copy = spell.copySpell(); - copy.setControllerId(source.getControllerId()); - copy.setCopiedSpell(true); - game.getStack().push(copy); - copy.chooseNewTargets(game, source.getControllerId()); - Spell sourceSpell = (Spell) game.getStack().getStackObject(source.getSourceId()); - if (sourceSpell != null) { - if (sourceSpell.getFromZone() == Zone.GRAVEYARD) { - copy = spell.copySpell(); - copy.setControllerId(source.getControllerId()); - copy.setCopiedSpell(true); - game.getStack().push(copy); - copy.chooseNewTargets(game, source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + if (spell != null) { + Spell copy = spell.copySpell(); + copy.setControllerId(source.getControllerId()); + copy.setCopiedSpell(true); + game.getStack().push(copy); + copy.chooseNewTargets(game, source.getControllerId()); + game.informPlayers(new StringBuilder(controller.getName()).append(copy.getActivatedMessage(game)).toString()); + Spell sourceSpell = (Spell) game.getStack().getStackObject(source.getSourceId()); + if (sourceSpell != null) { + if (sourceSpell.getFromZone() == Zone.GRAVEYARD) { + copy = spell.copySpell(); + copy.setControllerId(source.getControllerId()); + copy.setCopiedSpell(true); + game.getStack().push(copy); + copy.chooseNewTargets(game, source.getControllerId()); + game.informPlayers(new StringBuilder(controller.getName()).append(copy.getActivatedMessage(game)).toString()); + } } + return true; } - return true; } return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/IncreasingCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/IncreasingCardsTest.java index 9824db3d49..fdb0c57829 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/IncreasingCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/IncreasingCardsTest.java @@ -43,7 +43,11 @@ public class IncreasingCardsTest extends CardTestPlayerBase { assertExileCount("Increasing Ambition", 1); } - + // Increasing Confusion {X}{U} + // Sorcery + // Target player puts the top X cards of his or her library into his or her graveyard. + // If Increasing Confusion was cast from a graveyard, that player puts twice that many + // cards into his or her graveyard instead. @Test public void testIncreasingConfusion() { addCard(Zone.BATTLEFIELD, playerA, "Island", 4); @@ -102,6 +106,11 @@ public class IncreasingCardsTest extends CardTestPlayerBase { } + // Increasing Vengeance + // Instant + // Copy target instant or sorcery spell you control. If Increasing Vengeance was cast from a graveyard, copy that spell twice instead. You may choose new targets for the copies. + // Flashback {3}{R}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.) + @Test public void testIncreasingVengeance() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 1adeb17d9b..06f32325ce 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -49,6 +49,7 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.PostResolveEffect; +import mage.abilities.keyword.FlashbackAbility; import mage.abilities.mana.ManaAbility; import mage.cards.Card; import mage.choices.Choice; @@ -219,15 +220,25 @@ public abstract class AbilityImpl> implements Ability { } } + // if ability can be cast for no mana, clear the mana costs now, because additional mana costs must be paid. + // For Flashback ability can be set X before, so the X costs have to be restored for the flashbacked ability + if (noMana) { + int xValue = this.getManaCostsToPay().getX(); + this.getManaCostsToPay().clear(); + VariableManaCost xCosts = new VariableManaCost(); + xCosts.setAmount(xValue); + this.getManaCostsToPay().add(xCosts); + } // 20130201 - 601.2b // If the spell has alternative or additional costs that will be paid as it's being cast such // as buyback, kicker, or convoke costs (see rules 117.8 and 117.9), the player announces his // or her intentions to pay any or all of those costs (see rule 601.2e). // A player can't apply two alternative methods of casting or two alternative costs to a single spell. - if (card != null) { + if (card != null && !(this instanceof FlashbackAbility)) { boolean alternativeCostisUsed = false; for (Ability ability : card.getAbilities()) { - if (ability instanceof AlternativeSourceCosts) { + // if cast for noMana no Alternative costs are allowed + if (!noMana && ability instanceof AlternativeSourceCosts) { AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability; if (alternativeSpellCosts.isAvailable(this, game)) { if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) { @@ -241,7 +252,8 @@ public abstract class AbilityImpl> implements Ability { ((OptionalAdditionalSourceCosts)ability).addOptionalAdditionalCosts(this, game); } } - if (!alternativeCostisUsed) { + // controller specific alternate spell costs + if (!noMana && !alternativeCostisUsed) { if (this.getAbilityType().equals(AbilityType.SPELL)) { for (AlternativeSourceCosts alternativeSourceCosts: controller.getAlternativeSourceCosts()) { if (alternativeSourceCosts.isAvailable(this, game)) { @@ -328,8 +340,8 @@ public abstract class AbilityImpl> implements Ability { if (!useAlternativeCost(game)) { // old way still used? - //20100716 - 601.2f - if (!manaCostsToPay.pay(this, game, sourceId, activatorId, noMana)) { + //20100716 - 601.2f (noMana is not used here, because mana costs were cleared for this abaility before adding additional costs and applying cost modification effects) + if (!manaCostsToPay.pay(this, game, sourceId, activatorId, false)) { logger.debug("activate failed - mana"); return false; } @@ -385,6 +397,7 @@ public abstract class AbilityImpl> implements Ability { * * @param game * @param noMana + * @param controller * @return variableManaCost for posting to log later */ protected VariableManaCost handleManaXCosts(Game game, boolean noMana, Player controller) { diff --git a/Mage/src/mage/abilities/SpellAbility.java b/Mage/src/mage/abilities/SpellAbility.java index 2d01f1f23b..df8558afc6 100644 --- a/Mage/src/mage/abilities/SpellAbility.java +++ b/Mage/src/mage/abilities/SpellAbility.java @@ -116,7 +116,7 @@ public class SpellAbility extends ActivatedAbilityImpl { @Override public String getGameLogMessage(Game game) { - return new StringBuilder(" casts ").append(getMessageText(game)).toString(); + return getMessageText(game); } @Override diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java index 0caacf25d2..9eca6f56b3 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java @@ -148,7 +148,7 @@ public class ManaCostsImpl extends ArrayList implements M @Override public ManaCosts getUnpaid() { - ManaCosts unpaid = new ManaCostsImpl(); + ManaCosts unpaid = new ManaCostsImpl<>(); for (T cost : this) { if (!(cost instanceof VariableManaCost) && !cost.isPaid()) { unpaid.add((T) cost.getUnpaid()); @@ -159,7 +159,7 @@ public class ManaCostsImpl extends ArrayList implements M @Override public ManaCosts getUnpaidVariableCosts() { - ManaCosts unpaid = new ManaCostsImpl(); + ManaCosts unpaid = new ManaCostsImpl<>(); for (ManaCost cost : this) { if (cost instanceof VariableManaCost && !cost.isPaid()) { unpaid.add((T) cost.getUnpaid()); @@ -171,7 +171,7 @@ public class ManaCostsImpl extends ArrayList implements M @Override public List getVariableCosts() { - List variableCosts = new ArrayList(); + List variableCosts = new ArrayList<>(); for (ManaCost cost : this) { if (cost instanceof VariableCost) { variableCosts.add((VariableCost) cost); diff --git a/Mage/src/mage/abilities/keyword/FlashbackAbility.java b/Mage/src/mage/abilities/keyword/FlashbackAbility.java index 349da62513..a097d9cd85 100644 --- a/Mage/src/mage/abilities/keyword/FlashbackAbility.java +++ b/Mage/src/mage/abilities/keyword/FlashbackAbility.java @@ -27,6 +27,7 @@ */ package mage.abilities.keyword; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.SpellAbility; @@ -73,6 +74,17 @@ public class FlashbackAbility extends SpellAbility { this.abilityName = ability.abilityName; } + @Override + public boolean canActivate(UUID playerId, Game game) { + if (super.canActivate(playerId, game)) { + Card card = game.getCard(getSourceId()); + if (card != null) { + return card.getSpellAbility().canActivate(playerId, game); + } + } + return false; + } + @Override public FlashbackAbility copy() { return new FlashbackAbility(this); @@ -157,11 +169,13 @@ class FlashbackEffect extends OneShotEffect { } spellAbility.clear(); + // used if flashbacked spell has a {X} cost int amount = source.getManaCostsToPay().getX(); spellAbility.getManaCostsToPay().setX(amount); for (Target target : spellAbility.getTargets()) { target.setRequired(true); } + game.informPlayers(new StringBuilder(controller.getName()).append(" flashbacks ").append(card.getName()).toString()); return controller.cast(spellAbility, game, true); } } diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 18db89d8fb..f3cc359e7c 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -146,7 +146,13 @@ public class Spell> implements StackObject, Card { } public String getActivatedMessage(Game game) { - return ability.getGameLogMessage(game); + StringBuilder sb = new StringBuilder(); + if (isCopiedSpell()) { + sb.append(" copies "); + } else { + sb.append(" casts "); + } + return sb.append(ability.getGameLogMessage(game)).toString(); } @Override