diff --git a/Mage.Sets/src/mage/cards/a/ArmedDangerous.java b/Mage.Sets/src/mage/cards/a/ArmedDangerous.java index c8867c1c86..603ad583e1 100644 --- a/Mage.Sets/src/mage/cards/a/ArmedDangerous.java +++ b/Mage.Sets/src/mage/cards/a/ArmedDangerous.java @@ -22,13 +22,12 @@ public final class ArmedDangerous extends SplitCard { // Target creature gets +1/+1 and gains double strike until end of turn. getLeftHalfCard().getSpellAbility().addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn)); getLeftHalfCard().getSpellAbility().addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); - getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("+1/+1 and double strike")); // Dangerous // All creatures able to block target creature this turn do so. getRightHalfCard().getSpellAbility().addEffect(new MustBeBlockedByAllTargetEffect(Duration.EndOfTurn)); - getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); - + getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("all creatures block")); } private ArmedDangerous(final ArmedDangerous card) { diff --git a/Mage.Sets/src/mage/cards/f/FleshBlood.java b/Mage.Sets/src/mage/cards/f/FleshBlood.java index e9d240ccd5..c1bdd47017 100644 --- a/Mage.Sets/src/mage/cards/f/FleshBlood.java +++ b/Mage.Sets/src/mage/cards/f/FleshBlood.java @@ -2,6 +2,7 @@ package mage.cards.f; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; import mage.cards.Card; import mage.cards.CardSetInfo; import mage.cards.SplitCard; @@ -14,7 +15,6 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetControlledCreaturePermanent; @@ -29,16 +29,16 @@ public final class FleshBlood extends SplitCard { // Flesh // Exile target creature card from a graveyard. Put X +1/+1 counters on target creature, where X is the power of the card you exiled. - Target target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE); - getLeftHalfCard().getSpellAbility().addTarget(target); - getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); getLeftHalfCard().getSpellAbility().addEffect(new FleshEffect()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE).withChooseHint("to exile")); + getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("to put X +1/+1 counters on")); + // Blood // Target creature you control deals damage equal to its power to any target. - getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - getRightHalfCard().getSpellAbility().addTarget(new TargetAnyTarget()); - getRightHalfCard().getSpellAbility().addEffect(new BloodEffect()); + getRightHalfCard().getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()); + getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent().withChooseHint("to deal damage equal to its power")); + getRightHalfCard().getSpellAbility().addTarget(new TargetAnyTarget().withChooseHint("to deal damage to")); } private FleshBlood(final FleshBlood card) { @@ -86,41 +86,3 @@ class FleshEffect extends OneShotEffect { } } - -class BloodEffect extends OneShotEffect { - - public BloodEffect() { - super(Outcome.Damage); - staticText = "Target creature you control deals damage equal to its power to any target"; - } - - public BloodEffect(final BloodEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent sourcePermanent = game.getPermanent(source.getFirstTarget()); - if (sourcePermanent == null) { - sourcePermanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); - } - - Permanent targetCreature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (sourcePermanent != null && targetCreature != null) { - targetCreature.damage(sourcePermanent.getPower().getValue(), sourcePermanent.getId(), source, game, false, true); - return true; - } - Player targetPlayer = game.getPlayer(source.getTargets().get(1).getFirstTarget()); - if (sourcePermanent != null && targetPlayer != null) { - targetPlayer.damage(sourcePermanent.getPower().getValue(), sourcePermanent.getId(), source, game); - return true; - } - return false; - } - - @Override - public BloodEffect copy() { - return new BloodEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/g/GiveTake.java b/Mage.Sets/src/mage/cards/g/GiveTake.java index 31b85ef141..354f714cd2 100644 --- a/Mage.Sets/src/mage/cards/g/GiveTake.java +++ b/Mage.Sets/src/mage/cards/g/GiveTake.java @@ -29,12 +29,12 @@ public final class GiveTake extends SplitCard { // Give // Put three +1/+1 counters on target creature. getLeftHalfCard().getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(3))); - getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("to put counters on")); // Take // Remove all +1/+1 counters from target creature you control. Draw that many cards. getRightHalfCard().getSpellAbility().addEffect(new TakeEffect()); - getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent().withChooseHint("to remove counters from")); } private GiveTake(final GiveTake card) { diff --git a/Mage.Sets/src/mage/cards/p/ProtectServe.java b/Mage.Sets/src/mage/cards/p/ProtectServe.java index 8a63613ae7..8319eb01b7 100644 --- a/Mage.Sets/src/mage/cards/p/ProtectServe.java +++ b/Mage.Sets/src/mage/cards/p/ProtectServe.java @@ -18,13 +18,12 @@ public final class ProtectServe extends SplitCard { // Protect // Target creature gets +2/+4 until end of turn. getLeftHalfCard().getSpellAbility().addEffect(new BoostTargetEffect(2, 4, Duration.EndOfTurn)); - getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets +2/+4")); // Serve // Target creature gets -6/-0 until end of turn. getRightHalfCard().getSpellAbility().addEffect(new BoostTargetEffect(-6, 0, Duration.EndOfTurn)); - getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); - + getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets -6/-0")); } private ProtectServe(final ProtectServe card) { diff --git a/Mage.Sets/src/mage/cards/t/ToilTrouble.java b/Mage.Sets/src/mage/cards/t/ToilTrouble.java index 5d33f965a9..49e8ce37f4 100644 --- a/Mage.Sets/src/mage/cards/t/ToilTrouble.java +++ b/Mage.Sets/src/mage/cards/t/ToilTrouble.java @@ -20,7 +20,7 @@ public final class ToilTrouble extends SplitCard { // Toil // Target player draws two cards and loses 2 life. - getLeftHalfCard().getSpellAbility().addTarget(new TargetPlayer()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetPlayer().withChooseHint("to draw two cards and lose 2 life")); getLeftHalfCard().getSpellAbility().addEffect(new DrawCardTargetEffect(2)); getLeftHalfCard().getSpellAbility().addEffect(new LoseLifeTargetEffect(2)); @@ -29,7 +29,7 @@ public final class ToilTrouble extends SplitCard { Effect effect = new DamageTargetEffect(CardsInTargetHandCount.instance); effect.setText("Trouble deals damage to target player equal to the number of cards in that player's hand"); getRightHalfCard().getSpellAbility().addEffect(effect); - getRightHalfCard().getSpellAbility().addTarget(new TargetPlayer()); + getRightHalfCard().getSpellAbility().addTarget(new TargetPlayer().withChooseHint("to deal damage to")); } diff --git a/Mage.Sets/src/mage/cards/t/TurnBurn.java b/Mage.Sets/src/mage/cards/t/TurnBurn.java index 8ce2a361ff..05304b56a9 100644 --- a/Mage.Sets/src/mage/cards/t/TurnBurn.java +++ b/Mage.Sets/src/mage/cards/t/TurnBurn.java @@ -30,14 +30,14 @@ public final class TurnBurn extends SplitCard { Effect effect = new BecomesCreatureTargetEffect(new WeirdToken(), true, false, Duration.EndOfTurn); effect.setText("Until end of turn, target creature loses all abilities and becomes a red Weird with base power and toughness 0/1"); getLeftHalfCard().getSpellAbility().addEffect(effect); - getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("becomes a Weird")); // Burn // Burn deals 2 damage to any target. effect = new DamageTargetEffect(2); effect.setText("Burn deals 2 damage to any target"); getRightHalfCard().getSpellAbility().addEffect(effect); - getRightHalfCard().getSpellAbility().addTarget(new TargetAnyTarget()); + getRightHalfCard().getSpellAbility().addTarget(new TargetAnyTarget().withChooseHint("2 damage")); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/split/CastSplitCardsWithFuseTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/split/CastSplitCardsWithFuseTest.java index 2cd3f8e79f..0d20a511fe 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/split/CastSplitCardsWithFuseTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/split/CastSplitCardsWithFuseTest.java @@ -94,4 +94,37 @@ public class CastSplitCardsWithFuseTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Juggernaut", 1); assertGraveyardCount(playerB, "Absolute Grace", 1); } + + @Test + public void testProtectionFromFusedSpell() { + // https://github.com/magefree/mage/issues/9545 + + addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 5); + // INSTANT + // Turn {2}{U} + // Until end of turn, target creature loses all abilities and becomes a red Weird with base power and toughness 0/1. + // Burn {1}{R} + // Burn deals 2 damage to any target. + // Fuse (You may cast one or both halves of this card from your hand.) + addCard(Zone.HAND, playerA, "Turn // Burn"); + + // {R}: Keeper of Kookus gains protection from red until end of turn. + addCard(Zone.BATTLEFIELD, playerB, "Keeper of Kookus"); + addCard(Zone.BATTLEFIELD, playerB, "Suq'Ata Lancer"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "fused Turn // Burn"); + addTarget(playerA, "Keeper of Kookus"); + addTarget(playerA, "Suq'Ata Lancer"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{R}: "); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Turn // Burn", 1); + assertGraveyardCount(playerB, "Suq'Ata Lancer", 1); + assertPermanentCount(playerB, "Keeper of Kookus", 1); + assertPowerToughness(playerB, "Keeper of Kookus", 1, 1); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageWithPowerFromOneToAnotherTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageWithPowerFromOneToAnotherTargetEffect.java index 0a3500533e..361526b785 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageWithPowerFromOneToAnotherTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageWithPowerFromOneToAnotherTargetEffect.java @@ -16,7 +16,7 @@ public class DamageWithPowerFromOneToAnotherTargetEffect extends OneShotEffect { String firstTargetName; public DamageWithPowerFromOneToAnotherTargetEffect() { - this((String) null); + this(""); } public DamageWithPowerFromOneToAnotherTargetEffect(String firstTargetName) { @@ -64,10 +64,6 @@ public class DamageWithPowerFromOneToAnotherTargetEffect extends OneShotEffect { throw new IllegalStateException("It must have two targets, but found " + mode.getTargets().size()); } - String targetName = mode.getTargets().get(1).getTargetName(); - // Target creature you control deals damage equal to its power to target creature you don't control - String sb = (this.firstTargetName != null ? this.firstTargetName : "Target " + mode.getTargets().get(0).getTargetName()) + - " deals damage equal to its power to " + (targetName.contains("other") ? "" : "target ") + targetName; - return sb; + return (firstTargetName.isEmpty() ? mode.getTargets().get(0).getDescription() : firstTargetName) + " deals damage equal to its power to " + mode.getTargets().get(1).getDescription(); } } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 92126c2542..2289fa533e 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -44,7 +44,6 @@ public class Spell extends StackObjectImpl implements Card { private static final Logger logger = Logger.getLogger(Spell.class); private final List spellAbilities = new ArrayList<>(); - private final List spellCards = new ArrayList<>(); private final Card card; private final ObjectColor color; @@ -67,6 +66,10 @@ public class Spell extends StackObjectImpl implements Card { private ActivationManaAbilityStep currentActivatingManaAbilitiesStep = ActivationManaAbilityStep.BEFORE; public Spell(Card card, SpellAbility ability, UUID controllerId, Zone fromZone, Game game) { + this(card, ability, controllerId, fromZone, game, false); + } + + private Spell(Card card, SpellAbility ability, UUID controllerId, Zone fromZone, Game game, boolean isCopy) { Card affectedCard = card; // TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides) @@ -85,12 +88,16 @@ public class Spell extends StackObjectImpl implements Card { this.ability = ability; this.ability.setControllerId(controllerId); if (ability.getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { - spellCards.add(((SplitCard) affectedCard).getLeftHalfCard()); - spellAbilities.add(((SplitCard) affectedCard).getLeftHalfCard().getSpellAbility().copy()); - spellCards.add(((SplitCard) affectedCard).getRightHalfCard()); - spellAbilities.add(((SplitCard) affectedCard).getRightHalfCard().getSpellAbility().copy()); + // if this spell is going to be a copy, these abilities will be copied in copySpell + if (!isCopy) { + SpellAbility left = ((SplitCard) affectedCard).getLeftHalfCard().getSpellAbility().copy(); + SpellAbility right = ((SplitCard) affectedCard).getRightHalfCard().getSpellAbility().copy(); + left.setSourceId(ability.getSourceId()); + right.setSourceId(ability.getSourceId()); + spellAbilities.add(left); + spellAbilities.add(right); + } } else { - spellCards.add(affectedCard); spellAbilities.add(ability); } this.controllerId = controllerId; @@ -104,19 +111,12 @@ public class Spell extends StackObjectImpl implements Card { for (SpellAbility spellAbility : spell.spellAbilities) { this.spellAbilities.add(spellAbility.copy()); } - for (Card spellCard : spell.spellCards) { - this.spellCards.add(spellCard.copy()); - } if (spell.spellAbilities.get(0).equals(spell.ability)) { this.ability = this.spellAbilities.get(0); } else { this.ability = spell.ability.copy(); } - if (spell.spellCards.get(0).equals(spell.card)) { - this.card = spellCards.get(0); - } else { - this.card = spell.card.copy(); - } + this.card = spell.card.copy(); this.fromZone = spell.fromZone; this.color = spell.color.copy(); @@ -807,15 +807,17 @@ public class Spell extends StackObjectImpl implements Card { Card copiedPart = (Card) mapOldToNew.get(this.card.getId()); // copy spell - Spell spellCopy = new Spell(copiedPart, this.ability.copySpell(this.card, copiedPart), this.controllerId, this.fromZone, game); - boolean firstDone = false; + Spell spellCopy = new Spell(copiedPart, this.ability.copySpell(this.card, copiedPart), this.controllerId, this.fromZone, game, true); + UUID copiedSourceId = spellCopy.ability.getSourceId(); + boolean skipFirst = (this.ability.getSpellAbilityType() != SpellAbilityType.SPLIT_FUSED); for (SpellAbility spellAbility : this.getSpellAbilities()) { - if (!firstDone) { - firstDone = true; + if (skipFirst) { + skipFirst = false; continue; } SpellAbility newAbility = spellAbility.copy(); // e.g. spliced spell newAbility.newId(); + newAbility.setSourceId(copiedSourceId); spellCopy.addSpellAbility(newAbility); } spellCopy.setCopy(true, this);