Cleanup: replace custom code with common classes, text fixes to abilities (#10304)

* Use common FirstCombatPhaseCondition on Raiyuu, Storm's Edge

* Use common ReturnFromExileForSourceEffect on Parallax Wave

* Use common exile effects on Prowling Geistcatcher (attempt to fix #9981)

* Fix text: Fading ability

* Fix text: Endangered Armodon

* Fix text: Nemata, Primeval Warden

* Fix text: Capitalization on alternative/additional costs other than mana
This commit is contained in:
xenohedron 2023-05-09 10:01:48 -04:00 committed by GitHub
parent 550d719498
commit 4c13b42dee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 41 additions and 111 deletions

View file

@ -20,7 +20,7 @@ import java.util.UUID;
*/
public final class EndangeredArmodon extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with toughness 2 or less");
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature with toughness 2 or less");
static {
filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, 3));

View file

@ -30,9 +30,11 @@ import java.util.UUID;
public final class NemataPrimevalWarden extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Saproling");
private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("Saprolings");
static {
filter.add(SubType.SAPROLING.getPredicate());
filter2.add(SubType.SAPROLING.getPredicate());
}
public NemataPrimevalWarden(UUID ownerId, CardSetInfo setInfo) {
@ -60,7 +62,7 @@ public final class NemataPrimevalWarden extends CardImpl {
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new DrawCardSourceControllerEffect(1),
new ManaCostsImpl<>("{1}{B}"));
ability2.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false)));
ability2.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(2, 2, filter2, false)));
this.addAbility(ability2);
}

View file

@ -1,27 +1,21 @@
package mage.cards.p;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTargetForSourceEffect;
import mage.abilities.effects.common.ReturnFromExileForSourceEffect;
import mage.abilities.keyword.FadingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.ExileZone;
import mage.game.Game;
import mage.game.permanent.PermanentToken;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
@ -41,7 +35,7 @@ public final class ParallaxWave extends CardImpl {
this.addAbility(ability);
// When Parallax Wave leaves the battlefield, each player returns to the battlefield all cards they own exiled with Parallax Wave.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ParallaxWaveEffect(), false));
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false));
}
@ -54,38 +48,3 @@ public final class ParallaxWave extends CardImpl {
return new ParallaxWave(this);
}
}
class ParallaxWaveEffect extends OneShotEffect {
public ParallaxWaveEffect() {
super(Outcome.Benefit);
this.staticText = "each player returns to the battlefield all cards they own exiled with {this}";
}
public ParallaxWaveEffect(final ParallaxWaveEffect effect) {
super(effect);
}
@Override
public ParallaxWaveEffect copy() {
return new ParallaxWaveEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
MageObject sourceObject = source.getSourceObject(game);
Player controller = game.getPlayer(source.getControllerId());
if (sourceObject != null && controller != null) {
int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1;
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter);
if (exileZoneId != null) {
ExileZone exileZone = game.getExile().getExileZone(exileZoneId);
if (exileZone != null) {
return controller.moveCards(exileZone.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null);
}
return true;
}
}
return false;
}
}

View file

@ -4,8 +4,8 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.common.SacrificePermanentTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.abilities.effects.common.ExileTargetForSourceEffect;
import mage.abilities.effects.common.ReturnFromExileForSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -14,12 +14,9 @@ import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.game.ExileZone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.UUID;
@ -43,7 +40,8 @@ public final class ProwlingGeistcatcher extends CardImpl {
));
// When Prowling Geistcatcher leaves the battlefield, return each card exiled with it to the battlefield under your control.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ProwlingGeistcatcherReturnEffect(), false));
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD)
.setText("return each card exiled with it to the battlefield under your control"), false));
}
private ProwlingGeistcatcher(final ProwlingGeistcatcher card) {
@ -56,10 +54,11 @@ public final class ProwlingGeistcatcher extends CardImpl {
}
}
class ProwlingGeistcatcherExileEffect extends OneShotEffect {
class ProwlingGeistcatcherExileEffect extends ExileTargetForSourceEffect {
ProwlingGeistcatcherExileEffect() {
super(Outcome.Benefit);
super();
setOutcome(Outcome.Benefit);
staticText = "exile it. If that creature was a token, put a +1/+1 counter on {this}";
}
@ -74,15 +73,7 @@ class ProwlingGeistcatcherExileEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (player != null && card != null) {
player.moveCardsToExile(
card, source, game, true,
CardUtil.getExileZoneId(game, source),
CardUtil.getSourceName(game, source)
);
}
super.apply(game, source);
Permanent exiled = (Permanent) getValue("sacrificedPermanent");
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (exiled instanceof PermanentToken && permanent != null) {
@ -91,28 +82,3 @@ class ProwlingGeistcatcherExileEffect extends OneShotEffect {
return true;
}
}
class ProwlingGeistcatcherReturnEffect extends OneShotEffect {
ProwlingGeistcatcherReturnEffect() {
super(Outcome.Benefit);
staticText = "return each card exiled with it to the battlefield under your control";
}
private ProwlingGeistcatcherReturnEffect(final ProwlingGeistcatcherReturnEffect effect) {
super(effect);
}
@Override
public ProwlingGeistcatcherReturnEffect copy() {
return new ProwlingGeistcatcherReturnEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source));
return player != null && exileZone != null && !exileZone.isEmpty()
&& player.moveCards(exileZone, Zone.BATTLEFIELD, source, game);
}
}

View file

@ -3,7 +3,7 @@ package mage.cards.r;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAloneControlledTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.FirstCombatPhaseCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.AdditionalCombatPhaseEffect;
import mage.abilities.effects.common.UntapTargetEffect;
@ -13,9 +13,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TurnPhase;
import mage.filter.StaticFilters;
import mage.game.Game;
import java.util.UUID;
@ -43,7 +41,7 @@ public final class RaiyuuStormsEdge extends CardImpl {
true, false
);
ability.addEffect(new ConditionalOneShotEffect(
new AdditionalCombatPhaseEffect(), RaiyuuStormsEdgeCondition.instance,
new AdditionalCombatPhaseEffect(), FirstCombatPhaseCondition.instance,
"If it's the first combat phase of the turn, there is an additional combat phase after this phase"
));
this.addAbility(ability);
@ -58,12 +56,3 @@ public final class RaiyuuStormsEdge extends CardImpl {
return new RaiyuuStormsEdge(this);
}
}
enum RaiyuuStormsEdgeCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
return game.getTurn().getPhase(TurnPhase.COMBAT).getCount() == 0;
}
}

View file

@ -2,6 +2,7 @@ package mage.abilities.costs;
import mage.abilities.costs.mana.ManaCost;
import mage.game.Game;
import mage.util.CardUtil;
/**
* Alternative costs
@ -62,7 +63,7 @@ public class AlternativeCostImpl<T extends AlternativeCostImpl<T>> extends Costs
@Override
public String getReminderText() {
if (reminderText != null && !reminderText.isEmpty()) {
return "<i>(" + reminderText.replace("{cost}", this.getText(true)) + ")</i>";
return "<i>(" + reminderText.replace("{cost}", CardUtil.getTextWithFirstCharLowerCase(this.getText(true))) + ")</i>";
}
return "";
}

View file

@ -1,6 +1,7 @@
package mage.abilities.costs;
import mage.abilities.costs.mana.VariableManaCost;
import mage.util.CardUtil;
/**
* @author LevelX2
@ -44,8 +45,8 @@ public class OptionalAdditionalCostImpl extends CostsImpl<Cost> implements Optio
}
/**
* Returns the complete text for the addional cost or if onlyCost is true
* only the pure text fore the included native cost
* Returns the complete text for the additional cost or if onlyCost is true
* only the pure text for the included native cost
*
* @param onlyCost
* @return
@ -55,7 +56,7 @@ public class OptionalAdditionalCostImpl extends CostsImpl<Cost> implements Optio
if (onlyCost) {
return getText();
} else {
return name + delimiter + getText();
return name + delimiter + getText() + (delimiter.equals("&mdash;") ? "." : "");
}
}
@ -68,7 +69,7 @@ public class OptionalAdditionalCostImpl extends CostsImpl<Cost> implements Optio
public String getReminderText() {
String replace = "";
if (reminderText != null && !reminderText.isEmpty()) {
replace = reminderText.replace("{cost}", this.getText(true));
replace = reminderText.replace("{cost}", CardUtil.getTextWithFirstCharLowerCase(this.getText(true)));
}
return replace;
}

View file

@ -6,11 +6,13 @@ import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.Card;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
/*
* 702.31. Fading
@ -31,10 +33,20 @@ public class FadingAbility extends EntersBattlefieldAbility {
Ability ability = new BeginningOfUpkeepTriggeredAbility(new FadingEffect(), TargetController.YOU, false);
ability.setRuleVisible(false);
addSubAbility(ability);
String cardTypeName;
if (card.getCardType().contains(CardType.CREATURE)) {
cardTypeName = "creature";
} else if (card.getCardType().contains(CardType.ARTIFACT)) {
cardTypeName = "artifact";
} else if (card.getCardType().contains(CardType.ENCHANTMENT)) {
cardTypeName = "enchantment";
} else {
cardTypeName = "permanent";
}
ruleText = "Fading " + fadeCounter
+ (shortRuleText ? ""
: " <i>(This permanent enters the battlefield with " + fadeCounter + " fade counters on it."
+ " At the beginning of your upkeep, remove a fade counter from this permanent. If you can't, sacrifice the permanent.)</i>");
: " <i>(This " + cardTypeName + " enters the battlefield with " + CardUtil.numberToText(fadeCounter) + " fade counters on it."
+ " At the beginning of your upkeep, remove a fade counter from it. If you can't, sacrifice it.)</i>");
}
public FadingAbility(final FadingAbility ability) {
@ -57,7 +69,7 @@ class FadingEffect extends OneShotEffect {
FadingEffect() {
super(Outcome.Sacrifice);
staticText = "remove a fade counter from this permanent. If you can't, sacrifice the permanent";
staticText = "remove a fade counter from {this}. If you can't, sacrifice it";
}
FadingEffect(final FadingEffect effect) {

View file

@ -103,7 +103,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
public final OptionalAdditionalCost addKickerCost(Cost cost) {
OptionalAdditionalCost newCost = new OptionalAdditionalCostImpl(
keywordText, "-", reminderText, cost);
keywordText, "&mdash;", reminderText, cost);
addKickerCostAndSetup(newCost);
return newCost;
}