mirror of
https://github.com/correl/mage.git
synced 2024-12-26 03:00:11 +00:00
Fixed face down cost modification (related to 653a2dd7b2
)
This commit is contained in:
parent
dfaf09e76c
commit
97c427375d
6 changed files with 92 additions and 29 deletions
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
package mage.cards.d;
|
package mage.cards.d;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
|
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -9,10 +7,11 @@ import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterCreatureCard;
|
import mage.filter.common.FilterCreatureCard;
|
||||||
import mage.filter.predicate.other.FaceDownPredicate;
|
import mage.filter.predicate.other.FaceDownCastablePredicate;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author North
|
* @author North
|
||||||
*/
|
*/
|
||||||
public final class DreamChisel extends CardImpl {
|
public final class DreamChisel extends CardImpl {
|
||||||
|
@ -20,11 +19,11 @@ public final class DreamChisel extends CardImpl {
|
||||||
private static final FilterCreatureCard filter = new FilterCreatureCard("Face-down creature spells");
|
private static final FilterCreatureCard filter = new FilterCreatureCard("Face-down creature spells");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(FaceDownPredicate.instance);
|
filter.add(FaceDownCastablePredicate.instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DreamChisel(UUID ownerId, CardSetInfo setInfo) {
|
public DreamChisel(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
|
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
|
||||||
|
|
||||||
// Face-down creature spells you cast cost {1} less to cast.
|
// Face-down creature spells you cast cost {1} less to cast.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 1)));
|
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 1)));
|
||||||
|
|
|
@ -5,6 +5,7 @@ import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||||
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
|
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
@ -14,10 +15,9 @@ import mage.constants.WatcherScope;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
import mage.filter.FilterPermanent;
|
import mage.filter.FilterPermanent;
|
||||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
import mage.filter.predicate.ObjectPlayer;
|
import mage.filter.predicate.Predicate;
|
||||||
import mage.filter.predicate.ObjectPlayerPredicate;
|
import mage.filter.predicate.other.FaceDownCastablePredicate;
|
||||||
import mage.filter.predicate.other.FaceDownPredicate;
|
import mage.filter.predicate.other.FaceDownPredicate;
|
||||||
import mage.game.Controllable;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
|
@ -32,12 +32,12 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public final class KadenaSlinkingSorcerer extends CardImpl {
|
public final class KadenaSlinkingSorcerer extends CardImpl {
|
||||||
|
|
||||||
private static final FilterCard filter = new FilterCard();
|
private static final FilterCard filterFirstFaceDownSpell = new FilterCard("first face-down creature spell");
|
||||||
private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent("a face-down creature");
|
private static final FilterPermanent filterFaceDownPermanent = new FilterControlledCreaturePermanent("a face-down creature");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(KadenaSlinkingSorcererPredicate.instance);
|
filterFirstFaceDownSpell.add(KadenaSlinkingSorcererPredicate.instance);
|
||||||
filter2.add(FaceDownPredicate.instance);
|
filterFaceDownPermanent.add(FaceDownPredicate.instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KadenaSlinkingSorcerer(UUID ownerId, CardSetInfo setInfo) {
|
public KadenaSlinkingSorcerer(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
@ -51,13 +51,13 @@ public final class KadenaSlinkingSorcerer extends CardImpl {
|
||||||
|
|
||||||
// The first face-down creature spell you cast each turn costs {3} less to cast.
|
// The first face-down creature spell you cast each turn costs {3} less to cast.
|
||||||
this.addAbility(new SimpleStaticAbility(
|
this.addAbility(new SimpleStaticAbility(
|
||||||
new SpellsCostReductionControllerEffect(filter, 3)
|
new SpellsCostReductionControllerEffect(filterFirstFaceDownSpell, 3)
|
||||||
.setText("The first face-down creature spell you cast each turn costs {3} less to cast.")
|
.setText("The first face-down creature spell you cast each turn costs {3} less to cast.")
|
||||||
), new KadenaSlinkingSorcererWatcher());
|
), new KadenaSlinkingSorcererWatcher());
|
||||||
|
|
||||||
// Whenever a face-down creature enters the battlefield under your control, draw a card.
|
// Whenever a face-down creature enters the battlefield under your control, draw a card.
|
||||||
this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
|
this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
|
||||||
new DrawCardSourceControllerEffect(1), filter2
|
new DrawCardSourceControllerEffect(1), filterFaceDownPermanent
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,16 +71,15 @@ public final class KadenaSlinkingSorcerer extends CardImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum KadenaSlinkingSorcererPredicate implements ObjectPlayerPredicate<ObjectPlayer<Controllable>> {
|
enum KadenaSlinkingSorcererPredicate implements Predicate<Card> {
|
||||||
instance;
|
instance;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(ObjectPlayer<Controllable> input, Game game) {
|
public boolean apply(Card input, Game game) {
|
||||||
if (input.getObject() instanceof Spell
|
KadenaSlinkingSorcererWatcher watcher = game.getState().getWatcher(KadenaSlinkingSorcererWatcher.class);
|
||||||
&& ((Spell) input.getObject()).isCreature()
|
if (watcher != null) {
|
||||||
&& ((Spell) input.getObject()).isFaceDown(game)) {
|
return FaceDownCastablePredicate.instance.apply(input, game)
|
||||||
KadenaSlinkingSorcererWatcher watcher = game.getState().getWatcher(KadenaSlinkingSorcererWatcher.class);
|
&& !watcher.castFaceDownThisTurn(input.getOwnerId());
|
||||||
return watcher != null && !watcher.castFaceDownThisTurn(input.getPlayerId());
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
package mage.cards.o;
|
package mage.cards.o;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
|
@ -14,10 +12,11 @@ import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterCreatureCard;
|
import mage.filter.common.FilterCreatureCard;
|
||||||
import mage.filter.predicate.other.FaceDownPredicate;
|
import mage.filter.predicate.other.FaceDownCastablePredicate;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public final class ObscuringAether extends CardImpl {
|
public final class ObscuringAether extends CardImpl {
|
||||||
|
@ -25,7 +24,7 @@ public final class ObscuringAether extends CardImpl {
|
||||||
private static final FilterCreatureCard filter = new FilterCreatureCard("Face-down creature spells");
|
private static final FilterCreatureCard filter = new FilterCreatureCard("Face-down creature spells");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(FaceDownPredicate.instance);
|
filter.add(FaceDownCastablePredicate.instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObscuringAether(UUID ownerId, CardSetInfo setInfo) {
|
public ObscuringAether(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
|
|
@ -1089,7 +1089,7 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_MorphWithCostReductionMustBePlayable_MorphCondition() {
|
public void test_MorphWithCostReductionMustBePlayable_MorphCondition1() {
|
||||||
// {1}{U} creature
|
// {1}{U} creature
|
||||||
// Morph {1}{U} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)
|
// Morph {1}{U} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)
|
||||||
// When Willbender is turned face up, change the target of target spell or ability with a single target.
|
// When Willbender is turned face up, change the target of target spell or ability with a single target.
|
||||||
|
@ -1110,4 +1110,36 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1);
|
assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MorphWithCostReductionMustBePlayable_MorphCondition2() {
|
||||||
|
// {1}{U} creature
|
||||||
|
// Morph {1}{U} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)
|
||||||
|
// When Willbender is turned face up, change the target of target spell or ability with a single target.
|
||||||
|
addCard(Zone.HAND, playerA, "Willbender", 2);
|
||||||
|
//addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||||
|
//
|
||||||
|
// The first face-down creature spell you cast each turn costs {3} less to cast.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Kadena, Slinking Sorcerer");
|
||||||
|
|
||||||
|
// creature one - get cost reduce
|
||||||
|
checkPlayableAbility("can", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender", true);
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender");
|
||||||
|
setChoice(playerA, "Yes"); // morph
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
// creature two - do not get cost reduce
|
||||||
|
checkPlayableAbility("can't by no reduce", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender", false);
|
||||||
|
|
||||||
|
// on next turn it can cost reduce again
|
||||||
|
checkPlayableAbility("can't by not your turn", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender", false);
|
||||||
|
checkPlayableAbility("can", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender", true);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(3, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package mage.filter.predicate.other;
|
||||||
|
|
||||||
|
import mage.abilities.keyword.MorphAbility;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.filter.predicate.Predicate;
|
||||||
|
import mage.game.Game;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public enum FaceDownCastablePredicate implements Predicate<Card> {
|
||||||
|
instance;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Card input, Game game) {
|
||||||
|
// is card able to cast as face down
|
||||||
|
return input.getAbilities(game).containsClass(MorphAbility.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Face-down";
|
||||||
|
}
|
||||||
|
}
|
|
@ -3156,6 +3156,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
sourceObject.adjustCosts(copyAbility, game);
|
sourceObject.adjustCosts(copyAbility, game);
|
||||||
game.getContinuousEffects().costModification(copyAbility, game);
|
game.getContinuousEffects().costModification(copyAbility, game);
|
||||||
|
|
||||||
|
// reduced all cost
|
||||||
|
if (copyAbility.getManaCostsToPay().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
for (Mana mana : copyAbility.getManaCostsToPay().getOptions()) {
|
for (Mana mana : copyAbility.getManaCostsToPay().getOptions()) {
|
||||||
if (availableMana.enough(mana)) {
|
if (availableMana.enough(mana)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -3193,6 +3198,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
sourceObject.adjustCosts(copyAbility, game);
|
sourceObject.adjustCosts(copyAbility, game);
|
||||||
game.getContinuousEffects().costModification(copyAbility, game);
|
game.getContinuousEffects().costModification(copyAbility, game);
|
||||||
|
|
||||||
|
// reduced all cost
|
||||||
|
if (copyAbility.getManaCostsToPay().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
for (Mana mana : copyAbility.getManaCostsToPay().getOptions()) {
|
for (Mana mana : copyAbility.getManaCostsToPay().getOptions()) {
|
||||||
if (availableMana.enough(mana)) {
|
if (availableMana.enough(mana)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -3260,7 +3270,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
// So make it available all the time
|
// So make it available all the time
|
||||||
boolean canUse;
|
boolean canUse;
|
||||||
if (ability instanceof MorphAbility && object instanceof Card && game.canPlaySorcery(getId())) {
|
if (ability instanceof MorphAbility && object instanceof Card && game.canPlaySorcery(getId())) {
|
||||||
canUse = canPlayCardByAlternateCost((Card) object, availableMana, ability, game);
|
canUse = canPlayCardByAlternateCost((Card) object, availableMana, playAbility, game);
|
||||||
} else {
|
} else {
|
||||||
canUse = canPlay(playAbility, availableMana, object, game); // canPlay already checks alternative source costs and all conditions
|
canUse = canPlay(playAbility, availableMana, object, game); // canPlay already checks alternative source costs and all conditions
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue