mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 05:22:02 -08:00
[AFR] Implemented Xanathar, Guild Kingpin (#8045)
* [AFR] Implemented Xanathar, Guild Kingpin Co-authored-by: Oleg Agafonov <jaydi85@gmail.com>
This commit is contained in:
parent
65761b085f
commit
f03a410b9e
25 changed files with 477 additions and 55 deletions
|
|
@ -4,48 +4,102 @@ import mage.MageObject;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class LookAtTopCardOfLibraryAnyTimeEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final TargetController targetLibrary;
|
||||
|
||||
public LookAtTopCardOfLibraryAnyTimeEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
|
||||
staticText = "You may look at the top card of your library any time.";
|
||||
this(TargetController.YOU, Duration.WhileOnBattlefield);
|
||||
}
|
||||
|
||||
private LookAtTopCardOfLibraryAnyTimeEffect(final LookAtTopCardOfLibraryAnyTimeEffect effect) {
|
||||
public LookAtTopCardOfLibraryAnyTimeEffect(TargetController targetLibrary, Duration duration) {
|
||||
super(duration, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
|
||||
this.targetLibrary = targetLibrary;
|
||||
|
||||
String libInfo;
|
||||
switch (this.targetLibrary) {
|
||||
case YOU:
|
||||
libInfo = "your library";
|
||||
break;
|
||||
case OPPONENT:
|
||||
libInfo = "opponents libraries";
|
||||
break;
|
||||
case SOURCE_TARGETS:
|
||||
libInfo = "target player's library";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown target library type: " + targetLibrary);
|
||||
}
|
||||
staticText = duration.toString().isEmpty() ? "" : duration + " you may look at the top card of " + libInfo + " any time.";
|
||||
}
|
||||
|
||||
protected LookAtTopCardOfLibraryAnyTimeEffect(final LookAtTopCardOfLibraryAnyTimeEffect effect) {
|
||||
super(effect);
|
||||
this.targetLibrary = effect.targetLibrary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (game.inCheckPlayableState()) { // Ignored - see https://github.com/magefree/mage/issues/6994
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Card topCard = controller.getLibrary().getFromTop(game);
|
||||
if (topCard == null) {
|
||||
if (!canLookAtNextTopLibraryCard(game)) {
|
||||
return false;
|
||||
}
|
||||
MageObject obj = source.getSourceObject(game);
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!canLookAtNextTopLibraryCard(game)) {
|
||||
|
||||
Set<UUID> needPlayers = new HashSet<>();
|
||||
switch (this.targetLibrary) {
|
||||
case YOU: {
|
||||
needPlayers.add(source.getControllerId());
|
||||
break;
|
||||
}
|
||||
case OPPONENT: {
|
||||
needPlayers.addAll(game.getOpponents(source.getControllerId()));
|
||||
break;
|
||||
}
|
||||
case SOURCE_TARGETS: {
|
||||
needPlayers.addAll(CardUtil.getAllSelectedTargets(source, game));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Set<Card> needCards = new HashSet<>();
|
||||
needPlayers.stream()
|
||||
.map(game::getPlayer)
|
||||
.filter(Objects::nonNull)
|
||||
.map(player -> player.getLibrary().getFromTop(game))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(needCards::add);
|
||||
if (needCards.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
controller.lookAtCards("Top card of " + obj.getIdName() + " controller's library", topCard, game);
|
||||
|
||||
// all fine, can show top card
|
||||
needCards.forEach(topCard -> {
|
||||
Player owner = game.getPlayer(topCard.getOwnerId());
|
||||
controller.lookAtCards(String.format("%s: top card of %s", obj.getName(), owner == null ? "error" : owner.getName()), topCard, game);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.TargetController;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class LookAtTopCardOfLibraryAnyTimeTargetEffect extends LookAtTopCardOfLibraryAnyTimeEffect {
|
||||
|
||||
public LookAtTopCardOfLibraryAnyTimeTargetEffect(Duration duration) {
|
||||
super(TargetController.SOURCE_TARGETS, duration);
|
||||
}
|
||||
|
||||
private LookAtTopCardOfLibraryAnyTimeTargetEffect(final LookAtTopCardOfLibraryAnyTimeTargetEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LookAtTopCardOfLibraryAnyTimeTargetEffect copy() {
|
||||
return new LookAtTopCardOfLibraryAnyTimeTargetEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,11 +6,14 @@ import mage.cards.Card;
|
|||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
|
@ -19,20 +22,44 @@ import java.util.UUID;
|
|||
public class PlayTheTopCardEffect extends AsThoughEffectImpl {
|
||||
|
||||
private final FilterCard filter;
|
||||
private final TargetController targetLibrary;
|
||||
|
||||
// can play card or can play lands/cast spells, see two modes below
|
||||
private final boolean canPlayCardOnly;
|
||||
|
||||
|
||||
/**
|
||||
* Support targets, use TargetController.SOURCE_TARGETS
|
||||
*/
|
||||
public PlayTheTopCardEffect() {
|
||||
this(new FilterCard("play lands and cast spells"), false);
|
||||
this(TargetController.YOU);
|
||||
}
|
||||
|
||||
public PlayTheTopCardEffect(FilterCard filter, boolean canPlayCardOnly) {
|
||||
public PlayTheTopCardEffect(TargetController targetLibrary) {
|
||||
this(targetLibrary, new FilterCard("play lands and cast spells"), false);
|
||||
}
|
||||
|
||||
public PlayTheTopCardEffect(TargetController targetLibrary, FilterCard filter, boolean canPlayCardOnly) {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
this.filter = filter;
|
||||
this.targetLibrary = targetLibrary;
|
||||
this.canPlayCardOnly = canPlayCardOnly;
|
||||
this.staticText = "You may " + filter.getMessage() + " from the top of your library";
|
||||
|
||||
String libInfo;
|
||||
switch (this.targetLibrary) {
|
||||
case YOU:
|
||||
libInfo = "your library";
|
||||
break;
|
||||
case OPPONENT:
|
||||
libInfo = "opponents libraries";
|
||||
break;
|
||||
case SOURCE_TARGETS:
|
||||
libInfo = "target player's library";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown target library type: " + targetLibrary);
|
||||
}
|
||||
this.staticText = "You may " + filter.getMessage() + " from the top of " + libInfo;
|
||||
|
||||
// verify check: if you see "card" text in the rules then use card mode
|
||||
// (there aren't any real cards after oracle update, but can be added in the future)
|
||||
|
|
@ -44,6 +71,7 @@ public class PlayTheTopCardEffect extends AsThoughEffectImpl {
|
|||
public PlayTheTopCardEffect(final PlayTheTopCardEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.targetLibrary = effect.targetLibrary;
|
||||
this.canPlayCardOnly = effect.canPlayCardOnly;
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +99,7 @@ public class PlayTheTopCardEffect extends AsThoughEffectImpl {
|
|||
}
|
||||
|
||||
if (this.canPlayCardOnly) {
|
||||
// check whole card intead part
|
||||
// check whole card instead part
|
||||
cardToCheck = cardToCheck.getMainCard();
|
||||
}
|
||||
|
||||
|
|
@ -80,16 +108,50 @@ public class PlayTheTopCardEffect extends AsThoughEffectImpl {
|
|||
return false;
|
||||
}
|
||||
|
||||
// must be your card
|
||||
Player player = game.getPlayer(cardToCheck.getOwnerId());
|
||||
if (player == null || !player.getId().equals(affectedControllerId)) {
|
||||
Player cardOwner = game.getPlayer(cardToCheck.getOwnerId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (cardOwner == null || controller == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// must be from your library
|
||||
Card topCard = player.getLibrary().getFromTop(game);
|
||||
if (topCard == null || !topCard.getId().equals(cardToCheck.getMainCard().getId())) {
|
||||
return false;
|
||||
// must be your or opponents library
|
||||
switch (this.targetLibrary) {
|
||||
case YOU: {
|
||||
Card topCard = controller.getLibrary().getFromTop(game);
|
||||
if (topCard == null || !topCard.getId().equals(cardToCheck.getMainCard().getId())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OPPONENT: {
|
||||
if (!game.getOpponents(controller.getId()).contains(cardOwner.getId())) {
|
||||
return false;
|
||||
}
|
||||
Card topCard = cardOwner.getLibrary().getFromTop(game);
|
||||
if (topCard == null || !topCard.getId().equals(cardToCheck.getMainCard().getId())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SOURCE_TARGETS: {
|
||||
UUID needCardId = cardToCheck.getMainCard().getId();
|
||||
if (CardUtil.getAllSelectedTargets(source, game).stream()
|
||||
.map(game::getPlayer)
|
||||
.filter(Objects::nonNull)
|
||||
.noneMatch(player -> {
|
||||
Card topCard = player.getLibrary().getFromTop(game);
|
||||
return topCard != null && topCard.getId().equals(needCardId);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// can't cast without mana cost
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import mage.constants.TargetController;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class PlayTheTopCardTargetEffect extends PlayTheTopCardEffect {
|
||||
|
||||
public PlayTheTopCardTargetEffect() {
|
||||
super(TargetController.SOURCE_TARGETS);
|
||||
}
|
||||
|
||||
public PlayTheTopCardTargetEffect(final PlayTheTopCardTargetEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayTheTopCardTargetEffect copy() {
|
||||
return new PlayTheTopCardTargetEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ public enum Outcome {
|
|||
PutManaInPool(true),
|
||||
Regenerate(true),
|
||||
PreventDamage(true), // TODO: check good or bad
|
||||
PreventCast(false), // TODO: check good or bad
|
||||
PreventCast(false),
|
||||
RedirectDamage(true), // TODO: check good or bad
|
||||
Tap(false),
|
||||
Transform(true),
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ public enum TargetController {
|
|||
OWNER,
|
||||
CONTROLLER_ATTACHED_TO,
|
||||
NEXT,
|
||||
EACH_PLAYER;
|
||||
EACH_PLAYER,
|
||||
SOURCE_TARGETS;
|
||||
|
||||
private final OwnerPredicate ownerPredicate;
|
||||
private final PlayerPredicate playerPredicate;
|
||||
|
|
|
|||
|
|
@ -11,11 +11,24 @@ import mage.players.Player;
|
|||
*/
|
||||
|
||||
public enum CardOnTopOfLibraryPredicate implements ObjectPlayerPredicate<ObjectPlayer<Card>> {
|
||||
instance;
|
||||
YOUR,
|
||||
ANY;
|
||||
|
||||
@Override
|
||||
public boolean apply(ObjectPlayer<Card> input, Game game) {
|
||||
Player player = game.getPlayer(input.getObject().getOwnerId());
|
||||
|
||||
Player player;
|
||||
switch (this) {
|
||||
case YOUR:
|
||||
player = game.getPlayer(input.getPlayerId());
|
||||
break;
|
||||
|
||||
case ANY:
|
||||
default:
|
||||
player = game.getPlayer(input.getObject().getOwnerId());
|
||||
break;
|
||||
}
|
||||
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue