mirror of
https://github.com/correl/mage.git
synced 2024-12-25 19:25:41 +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("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("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 Charm", 208, Rarity.UNCOMMON, mage.cards.o.ObscuraCharm.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 resolving = false;
|
||||
private UUID commandedBy = null; // for Word of Command
|
||||
private int startingLoyalty;
|
||||
|
||||
private ActivationManaAbilityStep currentActivatingManaAbilitiesStep = ActivationManaAbilityStep.BEFORE;
|
||||
|
||||
|
@ -78,6 +79,7 @@ public class Spell extends StackObjectImpl implements Card {
|
|||
this.color = affectedCard.getColor(null).copy();
|
||||
this.frameColor = affectedCard.getFrameColor(null).copy();
|
||||
this.frameStyle = affectedCard.getFrameStyle();
|
||||
this.startingLoyalty = affectedCard.getStartingLoyalty();
|
||||
this.id = ability.getId();
|
||||
this.zoneChangeCounter = affectedCard.getZoneChangeCounter(game); // sync card's ZCC with spell (copy spell settings)
|
||||
this.ability = ability;
|
||||
|
@ -131,6 +133,7 @@ public class Spell extends StackObjectImpl implements Card {
|
|||
|
||||
this.currentActivatingManaAbilitiesStep = spell.currentActivatingManaAbilitiesStep;
|
||||
this.targetChanged = spell.targetChanged;
|
||||
this.startingLoyalty = spell.startingLoyalty;
|
||||
}
|
||||
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
|
@ -654,11 +657,12 @@ public class Spell extends StackObjectImpl implements Card {
|
|||
|
||||
@Override
|
||||
public int getStartingLoyalty() {
|
||||
return card.getStartingLoyalty();
|
||||
return this.startingLoyalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartingLoyalty(int startingLoyalty) {
|
||||
this.startingLoyalty = startingLoyalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -109,6 +109,8 @@ public class CopyTokenFunction implements Function<Token, Card> {
|
|||
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)
|
||||
target.setZoneChangeCounter(spell.getZoneChangeCounter(game), game);
|
||||
// Copy starting loyalty from spell (Ob Nixilis, the Adversary)
|
||||
target.setStartingLoyalty(spell.getStartingLoyalty());
|
||||
} else {
|
||||
target.setZoneChangeCounter(source.getZoneChangeCounter(game), game);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue