diff --git a/Mage.Sets/src/mage/cards/e/ElderOwynLyons.java b/Mage.Sets/src/mage/cards/e/ElderOwynLyons.java new file mode 100644 index 00000000000..3fa01c47e8e --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElderOwynLyons.java @@ -0,0 +1,57 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrDiesSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.WardAbility; +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.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author notgreat + */ +public final class ElderOwynLyons extends CardImpl { + + public ElderOwynLyons(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Artifacts you control have ward {1}. + this.addAbility(new SimpleStaticAbility( + new GainAbilityControlledEffect( + new WardAbility(new GenericManaCost(1)), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACTS + ) + )); + + // When Elder Owyn Lyons enters the battlefield or dies, return target artifact card from your graveyard to your hand. + Ability ability = new EntersBattlefieldOrDiesSourceTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); + this.addAbility(ability); + } + + private ElderOwynLyons(final ElderOwynLyons card) { + super(card); + } + + @Override + public ElderOwynLyons copy() { + return new ElderOwynLyons(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GunnerConscript.java b/Mage.Sets/src/mage/cards/g/GunnerConscript.java new file mode 100644 index 00000000000..46245e98259 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GunnerConscript.java @@ -0,0 +1,101 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.AdditiveDynamicValue; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.AuraAttachedCount; +import mage.abilities.dynamicvalue.common.EquipmentAttachedCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.JunkToken; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author notgreat + */ +public final class GunnerConscript extends CardImpl { + + public GunnerConscript(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Gunner Conscript gets +1/+1 for each Aura and Equipment attached to it. + DynamicValue totalAmount = new AdditiveDynamicValue(new AuraAttachedCount(), new EquipmentAttachedCount()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new BoostSourceEffect(totalAmount, totalAmount, Duration.WhileOnBattlefield) + .setText("{this} gets +1/+1 for each Aura and Equipment attached to it"))); + + // When Gunner Conscript dies, if it was enchanted, create a Junk token. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new DiesSourceTriggeredAbility(new CreateTokenEffect(new JunkToken())), GunnerConscriptEnchantedCondition.instance, + "When Gunner Conscript dies, if it was enchanted, create a Junk token.")); + + // When Gunner Conscript dies, if it was equipped, create a Junk token. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new DiesSourceTriggeredAbility(new CreateTokenEffect(new JunkToken())), GunnerConscriptEquippedCondition.instance, + "When Gunner Conscript dies, if it was equipped, create a Junk token.")); + } + + private GunnerConscript(final GunnerConscript card) { + super(card); + } + + @Override + public GunnerConscript copy() { + return new GunnerConscript(this); + } +} + + +// Derived from KollTheForgemaster +// Custom predicates call getPermanentOrLKIBattlefield (needed for the death trigger to work correctly) +enum GunnerConscriptEnchantedCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = source.getSourcePermanentOrLKI(game); + return sourcePermanent != null && sourcePermanent.getAttachments() + .stream() + .map(game::getPermanentOrLKIBattlefield) + .filter(Objects::nonNull) + .anyMatch(permanent -> permanent.isEnchantment(game)); + } +} + +enum GunnerConscriptEquippedCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = source.getSourcePermanentOrLKI(game); + return sourcePermanent != null && sourcePermanent.getAttachments() + .stream() + .map(game::getPermanentOrLKIBattlefield) + .filter(Objects::nonNull) + .anyMatch(attachment -> attachment.hasSubtype(SubType.EQUIPMENT, game)); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IanTheReckless.java b/Mage.Sets/src/mage/cards/i/IanTheReckless.java new file mode 100644 index 00000000000..e1bac548138 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IanTheReckless.java @@ -0,0 +1,62 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.ModifiedPredicate; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author notgreat + */ +public final class IanTheReckless extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(ModifiedPredicate.instance); + } + + private static final Condition condition = new SourceMatchesFilterCondition(filter); + + public IanTheReckless(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever Ian the Reckless attacks, if it's modified, you may have it deal damage equal to its power to you and any target. + TriggeredAbility ability = new AttacksTriggeredAbility(new DamageControllerEffect( + new SourcePermanentPowerCount()).setText("have it deal damage equal to its power to you"), true); + ability.addEffect(new DamageTargetEffect(new SourcePermanentPowerCount()).setText("and any target")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, + "Whenever {this} attacks, if it's modified, you may have it deal damage equal to its power to you and any target.")); + } + + private IanTheReckless(final IanTheReckless card) { + super(card); + } + + @Override + public IanTheReckless copy() { + return new IanTheReckless(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LegateLaniusCaesarsAce.java b/Mage.Sets/src/mage/cards/l/LegateLaniusCaesarsAce.java new file mode 100644 index 00000000000..e8ed7b3ba97 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LegateLaniusCaesarsAce.java @@ -0,0 +1,102 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetSacrifice; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author notgreat + */ +public final class LegateLaniusCaesarsAce extends CardImpl { + + public LegateLaniusCaesarsAce(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Decimate -- When Legate Lanius enters the battlefield, each opponent sacrifices a tenth of the creatures they control, rounded up. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LegateLaniusCaesarsAceSacrificeEffect()).withFlavorWord("Decimate")); + + // Whenever an opponent sacrifices a creature, put a +1/+1 counter on Legate Lanius. + this.addAbility(new SacrificePermanentTriggeredAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + StaticFilters.FILTER_PERMANENT_A_CREATURE, TargetController.OPPONENT, SetTargetPointer.NONE, false + )); + } + + private LegateLaniusCaesarsAce(final LegateLaniusCaesarsAce card) { + super(card); + } + + @Override + public LegateLaniusCaesarsAce copy() { + return new LegateLaniusCaesarsAce(this); + } +} + +//Based on SacrificeAllEffect +class LegateLaniusCaesarsAceSacrificeEffect extends OneShotEffect { + LegateLaniusCaesarsAceSacrificeEffect() { + super(Outcome.Sacrifice); + this.staticText = "each opponent sacrifices a tenth of the creatures they control, rounded up."; + } + + private LegateLaniusCaesarsAceSacrificeEffect(final LegateLaniusCaesarsAceSacrificeEffect effect) { + super(effect); + } + + @Override + public LegateLaniusCaesarsAceSacrificeEffect copy() { + return new LegateLaniusCaesarsAceSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set perms = new HashSet<>(); + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + // 1/10 rounded up + int num = (game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_A_CREATURE,playerId,source, game)+9)/10; + int numTargets = Math.min(num, game.getBattlefield().count(TargetSacrifice.makeFilter(StaticFilters.FILTER_PERMANENT_A_CREATURE), player.getId(), source, game)); + if (numTargets < 1) { + continue; + } + TargetSacrifice target = new TargetSacrifice(numTargets, StaticFilters.FILTER_PERMANENT_A_CREATURE); + while (!target.isChosen() && target.canChoose(playerId, source, game) && player.canRespond()) { + player.choose(Outcome.Sacrifice, target, source, game); + } + perms.addAll(target.getTargets()); + } + for (UUID permID : perms) { + Permanent permanent = game.getPermanent(permID); + if (permanent != null) { + permanent.sacrifice(source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Fallout.java b/Mage.Sets/src/mage/sets/Fallout.java index 6481915b37f..914553faf0b 100644 --- a/Mage.Sets/src/mage/sets/Fallout.java +++ b/Mage.Sets/src/mage/sets/Fallout.java @@ -99,6 +99,7 @@ public final class Fallout extends ExpansionSet { cards.add(new SetCardInfo("Dr. Madison Li", 3, Rarity.MYTHIC, mage.cards.d.DrMadisonLi.class)); cards.add(new SetCardInfo("Dragonskull Summit", 261, Rarity.RARE, mage.cards.d.DragonskullSummit.class)); cards.add(new SetCardInfo("Drowned Catacomb", 262, Rarity.RARE, mage.cards.d.DrownedCatacomb.class)); + cards.add(new SetCardInfo("Elder Owyn Lyons", 103, Rarity.UNCOMMON, mage.cards.e.ElderOwynLyons.class)); cards.add(new SetCardInfo("Electrosiphon", 104, Rarity.RARE, mage.cards.e.Electrosiphon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Electrosiphon", 414, Rarity.RARE, mage.cards.e.Electrosiphon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Electrosiphon", 632, Rarity.RARE, mage.cards.e.Electrosiphon.class, NON_FULL_USE_VARIOUS)); @@ -127,6 +128,7 @@ public final class Fallout extends ExpansionSet { cards.add(new SetCardInfo("Glimmer of Genius", 176, Rarity.UNCOMMON, mage.cards.g.GlimmerOfGenius.class)); cards.add(new SetCardInfo("Grave Titan", 346, Rarity.MYTHIC, mage.cards.g.GraveTitan.class)); cards.add(new SetCardInfo("Guardian Project", 199, Rarity.RARE, mage.cards.g.GuardianProject.class)); + cards.add(new SetCardInfo("Gunner Conscript", 77, Rarity.UNCOMMON, mage.cards.g.GunnerConscript.class)); cards.add(new SetCardInfo("Hancock, Ghoulish Mayor", 45, Rarity.RARE, mage.cards.h.HancockGhoulishMayor.class)); cards.add(new SetCardInfo("Hardened Scales", 200, Rarity.RARE, mage.cards.h.HardenedScales.class)); cards.add(new SetCardInfo("Harmonize", 201, Rarity.UNCOMMON, mage.cards.h.Harmonize.class)); @@ -136,6 +138,7 @@ public final class Fallout extends ExpansionSet { cards.add(new SetCardInfo("Hornet Queen", 350, Rarity.RARE, mage.cards.h.HornetQueen.class)); cards.add(new SetCardInfo("Hour of Reckoning", 161, Rarity.RARE, mage.cards.h.HourOfReckoning.class)); cards.add(new SetCardInfo("Hullbreaker Horror", 344, Rarity.RARE, mage.cards.h.HullbreakerHorror.class)); + cards.add(new SetCardInfo("Ian the Reckless", 59, Rarity.UNCOMMON, mage.cards.i.IanTheReckless.class)); cards.add(new SetCardInfo("Impassioned Orator", 162, Rarity.COMMON, mage.cards.i.ImpassionedOrator.class)); cards.add(new SetCardInfo("Inexorable Tide", 177, Rarity.RARE, mage.cards.i.InexorableTide.class)); cards.add(new SetCardInfo("Inspiring Call", 203, Rarity.UNCOMMON, mage.cards.i.InspiringCall.class)); @@ -151,6 +154,7 @@ public final class Fallout extends ExpansionSet { cards.add(new SetCardInfo("Kellogg, Dangerous Mind", 415, Rarity.RARE, mage.cards.k.KelloggDangerousMind.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kellogg, Dangerous Mind", 634, Rarity.RARE, mage.cards.k.KelloggDangerousMind.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kellogg, Dangerous Mind", 943, Rarity.RARE, mage.cards.k.KelloggDangerousMind.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Legate Lanius, Caesar's Ace", 107, Rarity.UNCOMMON, mage.cards.l.LegateLaniusCaesarsAce.class)); cards.add(new SetCardInfo("Lethal Scheme", 185, Rarity.RARE, mage.cards.l.LethalScheme.class)); cards.add(new SetCardInfo("Liberty Prime, Recharged", 5, Rarity.MYTHIC, mage.cards.l.LibertyPrimeRecharged.class)); cards.add(new SetCardInfo("Lightning Greaves", 233, Rarity.UNCOMMON, mage.cards.l.LightningGreaves.class));