Implement [MKM] Connecting the Dots; [PIP] Expert-Level Safe; related refactoring (#11922)

* Switch to common class for exiling top cards of your library

* Replace some custom classes with ReturnFromExileForSourceEffect; text-gen additions to that Effect

* Knowledge Vault: add tap cost to 1st ability, fix text on 3rd ability; Petradon: remove unused import

* [MKM] Implement Connecting the Dots

* [PIP] Implement Expert-Level Safe

* Set staticText in constructor

* Use {this} in Expert-Level Safe text

* Use createObjectRealtedWindowTitle for exile names

* Remove unnecessary field
This commit is contained in:
Cameron Merkel 2024-03-10 23:16:42 -05:00 committed by GitHub
parent 3945528d40
commit a7f808afb6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 308 additions and 366 deletions

View file

@ -0,0 +1,100 @@
package mage.abilities.effects.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
/**
* @author Cguy7777
*/
public class ExileCardsFromTopOfLibraryControllerEffect extends OneShotEffect {
private final int amount;
private final boolean toUniqueExileZone;
private final boolean faceDown;
public ExileCardsFromTopOfLibraryControllerEffect(int amount) {
this(amount, false);
}
public ExileCardsFromTopOfLibraryControllerEffect(int amount, boolean toUniqueExileZone) {
this(amount, toUniqueExileZone, false);
}
public ExileCardsFromTopOfLibraryControllerEffect(int amount, boolean toUniqueExileZone, boolean faceDown) {
this(amount, toUniqueExileZone, faceDown, false);
}
/**
* @param amount number of cards to exile
* @param toUniqueExileZone moves the card to a source object dependant
* unique exile zone, so another effect of the same source object (e.g.
* Theater of Horrors) can identify the card
* @param faceDown if true, cards are exiled face down
* @param withFaceDownReminderText if true, add the reminder text for exiling one face down card
*/
public ExileCardsFromTopOfLibraryControllerEffect(int amount, boolean toUniqueExileZone, boolean faceDown, boolean withFaceDownReminderText) {
super(Outcome.Exile);
this.amount = amount;
this.toUniqueExileZone = toUniqueExileZone;
this.faceDown = faceDown;
staticText = "exile the top "
+ ((amount > 1) ? CardUtil.numberToText(amount) + " cards" : "card")
+ " of your library"
+ (faceDown ? " face down" : "")
+ (withFaceDownReminderText ? ". <i>(You can't look at it.)</i>" : "");
}
protected ExileCardsFromTopOfLibraryControllerEffect(final ExileCardsFromTopOfLibraryControllerEffect effect) {
super(effect);
this.amount = effect.amount;
this.toUniqueExileZone = effect.toUniqueExileZone;
this.faceDown = effect.faceDown;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
UUID exileZoneId = null;
String exileZoneName = "";
if (toUniqueExileZone) {
MageObject sourceObject = source.getSourceObject(game);
if (sourceObject == null) {
return false;
}
exileZoneId = CardUtil.getExileZoneId(game, source);
exileZoneName = CardUtil.createObjectRealtedWindowTitle(source, game, null);
}
Set<Card> cards = controller.getLibrary().getTopCards(game, amount);
if (cards.isEmpty()) {
return true;
}
boolean exiledSuccessfully = false;
for (Card card : cards) {
card.setFaceDown(faceDown, game);
exiledSuccessfully |= controller.moveCardsToExile(card, source, game, !faceDown, exileZoneId, exileZoneName);
card.setFaceDown(faceDown, game);
}
return exiledSuccessfully;
}
@Override
public ExileCardsFromTopOfLibraryControllerEffect copy() {
return new ExileCardsFromTopOfLibraryControllerEffect(this);
}
}

View file

@ -22,6 +22,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect {
private final Zone returnToZone;
private boolean pluralCards;
private boolean pluralOwners;
private boolean putPhrasing;
/**
* @param zone Zone the card should return to
@ -31,6 +32,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect {
this.returnToZone = zone;
this.pluralCards = false;
this.pluralOwners = false;
this.putPhrasing = false;
updateText();
}
@ -39,6 +41,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect {
this.returnToZone = effect.returnToZone;
this.pluralCards = effect.pluralCards;
this.pluralOwners = effect.pluralOwners;
this.putPhrasing = effect.putPhrasing;
}
@Override
@ -77,16 +80,22 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect {
return true;
}
public ReturnFromExileForSourceEffect withText(boolean pluralCards, boolean pluralOwners) {
public ReturnFromExileForSourceEffect withText(boolean pluralCards, boolean pluralOwners, boolean putPhrasing) {
this.pluralCards = pluralCards;
this.pluralOwners = pluralOwners;
this.putPhrasing = putPhrasing;
updateText();
return this;
}
private void updateText() {
StringBuilder sb = new StringBuilder();
sb.append("return the exiled ").append(pluralCards ? "cards" : "card").append(" to ");
if (putPhrasing) {
sb.append("put ").append(pluralCards ? "all cards " : "the card ").append("exiled with {this} ");
sb.append(returnToZone == Zone.BATTLEFIELD ? "onto " : "into ");
} else {
sb.append("return the exiled ").append(pluralCards ? "cards" : "card").append(" to ");
}
if (returnToZone == Zone.BATTLEFIELD) {
sb.append("the battlefield under ");
}