Merge branch 'magefree:master' into case-of-the-pilfered-proof

This commit is contained in:
Matthew Wilson 2024-04-08 07:02:35 +03:00 committed by GitHub
commit e79bab6520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 540 additions and 3 deletions

View file

@ -55,6 +55,16 @@ public final class Main {
private static final Logger logger = Logger.getLogger(Main.class);
private static final MageVersion version = new MageVersion(Main.class);
// Server threads:
// - worker threads: creates for each connection, controls by maxPoolSize;
// - acceptor threads: processing requests to start a new connection, controls by numAcceptThreads;
// - backlog threads: processing waiting queue if maxPoolSize reached, controls by backlogSize;
// Usage hints:
// - if maxPoolSize reached then new clients will freeze in connection dialog until backlog queue overflow;
// - so for active server must increase maxPoolSize to big value like "max online * 10" or enable worker idle timeout
// - worker idle time will free unused worker thread, so new client can connect;
private static final int SERVER_WORKER_THREAD_IDLE_TIMEOUT_SECS = 5 * 60; // no needs to config, must be enabled for all
// arg settings can be setup by run script or IDE's program arguments like -xxx=yyy
// prop settings can be setup by -Dxxx=yyy in the launcher
// priority: default setting -> prop setting -> arg setting
@ -432,6 +442,7 @@ public final class Main {
((BisocketServerInvoker) invoker).setSecondaryBindPort(managerFactory.configSettings().getSecondaryBindPort());
((BisocketServerInvoker) invoker).setBacklog(managerFactory.configSettings().getBacklogSize());
((BisocketServerInvoker) invoker).setNumAcceptThreads(managerFactory.configSettings().getNumAcceptThreads());
((BisocketServerInvoker) invoker).setIdleTimeout(SERVER_WORKER_THREAD_IDLE_TIMEOUT_SECS);
}
@Override

View file

@ -0,0 +1,101 @@
package mage.cards.b;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;
/**
* @author TheElk801
*/
public final class BountyBoard extends CardImpl {
private static final FilterPermanent filter
= new FilterCreaturePermanent("a creature with a bounty counter on it");
static {
filter.add(CounterType.BOUNTY.getPredicate());
}
public BountyBoard(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {T}: Add one mana of any color.
this.addAbility(new AnyColorManaAbility());
// {1}, {T}: Put a bounty counter on target creature. Activate only as a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(
new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()), new GenericManaCost(1)
);
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
// Whenever a creature with a bounty counter on it dies, each of its controller's opponents draws a card and gains 2 life.
this.addAbility(new DiesCreatureTriggeredAbility(new BountyBoardEffect(), false, filter));
}
private BountyBoard(final BountyBoard card) {
super(card);
}
@Override
public BountyBoard copy() {
return new BountyBoard(this);
}
}
class BountyBoardEffect extends OneShotEffect {
BountyBoardEffect() {
super(Outcome.Benefit);
staticText = "each of its controller's opponents draws a card and gains 2 life";
}
private BountyBoardEffect(final BountyBoardEffect effect) {
super(effect);
}
@Override
public BountyBoardEffect copy() {
return new BountyBoardEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Optional.ofNullable(getValue("creatureDied"))
.map(Permanent.class::cast)
.map(Controllable::getControllerId)
.map(game::getOpponents)
.map(Collection::stream)
.orElseGet(Stream::empty)
.map(game::getPlayer)
.filter(Objects::nonNull)
.forEach(player -> {
player.drawCards(1, source, game);
player.gainLife(2, game, source);
});
return true;
}
}

View file

@ -0,0 +1,54 @@
package mage.cards.d;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageWithPowerFromSourceToAnotherTargetEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.OutlawPredicate;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class DeadBeforeSunrise extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
static {
filter.add(OutlawPredicate.instance);
}
public DeadBeforeSunrise(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}");
// Until end of turn, outlaw creatures you control get +1/+0 and gain "{T}: This creature deals damage equal to its power to target creature."
this.getSpellAbility().addEffect(new BoostControlledEffect(
1, 0, Duration.EndOfTurn, filter
).setText("until end of turn, outlaw creatures you control get +1/+0"));
Ability ability = new SimpleActivatedAbility(
new DamageWithPowerFromSourceToAnotherTargetEffect("this creature"), new TapSourceCost()
);
ability.addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new GainAbilityControlledEffect(
ability, Duration.EndOfTurn, filter
).setText("and gain \"{T}: This creature deals damage equal to its power to target creature.\""));
}
private DeadBeforeSunrise(final DeadBeforeSunrise card) {
super(card);
}
@Override
public DeadBeforeSunrise copy() {
return new DeadBeforeSunrise(this);
}
}

View file

@ -0,0 +1,77 @@
package mage.cards.g;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.keyword.UnearthAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class GraywatersFixer extends CardImpl {
public GraywatersFixer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}");
this.subtype.add(SubType.LIZARD);
this.subtype.add(SubType.MERCENARY);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Each outlaw creature card in your graveyard has encore {X}, where X is its mana value.
this.addAbility(new SimpleStaticAbility(new GraywatersFixerEffect()));
}
private GraywatersFixer(final GraywatersFixer card) {
super(card);
}
@Override
public GraywatersFixer copy() {
return new GraywatersFixer(this);
}
}
class GraywatersFixerEffect extends ContinuousEffectImpl {
GraywatersFixerEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = "each outlaw creature card in your graveyard has encore {X}, where X is its mana value";
}
private GraywatersFixerEffect(final GraywatersFixerEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
for (Card card : controller.getGraveyard().getCards(game)) {
if (!card.isCreature(game) || !card.isOutlaw(game)) {
continue;
}
UnearthAbility ability = new UnearthAbility(new GenericManaCost(card.getManaValue()));
ability.setSourceId(card.getId());
ability.setControllerId(card.getOwnerId());
game.getState().addOtherAbility(card, ability);
}
return true;
}
@Override
public GraywatersFixerEffect copy() {
return new GraywatersFixerEffect(this);
}
}

View file

@ -0,0 +1,102 @@
package mage.cards.p;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* @author Susucr
*/
public final class PreWarFormalwear extends CardImpl {
private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 3 or less from your graveyard");
static {
filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3));
filter.add(CardType.CREATURE.getPredicate());
}
public PreWarFormalwear(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}");
this.subtype.add(SubType.EQUIPMENT);
// When Pre-War Formalwear enters the battlefield, return target creature card with mana value 3 or less from your graveyard to the battlefield and attach Pre-War Formalwear to it.
Ability ability = new EntersBattlefieldTriggeredAbility(new PreWarFormalwerEffect());
ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability);
// Equipped creature gets +2/+2 and has vigilance.
ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield));
ability.addEffect(new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA).setText("and has vigilance"));
this.addAbility(ability);
// Equip {3}
this.addAbility(new EquipAbility(3));
}
private PreWarFormalwear(final PreWarFormalwear card) {
super(card);
}
@Override
public PreWarFormalwear copy() {
return new PreWarFormalwear(this);
}
}
class PreWarFormalwerEffect extends OneShotEffect {
PreWarFormalwerEffect() {
super(Outcome.PutCreatureInPlay);
staticText = "return target creature card with mana value 3 or less from your graveyard "
+ "to the battlefield and attach Pre-War Formalwear to it";
}
private PreWarFormalwerEffect(final PreWarFormalwerEffect effect) {
super(effect);
}
@Override
public PreWarFormalwerEffect copy() {
return new PreWarFormalwerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(source.getFirstTarget());
Player player = game.getPlayer(source.getControllerId());
if (card == null || player == null) {
return false;
}
player.moveCards(card, Zone.BATTLEFIELD, source, game);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
new AttachEffect(Outcome.BoostCreature)
.setTargetPointer(new FixedTarget(permanent.getId()))
.apply(game, source);
}
return true;
}
}

View file

@ -0,0 +1,71 @@
package mage.cards.p;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.keyword.PlotAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class PyreticCharge extends CardImpl {
public PyreticCharge(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}");
// Discard your hand, then draw four cards. For each card discarded this way, creatures you control get +1/+0 until end of turn.
this.getSpellAbility().addEffect(new PyreticChargeEffect());
// Plot {3}{R}
this.addAbility(new PlotAbility("{3}{R}"));
}
private PyreticCharge(final PyreticCharge card) {
super(card);
}
@Override
public PyreticCharge copy() {
return new PyreticCharge(this);
}
}
class PyreticChargeEffect extends OneShotEffect {
PyreticChargeEffect() {
super(Outcome.Benefit);
staticText = "discard your hand, then draw four cards. For each card discarded this way, " +
"creatures you control get +1/+0 until end of turn";
}
private PyreticChargeEffect(final PyreticChargeEffect effect) {
super(effect);
}
@Override
public PyreticChargeEffect copy() {
return new PyreticChargeEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
int count = player.getHand().size();
player.discard(count, false, false, source, game);
player.drawCards(4, source, game);
game.addEffect(new BoostControlledEffect(count, 0, Duration.EndOfTurn), source);
return true;
}
}

View file

@ -80,6 +80,7 @@ class SigardasVanguardEffect extends OneShotEffect {
return false;
}
TargetPermanent target = new TargetCreaturesWithDifferentPowers();
target.withNotTarget(true);
player.choose(outcome, target, source, game);
if (target.getTargets().isEmpty()) {
return false;

View file

@ -0,0 +1,61 @@
package mage.cards.t;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.mana.ConditionalAnyColorManaAbility;
import mage.abilities.mana.conditional.ConditionalSpellManaBuilder;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.FilterSpell;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ThievingVarmint extends CardImpl {
private static final FilterSpell filter = new FilterSpell("spells you don't own");
static {
filter.add(TargetController.NOT_YOU.getOwnerPredicate());
}
public ThievingVarmint(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
this.subtype.add(SubType.VARMINT);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
// Deathtouch
this.addAbility(DeathtouchAbility.getInstance());
// Lifelink
this.addAbility(LifelinkAbility.getInstance());
// {T}, Pay 1 life: Add two mana of any one color. Spend this mana only to cast spells you don't own.
Ability ability = new ConditionalAnyColorManaAbility(
new TapSourceCost(), 2,
new ConditionalSpellManaBuilder(filter), true
);
ability.addCost(new PayLifeCost(1));
this.addAbility(ability);
}
private ThievingVarmint(final ThievingVarmint card) {
super(card);
}
@Override
public ThievingVarmint copy() {
return new ThievingVarmint(this);
}
}

View file

@ -0,0 +1,53 @@
package mage.cards.t;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.NamePredicate;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TowerWinder extends CardImpl {
private static final FilterCard filter = new FilterCard("Command Tower");
static {
filter.add(new NamePredicate("Command Tower"));
}
public TowerWinder(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
this.subtype.add(SubType.SNAKE);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Reach
this.addAbility(ReachAbility.getInstance());
// Deathtouch
this.addAbility(DeathtouchAbility.getInstance());
// When Tower Winder enters the battlefield, search your library and/or graveyard for a card named Command Tower, reveal it, and put it into your hand. If you search your library this way, shuffle.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryGraveyardPutInHandEffect(filter)));
}
private TowerWinder(final TowerWinder card) {
super(card);
}
@Override
public TowerWinder copy() {
return new TowerWinder(this);
}
}

View file

@ -220,6 +220,7 @@ public final class Fallout extends ExpansionSet {
cards.add(new SetCardInfo("Plains", 317, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Powder Ganger", 65, Rarity.RARE, mage.cards.p.PowderGanger.class));
cards.add(new SetCardInfo("Prairie Stream", 280, Rarity.RARE, mage.cards.p.PrairieStream.class));
cards.add(new SetCardInfo("Pre-War Formalwear", 21, Rarity.RARE, mage.cards.p.PreWarFormalwear.class));
cards.add(new SetCardInfo("Puresteel Paladin", 170, Rarity.RARE, mage.cards.p.PuresteelPaladin.class));
cards.add(new SetCardInfo("Putrefy", 219, Rarity.UNCOMMON, mage.cards.p.Putrefy.class));
cards.add(new SetCardInfo("Radstorm", 37, Rarity.RARE, mage.cards.r.Radstorm.class));

View file

@ -46,6 +46,7 @@ public final class OutlawsOfThunderJunctionCommander extends ExpansionSet {
cards.add(new SetCardInfo("Bojuka Bog", 273, Rarity.COMMON, mage.cards.b.BojukaBog.class));
cards.add(new SetCardInfo("Bonders' Enclave", 274, Rarity.RARE, mage.cards.b.BondersEnclave.class));
cards.add(new SetCardInfo("Boros Charm", 216, Rarity.UNCOMMON, mage.cards.b.BorosCharm.class));
cards.add(new SetCardInfo("Bounty Board", 37, Rarity.RARE, mage.cards.b.BountyBoard.class));
cards.add(new SetCardInfo("Brainstealer Dragon", 127, Rarity.RARE, mage.cards.b.BrainstealerDragon.class));
cards.add(new SetCardInfo("Breena, the Demagogue", 217, Rarity.MYTHIC, mage.cards.b.BreenaTheDemagogue.class));
cards.add(new SetCardInfo("Cactus Preserve", 40, Rarity.RARE, mage.cards.c.CactusPreserve.class));
@ -77,6 +78,7 @@ public final class OutlawsOfThunderJunctionCommander extends ExpansionSet {
cards.add(new SetCardInfo("Darksteel Ingot", 256, Rarity.UNCOMMON, mage.cards.d.DarksteelIngot.class));
cards.add(new SetCardInfo("Darkwater Catacombs", 282, Rarity.RARE, mage.cards.d.DarkwaterCatacombs.class));
cards.add(new SetCardInfo("Dazzling Sphinx", 93, Rarity.RARE, mage.cards.d.DazzlingSphinx.class));
cards.add(new SetCardInfo("Dead Before Sunrise", 26, Rarity.RARE, mage.cards.d.DeadBeforeSunrise.class));
cards.add(new SetCardInfo("Deadly Dispute", 131, Rarity.COMMON, mage.cards.d.DeadlyDispute.class));
cards.add(new SetCardInfo("Decimate", 220, Rarity.RARE, mage.cards.d.Decimate.class));
cards.add(new SetCardInfo("Deep Analysis", 94, Rarity.COMMON, mage.cards.d.DeepAnalysis.class));
@ -128,6 +130,7 @@ public final class OutlawsOfThunderJunctionCommander extends ExpansionSet {
cards.add(new SetCardInfo("Glittering Stockpile", 167, Rarity.UNCOMMON, mage.cards.g.GlitteringStockpile.class));
cards.add(new SetCardInfo("Goblin Electromancer", 228, Rarity.COMMON, mage.cards.g.GoblinElectromancer.class));
cards.add(new SetCardInfo("Gonti, Lord of Luxury", 135, Rarity.RARE, mage.cards.g.GontiLordOfLuxury.class));
cards.add(new SetCardInfo("Graywater's Fixer", 36, Rarity.RARE, mage.cards.g.GraywatersFixer.class));
cards.add(new SetCardInfo("Grenzo, Havoc Raiser", 168, Rarity.RARE, mage.cards.g.GrenzoHavocRaiser.class));
cards.add(new SetCardInfo("Guttersnipe", 169, Rarity.COMMON, mage.cards.g.Guttersnipe.class));
cards.add(new SetCardInfo("Harrow", 194, Rarity.COMMON, mage.cards.h.Harrow.class));
@ -203,6 +206,7 @@ public final class OutlawsOfThunderJunctionCommander extends ExpansionSet {
cards.add(new SetCardInfo("Propaganda", 108, Rarity.UNCOMMON, mage.cards.p.Propaganda.class));
cards.add(new SetCardInfo("Pteramander", 109, Rarity.UNCOMMON, mage.cards.p.Pteramander.class));
cards.add(new SetCardInfo("Putrefy", 238, Rarity.UNCOMMON, mage.cards.p.Putrefy.class));
cards.add(new SetCardInfo("Pyretic Charge", 29, Rarity.RARE, mage.cards.p.PyreticCharge.class));
cards.add(new SetCardInfo("Queen Marchesa", 239, Rarity.RARE, mage.cards.q.QueenMarchesa.class));
cards.add(new SetCardInfo("Radical Idea", 110, Rarity.COMMON, mage.cards.r.RadicalIdea.class));
cards.add(new SetCardInfo("Rain of Riches", 177, Rarity.RARE, mage.cards.r.RainOfRiches.class));
@ -272,11 +276,13 @@ public final class OutlawsOfThunderJunctionCommander extends ExpansionSet {
cards.add(new SetCardInfo("Thief of Sanity", 243, Rarity.RARE, mage.cards.t.ThiefOfSanity.class));
cards.add(new SetCardInfo("Thieving Amalgam", 150, Rarity.RARE, mage.cards.t.ThievingAmalgam.class));
cards.add(new SetCardInfo("Thieving Skydiver", 118, Rarity.RARE, mage.cards.t.ThievingSkydiver.class));
cards.add(new SetCardInfo("Thieving Varmint", 23, Rarity.RARE, mage.cards.t.ThievingVarmint.class));
cards.add(new SetCardInfo("Think Twice", 119, Rarity.COMMON, mage.cards.t.ThinkTwice.class));
cards.add(new SetCardInfo("Third Path Iconoclast", 244, Rarity.UNCOMMON, mage.cards.t.ThirdPathIconoclast.class));
cards.add(new SetCardInfo("Three Visits", 209, Rarity.UNCOMMON, mage.cards.t.ThreeVisits.class));
cards.add(new SetCardInfo("Thrilling Discovery", 245, Rarity.COMMON, mage.cards.t.ThrillingDiscovery.class));
cards.add(new SetCardInfo("Titania, Protector of Argoth", 210, Rarity.MYTHIC, mage.cards.t.TitaniaProtectorOfArgoth.class));
cards.add(new SetCardInfo("Tower Winder", 34, Rarity.RARE, mage.cards.t.TowerWinder.class));
cards.add(new SetCardInfo("Trailblazer's Boots", 269, Rarity.UNCOMMON, mage.cards.t.TrailblazersBoots.class));
cards.add(new SetCardInfo("Treasure Cruise", 120, Rarity.COMMON, mage.cards.t.TreasureCruise.class));
cards.add(new SetCardInfo("Triton Shorestalker", 121, Rarity.COMMON, mage.cards.t.TritonShorestalker.class));

View file

@ -3,7 +3,7 @@ package mage.abilities.keyword;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.Cost;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.ExileSourceEffect;
@ -14,7 +14,6 @@ import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent;
/**
@ -32,7 +31,7 @@ import mage.game.events.ZoneChangeEvent;
*/
public class UnearthAbility extends ActivatedAbilityImpl {
public UnearthAbility(ManaCosts costs) {
public UnearthAbility(Cost costs) {
super(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, true, true), costs);
this.timing = TimingRule.SORCERY;
this.addEffect(new CreateDelayedTriggeredAbilityEffect(new UnearthDelayedTriggeredAbility()));