mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00: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
|
@ -9,6 +9,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterCard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -36,7 +37,7 @@ public final class ConspicuousSnoop extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect()));
|
||||
|
||||
// You may cast Goblin spells from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
|
||||
// As long as the top card of your library is a Goblin card, Conspicuous Snoop has all activated abilities of that card.
|
||||
this.addAbility(new SimpleStaticAbility(new GainActivatedAbilitiesOfTopCardEffect(filter.copy().withMessage("a Goblin card"))));
|
||||
|
|
|
@ -10,6 +10,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterLandCard;
|
||||
|
@ -34,7 +35,7 @@ public final class CourserOfKruphix extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect()));
|
||||
|
||||
// You may play lands from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
|
||||
// Whenever a land enters the battlefield under your control, you gain 1 life.
|
||||
this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new GainLifeEffect(1), StaticFilters.FILTER_LAND_A));
|
||||
|
|
|
@ -9,10 +9,7 @@ import mage.abilities.effects.common.continuous.PlayTheTopCardEffect;
|
|||
import mage.abilities.keyword.ProwessAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterNonlandCard;
|
||||
import mage.filter.predicate.Predicates;
|
||||
|
@ -29,7 +26,7 @@ public final class ElshaOfTheInfinite extends CardImpl {
|
|||
|
||||
static {
|
||||
filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
|
||||
filter.add(CardOnTopOfLibraryPredicate.instance);
|
||||
filter.add(CardOnTopOfLibraryPredicate.YOUR);
|
||||
}
|
||||
|
||||
public ElshaOfTheInfinite(UUID ownerId, CardSetInfo setInfo) {
|
||||
|
@ -48,7 +45,7 @@ public final class ElshaOfTheInfinite extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||
|
||||
// You may cast noncreature spells from the top of your library. If you cast a spell this way, you may cast it as though it had flash.
|
||||
Ability ability = new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false));
|
||||
Ability ability = new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false));
|
||||
ability.addEffect(new CastAsThoughItHadFlashAllEffect(
|
||||
Duration.WhileOnBattlefield, filter
|
||||
).setText("If you cast a spell this way, you may cast it as though it had flash."));
|
||||
|
|
|
@ -55,7 +55,7 @@ public final class GaleaKindlerOfHope extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||
|
||||
// You may cast Aura and Equipment spells from the top of your library. When you cast an Equipment spell this way, it gains "When this Equipment enters the battlefield, attach it to target creature you control."
|
||||
Ability ability = new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false));
|
||||
Ability ability = new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false));
|
||||
ability.addEffect(new InfoEffect("When you cast an Equipment spell this way, it gains " +
|
||||
"\"When this Equipment enters the battlefield, attach it to target creature you control.\""));
|
||||
this.addAbility(ability);
|
||||
|
|
|
@ -9,6 +9,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
|
||||
|
@ -35,7 +36,7 @@ public final class GarruksHorde extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect()));
|
||||
|
||||
// You may cast creature spells from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
}
|
||||
|
||||
private GarruksHorde(final GarruksHorde card) {
|
||||
|
|
|
@ -9,10 +9,7 @@ import mage.abilities.effects.common.continuous.PlayTheTopCardEffect;
|
|||
import mage.abilities.effects.common.continuous.PlayWithTheTopCardRevealedEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.game.Game;
|
||||
|
@ -49,7 +46,7 @@ public final class MelekIzzetParagon extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithTheTopCardRevealedEffect()));
|
||||
|
||||
// You may cast instant and sorcery spells from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
|
||||
// Whenever you cast an instant or sorcery spell from your library, copy it. You may choose new targets for the copy.
|
||||
this.addAbility(new MelekIzzetParagonTriggeredAbility());
|
||||
|
|
|
@ -12,6 +12,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterNonlandCard;
|
||||
|
@ -43,7 +44,7 @@ public final class MysticForge extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||
|
||||
// You may cast artifact spells and colorless spells from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
|
||||
// {T}, Pay 1 life: Exile the top card of your library.
|
||||
Ability ability = new SimpleActivatedAbility(new MysticForgeExileEffect(), new TapSourceCost());
|
||||
|
|
|
@ -10,6 +10,7 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterLandCard;
|
||||
|
||||
|
@ -39,7 +40,7 @@ public final class OracleOfMulDaya extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect()));
|
||||
|
||||
// You may play lands from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
}
|
||||
|
||||
private OracleOfMulDaya(final OracleOfMulDaya card) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.Predicates;
|
||||
|
@ -41,7 +42,7 @@ public final class PrecognitionField extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||
|
||||
// You may cast instant and sorcery spells from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
|
||||
// {3}: Exile the top card of your library.
|
||||
this.addAbility(new SimpleActivatedAbility(new PrecognitionFieldExileEffect(), new GenericManaCost(3)));
|
||||
|
|
|
@ -16,10 +16,7 @@ import mage.abilities.hint.common.MyTurnHint;
|
|||
import mage.abilities.keyword.FirstStrikeAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterLandCard;
|
||||
|
@ -51,7 +48,7 @@ public final class RadhaHeartOfKeld extends CardImpl {
|
|||
// You may look at the top card of your library any time, and you may play lands from the top of your library.
|
||||
LookAtTopCardOfLibraryAnyTimeEffect lookEffect = new LookAtTopCardOfLibraryAnyTimeEffect();
|
||||
lookEffect.setText("You may look at the top card of your library any time");
|
||||
PlayTheTopCardEffect playEffect = new PlayTheTopCardEffect(filter, false);
|
||||
PlayTheTopCardEffect playEffect = new PlayTheTopCardEffect(TargetController.YOU, filter, false);
|
||||
playEffect.setText(", and you may play lands from the top of your library");
|
||||
|
||||
SimpleStaticAbility lookAndPlayAbility = new SimpleStaticAbility(lookEffect);
|
||||
|
|
|
@ -15,6 +15,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
|
@ -61,7 +62,7 @@ public final class RangerClass extends CardImpl {
|
|||
|
||||
// You may cast creature spells from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(
|
||||
new PlayTheTopCardEffect(filter, false), 3
|
||||
new PlayTheTopCardEffect(TargetController.YOU, filter, false), 3
|
||||
)));
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.filter.predicate.mageobject.ChosenSubtypePredicate;
|
||||
|
||||
|
@ -45,7 +46,7 @@ public final class Realmwalker extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||
|
||||
// You may cast creature spells of the chosen type from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
}
|
||||
|
||||
private Realmwalker(final Realmwalker card) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
|
@ -58,7 +59,7 @@ class VergeRangersEffect extends PlayTheTopCardEffect {
|
|||
private static final FilterCard filter = new FilterLandCard("play lands");
|
||||
|
||||
public VergeRangersEffect() {
|
||||
super(filter, false);
|
||||
super(TargetController.YOU, filter, false);
|
||||
staticText = "As long as an opponent controls more lands than you, you may play lands from the top of your library";
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public final class VivienMonstersAdvocate extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||
|
||||
// You may cast creature spells from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
|
||||
// +1: Create a 3/3 green Beast creature token. Put your choice of a vigilance
|
||||
// counter, a reach counter, or a trample counter on it.
|
||||
|
|
|
@ -37,7 +37,7 @@ public final class VizierOfTheMenagerie extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||
|
||||
// You may cast creature spells from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(filter, false)));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(TargetController.YOU, filter, false)));
|
||||
|
||||
// You may spend mana as though it were mana of any type to cast creature spells.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VizierOfTheMenagerieManaEffect()));
|
||||
|
|
185
Mage.Sets/src/mage/cards/x/XanatharGuildKingpin.java
Normal file
185
Mage.Sets/src/mage/cards/x/XanatharGuildKingpin.java
Normal file
|
@ -0,0 +1,185 @@
|
|||
package mage.cards.x;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.AsThoughManaEffect;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.PlayTheTopCardTargetEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.ManaPoolItem;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetOpponent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author raphael-schulz
|
||||
*/
|
||||
public final class XanatharGuildKingpin extends CardImpl {
|
||||
|
||||
public XanatharGuildKingpin(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{B}");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.BEHOLDER);
|
||||
|
||||
this.power = new MageInt(5);
|
||||
this.toughness = new MageInt(6);
|
||||
|
||||
// At the beginning of your upkeep, choose target opponent. Until end of turn, that player can’t cast spells, you may look at the top card of their library any time, you may play the top card of their library, and you may spend mana as though it were mana of any color to cast spells this way.
|
||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(
|
||||
Zone.BATTLEFIELD, new XanatharGuildKingpinRuleModifyingEffect()
|
||||
.setText("choose target opponent. Until end of turn, that player can't cast spells,"),
|
||||
TargetController.YOU, false
|
||||
);
|
||||
ability.addEffect(new LookAtTopCardOfLibraryAnyTimeTargetEffect(Duration.EndOfTurn)
|
||||
.setText(" you may look at the top card of their library any time,"));
|
||||
ability.addEffect(new PlayTheTopCardTargetEffect()
|
||||
.setText(" you may play the top card of their library,"));
|
||||
ability.addEffect(new XanatharGuildKingpinSpendManaAsAnyColorOneShotEffect()
|
||||
.setText(" and you may spend mana as thought it were mana of any color to cast spells this way"));
|
||||
ability.addCustomOutcome(Outcome.PreventCast);
|
||||
ability.addTarget(new TargetOpponent());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private XanatharGuildKingpin(final XanatharGuildKingpin card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XanatharGuildKingpin copy() {
|
||||
return new XanatharGuildKingpin(this);
|
||||
}
|
||||
}
|
||||
|
||||
class XanatharGuildKingpinRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl {
|
||||
|
||||
public XanatharGuildKingpinRuleModifyingEffect() {
|
||||
super(Duration.EndOfTurn, Outcome.Benefit);
|
||||
}
|
||||
|
||||
private XanatharGuildKingpinRuleModifyingEffect(final XanatharGuildKingpinRuleModifyingEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XanatharGuildKingpinRuleModifyingEffect copy() {
|
||||
return new XanatharGuildKingpinRuleModifyingEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
if (targetPlayer != null && mageObject != null) {
|
||||
return "This turn you can't cast spells" +
|
||||
" (" + mageObject.getLogName() + ')';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.CAST_SPELL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
return event.getPlayerId().equals(getTargetPointer().getFirst(game, source));
|
||||
}
|
||||
}
|
||||
|
||||
class XanatharGuildKingpinSpendManaAsAnyColorOneShotEffect extends OneShotEffect {
|
||||
|
||||
public XanatharGuildKingpinSpendManaAsAnyColorOneShotEffect() {
|
||||
super(Outcome.Benefit);
|
||||
}
|
||||
|
||||
private XanatharGuildKingpinSpendManaAsAnyColorOneShotEffect(final XanatharGuildKingpinSpendManaAsAnyColorOneShotEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card topCard = game.getPlayer(source.getFirstTarget()).getLibrary().getFromTop(game);
|
||||
if (topCard == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int zcc = game.getState().getZoneChangeCounter(topCard.getId());
|
||||
game.addEffect(new SpendManaAsAnyColorToCastTopOfLibraryTargetEffect().setTargetPointer(new FixedTarget(topCard.getId(), zcc)), source);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XanatharGuildKingpinSpendManaAsAnyColorOneShotEffect copy() {
|
||||
return new XanatharGuildKingpinSpendManaAsAnyColorOneShotEffect(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SpendManaAsAnyColorToCastTopOfLibraryTargetEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
|
||||
|
||||
public SpendManaAsAnyColorToCastTopOfLibraryTargetEffect() {
|
||||
super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.EndOfTurn, Outcome.Benefit);
|
||||
}
|
||||
|
||||
public SpendManaAsAnyColorToCastTopOfLibraryTargetEffect(final SpendManaAsAnyColorToCastTopOfLibraryTargetEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpendManaAsAnyColorToCastTopOfLibraryTargetEffect copy() {
|
||||
return new SpendManaAsAnyColorToCastTopOfLibraryTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
FixedTarget fixedTarget = ((FixedTarget) getTargetPointer());
|
||||
UUID targetId = CardUtil.getMainCardId(game, fixedTarget.getTarget());
|
||||
|
||||
Card topCard = game.getPlayer(source.getFirstTarget()).getLibrary().getFromTop(game);
|
||||
if (topCard == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If top card of target opponent's library changed, discard the current ContinuousEffect and create a new one
|
||||
if (!topCard.getId().equals(targetId) && canLookAtNextTopLibraryCard(game) && !this.isDiscarded()) {
|
||||
int zcc = game.getState().getZoneChangeCounter(topCard.getId());
|
||||
game.addEffect(new SpendManaAsAnyColorToCastTopOfLibraryTargetEffect().setTargetPointer(new FixedTarget(topCard.getId(), zcc)), source);
|
||||
this.discard();
|
||||
}
|
||||
return source.isControlledBy(affectedControllerId)
|
||||
&& Objects.equals(objectId, targetId)
|
||||
&& game.getState().getZoneChangeCounter(objectId) <= fixedTarget.getZoneChangeCounter() + 1
|
||||
&& (game.getState().getZone(objectId) == Zone.STACK || game.getState().getZone(objectId) == Zone.LIBRARY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) {
|
||||
return mana.getFirstAvailable();
|
||||
}
|
||||
}
|
|
@ -281,6 +281,7 @@ public final class AdventuresInTheForgottenRealms extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Wish", 166, Rarity.RARE, mage.cards.w.Wish.class));
|
||||
cards.add(new SetCardInfo("Wizard Class", 81, Rarity.UNCOMMON, mage.cards.w.WizardClass.class));
|
||||
cards.add(new SetCardInfo("Wizard's Spellbook", 82, Rarity.RARE, mage.cards.w.WizardsSpellbook.class));
|
||||
cards.add(new SetCardInfo("Xanathar, Guild Kingpin", 239, Rarity.MYTHIC, mage.cards.x.XanatharGuildKingpin.class));
|
||||
cards.add(new SetCardInfo("Xorn", 167, Rarity.RARE, mage.cards.x.Xorn.class));
|
||||
cards.add(new SetCardInfo("You Come to a River", 83, Rarity.COMMON, mage.cards.y.YouComeToARiver.class));
|
||||
cards.add(new SetCardInfo("You Come to the Gnoll Camp", 168, Rarity.COMMON, mage.cards.y.YouComeToTheGnollCamp.class));
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package org.mage.test.cards.single.afr;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class XanatharGuildKingpinTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_Play() {
|
||||
removeAllCardsFromLibrary(playerA);
|
||||
removeAllCardsFromLibrary(playerB);
|
||||
skipInitShuffling();
|
||||
|
||||
// At the beginning of your upkeep, choose target opponent.
|
||||
// Until end of turn, that player can’t cast spells, you may look at the top card of their library any time,
|
||||
// you may play the top card of their library, and you may spend mana as though it were mana of any color
|
||||
// to cast spells this way.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Xanathar, Guild Kingpin");
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||
//
|
||||
addCard(Zone.HAND, playerA, "Thunderbolt");
|
||||
//
|
||||
addCard(Zone.HAND, playerB, "Lightning Bolt");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2);
|
||||
//
|
||||
addCard(Zone.LIBRARY, playerB, "Mountain");
|
||||
addCard(Zone.LIBRARY, playerB, "Lightning Bolt");
|
||||
addCard(Zone.LIBRARY, playerB, "Grizzly Bears");
|
||||
|
||||
// activate on opponent
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
// B can't cast spells
|
||||
checkPlayableAbility("B can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Lightning Bolt", false);
|
||||
// A can cast own and from B library
|
||||
checkPlayableAbility("A can cast own", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Thunderbolt", true);
|
||||
checkPlayableAbility("A can cast from B", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Grizzly Bears", true);
|
||||
|
||||
// cast from B and try another one with any color and full stack
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {B}", 2); // pay for {G} as any
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", null, "Grizzly Bears");
|
||||
addTarget(playerA, playerB); // bolt
|
||||
checkStackSize("multi cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
|
||||
|
||||
// B can cast again
|
||||
checkPlayableAbility("B can cast", 2, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Lightning Bolt", true);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(2, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
}
|
|
@ -4,25 +4,51 @@ 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
|
||||
|
@ -34,18 +60,46 @@ public class LookAtTopCardOfLibraryAnyTimeEffect extends ContinuousEffectImpl {
|
|||
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,17 +108,51 @@ 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);
|
||||
// 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
|
||||
if (!cardToCheck.isLand(game) && cardToCheck.getManaCost().isEmpty()) {
|
||||
|
|
|
@ -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…
Reference in a new issue