From 57c73a231d2748bbf00d875074873a58ba0fc9bf Mon Sep 17 00:00:00 2001 From: Sidorovich77 Date: Wed, 4 Sep 2024 18:24:45 +0300 Subject: [PATCH 1/7] Implement Arms Scavenger and 3 other cards, rework Seek effect --- Mage.Sets/src/mage/cards/a/ArmsScavenger.java | 71 ++++++++++ .../src/mage/cards/g/GeistpackAlpha.java | 82 ++++++++++++ .../src/mage/cards/s/SettleTheWilds.java | 73 +++++++++++ .../mage/cards/t/TibaltWickedTormentor.java | 123 ++++++++++++++++++ Mage.Sets/src/mage/sets/AlchemyInnistrad.java | 5 +- ...mSpellbookThenExileCastThisTurnEffect.java | 82 ++++++++++++ ...mSpellbookThenExilePlayThisTurnEffect.java | 82 ++++++++++++ .../effects/common/SeekCardEffect.java | 40 +++++- 8 files changed, 553 insertions(+), 5 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/ArmsScavenger.java create mode 100644 Mage.Sets/src/mage/cards/g/GeistpackAlpha.java create mode 100644 Mage.Sets/src/mage/cards/s/SettleTheWilds.java create mode 100644 Mage.Sets/src/mage/cards/t/TibaltWickedTormentor.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookThenExileCastThisTurnEffect.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookThenExilePlayThisTurnEffect.java diff --git a/Mage.Sets/src/mage/cards/a/ArmsScavenger.java b/Mage.Sets/src/mage/cards/a/ArmsScavenger.java new file mode 100644 index 000000000000..b571a1498e35 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArmsScavenger.java @@ -0,0 +1,71 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DraftFromSpellbookThenExilePlayThisTurnEffect; +import mage.abilities.effects.common.cost.AbilitiesCostReductionControllerEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * @author Sidorovich77 + */ +public final class ArmsScavenger extends CardImpl { + + private static final List spellbook = Collections.unmodifiableList(Arrays.asList( + "Boots of Speed", + "Ceremonial Knife", + "Cliffhaven Kitesail", + "Colossus Hammer", + "Dueling Rapier", + "Goldvein Pick", + "Jousting Lance", + "Mask of Immolation", + "Mirror Shield", + "Relic Axe", + "Rogue's Gloves", + "Scavenged Blade", + "Shield of the Realm", + "Spare Dagger", + "Tormentor's Helm" + )); + + public ArmsScavenger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + + // At the beginning of your upkeep, draft a card from Arms Scavenger’s spellbook, then exile it. Until end of turn, you may play that card. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DraftFromSpellbookThenExilePlayThisTurnEffect(spellbook), TargetController.YOU, false)); + + + // Equip abilities you activate cost {1} less to activate. + this.addAbility(new SimpleStaticAbility(new AbilitiesCostReductionControllerEffect( + EquipAbility.class, "Equip", 1 + ).setText("equip abilities you activate cost {1} less to activate"))); + + } + + private ArmsScavenger(final ArmsScavenger card) { + super(card); + } + + @Override + public ArmsScavenger copy() { + return new ArmsScavenger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GeistpackAlpha.java b/Mage.Sets/src/mage/cards/g/GeistpackAlpha.java new file mode 100644 index 000000000000..14124b78d95a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GeistpackAlpha.java @@ -0,0 +1,82 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author Sidorovich77 + */ +public final class GeistpackAlpha extends CardImpl { + + + public GeistpackAlpha(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.WOLF); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + + // When Geistpack Alpha dies, seek a permanent card with mana value equal to the number of lands you control. + this.addAbility(new DiesSourceTriggeredAbility(new GeistpackAlphaDiesEffect())); + + } + + private GeistpackAlpha(final GeistpackAlpha card) { + super(card); + } + + @Override + public GeistpackAlpha copy() { + return new GeistpackAlpha(this); + } +} + +class GeistpackAlphaDiesEffect extends OneShotEffect { + + GeistpackAlphaDiesEffect() { + super(Outcome.Benefit); + staticText = " seek a permanent card with mana value equal to the number of lands you control."; + } + + private GeistpackAlphaDiesEffect(final GeistpackAlphaDiesEffect effect) { + super(effect); + } + + @Override + public GeistpackAlphaDiesEffect copy() { + return new GeistpackAlphaDiesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int lands = game.getBattlefield().countAll(StaticFilters.FILTER_LAND, game.getControllerId(source.getSourceId()), game); + FilterPermanentCard filter = new FilterPermanentCard(); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, lands)); + player.seekCard(filter, source, game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java new file mode 100644 index 000000000000..a67253b2bfcf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java @@ -0,0 +1,73 @@ + +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author Sidorovich77 + */ +public final class SettleTheWilds extends CardImpl { + + public SettleTheWilds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Seek a basic land card and put it onto the battlefield tapped. + // Then seek a permanent card with mana value equal to the number of lands you control. + //this.getSpellAbility().addEffect(new SeekCardEffect(StaticFilters.FILTER_CARD_BASIC_LAND, Zone.BATTLEFIELD, true).setText("Seek a basic land card and put it onto the battlefield tapped. ")); + this.getSpellAbility().addEffect(new SettleTheWildsSeekEffect()); + + } + + private SettleTheWilds(final SettleTheWilds card) { + super(card); + } + + @Override + public SettleTheWilds copy() { + return new SettleTheWilds(this); + } +} + +class SettleTheWildsSeekEffect extends OneShotEffect { + + SettleTheWildsSeekEffect() { + super(Outcome.Benefit); + staticText = "Then seek a permanent card with mana value equal to the number of lands you control."; + } + + private SettleTheWildsSeekEffect(final SettleTheWildsSeekEffect effect) { + super(effect); + } + + @Override + public SettleTheWildsSeekEffect copy() { + return new SettleTheWildsSeekEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int lands = game.getBattlefield().countAll(StaticFilters.FILTER_LAND, game.getControllerId(source.getSourceId()), game); + FilterPermanentCard filter = new FilterPermanentCard(); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, lands)); + player.seekCard(filter, source, game); + return true; + } +} + diff --git a/Mage.Sets/src/mage/cards/t/TibaltWickedTormentor.java b/Mage.Sets/src/mage/cards/t/TibaltWickedTormentor.java new file mode 100644 index 000000000000..a3f26de7c2c7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TibaltWickedTormentor.java @@ -0,0 +1,123 @@ +package mage.cards.t; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DraftFromSpellbookThenExileCastThisTurnEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.mana.BasicManaEffect; +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.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.DevilToken; +import mage.players.Player; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * @author Sidorovich77 + */ +public final class TibaltWickedTormentor extends CardImpl { + + private static final List spellbook = Collections.unmodifiableList(Arrays.asList( + "Brimstone Vandal", + "Chained Brute", + "Charmbreaker Devils", + "Devil's Play", + "Festival Crasher", + "Forge Devil", + "Frenzied Devils", + "Havoc Jester", + "Hellrider", + "Hobblefiend", + "Pitchburn Devils", + "Sin Prodder", + "Spiteful Prankster", + "Tibalt's Rager", + "Torch Fiend" + )); + + public TibaltWickedTormentor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{R}{R}"); + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.TIBALT); + + this.setStartingLoyalty(3); + + // +1: Add {R}{R}. Draft a card from Tibalt, Wicked Tormentor’s spellbook, then exile it. Until end of turn, you may cast that card. + Ability ability = new LoyaltyAbility(new BasicManaEffect(Mana.RedMana(2)), 1); + ability.addEffect(new DraftFromSpellbookThenExileCastThisTurnEffect(spellbook)); + this.addAbility(ability); + + // +1: Tibalt, Wicked Tormentor deals 4 damage to target creature or planeswalker unless its controller has Tibalt deal 4 damage to them. + // If they do, you may discard a card. If you do, draw a card. + Ability ability1 = new LoyaltyAbility(new TibaltDamageEffect(), 1); + ability1.addTarget(new TargetCreatureOrPlaneswalker()); + this.addAbility(ability1); + + // -X: Create X 1/1 red Devil creature tokens with “When this creature dies, it deals 1 damage to any target.” + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DevilToken(), GetXValue.instance))); + } + + private TibaltWickedTormentor(final TibaltWickedTormentor card) { + super(card); + } + + @Override + public TibaltWickedTormentor copy() { + return new TibaltWickedTormentor(this); + } +} + +class TibaltDamageEffect extends OneShotEffect { + + TibaltDamageEffect() { + super(Outcome.Neutral); + this.staticText = " {this} deals 4 damage to target creature or planeswalker unless its controller has Tibalt deal 4 damage to them." + + " If they do, you may discard a card. If you do, draw a card."; + } + + private TibaltDamageEffect(final TibaltDamageEffect effect) { + super(effect); + } + + @Override + public TibaltDamageEffect copy() { + return new TibaltDamageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(permanent.getControllerId()); + if (player == null || controller == null) { + String message = "Have Tibalt, Wicked Tormentor do 4 damage to you?"; + if (controller.chooseUse(Outcome.Damage, message, source, game)) { + controller.damage(4, source.getSourceId(), source, game); + Effect effect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()); + effect.apply(game, source); + } else { + permanent.damage(4, source, game); + } + return true; + } + return false; + } +} + diff --git a/Mage.Sets/src/mage/sets/AlchemyInnistrad.java b/Mage.Sets/src/mage/sets/AlchemyInnistrad.java index ca5812d85654..d91c68b0b283 100644 --- a/Mage.Sets/src/mage/sets/AlchemyInnistrad.java +++ b/Mage.Sets/src/mage/sets/AlchemyInnistrad.java @@ -21,17 +21,20 @@ private AlchemyInnistrad() { this.hasBoosters = false; this.hasBasicLands = false; + cards.add(new SetCardInfo("Arms Scavenger", 35, Rarity.RARE, mage.cards.a.ArmsScavenger.class)); cards.add(new SetCardInfo("Citystalker Connoisseur", 27, Rarity.RARE, mage.cards.c.CitystalkerConnoisseur.class)); cards.add(new SetCardInfo("Cursebound Witch", 24, Rarity.UNCOMMON, mage.cards.c.CurseboundWitch.class)); cards.add(new SetCardInfo("Expedition Supplier", 6, Rarity.RARE, mage.cards.e.ExpeditionSupplier.class)); cards.add(new SetCardInfo("Faithful Disciple", 7, Rarity.UNCOMMON, mage.cards.f.FaithfulDisciple.class)); + cards.add(new SetCardInfo("Geistpack Alpha", 48, Rarity.RARE, mage.cards.g.GeistpackAlpha.class)); cards.add(new SetCardInfo("Ishkanah, Broodmother", 52, Rarity.MYTHIC, mage.cards.i.IshkanahBroodmother.class)); cards.add(new SetCardInfo("Key to the Archive", 59, Rarity.RARE, mage.cards.k.KeyToTheArchive.class)); cards.add(new SetCardInfo("Kindred Denial", 18, Rarity.UNCOMMON, mage.cards.k.KindredDenial.class)); cards.add(new SetCardInfo("Obsessive Collector", 19, Rarity.RARE, mage.cards.o.ObsessiveCollector.class)); - cards.add(new SetCardInfo("Sanguine Brushstroke", 32, Rarity.RARE, mage.cards.s.SanguineBrushstroke.class)); + cards.add(new SetCardInfo("Settle the Wilds", 55, Rarity.UNCOMMON, mage.cards.s.SettleTheWilds.class)); cards.add(new SetCardInfo("Soulstealer Axe", 60, Rarity.UNCOMMON, mage.cards.s.SoulstealerAxe.class)); cards.add(new SetCardInfo("Suntail Squadron", 11, Rarity.RARE, mage.cards.s.SuntailSquadron.class)); + cards.add(new SetCardInfo("Tibalt, Wicked Tormentor", 43, Rarity.MYTHIC, mage.cards.t.TibaltWickedTormentor.class)); cards.add(new SetCardInfo("Tireless Angler", 23, Rarity.RARE, mage.cards.t.TirelessAngler.class)); cards.add(new SetCardInfo("Toralf's Disciple", 44, Rarity.RARE, mage.cards.t.ToralfsDisciple.class)); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookThenExileCastThisTurnEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookThenExileCastThisTurnEffect.java new file mode 100644 index 000000000000..6904e68bdbac --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookThenExileCastThisTurnEffect.java @@ -0,0 +1,82 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.cards.Card; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceHintType; +import mage.choices.ChoiceImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; +import mage.players.Player; +import mage.util.RandomUtil; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Sidorovich77 + */ +public class DraftFromSpellbookThenExileCastThisTurnEffect extends OneShotEffect { + + private final List spellbook; + + public DraftFromSpellbookThenExileCastThisTurnEffect(List spellbook) { + super(Outcome.DrawCard); + this.spellbook = spellbook; + staticText = "draft a card from {this}'s spellbook, " + + "then exile it. Until end of turn, you may cast that card."; + } + + private DraftFromSpellbookThenExileCastThisTurnEffect(final DraftFromSpellbookThenExileCastThisTurnEffect effect) { + super(effect); + this.spellbook = effect.spellbook; + } + + @Override + public DraftFromSpellbookThenExileCastThisTurnEffect copy() { + return new DraftFromSpellbookThenExileCastThisTurnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Set toSelect = new HashSet<>(); + while (toSelect.size() < 3) { + toSelect.add(RandomUtil.randomFromCollection(spellbook)); + } + Choice choice = new ChoiceImpl(true, ChoiceHintType.CARD); + choice.setMessage("Choose a card to draft"); + choice.setChoices(toSelect); + player.choose(outcome, choice, game); + String cardName = choice.getChoice(); + if (cardName == null) { + return false; + } + CardInfo cardInfo = CardRepository + .instance + .findCards(new CardCriteria().name(cardName)) + .stream() + .findFirst() + .orElse(null); + if (cardInfo == null) { + return false; + } + Set cards = new HashSet<>(); + cards.add(cardInfo.createCard()); + game.loadCards(cards, player.getId()); + PlayFromNotOwnHandZoneTargetEffect.exileAndPlayFromExile(game, source, cards, TargetController.YOU, Duration.EndOfTurn, + false, false, true); + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookThenExilePlayThisTurnEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookThenExilePlayThisTurnEffect.java new file mode 100644 index 000000000000..f2ef12c8a96f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookThenExilePlayThisTurnEffect.java @@ -0,0 +1,82 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.cards.Card; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceHintType; +import mage.choices.ChoiceImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; +import mage.players.Player; +import mage.util.RandomUtil; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Sidorovich77 + */ +public class DraftFromSpellbookThenExilePlayThisTurnEffect extends OneShotEffect { + + private final List spellbook; + + public DraftFromSpellbookThenExilePlayThisTurnEffect(List spellbook) { + super(Outcome.DrawCard); + this.spellbook = spellbook; + staticText = "draft a card from {this}'s spellbook, " + + "then exile it. Until end of turn, you may play that card."; + } + + private DraftFromSpellbookThenExilePlayThisTurnEffect(final DraftFromSpellbookThenExilePlayThisTurnEffect effect) { + super(effect); + this.spellbook = effect.spellbook; + } + + @Override + public DraftFromSpellbookThenExilePlayThisTurnEffect copy() { + return new DraftFromSpellbookThenExilePlayThisTurnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Set toSelect = new HashSet<>(); + while (toSelect.size() < 3) { + toSelect.add(RandomUtil.randomFromCollection(spellbook)); + } + Choice choice = new ChoiceImpl(true, ChoiceHintType.CARD); + choice.setMessage("Choose a card to draft"); + choice.setChoices(toSelect); + player.choose(outcome, choice, game); + String cardName = choice.getChoice(); + if (cardName == null) { + return false; + } + CardInfo cardInfo = CardRepository + .instance + .findCards(new CardCriteria().name(cardName)) + .stream() + .findFirst() + .orElse(null); + if (cardInfo == null) { + return false; + } + Set cards = new HashSet<>(); + cards.add(cardInfo.createCard()); + game.loadCards(cards, player.getId()); + PlayFromNotOwnHandZoneTargetEffect.exileAndPlayFromExile(game, source, cards, TargetController.YOU, Duration.EndOfTurn, + false, false, false); + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java index 34cfc65fe09c..22841d9e9900 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java @@ -2,29 +2,48 @@ import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; +import mage.util.RandomUtil; + +import java.util.Set; +import java.util.stream.Collectors; /** * @author karapuzz14 */ public class SeekCardEffect extends OneShotEffect { private final FilterCard filter; + private final Zone inZone; + private final boolean tapped; + + public SeekCardEffect(FilterCard filter) { + this(filter, Zone.HAND, false); + } + public SeekCardEffect(FilterCard filter, Zone inZone) { + this(filter, inZone, false); + } /** * @param filter for selecting a card */ - public SeekCardEffect(FilterCard filter) { + public SeekCardEffect(FilterCard filter, Zone inZone, boolean tapped) { super(Outcome.Benefit); this.filter = filter; + this.inZone = inZone; + this.tapped = tapped; this.staticText = "seek a " + filter.getMessage(); } private SeekCardEffect(final SeekCardEffect effect) { super(effect); this.filter = effect.filter; + this.inZone = effect.inZone; + this.tapped = effect.tapped; } @Override @@ -35,11 +54,24 @@ public SeekCardEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - return controller.seekCard(filter, source, game); + Set cards = controller.getLibrary() + .getCards(game) + .stream() + .filter(card -> filter.match(card, getId(), source, game)) + .collect(Collectors.toSet()); + Card card = RandomUtil.randomFromCollection(cards); + if (card == null) { + return false; + } + game.informPlayers(controller.getLogName() + " seeks a card from their library"); + if (inZone == Zone.BATTLEFIELD) { + controller.moveCards(card, inZone, source, game, tapped, false, false, null); + } else { + controller.moveCards(card, inZone, source, game); + } + return true; } - return false; } From 623a20e740a66ff5bd1bc44ffa93d90a9b18eaf4 Mon Sep 17 00:00:00 2001 From: Sidorovich77 Date: Wed, 4 Sep 2024 18:53:42 +0300 Subject: [PATCH 2/7] Implement Arms Scavenger and 3 other cards, rework Seek effect --- Mage.Sets/src/mage/cards/s/SettleTheWilds.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java index a67253b2bfcf..0c56c0ec77a1 100644 --- a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java +++ b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java @@ -3,11 +3,13 @@ import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SeekCardEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.mageobject.ManaValuePredicate; @@ -26,7 +28,7 @@ public SettleTheWilds(UUID ownerId, CardSetInfo setInfo) { // Seek a basic land card and put it onto the battlefield tapped. // Then seek a permanent card with mana value equal to the number of lands you control. - //this.getSpellAbility().addEffect(new SeekCardEffect(StaticFilters.FILTER_CARD_BASIC_LAND, Zone.BATTLEFIELD, true).setText("Seek a basic land card and put it onto the battlefield tapped. ")); + this.getSpellAbility().addEffect(new SeekCardEffect(StaticFilters.FILTER_CARD_BASIC_LAND, Zone.BATTLEFIELD, true).setText("Seek a basic land card and put it onto the battlefield tapped. ")); this.getSpellAbility().addEffect(new SettleTheWildsSeekEffect()); } From d9992b4723aac3b3188542f3e6b5c218956d0d9a Mon Sep 17 00:00:00 2001 From: Sidorovich77 Date: Wed, 4 Sep 2024 19:12:20 +0300 Subject: [PATCH 3/7] Remove unfinished work --- .../src/mage/cards/s/SettleTheWilds.java | 75 ------------------ .../effects/common/SeekCardEffect.java | 78 ------------------- 2 files changed, 153 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java index 0c56c0ec77a1..e69de29bb2d1 100644 --- a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java +++ b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java @@ -1,75 +0,0 @@ - -package mage.cards.s; - -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.SeekCardEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.StaticFilters; -import mage.filter.common.FilterPermanentCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.Game; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author Sidorovich77 - */ -public final class SettleTheWilds extends CardImpl { - - public SettleTheWilds(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); - - // Seek a basic land card and put it onto the battlefield tapped. - // Then seek a permanent card with mana value equal to the number of lands you control. - this.getSpellAbility().addEffect(new SeekCardEffect(StaticFilters.FILTER_CARD_BASIC_LAND, Zone.BATTLEFIELD, true).setText("Seek a basic land card and put it onto the battlefield tapped. ")); - this.getSpellAbility().addEffect(new SettleTheWildsSeekEffect()); - - } - - private SettleTheWilds(final SettleTheWilds card) { - super(card); - } - - @Override - public SettleTheWilds copy() { - return new SettleTheWilds(this); - } -} - -class SettleTheWildsSeekEffect extends OneShotEffect { - - SettleTheWildsSeekEffect() { - super(Outcome.Benefit); - staticText = "Then seek a permanent card with mana value equal to the number of lands you control."; - } - - private SettleTheWildsSeekEffect(final SettleTheWildsSeekEffect effect) { - super(effect); - } - - @Override - public SettleTheWildsSeekEffect copy() { - return new SettleTheWildsSeekEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - int lands = game.getBattlefield().countAll(StaticFilters.FILTER_LAND, game.getControllerId(source.getSourceId()), game); - FilterPermanentCard filter = new FilterPermanentCard(); - filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, lands)); - player.seekCard(filter, source, game); - return true; - } -} - diff --git a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java index 22841d9e9900..e69de29bb2d1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java @@ -1,78 +0,0 @@ -package mage.abilities.effects.common; - -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; -import mage.util.RandomUtil; - -import java.util.Set; -import java.util.stream.Collectors; - -/** - * @author karapuzz14 - */ -public class SeekCardEffect extends OneShotEffect { - private final FilterCard filter; - private final Zone inZone; - private final boolean tapped; - - public SeekCardEffect(FilterCard filter) { - this(filter, Zone.HAND, false); - } - - public SeekCardEffect(FilterCard filter, Zone inZone) { - this(filter, inZone, false); - } - /** - * @param filter for selecting a card - */ - public SeekCardEffect(FilterCard filter, Zone inZone, boolean tapped) { - super(Outcome.Benefit); - this.filter = filter; - this.inZone = inZone; - this.tapped = tapped; - this.staticText = "seek a " + filter.getMessage(); - } - - private SeekCardEffect(final SeekCardEffect effect) { - super(effect); - this.filter = effect.filter; - this.inZone = effect.inZone; - this.tapped = effect.tapped; - } - - @Override - public SeekCardEffect copy() { - return new SeekCardEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Set cards = controller.getLibrary() - .getCards(game) - .stream() - .filter(card -> filter.match(card, getId(), source, game)) - .collect(Collectors.toSet()); - Card card = RandomUtil.randomFromCollection(cards); - if (card == null) { - return false; - } - game.informPlayers(controller.getLogName() + " seeks a card from their library"); - if (inZone == Zone.BATTLEFIELD) { - controller.moveCards(card, inZone, source, game, tapped, false, false, null); - } else { - controller.moveCards(card, inZone, source, game); - } - return true; - } - return false; - } - -} From 5304dcc56e61c5a013ccd6213c936f750640ade3 Mon Sep 17 00:00:00 2001 From: Sidorovich77 Date: Wed, 4 Sep 2024 19:15:49 +0300 Subject: [PATCH 4/7] Implement Arms Scavenger and 3 other cards, rework Seek effect --- .../src/mage/cards/s/SettleTheWilds.java | 75 ++++++++++++++++++ .../effects/common/SeekCardEffect.java | 78 +++++++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java index e69de29bb2d1..0c56c0ec77a1 100644 --- a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java +++ b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java @@ -0,0 +1,75 @@ + +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SeekCardEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author Sidorovich77 + */ +public final class SettleTheWilds extends CardImpl { + + public SettleTheWilds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Seek a basic land card and put it onto the battlefield tapped. + // Then seek a permanent card with mana value equal to the number of lands you control. + this.getSpellAbility().addEffect(new SeekCardEffect(StaticFilters.FILTER_CARD_BASIC_LAND, Zone.BATTLEFIELD, true).setText("Seek a basic land card and put it onto the battlefield tapped. ")); + this.getSpellAbility().addEffect(new SettleTheWildsSeekEffect()); + + } + + private SettleTheWilds(final SettleTheWilds card) { + super(card); + } + + @Override + public SettleTheWilds copy() { + return new SettleTheWilds(this); + } +} + +class SettleTheWildsSeekEffect extends OneShotEffect { + + SettleTheWildsSeekEffect() { + super(Outcome.Benefit); + staticText = "Then seek a permanent card with mana value equal to the number of lands you control."; + } + + private SettleTheWildsSeekEffect(final SettleTheWildsSeekEffect effect) { + super(effect); + } + + @Override + public SettleTheWildsSeekEffect copy() { + return new SettleTheWildsSeekEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int lands = game.getBattlefield().countAll(StaticFilters.FILTER_LAND, game.getControllerId(source.getSourceId()), game); + FilterPermanentCard filter = new FilterPermanentCard(); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, lands)); + player.seekCard(filter, source, game); + return true; + } +} + diff --git a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java index e69de29bb2d1..22841d9e9900 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java @@ -0,0 +1,78 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.util.RandomUtil; + +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author karapuzz14 + */ +public class SeekCardEffect extends OneShotEffect { + private final FilterCard filter; + private final Zone inZone; + private final boolean tapped; + + public SeekCardEffect(FilterCard filter) { + this(filter, Zone.HAND, false); + } + + public SeekCardEffect(FilterCard filter, Zone inZone) { + this(filter, inZone, false); + } + /** + * @param filter for selecting a card + */ + public SeekCardEffect(FilterCard filter, Zone inZone, boolean tapped) { + super(Outcome.Benefit); + this.filter = filter; + this.inZone = inZone; + this.tapped = tapped; + this.staticText = "seek a " + filter.getMessage(); + } + + private SeekCardEffect(final SeekCardEffect effect) { + super(effect); + this.filter = effect.filter; + this.inZone = effect.inZone; + this.tapped = effect.tapped; + } + + @Override + public SeekCardEffect copy() { + return new SeekCardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Set cards = controller.getLibrary() + .getCards(game) + .stream() + .filter(card -> filter.match(card, getId(), source, game)) + .collect(Collectors.toSet()); + Card card = RandomUtil.randomFromCollection(cards); + if (card == null) { + return false; + } + game.informPlayers(controller.getLogName() + " seeks a card from their library"); + if (inZone == Zone.BATTLEFIELD) { + controller.moveCards(card, inZone, source, game, tapped, false, false, null); + } else { + controller.moveCards(card, inZone, source, game); + } + return true; + } + return false; + } + +} From 254095f0ece4009f3ae695404157fa7c93fc591b Mon Sep 17 00:00:00 2001 From: Sidorovich77 Date: Sun, 8 Sep 2024 16:33:05 +0300 Subject: [PATCH 5/7] Fixed Tibalt for test. --- .../src/mage/cards/t/TibaltWickedTormentor.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/cards/t/TibaltWickedTormentor.java b/Mage.Sets/src/mage/cards/t/TibaltWickedTormentor.java index a3f26de7c2c7..bbca8412fbe9 100644 --- a/Mage.Sets/src/mage/cards/t/TibaltWickedTormentor.java +++ b/Mage.Sets/src/mage/cards/t/TibaltWickedTormentor.java @@ -64,8 +64,7 @@ public TibaltWickedTormentor(UUID ownerId, CardSetInfo setInfo) { ability.addEffect(new DraftFromSpellbookThenExileCastThisTurnEffect(spellbook)); this.addAbility(ability); - // +1: Tibalt, Wicked Tormentor deals 4 damage to target creature or planeswalker unless its controller has Tibalt deal 4 damage to them. - // If they do, you may discard a card. If you do, draw a card. + // +1: Tibalt, Wicked Tormentor deals 4 damage to target creature or planeswalker unless its controller has Tibalt deal 4 damage to them. If they do, you may discard a card. If you do, draw a card. Ability ability1 = new LoyaltyAbility(new TibaltDamageEffect(), 1); ability1.addTarget(new TargetCreatureOrPlaneswalker()); this.addAbility(ability1); @@ -104,9 +103,12 @@ public TibaltDamageEffect copy() { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); - Player player = game.getPlayer(source.getControllerId()); + if (permanent == null) { + return false; + } + Player you = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(permanent.getControllerId()); - if (player == null || controller == null) { + if (you != null || controller != null) { String message = "Have Tibalt, Wicked Tormentor do 4 damage to you?"; if (controller.chooseUse(Outcome.Damage, message, source, game)) { controller.damage(4, source.getSourceId(), source, game); @@ -117,7 +119,7 @@ public boolean apply(Game game, Ability source) { } return true; } - return false; + return true; } } From 8bfd51f25045a624c7b1a15d97781a0b56c4f3ff Mon Sep 17 00:00:00 2001 From: Sidorovich77 Date: Sun, 15 Sep 2024 14:46:17 +0300 Subject: [PATCH 6/7] Fix for review. --- .../src/mage/cards/g/GeistpackAlpha.java | 3 +- .../src/mage/cards/s/SettleTheWilds.java | 11 ++-- .../java/org/mage/test/player/TestPlayer.java | 5 ++ .../effects/common/SeekCardEffect.java | 55 ++++++++++--------- Mage/src/main/java/mage/players/Player.java | 6 ++ .../main/java/mage/players/PlayerImpl.java | 40 +++++++++++++- 6 files changed, 83 insertions(+), 37 deletions(-) diff --git a/Mage.Sets/src/mage/cards/g/GeistpackAlpha.java b/Mage.Sets/src/mage/cards/g/GeistpackAlpha.java index 14124b78d95a..5991d5e6db4e 100644 --- a/Mage.Sets/src/mage/cards/g/GeistpackAlpha.java +++ b/Mage.Sets/src/mage/cards/g/GeistpackAlpha.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.common.LandsYouControlHint; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -37,7 +38,7 @@ public GeistpackAlpha(UUID ownerId, CardSetInfo setInfo) { // When Geistpack Alpha dies, seek a permanent card with mana value equal to the number of lands you control. - this.addAbility(new DiesSourceTriggeredAbility(new GeistpackAlphaDiesEffect())); + this.addAbility(new DiesSourceTriggeredAbility(new GeistpackAlphaDiesEffect()).addHint(LandsYouControlHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java index 0c56c0ec77a1..9fabc2e944ab 100644 --- a/Mage.Sets/src/mage/cards/s/SettleTheWilds.java +++ b/Mage.Sets/src/mage/cards/s/SettleTheWilds.java @@ -26,9 +26,8 @@ public final class SettleTheWilds extends CardImpl { public SettleTheWilds(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); - // Seek a basic land card and put it onto the battlefield tapped. - // Then seek a permanent card with mana value equal to the number of lands you control. - this.getSpellAbility().addEffect(new SeekCardEffect(StaticFilters.FILTER_CARD_BASIC_LAND, Zone.BATTLEFIELD, true).setText("Seek a basic land card and put it onto the battlefield tapped. ")); + // Seek a basic land card and put it onto the battlefield tapped. Then seek a permanent card with mana value equal to the number of lands you control. + this.getSpellAbility().addEffect(new SeekCardEffect(StaticFilters.FILTER_CARD_BASIC_LAND_A, 1, Zone.BATTLEFIELD, true).setText("Seek a basic land card and put it onto the battlefield tapped")); this.getSpellAbility().addEffect(new SettleTheWildsSeekEffect()); } @@ -68,8 +67,6 @@ public boolean apply(Game game, Ability source) { int lands = game.getBattlefield().countAll(StaticFilters.FILTER_LAND, game.getControllerId(source.getSourceId()), game); FilterPermanentCard filter = new FilterPermanentCard(); filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, lands)); - player.seekCard(filter, source, game); - return true; + return player.seekCard(filter, source, game); } -} - +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index cf90889e0ead..865a4718d4f7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -3672,6 +3672,11 @@ public boolean seekCard(FilterCard filter, Ability source, Game game) { return computerPlayer.seekCard(filter, source, game); } + @Override + public Set seekCard(FilterCard filter, Zone inZone, boolean tapped, int amount, Ability source, Game game) { + return computerPlayer.seekCard(filter,inZone, tapped, amount, source, game); + } + @Override public void lookAtAllLibraries(Ability source, Game game) { computerPlayer.lookAtAllLibraries(source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java index 22841d9e9900..cfc7195fc8d6 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java @@ -1,6 +1,7 @@ package mage.abilities.effects.common; import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.Outcome; @@ -8,40 +9,58 @@ import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; -import mage.util.RandomUtil; +import mage.util.CardUtil; import java.util.Set; -import java.util.stream.Collectors; /** * @author karapuzz14 */ public class SeekCardEffect extends OneShotEffect { + private final FilterCard filter; + private final Zone inZone; + private final boolean tapped; + private final int amount; + public SeekCardEffect(FilterCard filter) { - this(filter, Zone.HAND, false); + this(filter, 1, Zone.HAND, false); + } + + public SeekCardEffect(FilterCard filter, int amount) { + this(filter, amount, Zone.HAND, false); } - public SeekCardEffect(FilterCard filter, Zone inZone) { - this(filter, inZone, false); + public SeekCardEffect(FilterCard filter, int amount, Zone inZone) { + this(filter, amount, inZone, false); } + /** * @param filter for selecting a card */ - public SeekCardEffect(FilterCard filter, Zone inZone, boolean tapped) { + public SeekCardEffect(FilterCard filter, int amount, Zone inZone, boolean tapped) { super(Outcome.Benefit); this.filter = filter; + this.amount = amount; this.inZone = inZone; this.tapped = tapped; - this.staticText = "seek a " + filter.getMessage(); + StringBuilder sb = new StringBuilder("seek "); + String value = StaticValue.get(amount).toString(); + sb.append(CardUtil.numberToText(value, "")); + if (amount > 1) { + sb.append(" "); + } + sb.append(filter.getMessage()); + this.staticText = sb.toString(); } private SeekCardEffect(final SeekCardEffect effect) { super(effect); this.filter = effect.filter; + this.amount = effect.amount; this.inZone = effect.inZone; this.tapped = effect.tapped; } @@ -54,25 +73,9 @@ public SeekCardEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Set cards = controller.getLibrary() - .getCards(game) - .stream() - .filter(card -> filter.match(card, getId(), source, game)) - .collect(Collectors.toSet()); - Card card = RandomUtil.randomFromCollection(cards); - if (card == null) { - return false; - } - game.informPlayers(controller.getLogName() + " seeks a card from their library"); - if (inZone == Zone.BATTLEFIELD) { - controller.moveCards(card, inZone, source, game, tapped, false, false, null); - } else { - controller.moveCards(card, inZone, source, game); - } - return true; - } - return false; + Set cards = controller.seekCard(filter, inZone, tapped, amount, source, game); + + return !cards.isEmpty(); } } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index d31f51d849d5..d7981564cb51 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -477,6 +477,12 @@ default boolean isComputer() { */ boolean seekCard(FilterCard filter, Ability source, Game game); + /** + * Gets random cards (or card) which matches the given filter and puts it in given zone + * Doesn't reveal the cards + */ + Set seekCard(FilterCard filter, Zone inZone, boolean tapped, int amount, Ability source, Game game); + /** * Reveals all players' libraries. Useful for abilities like Jace, Architect * of Thought's -8 that have effects that require information from all diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index c16aeb3f1884..ecc14aa06f1a 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -788,10 +788,10 @@ public int drawCards(int num, Ability source, Game game, GameEvent event) { } // if this method was called from a replacement event, pass the number of cards back through // (uncomment conditions if correct ruling is to only count cards drawn by the same player) - if (event instanceof DrawCardEvent /* && event.getPlayerId().equals(getId()) */ ) { + if (event instanceof DrawCardEvent /* && event.getPlayerId().equals(getId()) */) { ((DrawCardEvent) event).incrementCardsDrawn(numDrawn); } - if (event instanceof DrawTwoOrMoreCardsEvent /* && event.getPlayerId().equals(getId()) */ ) { + if (event instanceof DrawTwoOrMoreCardsEvent /* && event.getPlayerId().equals(getId()) */) { ((DrawTwoOrMoreCardsEvent) event).incrementCardsDrawn(numDrawn); } return numDrawn; @@ -1983,7 +1983,7 @@ public void untap(Game game) { do { playerCanceledSelection = false; // select permanents to untap to consume the "notMoreThan" effects - for (Map.Entry>, Integer> handledEntry : notMoreThanEffectsUsage.entrySet()) { + for (Entry>, Integer> handledEntry : notMoreThanEffectsUsage.entrySet()) { // select a permanent to untap for this entry int numberToUntap = handledEntry.getValue(); if (numberToUntap > 0) { @@ -2972,6 +2972,40 @@ public boolean seekCard(FilterCard filter, Ability source, Game game) { return true; } + @Override + public Set seekCard(FilterCard filter, Zone inZone, boolean tapped, int amount, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Set cards = controller.getLibrary() + .getCards(game) + .stream() + .filter(card -> filter.match(card, getId(), source, game)) + .collect(Collectors.toSet()); + + Set soughtCards = new HashSet<>(); + for (int i = 0; i < amount; i++) { + Card randomCard = RandomUtil.randomFromCollection(cards); + soughtCards.add(randomCard); + cards.remove(randomCard); + } + + if (soughtCards.size() > 1) { + game.informPlayers(controller.getLogName() + " seeks cards from their library"); + } else { + game.informPlayers(controller.getLogName() + " seeks a card from their library"); + } + + if (inZone == Zone.BATTLEFIELD) { + controller.moveCards(soughtCards, inZone, source, game, tapped, false, false, null); + } else { + controller.moveCards(soughtCards, inZone, source, game); + } + + return soughtCards; + } + return null; + } + @Override public void lookAtAllLibraries(Ability source, Game game) { for (UUID playerId : game.getState().getPlayersInRange(this.getId(), game)) { From 14948bfa649bd308f7f7eb4295495404a2200b04 Mon Sep 17 00:00:00 2001 From: Sidorovich77 Date: Sun, 15 Sep 2024 16:32:19 +0300 Subject: [PATCH 7/7] Fix for review. --- .../main/java/mage/abilities/effects/common/SeekCardEffect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java index cfc7195fc8d6..80821138111d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SeekCardEffect.java @@ -75,7 +75,7 @@ public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Set cards = controller.seekCard(filter, inZone, tapped, amount, source, game); - return !cards.isEmpty(); + return cards != null && !cards.isEmpty(); } }