mirror of
https://github.com/correl/mage.git
synced 2024-11-25 11:09:53 +00:00
Additional tests for morph and #6680
This commit is contained in:
parent
75220caf0f
commit
5ae041f39a
5 changed files with 235 additions and 77 deletions
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.cards.a;
|
package mage.cards.a;
|
||||||
|
|
||||||
import mage.abilities.costs.AlternativeCostSourceAbility;
|
import mage.abilities.costs.AlternativeCostSourceAbility;
|
||||||
|
@ -16,7 +15,6 @@ import mage.target.common.TargetCardInHand;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Backfir3
|
* @author Backfir3
|
||||||
*/
|
*/
|
||||||
public final class Abolish extends CardImpl {
|
public final class Abolish extends CardImpl {
|
||||||
|
@ -30,7 +28,6 @@ public final class Abolish extends CardImpl {
|
||||||
public Abolish(UUID ownerId, CardSetInfo setInfo) {
|
public Abolish(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{W}");
|
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{W}");
|
||||||
|
|
||||||
|
|
||||||
// You may discard a Plains card rather than pay Abolish's mana cost.
|
// You may discard a Plains card rather than pay Abolish's mana cost.
|
||||||
this.addAbility(new AlternativeCostSourceAbility(new DiscardTargetCost(new TargetCardInHand(filterCost))));
|
this.addAbility(new AlternativeCostSourceAbility(new DiscardTargetCost(new TargetCardInHand(filterCost))));
|
||||||
|
|
||||||
|
|
|
@ -1065,4 +1065,50 @@ public class MorphTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
assertAllCommandsUsed();
|
assertAllCommandsUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MorphWithCostReductionMustBePlayable_NormalCondition() {
|
||||||
|
// {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");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||||
|
//
|
||||||
|
// Creature spells you cast cost {1} less to cast.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Nylea, Keen-Eyed");
|
||||||
|
|
||||||
|
checkPlayableAbility("can", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender", true);
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender");
|
||||||
|
setChoice(playerA, "Yes"); // morph
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_MorphWithCostReductionMustBePlayable_MorphCondition() {
|
||||||
|
// {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");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||||
|
//
|
||||||
|
// Face-down creature spells you cast cost {1} less to cast.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Dream Chisel");
|
||||||
|
|
||||||
|
checkPlayableAbility("can", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender", true);
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Willbender");
|
||||||
|
setChoice(playerA, "Yes"); // morph
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
|
|
||||||
package org.mage.test.cards.cost.alternate;
|
package org.mage.test.cards.cost.alternate;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class UseAlternateSourceCostsTest extends CardTestPlayerBase {
|
public class UseAlternateSourceCostsTest extends CardTestPlayerBase {
|
||||||
|
@ -75,4 +74,85 @@ public class UseAlternateSourceCostsTest extends CardTestPlayerBase {
|
||||||
assertPermanentCount(playerA, "Gray Ogre", 1);
|
assertPermanentCount(playerA, "Gray Ogre", 1);
|
||||||
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_Playable_WithMana() {
|
||||||
|
// {1}{W}{W} instant
|
||||||
|
// You may discard a Plains card rather than pay Abolish's mana cost.
|
||||||
|
// Destroy target artifact or enchantment.
|
||||||
|
addCard(Zone.HAND, playerA, "Abolish");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||||
|
addCard(Zone.HAND, playerA, "Plains", 1); // discard cost
|
||||||
|
//
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Alpha Myr");
|
||||||
|
|
||||||
|
checkPlayableAbility("can", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Abolish", true);
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Abolish", "Alpha Myr");
|
||||||
|
setChoice(playerA, "Yes"); // use alternative cost
|
||||||
|
setChoice(playerA, "Plains");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerB, "Alpha Myr", 1);
|
||||||
|
assertTappedCount("Plains", false, 3); // must discard 1 instead tap
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_Playable_WithoutMana() {
|
||||||
|
// {1}{W}{W} instant
|
||||||
|
// You may discard a Plains card rather than pay Abolish's mana cost.
|
||||||
|
// Destroy target artifact or enchantment.
|
||||||
|
addCard(Zone.HAND, playerA, "Abolish");
|
||||||
|
//addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||||
|
addCard(Zone.HAND, playerA, "Plains", 1); // discard cost
|
||||||
|
//
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Alpha Myr");
|
||||||
|
|
||||||
|
checkPlayableAbility("can", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Abolish", true);
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Abolish", "Alpha Myr");
|
||||||
|
setChoice(playerA, "Yes"); // use alternative cost
|
||||||
|
setChoice(playerA, "Plains");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerB, "Alpha Myr", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_Playable_WithoutManaAndCost() {
|
||||||
|
// {1}{W}{W} instant
|
||||||
|
// You may discard a Plains card rather than pay Abolish's mana cost.
|
||||||
|
// Destroy target artifact or enchantment.
|
||||||
|
addCard(Zone.HAND, playerA, "Abolish");
|
||||||
|
//addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||||
|
//addCard(Zone.HAND, playerA, "Plains", 1); // discard cost
|
||||||
|
//
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Alpha Myr");
|
||||||
|
|
||||||
|
// can't see as playable (no mana for normal, no discard for alternative)
|
||||||
|
checkPlayableAbility("can't", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Abolish", false);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore // TODO: make test to check combo of alternative cost and cost reduction effects
|
||||||
|
public void test_Playable_WithCostReduction() {
|
||||||
|
addCard(Zone.HAND, playerA, "xxx");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package org.mage.test.cards.cost.modification;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class CostReduceWithConditionTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_PriceOfFame_Normal() {
|
||||||
|
// {3}{B}
|
||||||
|
// This spell costs {2} less to cast if it targets a legendary creature.
|
||||||
|
// Destroy target creature.
|
||||||
|
addCard(Zone.HAND, playerA, "Price of Fame", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Price of Fame", "Balduvian Bears");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerB, "Balduvian Bears", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
// TODO: implement workaround like putToStackAsNonPlayable for abilities, see https://github.com/magefree/mage/issues/6685
|
||||||
|
public void test_PriceOfFame_Reduce() {
|
||||||
|
// {3}{B}
|
||||||
|
// This spell costs {2} less to cast if it targets a legendary creature.
|
||||||
|
// Destroy target creature.
|
||||||
|
addCard(Zone.HAND, playerA, "Price of Fame", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4 - 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Anje Falkenrath", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Price of Fame", "Anje Falkenrath");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerB, "Anje Falkenrath", 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2852,7 +2852,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ManaOptions getManaAvailable(Game game) {
|
public ManaOptions getManaAvailable(Game game) {
|
||||||
ManaOptions available = new ManaOptions();
|
ManaOptions availableMana = new ManaOptions();
|
||||||
|
|
||||||
List<Abilities<ActivatedManaAbilityImpl>> sourceWithoutManaCosts = new ArrayList<>();
|
List<Abilities<ActivatedManaAbilityImpl>> sourceWithoutManaCosts = new ArrayList<>();
|
||||||
List<Abilities<ActivatedManaAbilityImpl>> sourceWithCosts = new ArrayList<>();
|
List<Abilities<ActivatedManaAbilityImpl>> sourceWithCosts = new ArrayList<>();
|
||||||
|
@ -2884,17 +2884,17 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Abilities<ActivatedManaAbilityImpl> manaAbilities : sourceWithoutManaCosts) {
|
for (Abilities<ActivatedManaAbilityImpl> manaAbilities : sourceWithoutManaCosts) {
|
||||||
available.addMana(manaAbilities, game);
|
availableMana.addMana(manaAbilities, game);
|
||||||
}
|
}
|
||||||
for (Abilities<ActivatedManaAbilityImpl> manaAbilities : sourceWithCosts) {
|
for (Abilities<ActivatedManaAbilityImpl> manaAbilities : sourceWithCosts) {
|
||||||
available.removeDuplicated();
|
availableMana.removeDuplicated();
|
||||||
available.addManaWithCost(manaAbilities, game);
|
availableMana.addManaWithCost(manaAbilities, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove duplicated variants (see ManaOptionsTest for info - when that rises)
|
// remove duplicated variants (see ManaOptionsTest for info - when that rises)
|
||||||
available.removeDuplicated();
|
availableMana.removeDuplicated();
|
||||||
|
|
||||||
return available;
|
return availableMana;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns only mana producers that don't require mana payment
|
// returns only mana producers that don't require mana payment
|
||||||
|
@ -2958,18 +2958,18 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ability
|
* @param ability
|
||||||
* @param available if null, it won't be checked if enough mana is available
|
* @param availableMana if null, it won't be checked if enough mana is available
|
||||||
* @param sourceObject
|
* @param sourceObject
|
||||||
* @param game
|
* @param game
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected boolean canPlay(ActivatedAbility ability, ManaOptions available, MageObject sourceObject, Game game) {
|
protected boolean canPlay(ActivatedAbility ability, ManaOptions availableMana, MageObject sourceObject, Game game) {
|
||||||
if (!(ability instanceof ActivatedManaAbilityImpl)) {
|
if (!(ability instanceof ActivatedManaAbilityImpl)) {
|
||||||
ActivatedAbility copy = ability.copy(); // Copy is needed because cost reduction effects modify e.g. the mana to activate/cast the ability
|
ActivatedAbility copy = ability.copy(); // Copy is needed because cost reduction effects modify e.g. the mana to activate/cast the ability
|
||||||
if (!copy.canActivate(playerId, game).canActivate()) {
|
if (!copy.canActivate(playerId, game).canActivate()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (available != null) {
|
if (availableMana != null) {
|
||||||
game.getContinuousEffects().costModification(copy, game);
|
game.getContinuousEffects().costModification(copy, game);
|
||||||
}
|
}
|
||||||
boolean canBeCastRegularly = true;
|
boolean canBeCastRegularly = true;
|
||||||
|
@ -2980,31 +2980,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
canBeCastRegularly = false;
|
canBeCastRegularly = false;
|
||||||
}
|
}
|
||||||
if (canBeCastRegularly) {
|
if (canBeCastRegularly) {
|
||||||
ManaOptions abilityOptions = copy.getMinimumCostToActivate(playerId, game);
|
if (canPayMinimumManaCost(copy, availableMana, game)) {
|
||||||
if (abilityOptions.isEmpty()) {
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
if (available == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MageObjectReference permittingObject = game.getContinuousEffects().asThough(copy.getSourceId(),
|
|
||||||
AsThoughEffectType.SPEND_OTHER_MANA, copy, copy.getControllerId(), game);
|
|
||||||
for (Mana mana : abilityOptions) {
|
|
||||||
for (Mana avail : available) {
|
|
||||||
// TODO: SPEND_OTHER_MANA effects with getAsThoughManaType can change mana type to pay,
|
|
||||||
// but that code processing it as any color, need to test and fix another use cases
|
|
||||||
// (example: Sunglasses of Urza - may spend white mana as though it were red mana)
|
|
||||||
|
|
||||||
//
|
|
||||||
// add tests for non any color like Sunglasses of Urza
|
|
||||||
if (permittingObject != null && mana.count() <= avail.count()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (mana.enough(avail)) { // here we need to check if spend mana as though allow to pay the mana cost
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3036,12 +3013,42 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ALTERNATIVE COST from source card (any AlternativeSourceCosts)
|
// ALTERNATIVE COST from source card (any AlternativeSourceCosts)
|
||||||
return canPlayCardByAlternateCost(game.getCard(ability.getSourceId()), available, copy, game);
|
return canPlayCardByAlternateCost(game.getCard(ability.getSourceId()), availableMana, copy, game);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions available, Ability ability, Game game) {
|
protected boolean canPayMinimumManaCost(ActivatedAbility ability, ManaOptions availableMana, Game game) {
|
||||||
|
ManaOptions abilityOptions = ability.getMinimumCostToActivate(playerId, game);
|
||||||
|
if (abilityOptions.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (availableMana == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(),
|
||||||
|
AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game);
|
||||||
|
for (Mana mana : abilityOptions) {
|
||||||
|
for (Mana avail : availableMana) {
|
||||||
|
// TODO: SPEND_OTHER_MANA effects with getAsThoughManaType can change mana type to pay,
|
||||||
|
// but that code processing it as any color, need to test and fix another use cases
|
||||||
|
// (example: Sunglasses of Urza - may spend white mana as though it were red mana)
|
||||||
|
|
||||||
|
//
|
||||||
|
// add tests for non any color like Sunglasses of Urza
|
||||||
|
if (permittingObject != null && mana.count() <= avail.count()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mana.enough(avail)) { // here we need to check if spend mana as though allow to pay the mana cost
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions availableMana, Ability ability, Game game) {
|
||||||
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
||||||
for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) {
|
for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) {
|
||||||
// if cast for noMana no Alternative costs are allowed
|
// if cast for noMana no Alternative costs are allowed
|
||||||
|
@ -3058,11 +3065,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (manaCosts.isEmpty()) {
|
if (manaCosts.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (available == null) {
|
if (availableMana == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (Mana mana : manaCosts.getOptions()) {
|
for (Mana mana : manaCosts.getOptions()) {
|
||||||
for (Mana avail : available) {
|
for (Mana avail : availableMana) {
|
||||||
if (mana.enough(avail)) {
|
if (mana.enough(avail)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3090,7 +3097,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
for (Mana mana : manaCosts.getOptions()) {
|
for (Mana mana : manaCosts.getOptions()) {
|
||||||
for (Mana avail : available) {
|
for (Mana avail : availableMana) {
|
||||||
if (mana.enough(avail)) {
|
if (mana.enough(avail)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3105,10 +3112,10 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ActivatedAbility findActivatedAbilityFromPlayable(MageObject object, ManaOptions manaAvailable, Ability ability, Game game) {
|
protected ActivatedAbility findActivatedAbilityFromPlayable(MageObject object, ManaOptions availableMana, Ability ability, Game game) {
|
||||||
|
|
||||||
// special mana to pay spell cost
|
// special mana to pay spell cost
|
||||||
ManaOptions manaFull = manaAvailable.copy();
|
ManaOptions manaFull = availableMana.copy();
|
||||||
if (ability instanceof SpellAbility) {
|
if (ability instanceof SpellAbility) {
|
||||||
for (AlternateManaPaymentAbility altAbility : CardUtil.getAbilities(object, game).stream()
|
for (AlternateManaPaymentAbility altAbility : CardUtil.getAbilities(object, game).stream()
|
||||||
.filter(a -> a instanceof AlternateManaPaymentAbility)
|
.filter(a -> a instanceof AlternateManaPaymentAbility)
|
||||||
|
@ -3139,7 +3146,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ActivatedAbility findActivatedAbilityFromAlternativeSourceCost(MageObject object, ManaOptions manaAvailable, Ability ability, Game game) {
|
protected ActivatedAbility findActivatedAbilityFromAlternativeSourceCost(MageObject object, ManaOptions availableMana, Ability ability, Game game) {
|
||||||
// return play ability that can activate AlternativeSourceCosts
|
// return play ability that can activate AlternativeSourceCosts
|
||||||
if (ability instanceof AlternativeSourceCosts && !(object instanceof Permanent)) {
|
if (ability instanceof AlternativeSourceCosts && !(object instanceof Permanent)) {
|
||||||
ActivatedAbility playAbility = null;
|
ActivatedAbility playAbility = null;
|
||||||
|
@ -3153,13 +3160,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 707.4.Objects that are cast face down are turned face down before they are put onto the stack
|
// 707.4.Objects that are cast face down are turned face down before they are put onto the stack
|
||||||
// (e.g. no lands per turn limit, no cast restrictions, another cost, etc)
|
// E.g. no lands per turn limit, no cast restrictions, cost reduce, etc
|
||||||
// so morph must checks only mana payment here
|
// Even mana cost can't be checked here without lookahead
|
||||||
|
// So make it available all the time
|
||||||
boolean canUse;
|
boolean canUse;
|
||||||
if (ability instanceof MorphAbility) {
|
if (ability instanceof MorphAbility) {
|
||||||
canUse = game.canPlaySorcery(playerId) && canPayAlternateSourceCostsAbility(object, playAbility, manaAvailable, ability, game);
|
canUse = game.canPlaySorcery(playerId) && ((MorphAbility) ability).isAvailable(playAbility, game);
|
||||||
} else {
|
} else {
|
||||||
canUse = canPlay(playAbility, manaAvailable, 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
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canUse) {
|
if (canUse) {
|
||||||
|
@ -3169,32 +3177,6 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean canPayAlternateSourceCostsAbility(MageObject sourceObject, Ability sourceAbility, ManaOptions available, Ability alternativeAbility, Game game) {
|
|
||||||
if (sourceAbility != null && ((AlternativeSourceCosts) alternativeAbility).isAvailable(sourceAbility, game)) {
|
|
||||||
if (alternativeAbility.getCosts().canPay(alternativeAbility, sourceObject.getId(), this.getId(), game)) {
|
|
||||||
ManaCostsImpl manaCosts = new ManaCostsImpl();
|
|
||||||
for (Cost cost : alternativeAbility.getCosts()) {
|
|
||||||
if (cost instanceof ManaCost) {
|
|
||||||
manaCosts.add((ManaCost) cost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (manaCosts.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
for (Mana mana : manaCosts.getOptions()) {
|
|
||||||
for (Mana avail : available) {
|
|
||||||
if (mana.enough(avail)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getPlayableFromObjectAll(Game game, Zone fromZone, MageObject object, ManaOptions availableMana, List<ActivatedAbility> output) {
|
private void getPlayableFromObjectAll(Game game, Zone fromZone, MageObject object, ManaOptions availableMana, List<ActivatedAbility> output) {
|
||||||
if (fromZone == null || object == null) {
|
if (fromZone == null || object == null) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue