[DTK] reworked Living Lore, fixed death trigger

This commit is contained in:
Evan Kranzler 2022-04-04 23:04:09 -04:00
parent e7a9988fe7
commit 09402609ef
3 changed files with 133 additions and 146 deletions

View file

@ -1,30 +1,33 @@
package mage.cards.l; package mage.cards.l;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt; import mage.MageInt;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.DealsCombatDamageTriggeredAbility; import mage.abilities.common.DealsCombatDamageTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.*; import mage.constants.*;
import mage.filter.common.FilterInstantOrSorceryCard; import mage.filter.StaticFilters;
import mage.game.ExileZone; import mage.game.ExileZone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class LivingLore extends CardImpl { public final class LivingLore extends CardImpl {
@ -36,15 +39,21 @@ public final class LivingLore extends CardImpl {
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
// As Living Lore enters the battlefield, exile an instant or sorcery card from your graveyard. // As Living Lore enters the battlefield, exile an instant or sorcery card from your graveyard.
this.addAbility(new AsEntersBattlefieldAbility(new LivingLoreExileEffect(), this.addAbility(new AsEntersBattlefieldAbility(
"exile an instant or sorcery card from your graveyard")); new LivingLoreExileEffect(), "exile an instant or sorcery card from your graveyard"
));
// Living Lore's power and toughness are each equal to the exiled card's converted mana cost. // Living Lore's power and toughness are each equal to the exiled card's converted mana cost.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new LivingLoreSetPowerToughnessSourceEffect())); this.addAbility(new SimpleStaticAbility(
Zone.ALL, new SetPowerToughnessSourceEffect(LivingLoreValue.instance, Duration.EndOfGame)
.setText("{this}'s power and toughness are each equal to the exiled card's mana value")
));
// Whenever Living Lore deals combat damage, you may sacrifice it. If you do, // Whenever Living Lore deals combat damage, you may sacrifice it. If you do,
// you may cast the exiled card without paying its mana cost. // you may cast the exiled card without paying its mana cost.
this.addAbility(new DealsCombatDamageTriggeredAbility(new LivingLoreSacrificeEffect(), true)); this.addAbility(new DealsCombatDamageTriggeredAbility(new DoIfCostPaid(
new LivingLoreCastEffect(), new SacrificeSourceCost().setText("sacrifice it")
), false));
} }
private LivingLore(final LivingLore card) { private LivingLore(final LivingLore card) {
@ -76,125 +85,82 @@ class LivingLoreExileEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); if (controller == null) {
if (sourcePermanent != null && controller != null) {
TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(
new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"));
if (controller.chooseTarget(outcome, target, source, game)) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(),
game.getState().getZoneChangeCounter(source.getSourceId()) + 1);
Card card = controller.getGraveyard().get(target.getFirstTarget(), game);
if (card != null) {
controller.moveCardsToExile(card, source, game, true, exileId,
sourcePermanent.getIdName());
}
}
return true;
}
return false; return false;
} }
TargetCard target = new TargetCardInYourGraveyard(
} StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD
);
class LivingLoreSetPowerToughnessSourceEffect extends ContinuousEffectImpl { target.setNotTarget(true);
controller.chooseTarget(outcome, target, source, game);
public LivingLoreSetPowerToughnessSourceEffect() { Card card = game.getCard(target.getFirstTarget());
super(Duration.Custom, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature); if (card == null) {
staticText = "{this}'s power and toughness are each equal to the exiled card's mana value"; return false;
} }
controller.moveCardsToExile(
public LivingLoreSetPowerToughnessSourceEffect(final LivingLoreSetPowerToughnessSourceEffect effect) { card, source, game, true,
super(effect); CardUtil.getExileZoneId(game, source, 1),
} CardUtil.getSourceName(game, source)
);
@Override
public LivingLoreSetPowerToughnessSourceEffect copy() {
return new LivingLoreSetPowerToughnessSourceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
int zcc = game.getState().getZoneChangeCounter(source.getSourceId());
if (permanent == null) {
permanent = game.getPermanentEntering(source.getSourceId());
zcc++;
}
if (permanent == null) {
return true; return true;
} }
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), zcc); }
if (exileId != null) {
ExileZone exileZone = game.getExile().getExileZone(exileId); enum LivingLoreValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int offset = game.getPermanent(sourceAbility.getSourceId()) != null ? 1 : 0;
ExileZone exileZone = game
.getExile()
.getExileZone(CardUtil.getExileZoneId(game, sourceAbility, offset));
if (exileZone == null) { if (exileZone == null) {
return false; return 0;
} }
Card exiledCard = null; return exileZone
for (Card card : exileZone.getCards(game)) { .getCards(game)
exiledCard = card; .stream()
break; .mapToInt(MageObject::getManaValue)
.sum();
} }
if (exiledCard != null) {
int value = exiledCard.getManaValue(); @Override
permanent.getPower().setValue(value); public LivingLoreValue copy() {
permanent.getToughness().setValue(value); return this;
} }
}
return true; @Override
public String getMessage() {
return "";
} }
} }
class LivingLoreSacrificeEffect extends OneShotEffect { class LivingLoreCastEffect extends OneShotEffect {
public LivingLoreSacrificeEffect() { LivingLoreCastEffect() {
super(Outcome.PlayForFree); super(Outcome.PlayForFree);
this.staticText = "you may sacrifice it. If you do, you may cast " this.staticText = "you may cast the exiled card without paying its mana cost";
+ "the exiled card without paying its mana cost";
} }
public LivingLoreSacrificeEffect(final LivingLoreSacrificeEffect effect) { public LivingLoreCastEffect(final LivingLoreCastEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public LivingLoreSacrificeEffect copy() { public LivingLoreCastEffect copy() {
return new LivingLoreSacrificeEffect(this); return new LivingLoreCastEffect(this);
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, -2));
MageObject mageObject = source.getSourceObject(game); return controller != null
Permanent permanent = game.getPermanent(source.getSourceId()); && exileZone != null
if (permanent != null && !exileZone.isEmpty()
&& mageObject != null && CardUtil.castSpellWithAttributesForFree(
&& new MageObjectReference(permanent, game).refersTo(mageObject, game)) { controller, source, game, new CardsImpl(exileZone), StaticFilters.FILTER_CARD
if (permanent.sacrifice(source, game)) { );
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(),
source.getSourceObjectZoneChangeCounter());
if (exileId != null) {
ExileZone exileZone = game.getExile().getExileZone(exileId);
Card exiledCard = null;
if (exileZone != null) {
for (Card card : exileZone.getCards(game)) {
exiledCard = card;
break;
}
}
if (exiledCard != null) {
if (exiledCard.getSpellAbility().canChooseTarget(game, controller.getId())) {
game.getState().setValue("PlayFromNotOwnHandZone" + exiledCard.getId(), Boolean.TRUE);
controller.cast(controller.chooseAbilityForCast(exiledCard, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + exiledCard.getId(), null);
}
}
}
}
}
return true;
}
return false;
} }
} }

View file

@ -1,33 +0,0 @@
package org.mage.test.cards.replacement.entersBattlefield;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class LivingLoreTest extends CardTestPlayerBase {
/**
* That the +1/+1 counters are added to Living Lore before state based
* actions take place
*/
@Test
public void testCountersAdded() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.HAND, playerA, "Living Lore"); //{3}{U}
addCard(Zone.GRAVEYARD, playerA, "Natural Connection", 1); // {2}{G}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Living Lore");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Living Lore", 1);
assertPowerToughness(playerA, "Living Lore", 3, 3);
}
}

View file

@ -0,0 +1,54 @@
package org.mage.test.cards.single.dtk;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author LevelX2
*/
public class LivingLoreTest extends CardTestPlayerBase {
/**
* That the +1/+1 counters are added to Living Lore before state based
* actions take place
*/
@Test
public void testCountersAdded() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.HAND, playerA, "Living Lore"); //{3}{U}
addCard(Zone.GRAVEYARD, playerA, "Natural Connection", 1); // {2}{G}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Living Lore");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Living Lore", 1);
assertPowerToughness(playerA, "Living Lore", 3, 3);
}
@Test
public void testCastSpell() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.HAND, playerA, "Living Lore"); //{3}{U}
addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt", 1); // {R}
addTarget(playerA, "Lightning Bolt");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Living Lore");
attack(3, playerA, "Living Lore", playerB);
setChoice(playerA, true); // sacrifice
setChoice(playerA, true); // cast spell
addTarget(playerA, playerB);
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_COMBAT);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Living Lore", 0);
assertGraveyardCount(playerA, "Lightning Bolt", 1);
assertLife(playerB, 20 - 1 - 3);
}
}