mirror of
https://github.com/correl/mage.git
synced 2025-03-30 09:08:36 -09:00
[VOC] Implemented Shadowgrange Archfiend AND Changed MadnessAbility (#8628)
* Implemented Shadowgrange Archfiend * Changed MadnessAbility to work with cards which also require life to be paid as part of the madness cost (so far only Shadowgrange Archfiend). * Updated Shadowgrange Archfiend to work with new Madness implementation (and actually cost life to cast using madness) * Removed unnecessary variable
This commit is contained in:
parent
9ec6b617b8
commit
5945aaeda4
3 changed files with 233 additions and 63 deletions
Mage.Sets/src/mage
Mage/src/main/java/mage/abilities/keyword
138
Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java
Normal file
138
Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java
Normal file
|
@ -0,0 +1,138 @@
|
|||
package mage.cards.s;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.abilities.keyword.MadnessAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.PowerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Alex-Vasile
|
||||
*/
|
||||
public final class ShadowgrangeArchfiend extends CardImpl {
|
||||
public ShadowgrangeArchfiend(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{B}");
|
||||
this.subtype.add(SubType.DEMON);
|
||||
|
||||
this.power = new MageInt(8);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// When Shadowgrange Archfiend enters the battlefield,
|
||||
// each opponent sacrifices a creature with the greatest power among creatures they control.
|
||||
// You gain life equal to the greatest power among creatures sacrificed this way.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new ShadowgrangeArchfiendEffect()));
|
||||
|
||||
// Madness—{2}{B}, Pay 8 life.
|
||||
MadnessAbility madnessAbility = new MadnessAbility(this, new ManaCostsImpl<>("{2}{B}"), 8);
|
||||
this.addAbility(madnessAbility);
|
||||
}
|
||||
|
||||
private ShadowgrangeArchfiend(final ShadowgrangeArchfiend card) { super(card); }
|
||||
|
||||
@Override
|
||||
public ShadowgrangeArchfiend copy() { return new ShadowgrangeArchfiend(this); }
|
||||
}
|
||||
|
||||
class ShadowgrangeArchfiendEffect extends OneShotEffect {
|
||||
|
||||
public ShadowgrangeArchfiendEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "each opponent sacrifices a creature with the greatest power among creatures they control. " +
|
||||
"You gain life equal to the greatest power among creatures sacrificed this way";
|
||||
}
|
||||
|
||||
private ShadowgrangeArchfiendEffect(final ShadowgrangeArchfiendEffect effect) { super(effect); }
|
||||
|
||||
@Override
|
||||
public ShadowgrangeArchfiendEffect copy() { return new ShadowgrangeArchfiendEffect(this); }
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {return false; }
|
||||
|
||||
List<Permanent> toSacrifice = new ArrayList<>();
|
||||
|
||||
// Iterate through each opponent
|
||||
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
|
||||
if (!controller.hasOpponent(playerId, game)) { continue; }
|
||||
|
||||
Player opponent = game.getPlayer(playerId);
|
||||
if (opponent == null) { continue; }
|
||||
|
||||
int greatestPower = Integer.MIN_VALUE;
|
||||
int numberOfCreatures = 0;
|
||||
Permanent creatureToSacrifice = null;
|
||||
|
||||
// Iterature through each creature
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) {
|
||||
if (permanent.getPower().getValue() > greatestPower) {
|
||||
greatestPower = permanent.getPower().getValue();
|
||||
numberOfCreatures = 1;
|
||||
creatureToSacrifice = permanent;
|
||||
} else if (permanent.getPower().getValue() == greatestPower) {
|
||||
numberOfCreatures++;
|
||||
}
|
||||
}
|
||||
|
||||
// If multiple creatures are tied for having the greatest power
|
||||
if (numberOfCreatures > 1) {
|
||||
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(
|
||||
"creature to sacrifice with power equal to " + greatestPower);
|
||||
filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, greatestPower));
|
||||
Target target = new TargetControlledCreaturePermanent(filter);
|
||||
if (opponent.choose(outcome, target, playerId, game)) {
|
||||
creatureToSacrifice = game.getPermanent(target.getFirstTarget());
|
||||
}
|
||||
}
|
||||
|
||||
if (creatureToSacrifice != null) {
|
||||
toSacrifice.add(creatureToSacrifice);
|
||||
}
|
||||
}
|
||||
|
||||
int greatestPowerAmongAllCreaturesSacked = Integer.MIN_VALUE;
|
||||
int powerOfCurrentCreature;
|
||||
|
||||
// Sack the creatures and save the greaterest power amoung those which were sacked
|
||||
for (Permanent permanent : toSacrifice) {
|
||||
powerOfCurrentCreature = permanent.getPower().getValue();
|
||||
|
||||
// Try to sack it
|
||||
if (permanent.sacrifice(source, game)) {
|
||||
if (powerOfCurrentCreature > greatestPowerAmongAllCreaturesSacked) {
|
||||
greatestPowerAmongAllCreaturesSacked = powerOfCurrentCreature;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gain life equal to the power of greatest creature sacked, if it is positive
|
||||
if (greatestPowerAmongAllCreaturesSacked > 0) {
|
||||
new GainLifeEffect(greatestPowerAmongAllCreaturesSacked).apply(game, source);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -131,6 +131,8 @@ public final class CrimsonVowCommander extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Scion of Opulence", 28, Rarity.RARE, mage.cards.s.ScionOfOpulence.class));
|
||||
cards.add(new SetCardInfo("Shacklegeist", 112, Rarity.RARE, mage.cards.s.Shacklegeist.class));
|
||||
cards.add(new SetCardInfo("Shadowblood Ridge", 181, Rarity.RARE, mage.cards.s.ShadowbloodRidge.class));
|
||||
cards.add(new SetCardInfo("Shadowgrange Archfiend", 22, Rarity.RARE, mage.cards.s.ShadowgrangeArchfiend.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Shadowgrange Archfiend", 60, Rarity.RARE, mage.cards.s.ShadowgrangeArchfiend.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Sinister Waltz", 30, Rarity.RARE, mage.cards.s.SinisterWaltz.class));
|
||||
cards.add(new SetCardInfo("Sire of the Storm", 113, Rarity.UNCOMMON, mage.cards.s.SireOfTheStorm.class));
|
||||
cards.add(new SetCardInfo("Sky Diamond", 167, Rarity.COMMON, mage.cards.s.SkyDiamond.class));
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
@ -52,14 +50,28 @@ public class MadnessAbility extends StaticAbility {
|
|||
|
||||
private final String rule;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MadnessAbility(Card card, ManaCosts madnessCost) {
|
||||
super(Zone.HAND, new MadnessReplacementEffect((ManaCosts<ManaCost>) madnessCost));
|
||||
addSubAbility(new MadnessTriggeredAbility((ManaCosts<ManaCost>) madnessCost, getOriginalId()));
|
||||
rule = "Madness " + madnessCost.getText() + " <i>(If you discard this card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.)</i>";
|
||||
public MadnessAbility(Card card, ManaCosts<ManaCost> madnessCost) {
|
||||
this(card, madnessCost, 0);
|
||||
}
|
||||
|
||||
public MadnessAbility(final MadnessAbility ability) {
|
||||
public MadnessAbility(Card card, ManaCosts<ManaCost> madnessCost, int lifeCost) {
|
||||
super(Zone.HAND, new MadnessReplacementEffect(madnessCost, lifeCost));
|
||||
addSubAbility(new MadnessTriggeredAbility(madnessCost, lifeCost, getOriginalId()));
|
||||
|
||||
String costText;
|
||||
|
||||
if (lifeCost > 0) {
|
||||
costText = "Madness—" + madnessCost.getText() + ", Pay " + lifeCost + " life.";
|
||||
} else {
|
||||
costText = "Madness " + madnessCost.getText();
|
||||
}
|
||||
|
||||
this.rule = costText + " <i>(If you discard this card, discard it into exile. " +
|
||||
"When you do, cast it for its madness cost or put it into your graveyard.)</i>";
|
||||
}
|
||||
|
||||
|
||||
private MadnessAbility(final MadnessAbility ability) {
|
||||
super(ability);
|
||||
this.rule = ability.rule;
|
||||
}
|
||||
|
@ -81,12 +93,21 @@ public class MadnessAbility extends StaticAbility {
|
|||
|
||||
class MadnessReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
public MadnessReplacementEffect(ManaCosts<ManaCost> madnessCost) {
|
||||
public MadnessReplacementEffect(ManaCosts<ManaCost> madnessCost, int lifeCost) {
|
||||
super(Duration.EndOfGame, Outcome.Benefit);
|
||||
staticText = "Madness " + madnessCost.getText() + " <i>(If you discard this card, you may cast it for its madness cost instead of putting it into your graveyard.)</i>";
|
||||
|
||||
String costText;
|
||||
|
||||
if (lifeCost > 0) {
|
||||
costText = "Madness—" + madnessCost.getText() + ", Pay " + lifeCost + " life.";
|
||||
} else {
|
||||
costText = "Madness " + madnessCost.getText();
|
||||
}
|
||||
|
||||
staticText = costText + " <i>(If you discard this card, you may cast it for its madness cost instead of putting it into your graveyard.)</i>";
|
||||
}
|
||||
|
||||
public MadnessReplacementEffect(final MadnessReplacementEffect effect) {
|
||||
private MadnessReplacementEffect(final MadnessReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
@ -103,18 +124,19 @@ class MadnessReplacementEffect extends ReplacementEffectImpl {
|
|||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null) {
|
||||
if (controller.moveCardToExileWithInfo(card, source.getSourceId(), "Madness", source, game, ((ZoneChangeEvent) event).getFromZone(), true)) {
|
||||
game.applyEffects(); // needed to add Madness ability to cards (e.g. by Falkenrath Gorger)
|
||||
GameEvent gameEvent = new MadnessCardExiledEvent(card.getId(), source, controller.getId());
|
||||
game.fireEvent(gameEvent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (controller == null) { return false; }
|
||||
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card == null) { return false; }
|
||||
|
||||
// TODO, deal with deprecated call
|
||||
if (controller.moveCardToExileWithInfo(card, source.getSourceId(), "Madness", source, game, ((ZoneChangeEvent) event).getFromZone(), true)) {
|
||||
game.applyEffects(); // needed to add Madness ability to cards (e.g. by Falkenrath Gorger)
|
||||
GameEvent gameEvent = new MadnessCardExiledEvent(card.getId(), source, controller.getId());
|
||||
game.fireEvent(gameEvent);
|
||||
}
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -125,7 +147,8 @@ class MadnessReplacementEffect extends ReplacementEffectImpl {
|
|||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
return event.getTargetId().equals(source.getSourceId())
|
||||
&& ((ZoneChangeEvent) event).getFromZone() == Zone.HAND && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD;
|
||||
&& ((ZoneChangeEvent) event).getFromZone() == Zone.HAND
|
||||
&& ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -138,13 +161,13 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
private final UUID madnessOriginalId;
|
||||
|
||||
MadnessTriggeredAbility(ManaCosts<ManaCost> madnessCost, UUID madnessOriginalId) {
|
||||
super(Zone.EXILED, new MadnessCastEffect(madnessCost), true);
|
||||
MadnessTriggeredAbility(ManaCosts<ManaCost> madnessCost, int lifeCost, UUID madnessOriginalId) {
|
||||
super(Zone.EXILED, new MadnessCastEffect(madnessCost, lifeCost), true);
|
||||
this.madnessOriginalId = madnessOriginalId;
|
||||
this.setRuleVisible(false);
|
||||
}
|
||||
|
||||
MadnessTriggeredAbility(final MadnessTriggeredAbility ability) {
|
||||
private MadnessTriggeredAbility(final MadnessTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.madnessOriginalId = ability.madnessOriginalId;
|
||||
}
|
||||
|
@ -161,23 +184,23 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return event.getSourceId().equals(madnessOriginalId); // Check that the event was from the connected replacement effect
|
||||
// Check that the event was from the connected replacement effect
|
||||
return event.getSourceId().equals(madnessOriginalId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resolve(Game game) {
|
||||
if (!super.resolve(game)) {
|
||||
Card card = game.getCard(getSourceId());
|
||||
if (card != null) {
|
||||
Player owner = game.getPlayer(card.getOwnerId());
|
||||
if (owner != null) {
|
||||
// if cast was not successfull, the card is moved to graveyard
|
||||
owner.moveCards(card, Zone.GRAVEYARD, this, game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (super.resolve(game)) { return true; }
|
||||
|
||||
Card card = game.getCard(getSourceId());
|
||||
if (card == null) { return false; }
|
||||
|
||||
Player owner = game.getPlayer(card.getOwnerId());
|
||||
if (owner == null) { return false; }
|
||||
|
||||
// if cast was not successfull, the card is moved to graveyard
|
||||
owner.moveCards(card, Zone.GRAVEYARD, this, game);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -189,43 +212,52 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl {
|
|||
class MadnessCastEffect extends OneShotEffect {
|
||||
|
||||
private final ManaCosts<ManaCost> madnessCost;
|
||||
private final int lifeCost;
|
||||
|
||||
public MadnessCastEffect(ManaCosts<ManaCost> madnessCost) {
|
||||
public MadnessCastEffect(ManaCosts<ManaCost> madnessCost, int lifeCost) {
|
||||
super(Outcome.Benefit);
|
||||
this.madnessCost = madnessCost;
|
||||
staticText = "you may cast it by paying " + madnessCost.getText() + " instead of putting it into your graveyard";
|
||||
this.lifeCost = lifeCost;
|
||||
|
||||
String costText;
|
||||
|
||||
if (lifeCost > 0) {
|
||||
costText = madnessCost.getText() + " and " + lifeCost + " life";
|
||||
} else {
|
||||
costText = madnessCost.getText();
|
||||
}
|
||||
|
||||
staticText = "you may cast it by paying " + costText + " instead of putting it into your graveyard";
|
||||
}
|
||||
|
||||
public MadnessCastEffect(final MadnessCastEffect effect) {
|
||||
private MadnessCastEffect(final MadnessCastEffect effect) {
|
||||
super(effect);
|
||||
this.madnessCost = effect.madnessCost;
|
||||
this.lifeCost = effect.lifeCost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MadnessCastEffect copy() { return new MadnessCastEffect(this); }
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
if (card == null) { return false; }
|
||||
|
||||
Player owner = game.getPlayer(card.getOwnerId());
|
||||
if (owner == null) {
|
||||
return false;
|
||||
}
|
||||
if (owner == null) { return false; }
|
||||
|
||||
// replace with the new cost
|
||||
// Replace with the new cost
|
||||
SpellAbility castByMadness = card.getSpellAbility().copy();
|
||||
ManaCosts<ManaCost> costRef = castByMadness.getManaCostsToPay();
|
||||
castByMadness.setSpellAbilityType(SpellAbilityType.BASE_ALTERNATE);
|
||||
castByMadness.setSpellAbilityCastMode(SpellAbilityCastMode.MADNESS);
|
||||
castByMadness.getCosts().clear();
|
||||
castByMadness.addCost(new PayLifeCost(this.lifeCost));
|
||||
costRef.clear();
|
||||
costRef.add(madnessCost);
|
||||
return owner.cast(castByMadness, game, false, new ApprovingObject(source, game));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MadnessCastEffect copy() {
|
||||
return new MadnessCastEffect(this);
|
||||
return owner.cast(castByMadness, game, false, new ApprovingObject(source, game));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,12 +268,10 @@ enum MadnessCondition implements Condition {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject madnessSpell = game.getLastKnownInformation(source.getSourceId(), Zone.STACK, source.getSourceObjectZoneChangeCounter() - 1);
|
||||
if (madnessSpell instanceof Spell) {
|
||||
if (((Spell) madnessSpell).getSpellAbility() != null) {
|
||||
return ((Spell) madnessSpell).getSpellAbility().getSpellAbilityCastMode() == SpellAbilityCastMode.MADNESS;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!(madnessSpell instanceof Spell)) { return false; }
|
||||
|
||||
if (((Spell) madnessSpell).getSpellAbility() == null) { return false; }
|
||||
|
||||
return ((Spell) madnessSpell).getSpellAbility().getSpellAbilityCastMode() == SpellAbilityCastMode.MADNESS;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue