[DFT] Implement Ketramose, the New Dawn and implement exile condition and dynamic value

This commit is contained in:
jmlundeen 2025-02-21 21:19:34 -06:00
parent e22a3ec19f
commit cbb3012b05
4 changed files with 261 additions and 0 deletions

View file

@ -0,0 +1,113 @@
package mage.cards.k;
import mage.MageInt;
import mage.abilities.BatchTriggeredAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.CardsInExileCondition;
import mage.abilities.dynamicvalue.common.CardsInExileCount;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.abilities.effects.common.combat.CantAttackBlockUnlessConditionSourceEffect;
import mage.abilities.keyword.IndestructibleAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeBatchEvent;
import mage.game.events.ZoneChangeEvent;
import java.util.UUID;
/**
* @author Jmlundeen
*/
public final class KetramoseTheNewDawn extends CardImpl {
public KetramoseTheNewDawn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{B}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.GOD);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Menace
this.addAbility(new MenaceAbility());
// Lifelink
this.addAbility(LifelinkAbility.getInstance());
// Indestructible
this.addAbility(IndestructibleAbility.getInstance());
// Ketramose can't attack or block unless there are seven or more cards in exile.
this.addAbility(new SimpleStaticAbility(
new CantAttackBlockUnlessConditionSourceEffect(new CardsInExileCondition(ComparisonType.MORE_THAN, 6, CardsInExileCount.ALL))
.setText("{this} can't attack or block unless there are seven or more cards in exile")
).addHint(CardsInExileCount.ALL.getHint()));
// Whenever one or more cards are put into exile from graveyards and/or the battlefield during your turn, you draw a card and lose 1 life.
this.addAbility(new KetramoseTriggeredAbility());
}
private KetramoseTheNewDawn(final KetramoseTheNewDawn card) {
super(card);
}
@Override
public KetramoseTheNewDawn copy() {
return new KetramoseTheNewDawn(this);
}
}
class KetramoseTriggeredAbility extends TriggeredAbilityImpl implements BatchTriggeredAbility<ZoneChangeEvent> {
KetramoseTriggeredAbility() {
super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false);
this.addEffect(new LoseLifeSourceControllerEffect(1));
}
private KetramoseTriggeredAbility(final KetramoseTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE_BATCH;
}
@Override
public boolean checkEvent(ZoneChangeEvent event, Game game) {
if (event.getToZone() != Zone.EXILED) {
return false;
}
return event.getFromZone() == Zone.GRAVEYARD || event.getFromZone() == Zone.BATTLEFIELD;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return game.getActivePlayerId().equals(getControllerId())
&& !getFilteredEvents((ZoneChangeBatchEvent) event, game).isEmpty();
}
@Override
public TriggeredAbility copy()
{
return new KetramoseTriggeredAbility(this);
}
@Override
public String getRule() {
return "Whenever one or more cards are put into exile from graveyards"
+ " and/or the battlefield during your turn, you draw a card and lose 1 life.";
}
}

View file

@ -131,6 +131,10 @@ public final class Aetherdrift extends ExpansionSet {
cards.add(new SetCardInfo("Jungle Hollow", 256, Rarity.COMMON, mage.cards.j.JungleHollow.class));
cards.add(new SetCardInfo("Kalakscion, Hunger Tyrant", 93, Rarity.UNCOMMON, mage.cards.k.KalakscionHungerTyrant.class));
cards.add(new SetCardInfo("Keen Buccaneer", 48, Rarity.COMMON, mage.cards.k.KeenBuccaneer.class));
cards.add(new SetCardInfo("Ketramose, the New Dawn", 209, Rarity.MYTHIC, mage.cards.k.KetramoseTheNewDawn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ketramose, the New Dawn", 350, Rarity.MYTHIC, mage.cards.k.KetramoseTheNewDawn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ketramose, the New Dawn", 482, Rarity.MYTHIC, mage.cards.k.KetramoseTheNewDawn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ketramose, the New Dawn", 549, Rarity.MYTHIC, mage.cards.k.KetramoseTheNewDawn.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kickoff Celebrations", 135, Rarity.COMMON, mage.cards.k.KickoffCelebrations.class));
cards.add(new SetCardInfo("Lagorin, Soul of Alacria", 211, Rarity.UNCOMMON, mage.cards.l.LagorinSoulOfAlacria.class));
cards.add(new SetCardInfo("Leonin Surveyor", 18, Rarity.COMMON, mage.cards.l.LeoninSurveyor.class));

View file

@ -0,0 +1,34 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.abilities.dynamicvalue.common.CardsInExileCount;
import mage.constants.ComparisonType;
import mage.game.Game;
public class CardsInExileCondition implements Condition
{
private final ComparisonType type;
private final int count;
private CardsInExileCount cardsInExileCount;
public CardsInExileCondition(ComparisonType type, int count)
{
this(type, count, CardsInExileCount.YOU);
}
public CardsInExileCondition(ComparisonType type, int count, CardsInExileCount cardsInExileCount)
{
this.type = type;
this.count = count;
this.cardsInExileCount = cardsInExileCount;
}
@Override
public boolean apply(Game game, Ability source)
{
int exileCards = cardsInExileCount.calculate(game, source, null);
return ComparisonType.compare(exileCards, type, count);
}
}

View file

@ -0,0 +1,110 @@
package mage.abilities.dynamicvalue.common;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.hint.Hint;
import mage.cards.Card;
import mage.constants.CardType;
import mage.game.Game;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author JayDi85
*/
public enum CardsInExileCount implements DynamicValue {
YOU("you"),
ALL("all players"),
OPPONENTS("your opponents'");
private final String message;
private final CardsInExileHint hint;
CardsInExileCount(String message) {
this.message = "The number of cards owned by " + message + " in exile";
this.hint = new CardsInExileHint(this);
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return getExileCards(game, sourceAbility)
.mapToInt(x -> 1)
.sum();
}
@Override
public CardsInExileCount copy() {
return this;
}
@Override
public String toString() {
return "X";
}
@Override
public String getMessage() {
return message;
}
public Hint getHint() {
return hint;
}
public Stream<Card> getExileCards(Game game, Ability ability) {
Collection<UUID> playerIds;
switch (this) {
case YOU:
playerIds = Collections.singletonList(ability.getControllerId());
break;
case OPPONENTS:
playerIds = game.getOpponents(ability.getControllerId());
break;
case ALL:
playerIds = game.getState().getPlayersInRange(ability.getControllerId(), game);
break;
default:
throw new IllegalArgumentException("Wrong code usage: miss implementation for " + this);
}
return playerIds.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.map(player -> game.getExile().getAllCards(game, player.getId()))
.flatMap(Collection::stream)
.filter(Objects::nonNull);
}
}
class CardsInExileHint implements Hint {
CardsInExileCount value;
CardsInExileHint(CardsInExileCount value) {
this.value = value;
}
private CardsInExileHint(final CardsInExileHint hint) {
this.value = hint.value;
}
@Override
public String getText(Game game, Ability ability) {
int count = value.getExileCards(game, ability)
.mapToInt(x -> 1)
.sum();
return this.value.getMessage() + ": " + count;
}
@Override
public CardsInExileHint copy() {
return new CardsInExileHint(this);
}
}