diff --git a/Mage.Sets/src/mage/cards/l/LifestreamsBlessing.java b/Mage.Sets/src/mage/cards/l/LifestreamsBlessing.java new file mode 100644 index 00000000000..450b5f036bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LifestreamsBlessing.java @@ -0,0 +1,141 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.MageObject; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.ForetellAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LifestreamsBlessing extends CardImpl { + + public LifestreamsBlessing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{G}{G}"); + + // Draw X cards, where X is the greatest power among creatures you controlled as you cast this spell. If this spell was cast from exile, you gain twice X life. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(LifestreamsBlessingValue.ONCE)); + this.getSpellAbility().addEffect(new GainLifeEffect(LifestreamsBlessingValue.TWICE) + .setText("if this spell was cast from exile, you gain twice X life")); + this.getSpellAbility().addWatcher(new LifestreamsBlessingWatcher()); + + // Foretell {4}{G} + this.addAbility(new ForetellAbility(this, "{4}{G}")); + } + + private LifestreamsBlessing(final LifestreamsBlessing card) { + super(card); + } + + @Override + public LifestreamsBlessing copy() { + return new LifestreamsBlessing(this); + } +} + +enum LifestreamsBlessingValue implements DynamicValue { + ONCE(false), + TWICE(true); + private final boolean flag; + + LifestreamsBlessingValue(boolean flag) { + this.flag = flag; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + if (flag && !Optional + .ofNullable(sourceAbility) + .map(Ability::getSourceId) + .map(game::getSpell) + .map(Spell::getFromZone) + .map(Zone.EXILED::match) + .orElse(false)) { + return 0; + } + return (flag ? 2 : 1) * LifestreamsBlessingWatcher.getValue(game, sourceAbility); + } + + @Override + public LifestreamsBlessingValue copy() { + return this; + } + + @Override + public String getMessage() { + return "the greatest power among creatures you controlled as you cast this spell"; + } + + @Override + public String toString() { + return "X"; + } +} + +class LifestreamsBlessingWatcher extends Watcher { + + private final Map map = new HashMap<>(); + + LifestreamsBlessingWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST) { + return; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null) { + return; + } + map.put( + new MageObjectReference(spell.getSpellAbility().getSourceId(), game), + game.getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, spell.getControllerId(), game + ) + .stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .max() + .orElse(0) + ); + } + + @Override + public void reset() { + super.reset(); + map.clear(); + } + + static int getValue(Game game, Ability source) { + return game + .getState() + .getWatcher(LifestreamsBlessingWatcher.class) + .map + .getOrDefault(new MageObjectReference( + source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game + ), 0); + } +} diff --git a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java index 654c15de063..a626df8978b 100644 --- a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java +++ b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java @@ -226,6 +226,8 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Krile Baldesion", 86, Rarity.RARE, mage.cards.k.KrileBaldesion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Legions to Ashes", 326, Rarity.RARE, mage.cards.l.LegionsToAshes.class)); cards.add(new SetCardInfo("Lethal Scheme", 277, Rarity.RARE, mage.cards.l.LethalScheme.class)); + cards.add(new SetCardInfo("Lifestream's Blessing", 122, Rarity.RARE, mage.cards.l.LifestreamsBlessing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lifestream's Blessing", 67, Rarity.RARE, mage.cards.l.LifestreamsBlessing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lightning Greaves", 349, Rarity.UNCOMMON, mage.cards.l.LightningGreaves.class)); cards.add(new SetCardInfo("Lingering Souls", 245, Rarity.UNCOMMON, mage.cards.l.LingeringSouls.class)); cards.add(new SetCardInfo("Locke, Treasure Hunter", 177, Rarity.RARE, mage.cards.l.LockeTreasureHunter.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/LifestreamsBlessingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/LifestreamsBlessingTest.java new file mode 100644 index 00000000000..7330cb5246e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/LifestreamsBlessingTest.java @@ -0,0 +1,92 @@ +package org.mage.test.cards.single.fic; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class LifestreamsBlessingTest extends CardTestPlayerBase { + + private static final String blessing = "Lifestream's Blessing"; + private static final String jackal = "Trained Jackal"; + private static final String bear = "Ashcoat Bear"; + private static final String giant = "Hill Giant"; + + @Test + public void testRegular() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.BATTLEFIELD, playerA, jackal); + addCard(Zone.BATTLEFIELD, playerB, giant); + addCard(Zone.HAND, playerA, blessing); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, blessing); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertHandCount(playerA, 1); + assertLife(playerA, 20); + } + + @Test + public void testFlashIn22() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6 + 2); + addCard(Zone.BATTLEFIELD, playerA, jackal); + addCard(Zone.BATTLEFIELD, playerB, giant); + addCard(Zone.HAND, playerA, blessing); + addCard(Zone.HAND, playerA, bear); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, blessing); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bear); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertHandCount(playerA, 1); + assertLife(playerA, 20); + } + + private static final String twincast = "Twincast"; + + @Test + public void testTwincast() { + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6 + 2); + addCard(Zone.BATTLEFIELD, playerA, jackal); + addCard(Zone.BATTLEFIELD, playerB, giant); + addCard(Zone.HAND, playerA, blessing); + addCard(Zone.HAND, playerA, twincast); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, blessing); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, twincast, blessing); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertHandCount(playerA, 1); + assertLife(playerA, 20); + } + + @Test + public void testForetell() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + addCard(Zone.BATTLEFIELD, playerA, jackal); + addCard(Zone.BATTLEFIELD, playerB, giant); + addCard(Zone.HAND, playerA, blessing); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "For"); + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "For"); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertHandCount(playerA, 1 + 1); + assertLife(playerA, 20 + 2); + } +}