mirror of
https://github.com/correl/mage.git
synced 2024-12-26 03:00:11 +00:00
(WIP) [SNC] Implemented Ob Nixilis, the Adversary (#8838)
* [SNC] Implemented Ob Nixilis, the Adversary * Allow starting loyalty to be changed on the stack Co-authored-by: Evan Kranzler <theelk801@gmail.com>
This commit is contained in:
parent
bf70d0b675
commit
d745141b7b
4 changed files with 233 additions and 1 deletions
225
Mage.Sets/src/mage/cards/o/ObNixilisTheAdversary.java
Normal file
225
Mage.Sets/src/mage/cards/o/ObNixilisTheAdversary.java
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
package mage.cards.o;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.LoyaltyAbility;
|
||||||
|
import mage.abilities.StaticAbility;
|
||||||
|
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
|
||||||
|
import mage.abilities.costs.Cost;
|
||||||
|
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
|
import mage.abilities.effects.common.DrawCardTargetEffect;
|
||||||
|
import mage.abilities.effects.common.InfoEffect;
|
||||||
|
import mage.abilities.effects.common.LoseLifeTargetEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
|
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.token.DevilToken;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
import mage.game.stack.StackObject;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.TargetPlayer;
|
||||||
|
import mage.target.common.TargetControlledPermanent;
|
||||||
|
import mage.util.functions.StackObjectCopyApplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author weirddan455
|
||||||
|
*/
|
||||||
|
public final class ObNixilisTheAdversary extends CardImpl {
|
||||||
|
|
||||||
|
public ObNixilisTheAdversary(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{B}{R}");
|
||||||
|
|
||||||
|
this.addSuperType(SuperType.LEGENDARY);
|
||||||
|
this.subtype.add(SubType.NIXILIS);
|
||||||
|
this.setStartingLoyalty(3);
|
||||||
|
|
||||||
|
// Casualty X. The copy isn't legendary and has starting loyalty X.
|
||||||
|
this.addAbility(new ObNixilisTheAdversaryCasualtyAbility(this));
|
||||||
|
|
||||||
|
// +1: Each opponent loses 2 life unless they discard a card. If you control a Demon or Devil, you gain 2 life.
|
||||||
|
this.addAbility(new LoyaltyAbility(new ObNixilisTheAdversaryDiscardEffect(), 1));
|
||||||
|
|
||||||
|
// −2: Create a 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target."
|
||||||
|
this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DevilToken()), -2));
|
||||||
|
|
||||||
|
// −7: Target player draws seven cards and loses 7 life.
|
||||||
|
Ability ability = new LoyaltyAbility(new DrawCardTargetEffect(7), -7);
|
||||||
|
ability.addEffect(new LoseLifeTargetEffect(7).setText("and loses 7 life"));
|
||||||
|
ability.addTarget(new TargetPlayer());
|
||||||
|
this.addAbility(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObNixilisTheAdversary(final ObNixilisTheAdversary card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObNixilisTheAdversary copy() {
|
||||||
|
return new ObNixilisTheAdversary(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObNixilisTheAdversaryCasualtyAbility extends StaticAbility {
|
||||||
|
|
||||||
|
public ObNixilisTheAdversaryCasualtyAbility(Card card) {
|
||||||
|
super(Zone.ALL, new InfoEffect(
|
||||||
|
"Casualty X. <i>(As you cast this spell, " +
|
||||||
|
"you may sacrifice a creature with power X. " +
|
||||||
|
"When you do, copy this spell. The copy becomes a token.)</i>"
|
||||||
|
));
|
||||||
|
card.getSpellAbility().addCost(new ObNixilisTheAdversaryCost());
|
||||||
|
this.setRuleAtTheTop(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObNixilisTheAdversaryCasualtyAbility(final ObNixilisTheAdversaryCasualtyAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObNixilisTheAdversaryCasualtyAbility copy() {
|
||||||
|
return new ObNixilisTheAdversaryCasualtyAbility(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObNixilisTheAdversaryCost extends SacrificeTargetCost {
|
||||||
|
|
||||||
|
public ObNixilisTheAdversaryCost() {
|
||||||
|
super(new TargetControlledPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT, true));
|
||||||
|
this.text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObNixilisTheAdversaryCost(final ObNixilisTheAdversaryCost cost) {
|
||||||
|
super(cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||||
|
if (!super.pay(ability, game, source, controllerId, noMana, costToPay)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<Permanent> sacrificedPermanents = getPermanents();
|
||||||
|
if (!sacrificedPermanents.isEmpty()) {
|
||||||
|
StackObjectCopyApplier applier = new ObNixilisTheAdversaryApplier(sacrificedPermanents.get(0).getPower().getValue());
|
||||||
|
game.fireReflexiveTriggeredAbility(new ReflexiveTriggeredAbility(
|
||||||
|
new ObNixilisTheAdversaryCopyEffect(applier), false, "when you do, copy this spell"
|
||||||
|
), source);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObNixilisTheAdversaryCost copy() {
|
||||||
|
return new ObNixilisTheAdversaryCost(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObNixilisTheAdversaryCopyEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
private final StackObjectCopyApplier applier;
|
||||||
|
|
||||||
|
public ObNixilisTheAdversaryCopyEffect(StackObjectCopyApplier applier) {
|
||||||
|
super(Outcome.Copy);
|
||||||
|
this.applier = applier;
|
||||||
|
this.staticText = "copy {this}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObNixilisTheAdversaryCopyEffect(final ObNixilisTheAdversaryCopyEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
this.applier = effect.applier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObNixilisTheAdversaryCopyEffect copy() {
|
||||||
|
return new ObNixilisTheAdversaryCopyEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Spell spell = game.getSpellOrLKIStack(source.getSourceId());
|
||||||
|
if (spell == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
spell.createCopyOnStack(game, source, source.getControllerId(), true, 1, applier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObNixilisTheAdversaryApplier implements StackObjectCopyApplier {
|
||||||
|
|
||||||
|
private final int loyalty;
|
||||||
|
|
||||||
|
public ObNixilisTheAdversaryApplier(int loyalty) {
|
||||||
|
this.loyalty = loyalty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modifySpell(StackObject stackObject, Game game) {
|
||||||
|
stackObject.getSuperType().remove(SuperType.LEGENDARY);
|
||||||
|
stackObject.setStartingLoyalty(loyalty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MageObjectReferencePredicate getNextNewTargetType(int copyNumber) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObNixilisTheAdversaryDiscardEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
public ObNixilisTheAdversaryDiscardEffect() {
|
||||||
|
super(Outcome.LoseLife);
|
||||||
|
this.staticText = "Each opponent loses 2 life unless they discard a card. If you control a Demon or Devil, you gain 2 life";
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObNixilisTheAdversaryDiscardEffect(final ObNixilisTheAdversaryDiscardEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObNixilisTheAdversaryDiscardEffect copy() {
|
||||||
|
return new ObNixilisTheAdversaryDiscardEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
UUID controllerId = source.getControllerId();
|
||||||
|
Player controller = game.getPlayer(controllerId);
|
||||||
|
if (controller == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (UUID opponentId : game.getOpponents(controllerId)) {
|
||||||
|
Player opponent = game.getPlayer(opponentId);
|
||||||
|
if (opponent == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (opponent.getHand().isEmpty() || !opponent.chooseUse(
|
||||||
|
Outcome.Discard, "Discard a card or lose 2 life?",
|
||||||
|
null, "Discard Card", "Lose 2 Life", source, game)
|
||||||
|
|| opponent.discard(1, false, false, source, game).isEmpty()) {
|
||||||
|
opponent.loseLife(2, game, source, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(controllerId)) {
|
||||||
|
if (permanent.hasSubtype(SubType.DEMON, game) || permanent.hasSubtype(SubType.DEVIL, game)) {
|
||||||
|
controller.gainLife(2, game, source);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -164,6 +164,7 @@ public final class StreetsOfNewCapenna extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Murder", 88, Rarity.COMMON, mage.cards.m.Murder.class));
|
cards.add(new SetCardInfo("Murder", 88, Rarity.COMMON, mage.cards.m.Murder.class));
|
||||||
cards.add(new SetCardInfo("Night Clubber", 89, Rarity.UNCOMMON, mage.cards.n.NightClubber.class));
|
cards.add(new SetCardInfo("Night Clubber", 89, Rarity.UNCOMMON, mage.cards.n.NightClubber.class));
|
||||||
cards.add(new SetCardInfo("Nimble Larcenist", 205, Rarity.UNCOMMON, mage.cards.n.NimbleLarcenist.class));
|
cards.add(new SetCardInfo("Nimble Larcenist", 205, Rarity.UNCOMMON, mage.cards.n.NimbleLarcenist.class));
|
||||||
|
cards.add(new SetCardInfo("Ob Nixilis, the Adversary", 206, Rarity.MYTHIC, mage.cards.o.ObNixilisTheAdversary.class));
|
||||||
cards.add(new SetCardInfo("Obscura Ascendancy", 207, Rarity.RARE, mage.cards.o.ObscuraAscendancy.class));
|
cards.add(new SetCardInfo("Obscura Ascendancy", 207, Rarity.RARE, mage.cards.o.ObscuraAscendancy.class));
|
||||||
cards.add(new SetCardInfo("Obscura Charm", 208, Rarity.UNCOMMON, mage.cards.o.ObscuraCharm.class));
|
cards.add(new SetCardInfo("Obscura Charm", 208, Rarity.UNCOMMON, mage.cards.o.ObscuraCharm.class));
|
||||||
cards.add(new SetCardInfo("Obscura Initiate", 50, Rarity.COMMON, mage.cards.o.ObscuraInitiate.class));
|
cards.add(new SetCardInfo("Obscura Initiate", 50, Rarity.COMMON, mage.cards.o.ObscuraInitiate.class));
|
||||||
|
|
|
@ -62,6 +62,7 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
private boolean countered;
|
private boolean countered;
|
||||||
private boolean resolving = false;
|
private boolean resolving = false;
|
||||||
private UUID commandedBy = null; // for Word of Command
|
private UUID commandedBy = null; // for Word of Command
|
||||||
|
private int startingLoyalty;
|
||||||
|
|
||||||
private ActivationManaAbilityStep currentActivatingManaAbilitiesStep = ActivationManaAbilityStep.BEFORE;
|
private ActivationManaAbilityStep currentActivatingManaAbilitiesStep = ActivationManaAbilityStep.BEFORE;
|
||||||
|
|
||||||
|
@ -78,6 +79,7 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
this.color = affectedCard.getColor(null).copy();
|
this.color = affectedCard.getColor(null).copy();
|
||||||
this.frameColor = affectedCard.getFrameColor(null).copy();
|
this.frameColor = affectedCard.getFrameColor(null).copy();
|
||||||
this.frameStyle = affectedCard.getFrameStyle();
|
this.frameStyle = affectedCard.getFrameStyle();
|
||||||
|
this.startingLoyalty = affectedCard.getStartingLoyalty();
|
||||||
this.id = ability.getId();
|
this.id = ability.getId();
|
||||||
this.zoneChangeCounter = affectedCard.getZoneChangeCounter(game); // sync card's ZCC with spell (copy spell settings)
|
this.zoneChangeCounter = affectedCard.getZoneChangeCounter(game); // sync card's ZCC with spell (copy spell settings)
|
||||||
this.ability = ability;
|
this.ability = ability;
|
||||||
|
@ -131,6 +133,7 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
|
|
||||||
this.currentActivatingManaAbilitiesStep = spell.currentActivatingManaAbilitiesStep;
|
this.currentActivatingManaAbilitiesStep = spell.currentActivatingManaAbilitiesStep;
|
||||||
this.targetChanged = spell.targetChanged;
|
this.targetChanged = spell.targetChanged;
|
||||||
|
this.startingLoyalty = spell.startingLoyalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean activate(Game game, boolean noMana) {
|
public boolean activate(Game game, boolean noMana) {
|
||||||
|
@ -654,11 +657,12 @@ public class Spell extends StackObjectImpl implements Card {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStartingLoyalty() {
|
public int getStartingLoyalty() {
|
||||||
return card.getStartingLoyalty();
|
return this.startingLoyalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStartingLoyalty(int startingLoyalty) {
|
public void setStartingLoyalty(int startingLoyalty) {
|
||||||
|
this.startingLoyalty = startingLoyalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -109,6 +109,8 @@ public class CopyTokenFunction implements Function<Token, Card> {
|
||||||
if (spell != null) {
|
if (spell != null) {
|
||||||
// copied spell puts to battlefield as token, so that token's ZCC must be synced with spell instead card (card can be moved before resolve)
|
// copied spell puts to battlefield as token, so that token's ZCC must be synced with spell instead card (card can be moved before resolve)
|
||||||
target.setZoneChangeCounter(spell.getZoneChangeCounter(game), game);
|
target.setZoneChangeCounter(spell.getZoneChangeCounter(game), game);
|
||||||
|
// Copy starting loyalty from spell (Ob Nixilis, the Adversary)
|
||||||
|
target.setStartingLoyalty(spell.getStartingLoyalty());
|
||||||
} else {
|
} else {
|
||||||
target.setZoneChangeCounter(source.getZoneChangeCounter(game), game);
|
target.setZoneChangeCounter(source.getZoneChangeCounter(game), game);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue