mirror of
https://github.com/magefree/mage.git
synced 2025-12-21 19:11:59 -08:00
rework Ghastly Conscription and Jeskai Infiltrator to common manifest code (#11898)
This commit is contained in:
parent
1c38644a5d
commit
9893032a36
4 changed files with 85 additions and 87 deletions
|
|
@ -1,18 +1,12 @@
|
|||
package mage.cards.g;
|
||||
|
||||
import java.util.*;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect;
|
||||
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect.FaceDownType;
|
||||
import mage.abilities.effects.keyword.ManifestEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
|
|
@ -20,6 +14,8 @@ import mage.game.Game;
|
|||
import mage.players.Player;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
|
|
@ -48,7 +44,10 @@ class GhastlyConscriptionEffect extends OneShotEffect {
|
|||
|
||||
GhastlyConscriptionEffect() {
|
||||
super(Outcome.PutCreatureInPlay);
|
||||
this.staticText = "Exile all creature cards from target player's graveyard in a face-down pile, shuffle that pile, then manifest those cards.<i> (To manifest a card, put it onto the battlefield face down as a 2/2 creature. Turn it face up at any time for its mana cost if it's a creature card.)</i>";
|
||||
this.staticText = "Exile all creature cards from target player's graveyard in a face-down pile, " +
|
||||
"shuffle that pile, then manifest those cards. " +
|
||||
"<i>(To manifest a card, put it onto the battlefield face down as a 2/2 creature. " +
|
||||
"Turn it face up at any time for its mana cost if it's a creature card.)</i>";
|
||||
}
|
||||
|
||||
private GhastlyConscriptionEffect(final GhastlyConscriptionEffect effect) {
|
||||
|
|
@ -62,39 +61,24 @@ class GhastlyConscriptionEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// TODO: migrate to shared manifested code
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
if (controller != null && targetPlayer != null) {
|
||||
if (controller == null || targetPlayer == null) {
|
||||
return false;
|
||||
}
|
||||
List<Card> cardsToManifest = new ArrayList<>();
|
||||
for (Card card : targetPlayer.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game)) {
|
||||
cardsToManifest.add(card);
|
||||
controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.GRAVEYARD, true);
|
||||
card.setFaceDown(true, game);
|
||||
}
|
||||
if (cardsToManifest.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
Collections.shuffle(cardsToManifest);
|
||||
game.informPlayers(controller.getLogName() + " shuffles the face-down pile");
|
||||
Ability newSource = source.copy();
|
||||
newSource.setWorksFaceDown(true);
|
||||
for (Card card : cardsToManifest) {
|
||||
ManaCosts manaCosts = null;
|
||||
if (card.isCreature(game)) {
|
||||
manaCosts = card.getSpellAbility() != null ? card.getSpellAbility().getManaCosts() : null;
|
||||
if (manaCosts == null) {
|
||||
manaCosts = new ManaCostsImpl<>("{0}");
|
||||
}
|
||||
}
|
||||
Card battlefieldCard = BecomesFaceDownCreatureEffect.findDefaultCardSideForFaceDown(game, card);
|
||||
MageObjectReference objectReference = new MageObjectReference(battlefieldCard.getId(), battlefieldCard.getZoneChangeCounter(game) + 1, game);
|
||||
game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource);
|
||||
}
|
||||
Set<Card> toBattlefield = new LinkedHashSet();
|
||||
toBattlefield.addAll(cardsToManifest);
|
||||
controller.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game, false, true, false, null);
|
||||
game.getState().processAction(game);
|
||||
ManifestEffect.doManifestCards(game, source, controller, new LinkedHashSet<>(cardsToManifest));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,25 @@
|
|||
|
||||
package mage.cards.j;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.common.CreatureCountCondition;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.decorator.ConditionalRestrictionEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect;
|
||||
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect;
|
||||
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect.FaceDownType;
|
||||
import mage.abilities.effects.keyword.ManifestEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.ExileZone;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
|
|
@ -81,38 +70,31 @@ class JeskaiInfiltratorEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// TODO: migrade to shared manifest code
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Set<Card> cardsToManifest = new HashSet<>();
|
||||
cardsToManifest.add(source.getSourcePermanentIfItStillExists(game));
|
||||
cardsToManifest.add(controller.getLibrary().getFromTop(game));
|
||||
UUID exileId = UUID.randomUUID();
|
||||
controller.moveCardsToExile(cardsToManifest, source, game, false, exileId, "");
|
||||
ExileZone exileZone = game.getExile().getExileZone(exileId);
|
||||
for (Card card : exileZone.getCards(game)) {
|
||||
card.setFaceDown(true, game);
|
||||
}
|
||||
game.fireUpdatePlayersEvent(); // removes Jeskai Infiltrator from Battlefield, so Jeskai Infiltrator returns as a fresh permanent to the battlefield with new position
|
||||
|
||||
Ability newSource = source.copy();
|
||||
newSource.setWorksFaceDown(true);
|
||||
//the Set will mimic the Shuffling
|
||||
exileZone.getCards(game).forEach(card -> {
|
||||
ManaCosts manaCosts = null;
|
||||
if (card.isCreature(game)) {
|
||||
manaCosts = card.getSpellAbility() != null ? card.getSpellAbility().getManaCosts() : null;
|
||||
if (manaCosts == null) {
|
||||
manaCosts = new ManaCostsImpl<>("{0}");
|
||||
}
|
||||
}
|
||||
Card battlefieldCard = BecomesFaceDownCreatureEffect.findDefaultCardSideForFaceDown(game, card);
|
||||
MageObjectReference objectReference = new MageObjectReference(battlefieldCard.getId(), battlefieldCard.getZoneChangeCounter(game) + 1, game);
|
||||
game.addEffect(new BecomesFaceDownCreatureEffect(manaCosts, objectReference, Duration.Custom, FaceDownType.MANIFESTED), newSource);
|
||||
});
|
||||
controller.moveCards(exileZone.getCards(game), Zone.BATTLEFIELD, source, game, false, true, false, null);
|
||||
return true;
|
||||
}
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
UUID exileId = UUID.randomUUID();
|
||||
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (sourcePermanent != null) {
|
||||
controller.moveCardsToExile(sourcePermanent, source, game, false, exileId, "");
|
||||
}
|
||||
Card topCard = controller.getLibrary().getFromTop(game);
|
||||
if (topCard != null) {
|
||||
controller.moveCardsToExile(topCard, source, game, false, exileId, "");
|
||||
}
|
||||
// need to get source permanent as card rather than permanent for next steps, hence this convoluted code
|
||||
List<Card> cardsToManifest = new ArrayList<>(game.getExile().getExileZone(exileId).getCards(game));
|
||||
if (cardsToManifest.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (Card card : cardsToManifest) {
|
||||
card.setFaceDown(true, game);
|
||||
}
|
||||
Collections.shuffle(cardsToManifest);
|
||||
game.informPlayers(controller.getLogName() + " shuffles the face-down pile");
|
||||
game.getState().processAction(game);
|
||||
ManifestEffect.doManifestCards(game, source, controller, new LinkedHashSet<>(cardsToManifest));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,8 +151,8 @@ public class ManifestTest extends CardTestPlayerBase {
|
|||
} else {
|
||||
String realPermanentName = currentGame.getBattlefield().getAllPermanents()
|
||||
.stream()
|
||||
.filter(p -> p.getName().equals(cardAfterBlink))
|
||||
.map(MageObject::getName)
|
||||
.filter(name -> name.equals(cardAfterBlink))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
Assert.assertEquals("after blink card must go to battlefield",
|
||||
|
|
@ -818,4 +818,36 @@ public class ManifestTest extends CardTestPlayerBase {
|
|||
permanent = findFaceDownPermanent(currentGame, playerB, playerB);
|
||||
assertFaceDownManifest("end game: must show for yourself", permanent, "Mountain", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJeskaiInfiltrator() {
|
||||
// Whenever Jeskai Infiltrator deals combat damage to a player,
|
||||
// exile it and the top card of your library in a face-down pile, shuffle that pile, then manifest those cards.
|
||||
String infiltrator = "Jeskai Infiltrator"; // 2/3
|
||||
String excommunicate = "Excommunicate"; // 2W Sorcery, Put target creature on top of its owner's library
|
||||
String missionary = "Lone Missionary"; // 2/1 for 1W, ETB gain 4 life
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8);
|
||||
addCard(Zone.BATTLEFIELD, playerA, infiltrator);
|
||||
addCard(Zone.BATTLEFIELD, playerA, missionary);
|
||||
addCard(Zone.HAND, playerA, excommunicate);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, excommunicate, missionary);
|
||||
|
||||
attack(1, playerA, infiltrator, playerB);
|
||||
|
||||
checkPlayableAbility("missionary manifest",1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}{W}: Turn ", true);
|
||||
checkPlayableAbility("infiltrator manifest",1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}{U}: Turn ", true);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, excommunicate, 1);
|
||||
assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2);
|
||||
assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2);
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 18);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ public class ManifestEffect extends OneShotEffect {
|
|||
permanent.setManifested(true);
|
||||
} else {
|
||||
// TODO: looks buggy, card can't be moved to battlefield, but face down effect already active
|
||||
// or it can be face down on another move to battalefield
|
||||
// or it can be face down on another move to battlefield
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue