mirror of
https://github.com/correl/mage.git
synced 2025-03-16 09:16:26 -09:00
[KHM] Implemented Cosima, God of the Voyage
This commit is contained in:
parent
af5331a9e4
commit
d056f6cec2
4 changed files with 317 additions and 22 deletions
295
Mage.Sets/src/mage/cards/c/CosimaGodOfTheVoyage.java
Normal file
295
Mage.Sets/src/mage/cards/c/CosimaGodOfTheVoyage.java
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
package mage.cards.c;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.MageObjectReference;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
|
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||||
|
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
|
||||||
|
import mage.abilities.effects.AsThoughEffectImpl;
|
||||||
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.keyword.CrewAbility;
|
||||||
|
import mage.cards.*;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.filter.FilterPermanent;
|
||||||
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class CosimaGodOfTheVoyage extends ModalDoubleFacesCard {
|
||||||
|
|
||||||
|
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.VEHICLE, "a Vehicle you control");
|
||||||
|
|
||||||
|
public CosimaGodOfTheVoyage(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo,
|
||||||
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GOD}, "{2}{U}",
|
||||||
|
"The Omenkeel", new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "{1}{U}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1.
|
||||||
|
// Cosima, God of the Voyage
|
||||||
|
// Legendary Creature - God
|
||||||
|
this.getLeftHalfCard().addSuperType(SuperType.LEGENDARY);
|
||||||
|
this.getLeftHalfCard().setPT(new MageInt(2), new MageInt(4));
|
||||||
|
|
||||||
|
// At the beginning of your upkeep, you may exile Cosima. If you do, it gains "Whenever a land enters the battlefield under your control, if Cosima is exiled, you may put a voyage counter on it. If you don't, return Cosima to the battlefield with X +1/+1 counters on it and draw X cards, where X is the number of voyage counters on it.
|
||||||
|
this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(
|
||||||
|
new CosimaGodOfTheVoyageEffect(), TargetController.YOU, true
|
||||||
|
));
|
||||||
|
|
||||||
|
// 2.
|
||||||
|
// The Omenkeel
|
||||||
|
// Legendary Artifact - Vehicle
|
||||||
|
this.getRightHalfCard().addSuperType(SuperType.LEGENDARY);
|
||||||
|
this.getRightHalfCard().setPT(new MageInt(3), new MageInt(3));
|
||||||
|
|
||||||
|
// Whenever a Vehicle you control deals combat damage to a player, that player exiles that many cards from the top of their library. You may play lands from among those cards for as long as they remain exiled.
|
||||||
|
this.getRightHalfCard().addAbility(new DealsDamageToAPlayerAllTriggeredAbility(
|
||||||
|
new TheOmenkeelEffect(), filter, false,
|
||||||
|
SetTargetPointer.PLAYER, true, true
|
||||||
|
));
|
||||||
|
|
||||||
|
// Crew 1
|
||||||
|
this.getRightHalfCard().addAbility(new CrewAbility(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CosimaGodOfTheVoyage(final CosimaGodOfTheVoyage card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CosimaGodOfTheVoyage copy() {
|
||||||
|
return new CosimaGodOfTheVoyage(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CosimaGodOfTheVoyageEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
CosimaGodOfTheVoyageEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
staticText = "exile {this}. If you do, it gains " +
|
||||||
|
"\"Whenever a land enters the battlefield under your control, if {this} is exiled, " +
|
||||||
|
"you may put a voyage counter on it. If you don't, return {this} to the battlefield " +
|
||||||
|
"with X +1/+1 counters on it and draw X cards, where X is the number of voyage counters on it.\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
private CosimaGodOfTheVoyageEffect(final CosimaGodOfTheVoyageEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CosimaGodOfTheVoyageEffect copy() {
|
||||||
|
return new CosimaGodOfTheVoyageEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
|
if (player == null || permanent == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Card card = game.getCard(permanent.getId());
|
||||||
|
player.moveCards(permanent, Zone.EXILED, source, game);
|
||||||
|
if (card == null || game.getState().getZone(card.getId()) != Zone.EXILED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
game.addEffect(new CosimaGodOfTheVoyageGainAbilityEffect(new MageObjectReference(card, game)), source);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CosimaGodOfTheVoyageGainAbilityEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
|
private final MageObjectReference mor;
|
||||||
|
|
||||||
|
CosimaGodOfTheVoyageGainAbilityEffect(MageObjectReference mor) {
|
||||||
|
super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
|
||||||
|
this.mor = mor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CosimaGodOfTheVoyageGainAbilityEffect(final CosimaGodOfTheVoyageGainAbilityEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
this.mor = effect.mor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CosimaGodOfTheVoyageGainAbilityEffect copy() {
|
||||||
|
return new CosimaGodOfTheVoyageGainAbilityEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Card card = mor.getCard(game);
|
||||||
|
if (card != null && game.getState().getZone(card.getId()) == Zone.EXILED) {
|
||||||
|
Ability ability = new CosimaGodOfTheVoyageTriggeredAbility();
|
||||||
|
ability.setSourceId(card.getId());
|
||||||
|
ability.setControllerId(source.getSourceId());
|
||||||
|
game.getState().addAbility(ability, card);
|
||||||
|
game.getState().addOtherAbility(card, ability);
|
||||||
|
} else {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CosimaGodOfTheVoyageTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
|
CosimaGodOfTheVoyageTriggeredAbility() {
|
||||||
|
super(Zone.EXILED, new CosimaGodOfTheVoyageReturnEffect());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CosimaGodOfTheVoyageTriggeredAbility(final CosimaGodOfTheVoyageTriggeredAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||||
|
return permanent != null && permanent.isLand() && permanent.isControlledBy(getControllerId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkInterveningIfClause(Game game) {
|
||||||
|
return game.getState().getZone(getSourceId()) == Zone.EXILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CosimaGodOfTheVoyageTriggeredAbility copy() {
|
||||||
|
return new CosimaGodOfTheVoyageTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
return "Whenever a land enters the battlefield under your control, if {this} is exiled, " +
|
||||||
|
"you may put a voyage counter on it. If you don't, return {this} to the battlefield " +
|
||||||
|
"with X +1/+1 counters on it and draw X cards, where X is the number of voyage counters on it.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CosimaGodOfTheVoyageReturnEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
CosimaGodOfTheVoyageReturnEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CosimaGodOfTheVoyageReturnEffect(final CosimaGodOfTheVoyageReturnEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CosimaGodOfTheVoyageReturnEffect copy() {
|
||||||
|
return new CosimaGodOfTheVoyageReturnEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
|
Card card = game.getCard(source.getSourceId());
|
||||||
|
if (player == null || card == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (player.chooseUse(outcome, "Add a voyage counter?", source, game)
|
||||||
|
&& card.addCounters(CounterType.VOYAGE.createInstance(), player.getId(), source, game)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int counterCount = card.getCounters(game).getCount(CounterType.VOYAGE);
|
||||||
|
player.moveCards(card, Zone.BATTLEFIELD, source, game);
|
||||||
|
if (counterCount < 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
player.drawCards(counterCount, source, game);
|
||||||
|
Permanent permanent = game.getPermanent(card.getId());
|
||||||
|
if (permanent != null) {
|
||||||
|
permanent.addCounters(CounterType.P1P1.createInstance(counterCount), player.getId(), source, game);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TheOmenkeelEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
TheOmenkeelEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
staticText = "that player exiles that many cards from the top of their library. " +
|
||||||
|
"You may play lands from among those cards for as long as they remain exiled.";
|
||||||
|
}
|
||||||
|
|
||||||
|
private TheOmenkeelEffect(final TheOmenkeelEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TheOmenkeelEffect copy() {
|
||||||
|
return new TheOmenkeelEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player player = game.getPlayer(source.getFirstTarget());
|
||||||
|
int damage = (Integer) getValue("damage");
|
||||||
|
if (player == null || damage < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, damage));
|
||||||
|
player.moveCards(cards, Zone.EXILED, source, game);
|
||||||
|
cards.removeIf(uuid -> game.getState().getZone(uuid) != Zone.EXILED);
|
||||||
|
cards.removeIf(uuid -> !game.getCard(uuid).isLand());
|
||||||
|
game.addEffect(new TheOmenkeelPlayFromExileEffect(cards, game), source);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TheOmenkeelPlayFromExileEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
|
private final Set<MageObjectReference> morSet = new HashSet<>();
|
||||||
|
|
||||||
|
TheOmenkeelPlayFromExileEffect(Cards cards, Game game) {
|
||||||
|
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||||
|
this.morSet.addAll(cards.stream().map(uuid -> new MageObjectReference(uuid, game)).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private TheOmenkeelPlayFromExileEffect(final TheOmenkeelPlayFromExileEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TheOmenkeelPlayFromExileEffect copy() {
|
||||||
|
return new TheOmenkeelPlayFromExileEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
|
||||||
|
if (!source.isControlledBy(affectedControllerId)
|
||||||
|
|| game.getState().getZone(sourceId) != Zone.EXILED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Card card = game.getCard(sourceId);
|
||||||
|
return card != null
|
||||||
|
&& card.isLand()
|
||||||
|
&& morSet.stream().anyMatch(mor -> mor.refersTo(card, game));
|
||||||
|
}
|
||||||
|
}
|
|
@ -91,6 +91,7 @@ public final class Kaldheim extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Cleaving Reaper", 376, Rarity.RARE, mage.cards.c.CleavingReaper.class));
|
cards.add(new SetCardInfo("Cleaving Reaper", 376, Rarity.RARE, mage.cards.c.CleavingReaper.class));
|
||||||
cards.add(new SetCardInfo("Codespell Cleric", 7, Rarity.COMMON, mage.cards.c.CodespellCleric.class));
|
cards.add(new SetCardInfo("Codespell Cleric", 7, Rarity.COMMON, mage.cards.c.CodespellCleric.class));
|
||||||
cards.add(new SetCardInfo("Colossal Plow", 236, Rarity.UNCOMMON, mage.cards.c.ColossalPlow.class));
|
cards.add(new SetCardInfo("Colossal Plow", 236, Rarity.UNCOMMON, mage.cards.c.ColossalPlow.class));
|
||||||
|
cards.add(new SetCardInfo("Cosima, God of the Voyage", 50, Rarity.RARE, mage.cards.c.CosimaGodOfTheVoyage.class));
|
||||||
cards.add(new SetCardInfo("Cosmos Elixir", 237, Rarity.RARE, mage.cards.c.CosmosElixir.class));
|
cards.add(new SetCardInfo("Cosmos Elixir", 237, Rarity.RARE, mage.cards.c.CosmosElixir.class));
|
||||||
cards.add(new SetCardInfo("Craven Hulk", 127, Rarity.COMMON, mage.cards.c.CravenHulk.class));
|
cards.add(new SetCardInfo("Craven Hulk", 127, Rarity.COMMON, mage.cards.c.CravenHulk.class));
|
||||||
cards.add(new SetCardInfo("Crippling Fear", 82, Rarity.RARE, mage.cards.c.CripplingFear.class));
|
cards.add(new SetCardInfo("Crippling Fear", 82, Rarity.RARE, mage.cards.c.CripplingFear.class));
|
||||||
|
|
|
@ -58,30 +58,28 @@ public class DealsDamageToAPlayerAllTriggeredAbility extends TriggeredAbilityImp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (!onlyCombat || ((DamagedPlayerEvent) event).isCombatDamage()) {
|
if (onlyCombat && !((DamagedPlayerEvent) event).isCombatDamage()) {
|
||||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
return false;
|
||||||
if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
}
|
||||||
for (Effect effect : this.getEffects()) {
|
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||||
effect.setValue("damage", event.getAmount());
|
if (permanent == null || !filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||||
effect.setValue("sourceId", event.getSourceId());
|
return false;
|
||||||
if (affectsDefendingPlayer) {
|
}
|
||||||
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
|
this.getEffects().setValue("damage", event.getAmount());
|
||||||
continue;
|
this.getEffects().setValue("sourceId", event.getSourceId());
|
||||||
}
|
if (affectsDefendingPlayer) {
|
||||||
switch (setTargetPointer) {
|
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||||
case PLAYER:
|
} else {
|
||||||
effect.setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
switch (setTargetPointer) {
|
||||||
break;
|
case PLAYER:
|
||||||
case PERMANENT:
|
this.getEffects().setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
||||||
effect.setTargetPointer(new FixedTarget(permanent.getId(), permanent.getZoneChangeCounter(game)));
|
break;
|
||||||
break;
|
case PERMANENT:
|
||||||
}
|
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||||
|
break;
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -164,6 +164,7 @@ public enum CounterType {
|
||||||
VIGILANCE("vigilance"),
|
VIGILANCE("vigilance"),
|
||||||
VITALITY("vitality"),
|
VITALITY("vitality"),
|
||||||
VORTEX("vortex"),
|
VORTEX("vortex"),
|
||||||
|
VOYAGE("voyage"),
|
||||||
WAGE("wage"),
|
WAGE("wage"),
|
||||||
WINCH("winch"),
|
WINCH("winch"),
|
||||||
WIND("wind"),
|
WIND("wind"),
|
||||||
|
|
Loading…
Add table
Reference in a new issue