forked from External/mage
Added Eye of the Ojer Taq.
This commit is contained in:
parent
f83073081d
commit
2a6b053e17
3 changed files with 315 additions and 0 deletions
211
Mage.Sets/src/mage/cards/a/ApexObservatory.java
Normal file
211
Mage.Sets/src/mage/cards/a/ApexObservatory.java
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
package mage.cards.a;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AsEntersBattlefieldAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTappedAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.AlternativeCostSourceAbility;
|
||||
import mage.abilities.costs.DynamicCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceCardType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class ApexObservatory extends CardImpl {
|
||||
|
||||
public ApexObservatory(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, null);
|
||||
|
||||
this.nightCard = true;
|
||||
|
||||
// Apex Observatory enters the battlefield tapped.
|
||||
this.addAbility(new EntersBattlefieldTappedAbility());
|
||||
|
||||
// Apex Observatory enters the battlefield tapped. As it enters, choose a card type shared among two exiled cards used to craft it.
|
||||
this.addAbility(new AsEntersBattlefieldAbility(new ChooseCardTypeEffect()));
|
||||
|
||||
// The next spell you cast this turn of the chosen type can be cast without paying its mana cost.
|
||||
this.addAbility(new SimpleActivatedAbility(new ApexObservatoryEffect(), new TapSourceCost()));
|
||||
}
|
||||
|
||||
private ApexObservatory(final ApexObservatory card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApexObservatory copy() {
|
||||
return new ApexObservatory(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ChooseCardTypeEffect extends OneShotEffect {
|
||||
|
||||
public ChooseCardTypeEffect() {
|
||||
super(Outcome.Neutral);
|
||||
staticText = "choose a card type shared among two exiled cards used to craft it.";
|
||||
}
|
||||
|
||||
protected ChooseCardTypeEffect(final ChooseCardTypeEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject mageObject = game.getPermanentEntering(source.getSourceId());
|
||||
List<CardType> exiledCardsCardType = new ArrayList<>();
|
||||
if (mageObject == null) {
|
||||
mageObject = game.getObject(source);
|
||||
}
|
||||
if (controller != null && mageObject != null) {
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
ExileZone exileZone = (ExileZone) game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, +1));
|
||||
if (exileZone == null) {
|
||||
return false;
|
||||
}
|
||||
for (Card card : exileZone.getCards(game)) {
|
||||
exiledCardsCardType.addAll(card.getCardType(game));
|
||||
}
|
||||
Choice cardTypeChoice = new ChoiceCardType();
|
||||
cardTypeChoice.getChoices().clear();
|
||||
cardTypeChoice.getChoices().addAll(exiledCardsCardType.stream().map(CardType::toString).collect(Collectors.toList()));
|
||||
// find only card types that each card shares; some cards have more than 1 card type
|
||||
Map<String, Integer> cardTypeCounts = new HashMap<>();
|
||||
for (String cardType : cardTypeChoice.getChoices()) {
|
||||
cardTypeCounts.put(cardType, 0);
|
||||
}
|
||||
|
||||
for (Card c : exileZone.getCards(game)) {
|
||||
for (CardType cardType : c.getCardType(game)) {
|
||||
if (cardTypeCounts.containsKey(cardType.toString())) {
|
||||
cardTypeCounts.put(cardType.toString(), cardTypeCounts.get(cardType.toString()) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> sharedCardTypes = new ArrayList<>();
|
||||
int numExiledCards = exileZone.getCards(game).size();
|
||||
for (Map.Entry<String, Integer> entry : cardTypeCounts.entrySet()) {
|
||||
if (entry.getValue() == numExiledCards) {
|
||||
sharedCardTypes.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
cardTypeChoice.getChoices().retainAll(sharedCardTypes);
|
||||
if (controller.choose(Outcome.Benefit, cardTypeChoice, game)) {
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + cardTypeChoice.getChoice());
|
||||
}
|
||||
// non-unique identifier for now until global one is setup. source won't work for the conditional check
|
||||
game.getState().setValue("ApexObservatory" + source.getControllerId().toString(), cardTypeChoice.getChoice());
|
||||
if (mageObject instanceof Permanent) {
|
||||
((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen card type: " + cardTypeChoice.getChoice()), game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChooseCardTypeEffect copy() {
|
||||
return new ChooseCardTypeEffect(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ApexObservatoryEffect extends ContinuousEffectImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("a spell");
|
||||
private final AlternativeCostSourceAbility alternativeCastingCostAbility = new ApexObservatoryAlternativeCostAbility(
|
||||
new SpellMatchesChosenTypeCondition(), null, filter, true, null
|
||||
);
|
||||
|
||||
public ApexObservatoryEffect() {
|
||||
super(Duration.EndOfTurn, Layer.RulesEffects, SubLayer.NA, Outcome.Neutral);
|
||||
staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost.";
|
||||
}
|
||||
|
||||
private ApexObservatoryEffect(final ApexObservatoryEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApexObservatoryEffect copy() {
|
||||
return new ApexObservatoryEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
controller.getAlternativeSourceCosts().add(alternativeCastingCostAbility);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class ApexObservatoryAlternativeCostAbility extends AlternativeCostSourceAbility {
|
||||
|
||||
public ApexObservatoryAlternativeCostAbility(Condition condition, String rule, FilterCard filter, boolean onlyMana, DynamicCost dynamicCost) {
|
||||
super(condition, rule, filter, onlyMana, dynamicCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(Ability source, Game game) {
|
||||
return super.isAvailable(source, game) && !AlternativeCostSourceAbility.getActivatedStatus(game, source, getOriginalId(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApexObservatoryAlternativeCostAbility copy() {
|
||||
return new ApexObservatoryAlternativeCostAbility(condition, rule, filter, onlyMana, dynamicCost);
|
||||
}
|
||||
}
|
||||
|
||||
class SpellMatchesChosenTypeCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// investigating a global unique identifier for situations like this; source doesn't refer to the main card
|
||||
return checkSpell(game.getObject(source), game, "ApexObservatory" + source.getControllerId().toString());
|
||||
}
|
||||
|
||||
public static boolean checkSpell(MageObject spell, Game game, String key) {
|
||||
if (spell instanceof Card) {
|
||||
Card card = (Card) spell;
|
||||
String chosenType = (String) game.getState().getValue(key);
|
||||
return chosenType != null && card.getCardType(game).toString().contains(chosenType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
102
Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java
Normal file
102
Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
package mage.cards.e;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.keyword.CraftAbility;
|
||||
import mage.abilities.mana.AnyColorManaAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.target.common.TargetCardInGraveyardBattlefieldOrStack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class EyeOfOjerTaq extends CardImpl {
|
||||
|
||||
public EyeOfOjerTaq(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
|
||||
|
||||
this.secondSideCardClazz = mage.cards.a.ApexObservatory.class;
|
||||
|
||||
// {T}: Add one mana of any color.
|
||||
this.addAbility(new AnyColorManaAbility());
|
||||
|
||||
// Craft with two that share a card type {6} ({6}, Exile this artifact, Exile the two from among other permanents you control
|
||||
// and/or cards from your graveyard: Return this card transformed under its owner’s control. Craft only as a sorcery.)
|
||||
this.addAbility(new CraftAbility(
|
||||
"{6}", "two that share a card type", new EyeOfOjerTaqTarget()
|
||||
));
|
||||
}
|
||||
|
||||
private EyeOfOjerTaq(final EyeOfOjerTaq card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EyeOfOjerTaq copy() {
|
||||
return new EyeOfOjerTaq(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EyeOfOjerTaqTarget extends TargetCardInGraveyardBattlefieldOrStack {
|
||||
|
||||
private static final FilterCard filterCard
|
||||
= new FilterCard();
|
||||
private static final FilterControlledPermanent filterPermanent
|
||||
= new FilterControlledPermanent();
|
||||
|
||||
static {
|
||||
filterCard.add(TargetController.YOU.getOwnerPredicate());
|
||||
filterPermanent.add(AnotherPredicate.instance);
|
||||
|
||||
}
|
||||
|
||||
EyeOfOjerTaqTarget() {
|
||||
super(2, 2, filterCard, filterPermanent);
|
||||
}
|
||||
|
||||
private EyeOfOjerTaqTarget(final EyeOfOjerTaqTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EyeOfOjerTaqTarget copy() {
|
||||
return new EyeOfOjerTaqTarget(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Card cardObject = game.getCard(id);
|
||||
return cardObject != null
|
||||
&& this.getTargets()
|
||||
.stream()
|
||||
.map(game::getCard)
|
||||
.noneMatch(c -> sharesCardtype(cardObject, c, game));
|
||||
}
|
||||
|
||||
public static boolean sharesCardtype(Card card1, Card card2, Game game) {
|
||||
if (card1.getId().equals(card2.getId())) {
|
||||
return false;
|
||||
}
|
||||
// this should be returned true, but the invert works.
|
||||
// if you note the code logic issue, please speak up.
|
||||
for (CardType type : card1.getCardType(game)) {
|
||||
if (card2.getCardType(game).contains(type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ public final class LostCavernsOfIxalanCommander extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Amulet of Vigor", 103, Rarity.RARE, mage.cards.a.AmuletOfVigor.class));
|
||||
cards.add(new SetCardInfo("Angrath's Marauders", 215, Rarity.RARE, mage.cards.a.AngrathsMarauders.class));
|
||||
cards.add(new SetCardInfo("Apex Altisaur", 232, Rarity.RARE, mage.cards.a.ApexAltisaur.class));
|
||||
cards.add(new SetCardInfo("Apex Observatory", 15, Rarity.MYTHIC, mage.cards.a.ApexObservatory.class));
|
||||
cards.add(new SetCardInfo("Arcane Signet", 104, Rarity.UNCOMMON, mage.cards.a.ArcaneSignet.class));
|
||||
cards.add(new SetCardInfo("Arch of Orazca", 319, Rarity.RARE, mage.cards.a.ArchOfOrazca.class));
|
||||
cards.add(new SetCardInfo("Archaeomancer's Map", 101, Rarity.RARE, mage.cards.a.ArchaeomancersMap.class));
|
||||
|
|
@ -119,6 +120,7 @@ public final class LostCavernsOfIxalanCommander extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Everflowing Chalice", 111, Rarity.UNCOMMON, mage.cards.e.EverflowingChalice.class));
|
||||
cards.add(new SetCardInfo("Evolution Sage", 240, Rarity.UNCOMMON, mage.cards.e.EvolutionSage.class));
|
||||
cards.add(new SetCardInfo("Evolving Wilds", 328, Rarity.COMMON, mage.cards.e.EvolvingWilds.class));
|
||||
cards.add(new SetCardInfo("Eye of Ojer Taq", 15, Rarity.MYTHIC, mage.cards.e.EyeOfOjerTaq.class));
|
||||
cards.add(new SetCardInfo("Exotic Orchard", 329, Rarity.RARE, mage.cards.e.ExoticOrchard.class));
|
||||
cards.add(new SetCardInfo("Expedition Map", 112, Rarity.UNCOMMON, mage.cards.e.ExpeditionMap.class));
|
||||
cards.add(new SetCardInfo("Explore", 241, Rarity.COMMON, mage.cards.e.Explore.class));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue