From 550562b1a9e2eaf3620dfbc38413abb21885621e Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 5 May 2025 14:39:38 -0400 Subject: [PATCH] [WHO] Implement Day of the Moon --- Mage.Sets/src/mage/cards/d/DayOfTheMoon.java | 111 ++++++++++++++++++ Mage.Sets/src/mage/sets/DoctorWho.java | 4 +- .../effects/common/ChooseACardNameEffect.java | 21 ++-- Mage/src/main/java/mage/game/GameState.java | 7 +- 4 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/d/DayOfTheMoon.java diff --git a/Mage.Sets/src/mage/cards/d/DayOfTheMoon.java b/Mage.Sets/src/mage/cards/d/DayOfTheMoon.java new file mode 100644 index 00000000000..550ef55db48 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DayOfTheMoon.java @@ -0,0 +1,111 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseACardNameEffect; +import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.targetpointer.FixedTargets; +import mage.util.CardUtil; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class DayOfTheMoon extends CardImpl { + + public DayOfTheMoon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I, II, III -- Choose a creature card name, then goad all creatures with a name chosen for Day of the Moon. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_III, new DayOfTheMoonEffect()); + this.addAbility(sagaAbility); + } + + private DayOfTheMoon(final DayOfTheMoon card) { + super(card); + } + + @Override + public DayOfTheMoon copy() { + return new DayOfTheMoon(this); + } +} + +class DayOfTheMoonEffect extends OneShotEffect { + + DayOfTheMoonEffect() { + super(Outcome.Benefit); + staticText = "choose a creature card name, then goad all creatures with a name chosen for {this}"; + } + + private DayOfTheMoonEffect(final DayOfTheMoonEffect effect) { + super(effect); + } + + @Override + public DayOfTheMoonEffect copy() { + return new DayOfTheMoonEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Choice cardChoice = ChooseACardNameEffect.TypeOfName.CREATURE_NAME.makeChoiceObject(); + player.choose(outcome, cardChoice, game); + String cardName = cardChoice.getChoice(); + List names = getOrSetValue(game, source); + names.add(cardName); + names.removeIf(Objects::nonNull); + if (names.isEmpty()) { + return true; + } + game.informPlayers( + CardUtil.getSourceLogName(game, source) + ": " + player.getName() + ", chosen name: [" + cardName + ']' + ); + Optional.ofNullable(source.getSourcePermanentIfItStillExists(game)) + .ifPresent(permanent -> permanent.addInfo( + "NAMED_CARD", CardUtil.addToolTipMarkTags( + "Chosen names: " + CardUtil.concatWithAnd(names) + ), game + )); + FilterPermanent filter = new FilterCreaturePermanent(); + filter.add(Predicates.or(names.stream().map(NamePredicate::new).collect(Collectors.toSet()))); + game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTargets( + game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game), game + )), source); + return true; + } + + private List getOrSetValue(Game game, Ability source) { + String key = source.getControllerId() + "_" + source.getSourceObjectZoneChangeCounter(); + List set = (List) game.getState().getValue(key); + if (set != null) { + return set; + } + return game.getState().setValue(key, new ArrayList<>()); + } +} diff --git a/Mage.Sets/src/mage/sets/DoctorWho.java b/Mage.Sets/src/mage/sets/DoctorWho.java index 0547496b619..f6f3aa268ba 100644 --- a/Mage.Sets/src/mage/sets/DoctorWho.java +++ b/Mage.Sets/src/mage/sets/DoctorWho.java @@ -237,8 +237,8 @@ public final class DoctorWho extends ExpansionSet { cards.add(new SetCardInfo("Day of Destiny", 206, Rarity.RARE, mage.cards.d.DayOfDestiny.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Day of Destiny", 464, Rarity.RARE, mage.cards.d.DayOfDestiny.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Day of Destiny", 797, Rarity.RARE, mage.cards.d.DayOfDestiny.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Day of the Moon", 684, Rarity.RARE, mage.cards.d.DayOfTheMoon.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("Day of the Moon", 79, Rarity.RARE, mage.cards.d.DayOfTheMoon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Day of the Moon", 684, Rarity.RARE, mage.cards.d.DayOfTheMoon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Day of the Moon", 79, Rarity.RARE, mage.cards.d.DayOfTheMoon.class, NON_FULL_USE_VARIOUS)); //cards.add(new SetCardInfo("Death in Heaven", 66, Rarity.RARE, mage.cards.d.DeathInHeaven.class, NON_FULL_USE_VARIOUS)); //cards.add(new SetCardInfo("Death in Heaven", 671, Rarity.RARE, mage.cards.d.DeathInHeaven.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Decaying Time Loop", 685, Rarity.UNCOMMON, mage.cards.d.DecayingTimeLoop.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 f3ac15bca08..78dc6e06d3c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java @@ -50,14 +50,7 @@ public class ChooseACardNameEffect extends OneShotEffect { return nameSupplier.get(); } - public String getChoice(Game game, Ability source) { - return getChoice(game.getPlayer(source.getControllerId()), game, source, true); - } - - public String getChoice(Player player, Game game, Ability source, boolean setValue) { - if (player == null) { - return null; - } + public Choice makeChoiceObject() { Choice cardChoice = new ChoiceImpl(true, ChoiceHintType.CARD); Set names = this.getNames(); if (names.isEmpty()) { @@ -68,6 +61,18 @@ public class ChooseACardNameEffect extends OneShotEffect { cardChoice.setChoices(names); cardChoice.setMessage(CardUtil.getTextWithFirstCharUpperCase(this.getMessage())); cardChoice.clearChoice(); + return cardChoice; + } + + public String getChoice(Game game, Ability source) { + return getChoice(game.getPlayer(source.getControllerId()), game, source, true); + } + + public String getChoice(Player player, Game game, Ability source, boolean setValue) { + if (player == null) { + return null; + } + Choice cardChoice = makeChoiceObject(); player.choose(Outcome.Detriment, cardChoice, game); String cardName = cardChoice.getChoice(); if (cardName == null) { diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index 3f13573471d..c9963203f9e 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -724,7 +724,7 @@ public class GameState implements Serializable, Copyable { /** * Returns a list of all players of the game ignoring range or if a player * has lost or left the game. - * + *

* Warning, it's ignore range, must be used by game engine only. */ public PlayerList getPlayerList() { @@ -734,7 +734,7 @@ public class GameState implements Serializable, Copyable { /** * Returns a list of all active players of the game, setting the playerId to * the current player of the list. - * + *

* Warning, it's ignore range, must be used by game engine only. */ public PlayerList getPlayerList(UUID playerId) { @@ -1369,8 +1369,9 @@ public class GameState implements Serializable, Copyable { * @param valueId * @param value */ - public void setValue(String valueId, Object value) { + public T setValue(String valueId, T value) { values.put(valueId, value); + return value; } /**