[WOE] Implement Agatha's Soul Cauldron (#11039)

* [WOE] Implement Agatha's Soul Cauldron

* add test

* remove static import
This commit is contained in:
Evan Kranzler 2023-08-26 17:56:46 -04:00 committed by GitHub
parent aa71f0ba8a
commit 73dffb8de9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 248 additions and 0 deletions

View file

@ -0,0 +1,193 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.AsThoughManaEffect;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.ExileZone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.ManaPoolItem;
import mage.players.Player;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.util.CardUtil;
import java.util.Collection;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class AgathasSoulCauldron extends CardImpl {
public AgathasSoulCauldron(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
this.supertype.add(SuperType.LEGENDARY);
// You may spend mana as though it were mana of any color to activate abilities of creatures you control.
this.addAbility(new SimpleStaticAbility(new AgathasSoulCauldronManaEffect()));
// Creatures you control with +1/+1 counters on them have all activated abilities of all creature cards exiled with Agatha's Soul Cauldron.
this.addAbility(new SimpleStaticAbility(new AgathasSoulCauldronAbilityEffect()));
// {T}: Exile target card from a graveyard. When a creature card is exiled this way, put a +1/+1 counter on target creature you control.
Ability ability = new SimpleActivatedAbility(new AgathasSoulCauldronExileEffect(), new TapSourceCost());
ability.addTarget(new TargetCardInGraveyard());
this.addAbility(ability);
}
private AgathasSoulCauldron(final AgathasSoulCauldron card) {
super(card);
}
@Override
public AgathasSoulCauldron copy() {
return new AgathasSoulCauldron(this);
}
}
class AgathasSoulCauldronManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
AgathasSoulCauldronManaEffect() {
super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "you may spend mana as though it were mana of any color to activate abilities of creatures you control";
}
private AgathasSoulCauldronManaEffect(final AgathasSoulCauldronManaEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public AgathasSoulCauldronManaEffect copy() {
return new AgathasSoulCauldronManaEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (!source.isControlledBy(affectedControllerId)) {
return false;
}
Permanent permanent = game.getPermanent(CardUtil.getMainCardId(game, objectId));
return permanent != null && permanent.isControlledBy(source.getControllerId()) && permanent.isCreature(game);
}
@Override
public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) {
return mana.getFirstAvailable();
}
}
class AgathasSoulCauldronAbilityEffect extends ContinuousEffectImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent();
static {
filter.add(CounterType.P1P1.getPredicate());
}
AgathasSoulCauldronAbilityEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = "creatures you control with +1/+1 counters on them have all " +
"activated abilities of all creature cards exiled with {this}";
}
private AgathasSoulCauldronAbilityEffect(final AgathasSoulCauldronAbilityEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(
game, source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId())
));
if (exileZone == null || exileZone.isEmpty()) {
return false;
}
Set<Ability> abilities = exileZone
.getCards(StaticFilters.FILTER_CARD_CREATURE, game)
.stream()
.map(card -> card.getAbilities(game))
.flatMap(Collection::stream)
.filter(ActivatedAbility.class::isInstance)
.collect(Collectors.toSet());
if (abilities.isEmpty()) {
return false;
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
for (Ability ability : abilities) {
permanent.addAbility(ability, source.getSourceId(), game);
}
}
return true;
}
@Override
public AgathasSoulCauldronAbilityEffect copy() {
return new AgathasSoulCauldronAbilityEffect(this);
}
}
class AgathasSoulCauldronExileEffect extends OneShotEffect {
AgathasSoulCauldronExileEffect() {
super(Outcome.Benefit);
staticText = "exile target card from a graveyard. When a creature card " +
"is exiled this way, put a +1/+1 counter on target creature you control";
}
private AgathasSoulCauldronExileEffect(final AgathasSoulCauldronExileEffect effect) {
super(effect);
}
@Override
public AgathasSoulCauldronExileEffect copy() {
return new AgathasSoulCauldronExileEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (player == null || card == null) {
return false;
}
player.moveCardsToExile(
card, source, game, true,
CardUtil.getExileZoneId(game, source),
CardUtil.getSourceName(game, source)
);
if (!card.isCreature(game)) {
return true;
}
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false
);
ability.addTarget(new TargetControlledCreaturePermanent());
game.fireReflexiveTriggeredAbility(ability, source);
return true;
}
}

View file

@ -23,6 +23,7 @@ public final class WildsOfEldraine extends ExpansionSet {
cards.add(new SetCardInfo("A Tale for the Ages", 34, Rarity.RARE, mage.cards.a.ATaleForTheAges.class));
cards.add(new SetCardInfo("Agatha of the Vile Cauldron", 199, Rarity.MYTHIC, mage.cards.a.AgathaOfTheVileCauldron.class));
cards.add(new SetCardInfo("Agatha's Champion", 160, Rarity.UNCOMMON, mage.cards.a.AgathasChampion.class));
cards.add(new SetCardInfo("Agatha's Soul Cauldron", 242, Rarity.MYTHIC, mage.cards.a.AgathasSoulCauldron.class));
cards.add(new SetCardInfo("Archive Dragon", 41, Rarity.UNCOMMON, mage.cards.a.ArchiveDragon.class));
cards.add(new SetCardInfo("Archon of the Wild Rose", 1, Rarity.RARE, mage.cards.a.ArchonOfTheWildRose.class));
cards.add(new SetCardInfo("Archon's Glory", 2, Rarity.COMMON, mage.cards.a.ArchonsGlory.class));

View file

@ -0,0 +1,54 @@
package org.mage.test.cards.single.woe;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author TheElk801
*/
public class AgathasSoulCauldronTest extends CardTestPlayerBase {
private static final String cauldron = "Agatha's Soul Cauldron";
private static final String medic = "Stone Haven Medic";
private static final String bear = "Grizzly Bears";
@Test
public void testManaColor() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerA, cauldron);
addCard(Zone.BATTLEFIELD, playerA, medic);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{W}");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLife(playerA, 20 + 1);
}
@Test
public void testExileTriggerAddAbility() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerA, cauldron);
addCard(Zone.BATTLEFIELD, playerA, bear);
addCard(Zone.GRAVEYARD, playerA, medic);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Exile", medic);
addTarget(playerA, bear);
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{W}");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertTapped(cauldron, true);
assertTapped(bear, true);
assertCounterCount(playerA, bear, CounterType.P1P1, 1);
assertLife(playerA, 20 + 1);
assertExileCount(playerA, medic, 1);
}
}