1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-03-30 09:08:36 -09:00

[VOC] Implemented Shadowgrange Archfiend AND Changed MadnessAbility ()

* 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:
Alex Vasile 2022-02-06 11:36:19 -05:00 committed by GitHub
parent 9ec6b617b8
commit 5945aaeda4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 233 additions and 63 deletions
Mage.Sets/src/mage
Mage/src/main/java/mage/abilities/keyword

View 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;
}
}

View file

@ -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));

View file

@ -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;
}
}