Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ public class ScryfallImageSupportCards {
add("SOA"); // Secrets of Strixhaven Mystical Archive
add("MSH"); // Marvel Super Heroes
add("MSC"); // Marvel Super Heroes Commander
add("HOB"); // The Hobbit

// Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks
add("CALC"); // Custom Alchemized versions of existing cards
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2971,6 +2971,10 @@ public class ScryfallImageSupportTokens {
put("SOC/Worm", "https://api.scryfall.com/cards/tsoc/26?format=image");
put("SOC/Zombie", "https://api.scryfall.com/cards/tsoc/12?format=image");

// HOB
put("HOB/Dwarf", "https://api.scryfall.com/cards/thob/6?format=image");
put("HOB/Treasure", "https://api.scryfall.com/cards/thob/12?format=image");

// UGL
put("UGL/Goblin", "https://api.scryfall.com/cards/tugl/92?format=image");
put("UGL/Pegasus", "https://api.scryfall.com/cards/tugl/89?format=image");
Expand Down
55 changes: 55 additions & 0 deletions Mage.Sets/src/mage/cards/a/AnUnexpectedParty.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package mage.cards.a;

import java.util.UUID;

import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.cards.AdventureCard;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.permanent.token.Dwarf22Token;

/**
*
* @author muz
*/
public final class AnUnexpectedParty extends AdventureCard {

private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type");

static {
filter.add(TargetController.YOU.getControllerPredicate());
}

public AnUnexpectedParty(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, new CardType[]{CardType.SORCERY}, "{2}{W}{W}", "At the Door", "{X}{2}{W}");

// As this enchantment enters, choose a creature type.
this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature)));
// Creatures you control of the chosen type get +2/+2.
this.addAbility(new SimpleStaticAbility(new BoostAllEffect(2, 2, Duration.WhileOnBattlefield, filter, false)));

// At the Door
// Create X 2/2 red Dwarf creature tokens.
this.getSpellCard().getSpellAbility().addEffect(new CreateTokenEffect(new Dwarf22Token(), GetXValue.instance));

this.finalizeAdventure();
}

private AnUnexpectedParty(final AnUnexpectedParty card) {
super(card);
}

@Override
public AnUnexpectedParty copy() {
return new AnUnexpectedParty(this);
}
}
118 changes: 118 additions & 0 deletions Mage.Sets/src/mage/cards/b/BilboLuckwearer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package mage.cards.b;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.common.DrawDiscardControllerEffect;
import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect;
import mage.abilities.keyword.CantBeBlockedSourceAbility;
import mage.cards.AdventureCard;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;

/**
*
* @author muz
*/
public final class BilboLuckwearer extends AdventureCard {

public BilboLuckwearer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{1}{U}", "Burglar's Plot", "{4}{U}");

this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HALFLING);
this.subtype.add(SubType.ROGUE);
this.power = new MageInt(1);
this.toughness = new MageInt(1);

// Bilbo can't be blocked.
this.addAbility(new CantBeBlockedSourceAbility());

// Whenever Bilbo deals combat damage to a player, draw a card, then discard a card.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(
new DrawDiscardControllerEffect(1, 1), false
));

// Burglar's Plot
// Exchange control of two target nonland permanents that share a card type.
this.getSpellCard().getSpellAbility().addEffect(new ExchangeControlTargetEffect(
Duration.EndOfGame, "Exchange control of two target permanents that share a card type."
));
this.getSpellCard().getSpellAbility().addTarget(new TargetPermanentsThatShareCardType());

this.finalizeAdventure();
}

private BilboLuckwearer(final BilboLuckwearer card) {
super(card);
}

@Override
public BilboLuckwearer copy() {
return new BilboLuckwearer(this);
}
}

class TargetPermanentsThatShareCardType extends TargetPermanent {

TargetPermanentsThatShareCardType() {
super(2, 2, StaticFilters.FILTER_PERMANENT, false);
targetName = "permanents that share a card type";
}

private TargetPermanentsThatShareCardType(final TargetPermanentsThatShareCardType target) {
super(target);
}

@Override
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
if (super.canTarget(playerId, id, source, game)) {
if (!getTargets().isEmpty()) {
Permanent targetOne = game.getPermanent(getTargets().get(0));
Permanent targetTwo = game.getPermanent(id);
if (targetOne == null || targetTwo == null) {
return false;
}
return targetOne.shareTypes(targetTwo, game);
}
return true;
}
return false;
}

@Override
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
Set<CardType> cardTypes = new HashSet<>();
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
for (CardType cardType : permanent.getCardType(game)) {
if (cardTypes.contains(cardType)) {
return true;
}
}
cardTypes.addAll(permanent.getCardType(game));
}
}
}
return false;
}

@Override
public TargetPermanentsThatShareCardType copy() {
return new TargetPermanentsThatShareCardType(this);
}
}
125 changes: 125 additions & 0 deletions Mage.Sets/src/mage/cards/b/BilboThiefInTheNight.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package mage.cards.b;

import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.other.SpellCastFromAnywhereOtherThanHand;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;

/**
*
* @author muz
*/
public final class BilboThiefInTheNight extends CardImpl {

private static final FilterCard filter = new FilterCard("Spells you cast from anywhere other than your hand");

static {
filter.add(SpellCastFromAnywhereOtherThanHand.instance);
}

public BilboThiefInTheNight(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}");

this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HALFLING);
this.subtype.add(SubType.ROGUE);
this.power = new MageInt(2);
this.toughness = new MageInt(2);

// Spells you cast from anywhere other than your hand cost {1} less to cast.
this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1)));

// Whenever Bilbo attacks, you may cast an artifact, instant, or sorcery spell from your graveyard. If an instant or sorcery spell cast this way would be put into your graveyard, exile it instead.
this.addAbility(new AttacksTriggeredAbility(new BilboThiefInTheNightEffect()));
}

private BilboThiefInTheNight(final BilboThiefInTheNight card) {
super(card);
}

@Override
public BilboThiefInTheNight copy() {
return new BilboThiefInTheNight(this);
}
}

class BilboThiefInTheNightEffect extends OneShotEffect {

private static final FilterCard filter = new FilterCard("an artifact, instant, or sorcery card");

static {
filter.add(Predicates.or(
CardType.ARTIFACT.getPredicate(),
CardType.INSTANT.getPredicate(),
CardType.SORCERY.getPredicate()
));
}

BilboThiefInTheNightEffect() {
super(Outcome.Benefit);
staticText = "you may cast an artifact, instant, or sorcery spell from your graveyard. " +
"If an instant or sorcery spell cast this way would be put into your graveyard, exile it instead";
}

private BilboThiefInTheNightEffect(final BilboThiefInTheNightEffect effect) {
super(effect);
}

@Override
public BilboThiefInTheNightEffect copy() {
return new BilboThiefInTheNightEffect(this);
}

@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
if (controller.getGraveyard().getCards(filter, source.getControllerId(), source, game).isEmpty()) {
return false;
}
if (!controller.chooseUse(Outcome.Benefit,
"Cast an artifact, instant, or sorcery spell from your graveyard?", source, game)) {
return true;
}
TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter);
target.withNotTarget(true);
if (!controller.choose(Outcome.Benefit, target, source, game)) {
return false;
}
Card card = game.getCard(target.getFirstTarget());
if (card == null) {
return false;
}
if (card.isInstantOrSorcery(game)) {
ContinuousEffect exileEffect = new ThatSpellGraveyardExileReplacementEffect(true);
exileEffect.setTargetPointer(new FixedTarget(card, game));
game.addEffect(exileEffect, source);
}
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
boolean result = CardUtil.castSingle(controller, source, game, card, false, null);
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
return result;
}
}
64 changes: 64 additions & 0 deletions Mage.Sets/src/mage/cards/m/MyPrecious.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package mage.cards.m;

import java.util.UUID;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.combat.CantBeBlockedAttachedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.abilities.keyword.HexproofAbility;
import mage.cards.AdventureCard;
import mage.cards.CardSetInfo;
import mage.constants.AttachmentType;
import mage.constants.CardType;

/**
*
* @author muz
*/
public final class MyPrecious extends AdventureCard {

public MyPrecious(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, new CardType[]{CardType.INSTANT}, "{3}", "Allure of Power", "{1}{B}");

this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.EQUIPMENT);

// Equipped creature has hexproof and can't be blocked.
Ability ability = new SimpleStaticAbility(
new GainAbilityAttachedEffect(HexproofAbility.getInstance(), AttachmentType.EQUIPMENT)
);
ability.addEffect(
new CantBeBlockedAttachedEffect(AttachmentType.EQUIPMENT).setText("and can't be blocked")
);
this.addAbility(ability);

// Equip - {2}, Pay 2 life.
ability = new EquipAbility(2);
ability.addCost(new PayLifeCost(2));
this.addAbility(ability);

// Allure of Power
// As an additional cost to cast this spell, sacrifice a creature.
// Draw two cards.
this.getSpellCard().getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE));
this.getSpellCard().getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2));

this.finalizeAdventure();
}

private MyPrecious(final MyPrecious card) {
super(card);
}

@Override
public MyPrecious copy() {
return new MyPrecious(this);
}
}
Loading
Loading