mirror of
https://github.com/correl/mage.git
synced 2024-11-25 11:09:53 +00:00
[DTK] reworked Living Lore, fixed death trigger
This commit is contained in:
parent
e7a9988fe7
commit
09402609ef
3 changed files with 133 additions and 146 deletions
|
@ -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
|
||||||
|
);
|
||||||
|
target.setNotTarget(true);
|
||||||
|
controller.chooseTarget(outcome, target, source, game);
|
||||||
|
Card card = game.getCard(target.getFirstTarget());
|
||||||
|
if (card == null) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
controller.moveCardsToExile(
|
||||||
class LivingLoreSetPowerToughnessSourceEffect extends ContinuousEffectImpl {
|
card, source, game, true,
|
||||||
|
CardUtil.getExileZoneId(game, source, 1),
|
||||||
public LivingLoreSetPowerToughnessSourceEffect() {
|
CardUtil.getSourceName(game, source)
|
||||||
super(Duration.Custom, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature);
|
);
|
||||||
staticText = "{this}'s power and toughness are each equal to the exiled card's mana value";
|
|
||||||
}
|
|
||||||
|
|
||||||
public LivingLoreSetPowerToughnessSourceEffect(final LivingLoreSetPowerToughnessSourceEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue