[NEC] fixed Kotori, Pilot Prodigy's granted crew ability not animating vehicles (fixes #8713)

This commit is contained in:
Evan Kranzler 2022-02-18 22:22:44 -05:00
parent 4c32272505
commit 8040e7d1e8
2 changed files with 60 additions and 32 deletions

View file

@ -15,23 +15,33 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
// http://magic.wizards.com/en/articles/archive/feature/kaladesh-mechanics-2016-09-02 // http://magic.wizards.com/en/articles/archive/feature/kaladesh-mechanics-2016-09-02
public class CrewTest extends CardTestPlayerBase { public class CrewTest extends CardTestPlayerBase {
private static final String lion = "Silvercoat Lion";
private static final String caravan = "Cultivator's Caravan";
private static final String fanatic = "Speedway Fanatic";
private static final String copter = "Smuggler's Copter";
private static final String evacuation = "Evacuation";
private static final String ox = "Giant Ox";
private static final String plow = "Colossal Plow";
private static final String kotori = "Kotori, Pilot Prodigy";
private static final String crusher = "Irontread Crusher";
@Test @Test
public void crewBasicTest() { public void crewBasicTest() {
// {T}: Add one mana of any color. // {T}: Add one mana of any color.
// Crew 3 (Tap any number of creatures you control with total power 3 or more: This Vehicle becomes an artifact creature until end of turn.)"; // Crew 3 (Tap any number of creatures you control with total power 3 or more: This Vehicle becomes an artifact creature until end of turn.)";
addCard(Zone.BATTLEFIELD, playerA, "Cultivator's Caravan", 1); addCard(Zone.BATTLEFIELD, playerA, caravan, 1);
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 2); addCard(Zone.BATTLEFIELD, playerA, lion, 2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 3"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 3");
setChoice(playerA, "Silvercoat Lion^Silvercoat Lion"); setChoice(playerA, lion + "^" + lion);
setStopAt(1, PhaseStep.BEGIN_COMBAT); setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute(); execute();
assertTappedCount("Silvercoat Lion", true, 2); assertTappedCount(lion, true, 2);
assertPowerToughness(playerA, "Cultivator's Caravan", 5, 5); assertPowerToughness(playerA, caravan, 5, 5);
assertType("Cultivator's Caravan", CardType.CREATURE, SubType.VEHICLE); assertType(caravan, CardType.CREATURE, SubType.VEHICLE);
} }
@Test @Test
@ -39,56 +49,71 @@ public class CrewTest extends CardTestPlayerBase {
// Flying // Flying
// Whenever Smuggler's Copter attacks or blocks, you may draw a card. If you do, discard a card. // Whenever Smuggler's Copter attacks or blocks, you may draw a card. If you do, discard a card.
// Crew 1 (Tap any number of creatures you control with total power 3 or more: This Vehicle becomes an artifact creature until end of turn.)"; // Crew 1 (Tap any number of creatures you control with total power 3 or more: This Vehicle becomes an artifact creature until end of turn.)";
addCard(Zone.BATTLEFIELD, playerA, "Smuggler's Copter", 1); addCard(Zone.BATTLEFIELD, playerA, copter, 1);
addCard(Zone.BATTLEFIELD, playerA, "Speedway Fanatic", 1); addCard(Zone.BATTLEFIELD, playerA, fanatic, 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 1"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 1");
setChoice(playerA, "Speedway Fanatic"); setChoice(playerA, fanatic);
setStopAt(1, PhaseStep.BEGIN_COMBAT); setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute(); execute();
assertTappedCount("Speedway Fanatic", true, 1); assertTappedCount(fanatic, true, 1);
assertPowerToughness(playerA, "Smuggler's Copter", 3, 3); assertPowerToughness(playerA, copter, 3, 3);
assertAbility(playerA, "Smuggler's Copter", HasteAbility.getInstance(), true); assertAbility(playerA, copter, HasteAbility.getInstance(), true);
assertType("Smuggler's Copter", CardType.CREATURE, SubType.VEHICLE); assertType(copter, CardType.CREATURE, SubType.VEHICLE);
} }
@Test @Test
public void testThatBouncingACrewedVehicleWillUncrewIt() { public void testThatBouncingACrewedVehicleWillUncrewIt() {
addCard(Zone.BATTLEFIELD, playerA, "Smuggler's Copter", 1); addCard(Zone.BATTLEFIELD, playerA, copter, 1);
addCard(Zone.BATTLEFIELD, playerA, "Speedway Fanatic", 1); addCard(Zone.BATTLEFIELD, playerA, fanatic, 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 7); addCard(Zone.BATTLEFIELD, playerA, "Island", 7);
addCard(Zone.HAND, playerA, "Evacuation", 1); addCard(Zone.HAND, playerA, evacuation, 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 1"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 1");
setChoice(playerA, "Speedway Fanatic"); setChoice(playerA, fanatic);
// Return all creatures to there owners hands // Return all creatures to there owners hands
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Evacuation"); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, evacuation);
// (Re)Cast Smugglers Copter // (Re)Cast Smugglers Copter
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Smuggler's Copter"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, copter);
setStopAt(1, PhaseStep.END_TURN); setStopAt(1, PhaseStep.END_TURN);
execute(); execute();
// Only crewed vehicles have card type creature // Only crewed vehicles have card type creature
assertNotType("Smuggler's Copter", CardType.CREATURE); assertNotType(copter, CardType.CREATURE);
} }
@Test @Test
public void testGiantOx() { public void testGiantOx() {
addCard(Zone.BATTLEFIELD, playerA, "Giant Ox"); addCard(Zone.BATTLEFIELD, playerA, ox);
addCard(Zone.BATTLEFIELD, playerA, "Colossal Plow"); addCard(Zone.BATTLEFIELD, playerA, plow);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute(); execute();
assertTapped("Giant Ox", true); assertTapped(ox, true);
assertType("Colossal Plow", CardType.CREATURE, true); assertType(plow, CardType.CREATURE, true);
}
@Test
public void testGrantedAbility() {
addCard(Zone.BATTLEFIELD, playerA, kotori);
addCard(Zone.BATTLEFIELD, playerA, crusher);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 2");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertTapped(kotori, true);
assertType(crusher, CardType.ARTIFACT, true);
assertType(crusher, CardType.CREATURE, SubType.VEHICLE);
} }
} }

View file

@ -1247,16 +1247,19 @@ public class ContinuousEffects implements Serializable {
} }
private boolean isAbilityStillExists(final Game game, final Ability ability, ContinuousEffect effect) { private boolean isAbilityStillExists(final Game game, final Ability ability, ContinuousEffect effect) {
final Card card = game.getPermanentOrLKIBattlefield(ability.getSourceId()); switch (effect.getDuration()) { // effects with fixed duration don't need an object with the source ability (e.g. a silence cast with isochronic Scepter has no more a card object
if (!(effect instanceof BecomesFaceDownCreatureEffect) case EndOfCombat:
&& (effect != null && !effect.getDuration().equals(Duration.Custom))) { // Custom effects do not depend on the creating permanent case EndOfGame:
if (card != null) { case EndOfStep:
return card.hasAbility(ability, game); case EndOfTurn:
} case OneUse:
} case Custom: // custom duration means the effect ends itself if needed
return true; return true;
} }
final Card card = game.getPermanentOrLKIBattlefield(ability.getSourceId());
return effect instanceof BecomesFaceDownCreatureEffect
|| effect == null || card == null || card.hasAbility(ability, game);
}
public Set<Ability> getLayeredEffectAbilities(ContinuousEffect effect) { public Set<Ability> getLayeredEffectAbilities(ContinuousEffect effect) {
return layeredEffects.getAbility(effect.getId()); return layeredEffects.getAbility(effect.getId());