forked from External/mage
Bestow rework/fixes (#13973)
* New Bestow test, minor improvements * Partially rework Bestow to not rely on perpetual card modifications * Add Bestow subtype tests, improve PrototypeTest * Fix Subtype existing without required card type * Improve docs, improve aura spell copy target copying check, improve subtype handling * Add additional test * Review improvements * Remove subtype/type check * Consolidate temporary becomeAura into function * Add Enchant Creature ability
This commit is contained in:
parent
95f53fc671
commit
8cd1bec19d
8 changed files with 248 additions and 166 deletions
|
|
@ -6,12 +6,17 @@ import mage.constants.CardType;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.filter.FilterPermanent;
|
||||||
|
import mage.filter.predicate.mageobject.NamePredicate;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.player.TestPlayer;
|
import org.mage.test.player.TestPlayer;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
|
|
@ -82,6 +87,7 @@ public class BestowTest extends CardTestPlayerBase {
|
||||||
assertSubtype("Hopeful Eidolon", SubType.AURA);
|
assertSubtype("Hopeful Eidolon", SubType.AURA);
|
||||||
assertType("Hopeful Eidolon", CardType.ENCHANTMENT, true);
|
assertType("Hopeful Eidolon", CardType.ENCHANTMENT, true);
|
||||||
assertType("Hopeful Eidolon", CardType.CREATURE, false);
|
assertType("Hopeful Eidolon", CardType.CREATURE, false);
|
||||||
|
assertNotSubtype("Hopeful Eidolon", SubType.SPIRIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -122,59 +128,63 @@ public class BestowTest extends CardTestPlayerBase {
|
||||||
@Test
|
@Test
|
||||||
public void bestowEnchantmentBecomesCreature() {
|
public void bestowEnchantmentBecomesCreature() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
|
addCard(Zone.BATTLEFIELD, playerA, "Safehold Elite"); // 2/2 creature + Persist to return as a 1/1
|
||||||
addCard(Zone.HAND, playerA, "Hopeful Eidolon");
|
addCard(Zone.HAND, playerA, "Hopeful Eidolon");
|
||||||
|
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
|
||||||
addCard(Zone.HAND, playerB, "Lightning Bolt");
|
addCard(Zone.HAND, playerB, "Lightning Bolt");
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hopeful Eidolon using bestow", "Silvercoat Lion");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hopeful Eidolon using bestow", "Safehold Elite");
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Silvercoat Lion");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Safehold Elite");
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
// because Boon Satyr is no creature on the battlefield, evolve may not trigger
|
|
||||||
assertLife(playerA, 20);
|
assertLife(playerA, 20);
|
||||||
assertLife(playerB, 20);
|
assertLife(playerB, 20);
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Silvercoat Lion", 0);
|
assertPermanentCount(playerA, "Safehold Elite", 1);
|
||||||
|
assertPowerToughness(playerA, "Safehold Elite", 1, 1);
|
||||||
assertPermanentCount(playerA, "Hopeful Eidolon", 1);
|
assertPermanentCount(playerA, "Hopeful Eidolon", 1);
|
||||||
assertPowerToughness(playerA, "Hopeful Eidolon", 1, 1);
|
assertPowerToughness(playerA, "Hopeful Eidolon", 1, 1);
|
||||||
|
assertType("Hopeful Eidolon", CardType.CREATURE, true);
|
||||||
Permanent hopefulEidolon = getPermanent("Hopeful Eidolon", playerA);
|
assertSubtype("Hopeful Eidolon", SubType.SPIRIT);
|
||||||
Assert.assertTrue("Hopeful Eidolon has to be a creature but is not", hopefulEidolon.isCreature(currentGame));
|
assertType("Hopeful Eidolon", CardType.ENCHANTMENT, true);
|
||||||
Assert.assertTrue("Hopeful Eidolon has to be an enchantment but is not", hopefulEidolon.isEnchantment(currentGame));
|
assertNotSubtype("Hopeful Eidolon", SubType.AURA);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that card cast with bestow will not be tapped, if creatures come
|
* Test that card cast with bestow will not be tapped, if creatures come
|
||||||
* into play tapped
|
* into play tapped. If it is cast with bestow but the target removed, it should be tapped.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void bestowEnchantmentWillNotBeTapped() {
|
public void bestowEnchantmentWillNotBeTapped() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 6);
|
addCustomEffect_TargetDestroy(playerA);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 10);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Silent Artisan");
|
addCard(Zone.BATTLEFIELD, playerA, "Silent Artisan");
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Boon Satyr");
|
addCard(Zone.HAND, playerA, "Boon Satyr");
|
||||||
|
addCard(Zone.HAND, playerA, "Leafcrown Dryad");
|
||||||
|
|
||||||
|
|
||||||
// Enchantment {1}{W}
|
// Enchantment {1}{W}
|
||||||
// Creatures your opponents control enter the battlefield tapped.
|
// Creatures your opponents control enter the battlefield tapped.
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Imposing Sovereign");
|
addCard(Zone.BATTLEFIELD, playerB, "Imposing Sovereign");
|
||||||
|
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Boon Satyr using bestow", "Silent Artisan");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boon Satyr using bestow", "Silent Artisan");
|
||||||
|
checkPT("Boon Satyr attached", 1, PhaseStep.BEGIN_COMBAT, playerA, "Silent Artisan", 7, 7);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Leafcrown Dryad using bestow", "Silent Artisan");
|
||||||
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "target destroy", "Silent Artisan");
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
// because Boon Satyr is no creature on the battlefield, evolve may not trigger
|
// Boon Satyr should not be tapped since it resolved as an aura, Leafcrown Dryad resolved as a creature
|
||||||
assertPermanentCount(playerA, "Silent Artisan", 1);
|
|
||||||
assertPowerToughness(playerA, "Silent Artisan", 7, 7);
|
|
||||||
// because cast with bestow, Boon Satyr may not be tapped
|
|
||||||
assertTapped("Boon Satyr", false);
|
assertTapped("Boon Satyr", false);
|
||||||
|
assertTapped("Leafcrown Dryad", true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,7 +281,6 @@ public class BestowTest extends CardTestPlayerBase {
|
||||||
assertHandCount(playerB, "Disdainful Stroke", 1);
|
assertHandCount(playerB, "Disdainful Stroke", 1);
|
||||||
assertPermanentCount(playerA, "Hypnotic Siren", 1);
|
assertPermanentCount(playerA, "Hypnotic Siren", 1);
|
||||||
|
|
||||||
// because cast with bestow, Boon Satyr may not be tapped
|
|
||||||
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||||
assertPowerToughness(playerA, "Silvercoat Lion", 3, 3);
|
assertPowerToughness(playerA, "Silvercoat Lion", 3, 3);
|
||||||
|
|
||||||
|
|
@ -551,4 +560,127 @@ public class BestowTest extends CardTestPlayerBase {
|
||||||
assertType("Nylea's Emissary", CardType.CREATURE, false);
|
assertType("Nylea's Emissary", CardType.CREATURE, false);
|
||||||
assertType("Nylea's Emissary", CardType.ENCHANTMENT, SubType.AURA);
|
assertType("Nylea's Emissary", CardType.ENCHANTMENT, SubType.AURA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastBestowFlashRootwaterShaman() {
|
||||||
|
addCard(Zone.HAND, playerA, "Nylea's Emissary"); // +3/+3, only an aura if cast with bestow
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 6);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Rootwater Shaman"); //aura spells with enchant creature have flash
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); // 1/1
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Nylea's Emissary using bestow", "Memnite");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Nylea's Emissary", 1);
|
||||||
|
assertPowerToughness(playerA, "Memnite", 4, 4);
|
||||||
|
assertType("Nylea's Emissary", CardType.CREATURE, false);
|
||||||
|
assertType("Nylea's Emissary", CardType.ENCHANTMENT, SubType.AURA);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that copied bestow works correctly both on the stack and battlefield, including with the creature removed
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void bestowCopiesTest() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 18);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Overloaded Mage-Ring", 2);
|
||||||
|
addCard(Zone.HAND, playerA, "Hopeful Eidolon", 2);
|
||||||
|
addCard(Zone.HAND, playerA, "Copy Enchantment");
|
||||||
|
addCard(Zone.HAND, playerA, "Mythos of Illuna");
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4);
|
||||||
|
addCard(Zone.HAND, playerB, "Lightning Blast");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hopeful Eidolon using bestow", "Silvercoat Lion");
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, {T}, Sacrifice", "Hopeful Eidolon");
|
||||||
|
setChoice(playerA, false);
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mythos of Illuna", "Hopeful Eidolon"); // Making a token copy of a resolved Bestow aura makes a token creature
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Copy Enchantment"); // Copying a resolved Bestow aura makes a creature
|
||||||
|
setChoice(playerA, true);
|
||||||
|
setChoice(playerA, "Hopeful Eidolon");
|
||||||
|
checkPT("Lion with 2x Hopeful Eidolon attached", 1, PhaseStep.BEGIN_COMBAT, playerA, "Silvercoat Lion", 4, 4);
|
||||||
|
checkPermanentCount("Four Hopeful Eidolons resolved", 1, PhaseStep.BEGIN_COMBAT, playerA, "Hopeful Eidolon", 4);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Hopeful Eidolon using bestow", "Silvercoat Lion");
|
||||||
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}, {T}, Sacrifice", "Hopeful Eidolon");
|
||||||
|
setChoice(playerA, false);
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Blast", "Silvercoat Lion");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Silvercoat Lion", 0);
|
||||||
|
assertPermanentCount(playerA, "Hopeful Eidolon", 6);
|
||||||
|
assertTokenCount(playerA, "Hopeful Eidolon", 2);
|
||||||
|
|
||||||
|
FilterPermanent filter = new FilterPermanent();
|
||||||
|
filter.add(new NamePredicate("Hopeful Eidolon"));
|
||||||
|
List<Permanent> eidolons = currentGame.getBattlefield().getAllActivePermanents(filter, currentGame);
|
||||||
|
Assert.assertEquals("Six Eidolons found with filter", 6, eidolons.size());
|
||||||
|
for (Permanent p : eidolons){
|
||||||
|
Assert.assertTrue("Is Enchantment", p.getCardType(currentGame).contains(CardType.ENCHANTMENT));
|
||||||
|
Assert.assertFalse("Is not Aura", p.getSubtype(currentGame).contains(SubType.AURA));
|
||||||
|
Assert.assertTrue("Is Creature", p.getCardType(currentGame).contains(CardType.CREATURE));
|
||||||
|
Assert.assertTrue("Is Spirit", p.getSubtype(currentGame).contains(SubType.SPIRIT));
|
||||||
|
Assert.assertEquals("Is 1 power", 1, p.getPower().getValue());
|
||||||
|
Assert.assertEquals("Is 1 toughness", 1, p.getToughness().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBestowSubtype() {
|
||||||
|
addCard(Zone.HAND, playerA, "Hopeful Eidolon", 2); // Spirit when cast as creature, not when cast as aura
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Waxmane Baku"); // May add a counter on casting a spirit spell
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Drogskol Cavalry"); // +2 life whenever another spirit enters
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hopeful Eidolon using bestow", "Waxmane Baku");
|
||||||
|
checkPermanentCounters("Not a Spirit, no KI counters", 1, PhaseStep.BEGIN_COMBAT, playerA, "Waxmane Baku", CounterType.KI, 0);
|
||||||
|
checkLife("Not a Spirit, no lifegain", 1, PhaseStep.BEGIN_COMBAT, playerA, 20);
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Hopeful Eidolon");
|
||||||
|
setChoice(playerA, true);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Hopeful Eidolon", 2);
|
||||||
|
assertPowerToughness(playerA, "Waxmane Baku", 3, 3);
|
||||||
|
assertCounterCount(playerA, "Waxmane Baku", CounterType.KI, 1);
|
||||||
|
assertLife(playerA, 22);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBestowSBATiming() {
|
||||||
|
addCard(Zone.HAND, playerA, "Hopeful Eidolon", 2); // +1/+1
|
||||||
|
addCard(Zone.HAND, playerA, "Pyroclasm", 2); // 2 damage
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plateau", 10);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Crusader of Odric");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Eager Cadet");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hopeful Eidolon using bestow", "Memnite", true);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hopeful Eidolon using bestow", "Eager Cadet");
|
||||||
|
checkPT("Memnite P/T", 1, PhaseStep.BEGIN_COMBAT, playerA, "Memnite", 2, 2);
|
||||||
|
checkPT("Eager Cadet P/T", 1, PhaseStep.BEGIN_COMBAT, playerA, "Eager Cadet", 2, 2);
|
||||||
|
checkPT("Crusader P/T", 1, PhaseStep.BEGIN_COMBAT, playerA, "Crusader of Odric", 3, 3);
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Pyroclasm");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Hopeful Eidolon", 2);
|
||||||
|
assertPermanentCount(playerA, "Crusader of Odric", 1);
|
||||||
|
assertDamageReceived(playerA, "Crusader of Odric", 2);
|
||||||
|
assertGraveyardCount(playerA, 3);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package org.mage.test.cards.abilities.keywords;
|
||||||
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
|
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
|
||||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||||
import mage.abilities.effects.common.GainLifeEffect;
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
import mage.abilities.keyword.HasteAbility;
|
import mage.abilities.keyword.HasteAbility;
|
||||||
|
|
@ -9,6 +10,7 @@ import mage.cards.Card;
|
||||||
import mage.constants.ComparisonType;
|
import mage.constants.ComparisonType;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import mage.filter.FilterPermanent;
|
||||||
import mage.filter.FilterSpell;
|
import mage.filter.FilterSpell;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.predicate.Predicate;
|
import mage.filter.predicate.Predicate;
|
||||||
|
|
@ -61,14 +63,22 @@ public class PrototypeTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void makeTester(Predicate<? super MageObject>... predicates) {
|
private void makeTester(Predicate<? super MageObject>... predicates) {
|
||||||
FilterSpell filter = new FilterSpell();
|
FilterSpell filterA = new FilterSpell();
|
||||||
|
FilterPermanent filterB = new FilterPermanent();
|
||||||
for (Predicate<? super MageObject> predicate : predicates) {
|
for (Predicate<? super MageObject> predicate : predicates) {
|
||||||
filter.add(predicate);
|
filterA.add(predicate);
|
||||||
|
filterB.add(predicate);
|
||||||
}
|
}
|
||||||
addCustomCardWithAbility(
|
addCustomCardWithAbility(
|
||||||
"tester", playerA,
|
"tester", playerA,
|
||||||
new SpellCastControllerTriggeredAbility(
|
new SpellCastControllerTriggeredAbility(
|
||||||
new GainLifeEffect(1), filter, false
|
new GainLifeEffect(1), filterA, false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
addCustomCardWithAbility(
|
||||||
|
"tester", playerB,
|
||||||
|
new EntersBattlefieldAllTriggeredAbility(
|
||||||
|
new GainLifeEffect(1), filterB, false
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -159,6 +169,7 @@ public class PrototypeTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerA, 20 + 1);
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -174,6 +185,7 @@ public class PrototypeTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerA, 20 + 1);
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -192,6 +204,7 @@ public class PrototypeTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerA, 20 + 1);
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -210,6 +223,7 @@ public class PrototypeTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerA, 20 + 1);
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -225,6 +239,7 @@ public class PrototypeTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerA, 20 + 1);
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -240,6 +255,7 @@ public class PrototypeTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerA, 20 + 1);
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -1127,14 +1127,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
||||||
|
|
||||||
int actualCount = 0;
|
int actualCount = 0;
|
||||||
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
|
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
|
||||||
if (permanent instanceof PermanentToken) {
|
if (permanent instanceof PermanentToken
|
||||||
if (permanent.getControllerId().equals(player.getId())) {
|
&& permanent.getControllerId().equals(player.getId())
|
||||||
if (isObjectHaveTargetNameOrAlias(player, permanent, tokenName)) {
|
&& isObjectHaveTargetNameOrAlias(player, permanent, tokenName)) {
|
||||||
actualCount++;
|
actualCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
Assert.assertEquals("(Battlefield) Tokens counts for " + player.getName() + " are not equal (" + tokenName + ')', count, actualCount);
|
Assert.assertEquals("(Battlefield) Tokens counts for " + player.getName() + " are not equal (" + tokenName + ')', count, actualCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,13 @@ import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.Costs;
|
import mage.abilities.costs.Costs;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.ReplacementEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
|
||||||
import mage.game.events.GameEvent.EventType;
|
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
import mage.target.common.TargetCreaturePermanent;
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
|
@ -90,9 +89,9 @@ public class BestowAbility extends SpellAbility {
|
||||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||||
this.addTarget(auraTarget);
|
this.addTarget(auraTarget);
|
||||||
this.addEffect(new AttachEffect(Outcome.BoostCreature));
|
this.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||||
Ability ability = new SimpleStaticAbility(new BestowEntersBattlefieldEffect());
|
Ability ability = new SimpleStaticAbility(new BestowTypeEffect());
|
||||||
ability.setRuleVisible(false);
|
ability.setRuleVisible(false);
|
||||||
addSubAbility(ability);
|
this.addSubAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BestowAbility(final BestowAbility ability) {
|
protected BestowAbility(final BestowAbility ability) {
|
||||||
|
|
@ -122,70 +121,65 @@ public class BestowAbility extends SpellAbility {
|
||||||
sb.append(" <i>(If you cast this card for its bestow cost, it's an Aura spell with enchant creature. It becomes a creature again if it's not attached to a creature.)</i>");
|
sb.append(" <i>(If you cast this card for its bestow cost, it's an Aura spell with enchant creature. It becomes a creature again if it's not attached to a creature.)</i>");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void becomeCreature(Permanent permanent, Game game) {
|
|
||||||
// permanently changes to the object
|
|
||||||
if (permanent != null) {
|
|
||||||
MageObject basicObject = permanent.getBasicMageObject();
|
|
||||||
if (basicObject != null) {
|
|
||||||
game.checkStateAndTriggered(); // Bug #8157
|
|
||||||
basicObject.getSubtype().remove(SubType.AURA);
|
|
||||||
basicObject.addCardType(CardType.CREATURE);
|
|
||||||
}
|
|
||||||
permanent.getSubtype().remove(SubType.AURA);
|
|
||||||
permanent.addCardType(CardType.CREATURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void becomeAura(Card card) {
|
public static void becomeAura(Card card) {
|
||||||
// permanently changes to the object
|
// permanently changes to the object, only use on copies
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
|
if (!card.getCardType().contains(CardType.ENCHANTMENT)) {
|
||||||
|
throw new IllegalStateException("Bestow perpetual becomeAura called on non-enchantment card");
|
||||||
|
}
|
||||||
card.addSubType(SubType.AURA);
|
card.addSubType(SubType.AURA);
|
||||||
card.removeCardType(CardType.CREATURE);
|
card.removeCardType(CardType.CREATURE);
|
||||||
card.addCardType(CardType.ENCHANTMENT);
|
card.removeAllCreatureTypes();
|
||||||
|
if (card instanceof Spell) {
|
||||||
|
((Spell) card).addAbilityForCopy(new EnchantAbility(new TargetCreaturePermanent()));
|
||||||
|
} else {
|
||||||
|
card.addAbility(new EnchantAbility(new TargetCreaturePermanent()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void becomeAura(Game game, MageObject object) {
|
||||||
|
// temporary changes only
|
||||||
|
if (object != null && object.getCardType(game).contains(CardType.ENCHANTMENT)) {
|
||||||
|
object.addSubType(game, SubType.AURA);
|
||||||
|
object.removeCardType(game, CardType.CREATURE);
|
||||||
|
object.removeAllCreatureTypes(game);
|
||||||
|
if (object instanceof Permanent) {
|
||||||
|
((Permanent) object).addAbility(new EnchantAbility(new TargetCreaturePermanent()), object.getId(), game);
|
||||||
|
} else if (object instanceof Spell) {
|
||||||
|
game.getState().addOtherAbility(((Spell) object).getCard(), new EnchantAbility(new TargetCreaturePermanent()));
|
||||||
|
} else if (object instanceof Card) {
|
||||||
|
game.getState().addOtherAbility((Card) object, new EnchantAbility(new TargetCreaturePermanent()));
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Bestow temporary becomeAura called on non-Permanent non-Spell object: " + object.getClass().getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BestowEntersBattlefieldEffect extends ReplacementEffectImpl {
|
class BestowTypeEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
public BestowEntersBattlefieldEffect() {
|
BestowTypeEffect() {
|
||||||
super(Duration.WhileOnBattlefield, Outcome.Neutral);
|
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BestowEntersBattlefieldEffect(final BestowEntersBattlefieldEffect effect) {
|
private BestowTypeEffect(final BestowTypeEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checksEventType(GameEvent event, Game game) {
|
public BestowTypeEffect copy() {
|
||||||
return EventType.ENTERS_THE_BATTLEFIELD_SELF == event.getType();
|
return new BestowTypeEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean apply(Game game, Ability source) {
|
||||||
return event.getTargetId().equals(source.getSourceId());
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
}
|
if (permanent == null) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
|
||||||
Permanent bestowPermanent = game.getPermanentEntering(source.getSourceId());
|
|
||||||
if (bestowPermanent == null || !bestowPermanent.hasSubtype(SubType.AURA, game)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (game.getPermanent(permanent.getAttachedTo()) != null){
|
||||||
// change types permanently
|
BestowAbility.becomeAura(game, permanent);
|
||||||
MageObject basicObject = bestowPermanent.getBasicMageObject();
|
|
||||||
if (basicObject != null && !basicObject.getSubtype().contains(SubType.AURA)) {
|
|
||||||
basicObject.addSubType(SubType.AURA);
|
|
||||||
basicObject.removeCardType(CardType.CREATURE);
|
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BestowEntersBattlefieldEffect copy() {
|
|
||||||
return new BestowEntersBattlefieldEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ class ReconfigureTypeEffect extends ContinuousEffectImpl {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
permanent.removeCardType(game, CardType.CREATURE);
|
permanent.removeCardType(game, CardType.CREATURE);
|
||||||
|
permanent.removeAllCreatureTypes(game);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2670,10 +2670,9 @@ public abstract class GameImpl implements Game {
|
||||||
Permanent attachedTo = getPermanent(perm.getAttachedTo());
|
Permanent attachedTo = getPermanent(perm.getAttachedTo());
|
||||||
if (attachedTo == null || !attachedTo.getAttachments().contains(perm.getId())) {
|
if (attachedTo == null || !attachedTo.getAttachments().contains(perm.getId())) {
|
||||||
// handle bestow unattachment
|
// handle bestow unattachment
|
||||||
Card card = this.getCard(perm.getId());
|
if (perm.getAbilities().stream().anyMatch(x -> x instanceof BestowAbility)) {
|
||||||
if (card != null && card.isCreature(this)) {
|
|
||||||
UUID wasAttachedTo = perm.getAttachedTo();
|
UUID wasAttachedTo = perm.getAttachedTo();
|
||||||
perm.attachTo(null, null, this);
|
perm.unattach(this);
|
||||||
fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
|
fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
|
||||||
} else if (movePermanentToGraveyardWithInfo(perm)) {
|
} else if (movePermanentToGraveyardWithInfo(perm)) {
|
||||||
somethingHappened = true;
|
somethingHappened = true;
|
||||||
|
|
@ -2683,11 +2682,9 @@ public abstract class GameImpl implements Game {
|
||||||
if (auraFilter instanceof FilterPermanent) {
|
if (auraFilter instanceof FilterPermanent) {
|
||||||
if (!((FilterPermanent) auraFilter).match(attachedTo, perm.getControllerId(), perm.getSpellAbility(), this)
|
if (!((FilterPermanent) auraFilter).match(attachedTo, perm.getControllerId(), perm.getSpellAbility(), this)
|
||||||
|| attachedTo.cantBeAttachedBy(perm, null, this, true)) {
|
|| attachedTo.cantBeAttachedBy(perm, null, this, true)) {
|
||||||
Card card = this.getCard(perm.getId());
|
if (perm.getAbilities().stream().anyMatch(x -> x instanceof BestowAbility)) {
|
||||||
if (card != null && card.isCreature(this)) {
|
|
||||||
UUID wasAttachedTo = perm.getAttachedTo();
|
UUID wasAttachedTo = perm.getAttachedTo();
|
||||||
perm.attachTo(null, null, this);
|
perm.unattach(this);
|
||||||
BestowAbility.becomeCreature(perm, this);
|
|
||||||
fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
|
fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
|
||||||
} else if (movePermanentToGraveyardWithInfo(perm)) {
|
} else if (movePermanentToGraveyardWithInfo(perm)) {
|
||||||
somethingHappened = true;
|
somethingHappened = true;
|
||||||
|
|
@ -2695,11 +2692,9 @@ public abstract class GameImpl implements Game {
|
||||||
}
|
}
|
||||||
} else if (!auraFilter.match(attachedTo, this) || attachedTo.cantBeAttachedBy(perm, null, this, true)) {
|
} else if (!auraFilter.match(attachedTo, this) || attachedTo.cantBeAttachedBy(perm, null, this, true)) {
|
||||||
// handle bestow unattachment
|
// handle bestow unattachment
|
||||||
Card card = this.getCard(perm.getId());
|
if (perm.getAbilities().stream().anyMatch(x -> x instanceof BestowAbility)) {
|
||||||
if (card != null && card.isCreature(this)) {
|
|
||||||
UUID wasAttachedTo = perm.getAttachedTo();
|
UUID wasAttachedTo = perm.getAttachedTo();
|
||||||
perm.attachTo(null, null, this);
|
perm.unattach(this);
|
||||||
BestowAbility.becomeCreature(perm, this);
|
|
||||||
fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
|
fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
|
||||||
} else if (movePermanentToGraveyardWithInfo(perm)) {
|
} else if (movePermanentToGraveyardWithInfo(perm)) {
|
||||||
somethingHappened = true;
|
somethingHappened = true;
|
||||||
|
|
|
||||||
|
|
@ -2061,24 +2061,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
//20180810 - 701.3d
|
|
||||||
//If an object leaves the zone it's in, all attached permanents become unattached
|
|
||||||
//note that this code doesn't actually detach anything, and is a bit of a bandaid
|
|
||||||
public void detachAllAttachments(Game game) {
|
|
||||||
for (UUID attachmentId : getAttachments()) {
|
|
||||||
Permanent attachment = game.getPermanent(attachmentId);
|
|
||||||
Card attachmentCard = game.getCard(attachmentId);
|
|
||||||
if (attachment != null && attachmentCard != null) {
|
|
||||||
//make bestow cards and licids into creatures
|
|
||||||
//aura test to stop bludgeon brawl shenanigans from using this code
|
|
||||||
//consider adding code to handle that case?
|
|
||||||
if (attachment.hasSubtype(SubType.AURA, game) && attachmentCard.isCreature(game)) {
|
|
||||||
BestowAbility.becomeCreature(attachment, game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
|
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
|
||||||
Zone fromZone = game.getState().getZone(objectId);
|
Zone fromZone = game.getState().getZone(objectId);
|
||||||
|
|
@ -2091,12 +2073,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
} else {
|
} else {
|
||||||
zoneChangeInfo = new ZoneChangeInfo(event);
|
zoneChangeInfo = new ZoneChangeInfo(event);
|
||||||
}
|
}
|
||||||
boolean successfullyMoved = ZonesHandler.moveCard(zoneChangeInfo, game, source);
|
return ZonesHandler.moveCard(zoneChangeInfo, game, source);
|
||||||
//20180810 - 701.3d
|
|
||||||
if (successfullyMoved) {
|
|
||||||
detachAllAttachments(game);
|
|
||||||
}
|
|
||||||
return successfullyMoved;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2107,11 +2084,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
ZoneChangeEvent event = new ZoneChangeEvent(this, source, ownerId, fromZone, Zone.EXILED, appliedEffects);
|
ZoneChangeEvent event = new ZoneChangeEvent(this, source, ownerId, fromZone, Zone.EXILED, appliedEffects);
|
||||||
ZoneChangeInfo.Exile zcInfo = new ZoneChangeInfo.Exile(event, exileId, name);
|
ZoneChangeInfo.Exile zcInfo = new ZoneChangeInfo.Exile(event, exileId, name);
|
||||||
|
|
||||||
boolean successfullyMoved = ZonesHandler.moveCard(zcInfo, game, source);
|
return ZonesHandler.moveCard(zcInfo, game, source);
|
||||||
//20180810 - 701.3d
|
|
||||||
if (successfullyMoved) {
|
|
||||||
detachAllAttachments(game);
|
|
||||||
}
|
|
||||||
return successfullyMoved;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import mage.game.MageObjectAttribute;
|
||||||
import mage.game.events.CopiedStackObjectEvent;
|
import mage.game.events.CopiedStackObjectEvent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.PermanentCard;
|
|
||||||
import mage.game.permanent.token.Token;
|
import mage.game.permanent.token.Token;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
|
@ -335,45 +334,39 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
counter(null, /*this.getSpellAbility()*/ game);
|
counter(null, /*this.getSpellAbility()*/ game);
|
||||||
return false;
|
return false;
|
||||||
} else if (this.isEnchantment(game) && this.hasSubtype(SubType.AURA, game)) {
|
} else if (this.isEnchantment(game) && this.hasSubtype(SubType.AURA, game)) {
|
||||||
if (ability.getTargets().stillLegal(ability, game)) {
|
|
||||||
boolean bestow = SpellAbilityCastMode.BESTOW.equals(ability.getSpellAbilityCastMode());
|
boolean bestow = SpellAbilityCastMode.BESTOW.equals(ability.getSpellAbilityCastMode());
|
||||||
|
if (ability.getTargets().stillLegal(ability, game)) {
|
||||||
if (bestow) {
|
if (bestow) {
|
||||||
// before put to play:
|
// before put to play:
|
||||||
// Must be removed first time, after that will be removed by continous effect
|
// Must be removed first time, after that will be removed by continous effect
|
||||||
// Otherwise effects like evolve trigger from creature comes into play event
|
// Otherwise effects like evolve trigger from creature comes into play event
|
||||||
card.removeCardType(CardType.CREATURE);
|
BestowAbility.becomeAura(game, card);
|
||||||
card.addSubType(game, SubType.AURA);
|
|
||||||
}
|
}
|
||||||
UUID permId;
|
UUID permId;
|
||||||
boolean flag;
|
boolean permanentCreated;
|
||||||
if (isCopy()) {
|
if (isCopy()) {
|
||||||
Token token = CopyTokenFunction.createTokenCopy(card, game, this);
|
Token token = CopyTokenFunction.createTokenCopy(card, game, this);
|
||||||
// The token that a resolving copy of a spell becomes isn’t said to have been “created.” (2020-09-25)
|
// The token that a resolving copy of a spell becomes isn’t said to have been “created.” (2020-09-25)
|
||||||
if (token.putOntoBattlefield(1, game, ability, getControllerId(), false, false, null, null, false)) {
|
if (token.putOntoBattlefield(1, game, ability, getControllerId(), false, false, null, null, false)) {
|
||||||
permId = token.getLastAddedTokenIds().stream().findFirst().orElse(null);
|
permId = token.getLastAddedTokenIds().stream().findFirst().orElse(null);
|
||||||
flag = true;
|
permanentCreated = true;
|
||||||
} else {
|
} else {
|
||||||
permId = null;
|
permId = null;
|
||||||
flag = false;
|
permanentCreated = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
permId = card.getId();
|
permId = card.getId();
|
||||||
MageObjectReference mor = new MageObjectReference(getSpellAbility());
|
MageObjectReference mor = new MageObjectReference(getSpellAbility());
|
||||||
game.storePermanentCostsTags(mor, getSpellAbility());
|
game.storePermanentCostsTags(mor, getSpellAbility());
|
||||||
flag = controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null);
|
permanentCreated = controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null);
|
||||||
}
|
}
|
||||||
if (flag) {
|
if (permanentCreated) {
|
||||||
if (bestow) {
|
if (bestow) {
|
||||||
// card will be copied during putOntoBattlefield, so the card of CardPermanent has to be changed
|
|
||||||
// TODO: Find a better way to prevent bestow creatures from being effected by creature affecting abilities
|
|
||||||
Permanent permanent = game.getPermanent(permId);
|
Permanent permanent = game.getPermanent(permId);
|
||||||
if (permanent instanceof PermanentCard) {
|
|
||||||
// after put to play:
|
|
||||||
// restore removed stats (see "before put to play" above)
|
|
||||||
permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set
|
permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set
|
||||||
card.addCardType(CardType.CREATURE);
|
// The continuous effect that makes the permanent an aura doesn't apply until after the permanent has already entered,
|
||||||
card.getSubtype().remove(SubType.AURA);
|
// so it must be modified manually here first. Same root cause as the Blood Moon problem https://github.com/magefree/mage/issues/4202
|
||||||
}
|
BestowAbility.becomeAura(game, permanent);
|
||||||
}
|
}
|
||||||
if (isCopy()) {
|
if (isCopy()) {
|
||||||
Permanent token = game.getPermanent(permId);
|
Permanent token = game.getPermanent(permId);
|
||||||
|
|
@ -381,7 +374,8 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (Ability ability2 : token.getAbilities()) {
|
for (Ability ability2 : token.getAbilities()) {
|
||||||
if (!bestow || ability2 instanceof BestowAbility) {
|
if (ability2 instanceof SpellAbility && ability2.getTargets().size() == 1) {
|
||||||
|
// Copy aura SpellAbility's targets into the new token's SpellAbility
|
||||||
ability2.getTargets().get(0).add(ability.getFirstTarget(), game);
|
ability2.getTargets().get(0).add(ability.getFirstTarget(), game);
|
||||||
ability2.getEffects().get(0).apply(game, ability2);
|
ability2.getEffects().get(0).apply(game, ability2);
|
||||||
return ability2.resolve(game);
|
return ability2.resolve(game);
|
||||||
|
|
@ -391,24 +385,13 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
}
|
}
|
||||||
return ability.resolve(game);
|
return ability.resolve(game);
|
||||||
}
|
}
|
||||||
if (bestow) {
|
|
||||||
card.addCardType(game, CardType.CREATURE);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature
|
// Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature
|
||||||
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) {
|
if (bestow) {
|
||||||
MageObjectReference mor = new MageObjectReference(getSpellAbility());
|
MageObjectReference mor = new MageObjectReference(getSpellAbility());
|
||||||
game.storePermanentCostsTags(mor, getSpellAbility());
|
game.storePermanentCostsTags(mor, getSpellAbility());
|
||||||
if (controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null)) {
|
return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null);
|
||||||
Permanent permanent = game.getPermanent(card.getId());
|
|
||||||
if (permanent instanceof PermanentCard) {
|
|
||||||
((PermanentCard) permanent).getCard().addCardType(game, CardType.CREATURE);
|
|
||||||
((PermanentCard) permanent).getCard().removeSubType(game, SubType.AURA);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
//20091005 - 608.2b
|
//20091005 - 608.2b
|
||||||
if (!game.isSimulation()) {
|
if (!game.isSimulation()) {
|
||||||
|
|
@ -585,10 +568,8 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
return cardTypes;
|
return cardTypes;
|
||||||
}
|
}
|
||||||
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) {
|
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) {
|
||||||
List<CardType> cardTypes = new ArrayList<>();
|
Card modifiedCard = this.getSpellAbility().getSpellAbilityCastMode().getTypeModifiedCardObjectCopy(card, this.getSpellAbility(), game);
|
||||||
cardTypes.addAll(card.getCardType(game));
|
return modifiedCard.getCardType(game);
|
||||||
cardTypes.remove(CardType.CREATURE);
|
|
||||||
return cardTypes;
|
|
||||||
}
|
}
|
||||||
return card.getCardType(game);
|
return card.getCardType(game);
|
||||||
}
|
}
|
||||||
|
|
@ -600,26 +581,19 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SubTypes getSubtype(Game game) {
|
public SubTypes getSubtype(Game game) {
|
||||||
|
// Bestow's changes are non-copiable, and must be reapplied
|
||||||
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) {
|
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) {
|
||||||
SubTypes subtypes = card.getSubtype(game);
|
Card modifiedCard = this.getSpellAbility().getSpellAbilityCastMode().getTypeModifiedCardObjectCopy(card, this.getSpellAbility(), game);
|
||||||
if (!subtypes.contains(SubType.AURA)) { // do it only once
|
return modifiedCard.getSubtype();
|
||||||
subtypes.add(SubType.AURA);
|
|
||||||
}
|
|
||||||
return subtypes;
|
|
||||||
}
|
}
|
||||||
return card.getSubtype(game);
|
return card.getSubtype(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSubtype(SubType subtype, Game game) {
|
public boolean hasSubtype(SubType subtype, Game game) {
|
||||||
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) { // workaround for Bestow (don't like it)
|
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) {
|
||||||
SubTypes subtypes = card.getSubtype(game);
|
Card modifiedCard = this.getSpellAbility().getSpellAbilityCastMode().getTypeModifiedCardObjectCopy(card, this.getSpellAbility(), game);
|
||||||
if (!subtypes.contains(SubType.AURA)) { // do it only once
|
return modifiedCard.hasSubtype(subtype, game);
|
||||||
subtypes.add(SubType.AURA);
|
|
||||||
}
|
|
||||||
if (subtypes.contains(subtype)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return card.hasSubtype(subtype, game);
|
return card.hasSubtype(subtype, game);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue