[LCI] Implement Kellan, Daring Traveler (#11332)

Also adds Map Token, a new Token with implicit rules:
> {1}, {T}, sacrifice {this}: target creature you control explores. Activate only as a sorcery.
This commit is contained in:
Susucre 2023-10-24 19:36:16 +02:00 committed by GitHub
parent 7ec64639bd
commit d440cf5b08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 184 additions and 0 deletions

View file

@ -0,0 +1,141 @@
package mage.cards.k;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.IntPlusDynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.cards.*;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.permanent.token.MapToken;
import mage.players.Player;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author Susucr
*/
public final class KellanDaringTraveler extends AdventureCard {
private static final DynamicValue xValue = new IntPlusDynamicValue(1, KellanDynamicValue.instance);
private static final Hint hint = new ValueHint("Number of opponents controlling an artifact", KellanDynamicValue.instance);
public KellanDaringTraveler(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{1}{W}", "Journey On", "{G}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.FAERIE);
this.subtype.add(SubType.SCOUT);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Whenever Kellan, Daring Traveler attacks, reveal the top card of your library. If it's a creature card with mana value 3 or less, put it into your hand. Otherwise, you may put it into your graveyard.
this.addAbility(new AttacksTriggeredAbility(new KellanDaringTravelerEffect()));
// Journey On
// Create X Map tokens, where X is one plus the number of opponents who control an artifact.
this.getSpellCard().getSpellAbility().addEffect(
new CreateTokenEffect(new MapToken(), xValue)
.setText("create X Map tokens, where X is one plus the number of opponents who control an artifact")
);
this.getSpellCard().getSpellAbility().addHint(hint);
this.finalizeAdventure();
}
private KellanDaringTraveler(final KellanDaringTraveler card) {
super(card);
}
@Override
public KellanDaringTraveler copy() {
return new KellanDaringTraveler(this);
}
}
enum KellanDynamicValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Set<UUID> playerControllingArtifacts = game
.getBattlefield()
.getActivePermanents(
StaticFilters.FILTER_PERMANENT_ARTIFACT,
sourceAbility.getControllerId(),
sourceAbility, game
).stream()
.map(Controllable::getControllerId)
.collect(Collectors.toSet());
return game.getOpponents(sourceAbility.getControllerId())
.stream()
.filter(p -> playerControllingArtifacts.contains(p))
.mapToInt(p -> 1)
.sum();
}
@Override
public KellanDynamicValue copy() {
return this;
}
@Override
public String getMessage() {
return "X";
}
}
class KellanDaringTravelerEffect extends OneShotEffect {
public KellanDaringTravelerEffect() {
super(Outcome.PutCreatureInPlay);
this.staticText = "reveal the top card of your library. "
+ "If it's a creature card with mana value 3 or less, put it into your hand. "
+ "Otherwise, you may put it into your graveyard.";
}
private KellanDaringTravelerEffect(final KellanDaringTravelerEffect effect) {
super(effect);
}
@Override
public KellanDaringTravelerEffect copy() {
return new KellanDaringTravelerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
if (controller == null || sourceObject == null) {
return false;
}
if (controller.getLibrary().hasCards()) {
Card card = controller.getLibrary().getFromTop(game);
Cards cards = new CardsImpl(card);
controller.revealCards(sourceObject.getIdName(), cards, game);
if (card != null) {
if (card.isCreature(game) && card.getManaValue() <= 3) {
controller.moveCards(card, Zone.HAND, source, game);
} else if (controller.chooseUse(Outcome.Neutral, "Put " + card.getIdName() + " in your graveyard?", source, game)) {
controller.moveCards(card, Zone.GRAVEYARD, source, game);
}
}
}
return true;
}
}

View file

@ -27,6 +27,7 @@ public final class LostCavernsOfIxalan extends ExpansionSet {
cards.add(new SetCardInfo("Ghalta, Stampede Tyrant", 185, Rarity.MYTHIC, mage.cards.g.GhaltaStampedeTyrant.class));
cards.add(new SetCardInfo("Huatli, Poet of Unity", 189, Rarity.MYTHIC, mage.cards.h.HuatliPoetOfUnity.class));
cards.add(new SetCardInfo("Island", 288, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Kellan, Daring Traveler", 231, Rarity.RARE, mage.cards.k.KellanDaringTraveler.class));
cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Ojer Axonil, Deepest Might", 317, Rarity.MYTHIC, mage.cards.o.OjerAxonilDeepestMight.class));
cards.add(new SetCardInfo("Plains", 287, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));

View file

@ -55,6 +55,7 @@ public enum SubType {
FORTIFICATION("Fortification", SubTypeSet.ArtifactType),
GOLD("Gold", SubTypeSet.ArtifactType),
INCUBATOR("Incubator", SubTypeSet.ArtifactType),
MAP("Map", SubTypeSet.ArtifactType),
POWERSTONE("Powerstone", SubTypeSet.ArtifactType),
TREASURE("Treasure", SubTypeSet.ArtifactType),
VEHICLE("Vehicle", SubTypeSet.ArtifactType),

View file

@ -0,0 +1,41 @@
package mage.game.permanent.token;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.keyword.ExploreTargetEffect;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.target.common.TargetControlledCreaturePermanent;
/**
* @author Susucr
*/
public final class MapToken extends TokenImpl {
public MapToken() {
super("Map Token", "Map token");
cardType.add(CardType.ARTIFACT);
subtype.add(SubType.MAP);
Ability ability = new ActivateAsSorceryActivatedAbility(
new ExploreTargetEffect(false)
.setText("target creature you control explores"),
new GenericManaCost(1)
);
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
}
protected MapToken(final MapToken token) {
super(token);
}
public MapToken copy() {
return new MapToken(this);
}
}