mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +00:00
[CLB] Fixed connive fizzling on stack when permanent that connived leaves the battlefield. Closes #9252.
This commit is contained in:
parent
8878dc5cc7
commit
8c22db650a
2 changed files with 196 additions and 5 deletions
|
@ -0,0 +1,183 @@
|
|||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Alex-Vasile
|
||||
* To have a creature connive, draw a card, then discard a card. If you discarded a nonland card, put a +1/+1 counter on that creature.
|
||||
*/
|
||||
public class ConniveTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Connive and discard a land.
|
||||
* Creature should not get a +1/+1 counter.
|
||||
*/
|
||||
@Test
|
||||
public void conniveDiscardLand() {
|
||||
// P/T : 1/2
|
||||
// {3}: Hypnotic Grifter connives
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Hypnotic Grifter");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.HAND, playerA, "Plains", 1); // To discard
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}");
|
||||
setChoice(playerA, "Plains");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPowerToughness(playerA, "Hypnotic Grifter", 1, 2); // Discarded a land card
|
||||
assertHandCount(playerA, 1); // 1 from drawing at start of turn
|
||||
assertGraveyardCount(playerA, "Plains", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connive and discard a creature.
|
||||
* Creature should get a +1/+1 counter.
|
||||
*/
|
||||
@Test
|
||||
public void conniveDiscardCreature() {
|
||||
// P/T : 1/2
|
||||
// {3}: Hypnotic Grifter connives
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Hypnotic Grifter");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.HAND, playerA, "Ledger Shredder", 1); // To discard
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}");
|
||||
setChoice(playerA, "Ledger Shredder");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPowerToughness(playerA, "Hypnotic Grifter", 2, 3); // Discarded a non-land
|
||||
assertHandCount(playerA, 1); // 1 from drawing at start of turn
|
||||
assertGraveyardCount(playerA, "Ledger Shredder", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connive + Madness.
|
||||
* Creature should get a +1/+1 counter and the madness card gets played.
|
||||
*/
|
||||
@Test
|
||||
public void conniveMadness() {
|
||||
// P/T : 1/2
|
||||
// {3}: Hypnotic Grifter connives
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Hypnotic Grifter");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
|
||||
// Target opponent loses 3 life and you gain 3 life.
|
||||
// Madness {B}
|
||||
addCard(Zone.HAND, playerA, "Alms of the Vein", 1); // To discard and use mad
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}");
|
||||
setChoice(playerA, "Alms of the Vein");
|
||||
setChoice(playerA, "Yes"); // Cast for Madness
|
||||
addTarget(playerA, playerB); // Target for Alms of the Vein
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPowerToughness(playerA, "Hypnotic Grifter", 2, 3); // Discarded a non-land
|
||||
assertHandCount(playerA, 1); // 1 from drawing at start of turn
|
||||
assertGraveyardCount(playerA, "Alms of the Vein", 1);
|
||||
|
||||
assertLife(playerA, 23); // 3 life gained from Alms of the Vein
|
||||
assertLife(playerB, 17); // 3 life lost from Alms of the Vein
|
||||
}
|
||||
|
||||
/**
|
||||
* Obscura Confluence allows you to connive a creature you don't control.
|
||||
* It's the only card that causes you to coonnive a creature you don't control.
|
||||
*/
|
||||
@Test
|
||||
public void conniveNonControlledCreature() {
|
||||
// Choose three. You may choose the same mode more than once.
|
||||
//• Until end of turn, target creature loses all abilities and has base power and toughness 1/1.
|
||||
//• Target creature connives. (Draw a card, then discard a card. If you discarded a nonland card, put a +1/+1 counter on that creature.)
|
||||
//• Target player returns a creature card from their graveyard to their hand.
|
||||
addCard(Zone.HAND, playerA, "Obscura Confluence"); // {1}{W}{U}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||
|
||||
addCard(Zone.HAND, playerB, "Plains", 3); // 3 land cards for conniving
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Crazed Goblin"); // 1/1 creature that is made to connive
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Obscura Confluence");
|
||||
setModeChoice(playerA, "2");
|
||||
setModeChoice(playerA, "2");
|
||||
setModeChoice(playerA, "2");
|
||||
addTarget(playerA, "Crazed Goblin");
|
||||
addTarget(playerA, "Crazed Goblin");
|
||||
addTarget(playerA, "Crazed Goblin");
|
||||
setChoice(playerB, "Plains");
|
||||
setChoice(playerB, "Plains");
|
||||
setChoice(playerB, "Plains");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPowerToughness(playerB, "Crazed Goblin", 1, 1); // Discarded only lands
|
||||
assertGraveyardCount(playerB, "Plains", 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reported bug: https://github.com/magefree/mage/issues/9252
|
||||
* Connive fizzles if the creature that connived leaves the battlefield before connive resolves.
|
||||
*
|
||||
* Ruling:
|
||||
* If a resolving spell or ability instructs a specific creature to connive but that creature has left the battlefield,
|
||||
* the creature still connives.
|
||||
* If you discard a nonland card this way, you won’t put a +1/+1 counter on anything.
|
||||
* Abilities that trigger “when [that creature] connives” will trigger.
|
||||
* (2022-04-29)
|
||||
*/
|
||||
@Test
|
||||
public void conniveDoesNotFizzle() {
|
||||
// {4}{U}
|
||||
// 3/2
|
||||
// When Psychic Pickpocket enters the battlefield, it connives.
|
||||
// When it connives this way, return up to one target nonland permanent to its owner’s hand.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||
addCard(Zone.HAND, playerA, "Psychic Pickpocket");
|
||||
addCard(Zone.HAND, playerA, "Swamp");
|
||||
|
||||
addCard(Zone.HAND, playerB, "Lightning Bolt");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Sol Ring"); // Target for Psychic Pickpocket
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Psychic Pickpocket");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); // Wait for ETB
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Psychic Pickpocket", "When");
|
||||
setChoice(playerA, "Swamp"); // Discard for connive
|
||||
addTarget(playerA, "Sol Ring"); // Target for Psychic Pickpocket
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertHandCount(playerA, 1); // Drew a card at start of turn
|
||||
assertHandCount(playerB, "Sol Ring", 1); // Returned by Psychic Pickpocket's ability
|
||||
assertGraveyardCount(playerA, "Swamp", 1); // Connived
|
||||
assertGraveyardCount(playerA, "Psychic Pickpocket", 1); // Destroyed by Lightning Bolt
|
||||
assertGraveyardCount(playerB, "Lightning Bolt", 1);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import mage.abilities.Mode;
|
|||
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
|
@ -48,19 +49,26 @@ public class ConniveSourceEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent != null) {
|
||||
connive(permanent, 1, source, game);
|
||||
}
|
||||
boolean connived = connive(permanent, 1, source, game);
|
||||
if (ability != null) {
|
||||
game.fireReflexiveTriggeredAbility(ability, source);
|
||||
}
|
||||
return permanent != null || ability != null;
|
||||
return connived || ability != null;
|
||||
}
|
||||
|
||||
public static boolean connive(Permanent permanent, int amount, Ability source, Game game) {
|
||||
if (amount < 1) {
|
||||
return false;
|
||||
}
|
||||
boolean permanentStillOnBattlefield;
|
||||
if (permanent == null) {
|
||||
// If the permanent was killed, get last known information
|
||||
permanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
|
||||
permanentStillOnBattlefield = false;
|
||||
} else {
|
||||
permanentStillOnBattlefield = true;
|
||||
}
|
||||
|
||||
Player player = game.getPlayer(permanent.getControllerId());
|
||||
if (player == null) {
|
||||
return false;
|
||||
|
@ -69,7 +77,7 @@ public class ConniveSourceEffect extends OneShotEffect {
|
|||
int counters = player
|
||||
.discard(amount, false, false, source, game)
|
||||
.count(StaticFilters.FILTER_CARDS_NON_LAND, game);
|
||||
if (counters > 0) {
|
||||
if (permanentStillOnBattlefield && counters > 0) {
|
||||
permanent.addCounters(CounterType.P1P1.createInstance(counters), source, game);
|
||||
}
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue