mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
Implemented Xyris and Kalamax (#6430)
* Implemented Xyris, the Writhing Storm * Name change for Xyris's draw ability. * Implemented Kalamax, the Stormsire. * Added Kalamax and Xyris to Commander2020Edition Set. * Updated XyrisTheWrithingStorm drawCards implementation. * Fixed bug where "First card drawn" was not enforced. * Removed unnecessary Predicates.or, and replaced custom effect with CreateTokenEffect
This commit is contained in:
parent
02730a194c
commit
1804b8df01
4 changed files with 295 additions and 0 deletions
137
Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java
Normal file
137
Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
package mage.cards.k;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.CopyTargetSpellEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.common.FilterInstantSpell;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.watchers.common.SpellsCastWatcher;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author AsterAether
|
||||
*/
|
||||
public final class KalamaxTheStormsire extends CardImpl {
|
||||
|
||||
public KalamaxTheStormsire(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}{R}");
|
||||
|
||||
this.addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.ELEMENTAL);
|
||||
this.subtype.add(SubType.DINOSAUR);
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// Whenever you cast your first instant spell each turn, if Kalamax, the Stormsire is tapped, copy that spell. You may choose new targets for the copy.
|
||||
this.addAbility(new KalamaxTheStormsireSpellCastAbility(), new SpellsCastWatcher());
|
||||
// Whenever you copy an instant spell, put a +1/+1 counter on Kalamax.
|
||||
this.addAbility(new KalamaxTheStormsireCopyTriggeredAbility());
|
||||
}
|
||||
|
||||
private KalamaxTheStormsire(final KalamaxTheStormsire card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KalamaxTheStormsire copy() {
|
||||
return new KalamaxTheStormsire(this);
|
||||
}
|
||||
}
|
||||
|
||||
class KalamaxTheStormsireSpellCastAbility extends SpellCastControllerTriggeredAbility {
|
||||
KalamaxTheStormsireSpellCastAbility() {
|
||||
super(new CopyTargetSpellEffect(true), new FilterInstantSpell(), false);
|
||||
}
|
||||
|
||||
KalamaxTheStormsireSpellCastAbility(KalamaxTheStormsireSpellCastAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KalamaxTheStormsireSpellCastAbility copy() {
|
||||
return new KalamaxTheStormsireSpellCastAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (super.checkTrigger(event, game)) {
|
||||
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
|
||||
if (watcher != null) {
|
||||
List<Spell> spells = watcher.getSpellsCastThisTurn(event.getPlayerId());
|
||||
if (spells != null && spells.stream().filter(MageObject::isInstant).count() == 1) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
if (spell != null && spell.isInstant()) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkInterveningIfClause(Game game) {
|
||||
Permanent permanent = game.getPermanent(getSourceId());
|
||||
return permanent != null && permanent.isTapped();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you cast your first instant spell each turn, " +
|
||||
"if Kalamax, the Stormsire is tapped, " +
|
||||
"copy that spell. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
||||
class KalamaxTheStormsireCopyTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
KalamaxTheStormsireCopyTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false);
|
||||
}
|
||||
|
||||
private KalamaxTheStormsireCopyTriggeredAbility(final KalamaxTheStormsireCopyTriggeredAbility effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.COPIED_STACKOBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Spell spell = game.getSpell(event.getTargetId());
|
||||
return spell != null && spell.isControlledBy(getControllerId()) && spell.isInstant();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KalamaxTheStormsireCopyTriggeredAbility copy() {
|
||||
return new KalamaxTheStormsireCopyTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you copy an instant spell, put a +1/+1 counter on {this}.";
|
||||
}
|
||||
}
|
129
Mage.Sets/src/mage/cards/x/XyrisTheWrithingStorm.java
Normal file
129
Mage.Sets/src/mage/cards/x/XyrisTheWrithingStorm.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
package mage.cards.x;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.token.SnakeToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.CardsDrawnDuringDrawStepWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author AsterAether
|
||||
*/
|
||||
public final class XyrisTheWrithingStorm extends CardImpl {
|
||||
|
||||
public XyrisTheWrithingStorm(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}{R}");
|
||||
|
||||
this.addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.SNAKE);
|
||||
this.subtype.add(SubType.LEVIATHAN);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(5);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Whenever an opponent draws a card except the first one they draw in each of their draw steps, create a 1/1 green Snake creature token.
|
||||
this.addAbility(new XyrisTheWrithingStormDrawAbility(), new CardsDrawnDuringDrawStepWatcher());
|
||||
// Whenever Xyris, the Writhing Storm deals combat damage to a player, you and that player each draw that many cards.
|
||||
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new XyrisTheWrithingStormCombatDamageEffect(), false, true));
|
||||
}
|
||||
|
||||
private XyrisTheWrithingStorm(final XyrisTheWrithingStorm card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XyrisTheWrithingStorm copy() {
|
||||
return new XyrisTheWrithingStorm(this);
|
||||
}
|
||||
}
|
||||
|
||||
class XyrisTheWrithingStormDrawAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public XyrisTheWrithingStormDrawAbility() {
|
||||
super(Zone.BATTLEFIELD, new CreateTokenEffect(new SnakeToken(), 1), false);
|
||||
}
|
||||
|
||||
public XyrisTheWrithingStormDrawAbility(final XyrisTheWrithingStormDrawAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DREW_CARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(event.getPlayerId(), game)) {
|
||||
if (game.isActivePlayer(event.getPlayerId())
|
||||
&& game.getPhase().getStep().getType() == PhaseStep.DRAW) {
|
||||
CardsDrawnDuringDrawStepWatcher watcher = game.getState().getWatcher(CardsDrawnDuringDrawStepWatcher.class);
|
||||
if (watcher != null && watcher.getAmountCardsDrawn(event.getPlayerId()) > 1) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriggeredAbility copy() {
|
||||
return new XyrisTheWrithingStormDrawAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever an opponent draws a card except the first one they draw in each of their draw steps, create a 1/1 green Snake creature token.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class XyrisTheWrithingStormCombatDamageEffect extends OneShotEffect {
|
||||
|
||||
public XyrisTheWrithingStormCombatDamageEffect() {
|
||||
super(Outcome.DrawCard);
|
||||
this.staticText = "you and that player each draw that many cards.";
|
||||
}
|
||||
|
||||
public XyrisTheWrithingStormCombatDamageEffect(final XyrisTheWrithingStormCombatDamageEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XyrisTheWrithingStormCombatDamageEffect copy() {
|
||||
return new XyrisTheWrithingStormCombatDamageEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player sourceController = game.getPlayer(source.getControllerId());
|
||||
Player damagedPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source));
|
||||
if (sourceController != null && damagedPlayer != null) {
|
||||
int amount = (Integer) getValue("damage");
|
||||
if (amount > 0) {
|
||||
sourceController.drawCards(amount, source.getSourceId(), game);
|
||||
damagedPlayer.drawCards(amount, source.getSourceId(), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -176,6 +176,7 @@ public final class Commander2020Edition extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Izzet Signet", 243, Rarity.UNCOMMON, mage.cards.i.IzzetSignet.class));
|
||||
cards.add(new SetCardInfo("Jace, Architect of Thought", 114, Rarity.MYTHIC, mage.cards.j.JaceArchitectOfThought.class));
|
||||
cards.add(new SetCardInfo("Jirina Kudro", 8, Rarity.MYTHIC, mage.cards.j.JirinaKudro.class));
|
||||
cards.add(new SetCardInfo("Kalamax, the Stormsire", 9, Rarity.MYTHIC, mage.cards.k.KalamaxTheStormsire.class));
|
||||
cards.add(new SetCardInfo("Kalemne's Captain", 92, Rarity.RARE, mage.cards.k.KalemnesCaptain.class));
|
||||
cards.add(new SetCardInfo("Karametra, God of Harvests", 218, Rarity.MYTHIC, mage.cards.k.KarametraGodOfHarvests.class));
|
||||
cards.add(new SetCardInfo("Kathril, Aspect Warper", 10, Rarity.MYTHIC, mage.cards.k.KathrilAspectWarper.class));
|
||||
|
@ -343,6 +344,7 @@ public final class Commander2020Edition extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Wydwen, the Biting Gale", 235, Rarity.RARE, mage.cards.w.WydwenTheBitingGale.class));
|
||||
cards.add(new SetCardInfo("Xathrid Necromancer", 141, Rarity.RARE, mage.cards.x.XathridNecromancer.class));
|
||||
cards.add(new SetCardInfo("Yannik, Scavenging Sentinel", 19, Rarity.MYTHIC, mage.cards.y.YannikScavengingSentinel.class));
|
||||
cards.add(new SetCardInfo("Xyris, the Writhing Storm", 18, Rarity.MYTHIC, mage.cards.x.XyrisTheWrithingStorm.class));
|
||||
cards.add(new SetCardInfo("Yavimaya Coast", 322, Rarity.RARE, mage.cards.y.YavimayaCoast.class));
|
||||
cards.add(new SetCardInfo("Yavimaya Dryad", 197, Rarity.UNCOMMON, mage.cards.y.YavimayaDryad.class));
|
||||
cards.add(new SetCardInfo("Zaxara, the Exemplary", 20, Rarity.MYTHIC, mage.cards.z.ZaxaraTheExemplary.class));
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package mage.filter.common;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.predicate.Predicates;
|
||||
|
||||
public class FilterInstantSpell extends FilterSpell {
|
||||
|
||||
public FilterInstantSpell() {
|
||||
this("instant spell");
|
||||
}
|
||||
|
||||
public FilterInstantSpell(String name) {
|
||||
super(name);
|
||||
this.add(CardType.INSTANT.getPredicate());
|
||||
}
|
||||
|
||||
public FilterInstantSpell(final FilterInstantSpell filter) {
|
||||
super(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterInstantSpell copy() {
|
||||
return new FilterInstantSpell(this);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue