diff --git a/Mage.Sets/src/mage/cards/p/PetrifiedHamlet.java b/Mage.Sets/src/mage/cards/p/PetrifiedHamlet.java new file mode 100644 index 000000000000..7e8de007a9d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PetrifiedHamlet.java @@ -0,0 +1,99 @@ +package mage.cards.p; + +import java.util.Optional; +import java.util.UUID; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.ChooseACardNameEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.ChosenNamePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.util.CardUtil; + +/** + * + * @author muz + */ +public final class PetrifiedHamlet extends CardImpl { + + private static final FilterPermanent filter = new FilterLandPermanent("lands with the chosen name"); + + static { + filter.add(ChosenNamePredicate.instance); + } + + public PetrifiedHamlet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // When this land enters, choose a land card name. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.LAND_NAME))); + + // Activated abilities of sources with the chosen name can't be activated unless they're mana abilities. + this.addAbility(new SimpleStaticAbility(new PetrifiedHamletCostEffect())); + + // Lands with the chosen name have "{T}: Add {C}." + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + new ColorlessManaAbility(), Duration.WhileOnBattlefield, filter + ))); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + } + + private PetrifiedHamlet(final PetrifiedHamlet card) { + super(card); + } + + @Override + public PetrifiedHamlet copy() { + return new PetrifiedHamlet(this); + } +} + +class PetrifiedHamletCostEffect extends ContinuousRuleModifyingEffectImpl { + + PetrifiedHamletCostEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "Activated abilities of sources with the chosen name can't be activated unless they're mana abilities"; + } + + private PetrifiedHamletCostEffect(final PetrifiedHamletCostEffect effect) { + super(effect); + } + + @Override + public PetrifiedHamletCostEffect copy() { + return new PetrifiedHamletCostEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ACTIVATE_ABILITY; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + MageObject object = game.getObject(event.getSourceId()); + String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + Optional ability = game.getAbility(event.getTargetId(), event.getSourceId()); + if (ability.isPresent() && object != null) { + return game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId()) // controller in range + && !ability.get().isManaAbility() + && CardUtil.haveSameNames(object, cardName, game); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/SecretsOfStrixhaven.java b/Mage.Sets/src/mage/sets/SecretsOfStrixhaven.java index 730e69bf03c8..446b73540596 100644 --- a/Mage.Sets/src/mage/sets/SecretsOfStrixhaven.java +++ b/Mage.Sets/src/mage/sets/SecretsOfStrixhaven.java @@ -105,6 +105,7 @@ private SecretsOfStrixhaven() { cards.add(new SetCardInfo("Pensive Professor", 321, Rarity.RARE, mage.cards.p.PensiveProfessor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Pensive Professor", 63, Rarity.RARE, mage.cards.p.PensiveProfessor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Pest Mascot", 209, Rarity.COMMON, mage.cards.p.PestMascot.class)); + cards.add(new SetCardInfo("Petrified Hamlet", 259, Rarity.RARE, mage.cards.p.PetrifiedHamlet.class)); cards.add(new SetCardInfo("Plains", 267, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", 272, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 273, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java index 78dc6e06d3cd..318074ddf74c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java @@ -26,6 +26,7 @@ public class ChooseACardNameEffect extends OneShotEffect { public enum TypeOfName { ALL("card name", CardRepository.instance::getNames), + LAND_NAME("land card name", CardRepository.instance::getLandNames), NOT_BASIC_LAND_NAME("card name other than a basic land card name", CardRepository.instance::getNotBasicLandNames), NONBASIC_LAND_NAME("nonbasic land card name", CardRepository.instance::getNonbasicLandNames), NON_ARTIFACT_AND_NON_LAND_NAME("nonartifact, nonland card name", CardRepository.instance::getNonArtifactAndNonLandNames), diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index d3ebbcfbc356..68d564fb1d0f 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -178,6 +178,26 @@ public synchronized Set getNames() { return names; } + public synchronized Set getLandNames() { + Set names = namesQueryCache.computeIfAbsent("getLandNames", x -> new TreeSet<>()); + if (!names.isEmpty()) { + return names; + } + try { + QueryBuilder qb = cardsDao.queryBuilder(); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.where().like("types", new SelectArg('%' + CardType.LAND.name() + '%')); + List results = cardsDao.query(qb.prepare()); + for (CardInfo card : results) { + addNewNames(card, names); + } + } catch (SQLException e) { + Logger.getLogger(CardRepository.class).error("Error getting land names from DB, possible low memory: " + e, e); + processMemoryErrors(e); + } + return names; + } + public synchronized Set getNonLandNames() { Set names = namesQueryCache.computeIfAbsent("getNonLandNames", x -> new TreeSet<>()); if (!names.isEmpty()) { diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 4a8df6da106c..33662ab7d5c1 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -62086,6 +62086,7 @@ Fields of Strife|Secrets of Strixhaven|255|C||Land|||This land enters tapped.${T Forum of Amity|Secrets of Strixhaven|256|C||Land|||This land enters tapped.${T}: Add {W} or {B}.${2}{W}{B}, {T}: Surveil 1.| Great Hall of the Biblioplex|Secrets of Strixhaven|257|R||Land|||{T}: Add {C}.${T}, Pay 1 life: Add one mana of any color. Spend this mana only to cast an instant or sorcery spell.${5}: If this land isn't a creature, it becomes a 2/4 Wizard creature with "Whenever you cast an instant or sorcery spell, this creature gets +1/+0 until end of turn." It's still a land.| Paradox Gardens|Secrets of Strixhaven|258|C||Land|||This land enters tapped.${T}: Add {G} or {U}.${2}{G}{U}, {T}: Surveil 1.| +Petrified Hamlet|Secrets of Strixhaven|259|R||Land|||When this land enters, choose a land card name.$Activated abilities of sources with the chosen name can't be activated unless they're mana abilities.$Lands with the chosen name have "{T}: Add {C}."${T}: Add {C}.| Shattered Sanctum|Secrets of Strixhaven|260|R||Land|||This land enters tapped unless you control two or more other lands.${T}: Add {W} or {B}.| Skycoach Waypoint|Secrets of Strixhaven|261|U||Land|||{T}: Add {C}.${3}, {T}: Target creature becomes prepared.| Spectacle Summit|Secrets of Strixhaven|262|C||Land|||This land enters tapped.${T}: Add {U} or {R}.${2}{U}{R}, {T}: Surveil 1.|