mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 21:42:07 -08:00
Text generation improvements for triggered abilities (#10638)
This commit is contained in:
parent
0c7965a725
commit
fa72e243e9
15 changed files with 86 additions and 43 deletions
|
|
@ -39,7 +39,7 @@ public final class BallroomBrawlers extends CardImpl {
|
|||
this.toughness = new MageInt(5);
|
||||
|
||||
// Whenever Ballroom Brawlers attacks, Ballroom Brawlers and up to one other target creature you control each gain your choice of first strike or lifelink until end of turn.
|
||||
Ability ability = new AttacksTriggeredAbility(new BallroomBrawlersEffect());
|
||||
Ability ability = new AttacksTriggeredAbility(new BallroomBrawlersEffect()).setReplaceRuleText(false);
|
||||
ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ public final class Hecatomb extends CardImpl {
|
|||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}{B}");
|
||||
|
||||
// When Hecatomb enters the battlefield, sacrifice Hecatomb unless you sacrifice four creatures.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new SacrificeTargetCost(new TargetControlledPermanent(4, filter2)))));
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(
|
||||
new SacrificeTargetCost(new TargetControlledPermanent(4, filter2))))
|
||||
.setReplaceRuleText(false));
|
||||
|
||||
// Tap an untapped Swamp you control: Hecatomb deals 1 damage to any target.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapTargetCost(new TargetControlledPermanent(1, 1, filter, true)));
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class HiddenPredatorsStateTriggeredAbility extends StateTriggeredAbility {
|
|||
|
||||
public HiddenPredatorsStateTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new HiddenPredatorsToken(), null, Duration.Custom));
|
||||
this.replaceRuleText = false;
|
||||
setTriggerPhrase("When an opponent controls a creature with power 4 or greater, if {this} is an enchantment, ");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class OpalAvengerStateTriggeredAbility extends StateTriggeredAbility {
|
|||
|
||||
public OpalAvengerStateTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new OpalAvengerToken(), null, Duration.Custom));
|
||||
this.replaceRuleText = false;
|
||||
setTriggerPhrase("When you have 10 or less life, if {this} is an enchantment, ");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ public final class SerraInquisitors extends CardImpl {
|
|||
this.toughness = new MageInt(3);
|
||||
|
||||
// Whenever Serra Inquisitors blocks or becomes blocked by one or more black creatures, Serra Inquisitors gets +2/+0 until end of turn.
|
||||
this.addAbility(new BlocksOrBecomesBlockedByOneOrMoreTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), filter, false));
|
||||
this.addAbility(new BlocksOrBecomesBlockedByOneOrMoreTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn),
|
||||
filter, false).setReplaceRuleText(false));
|
||||
}
|
||||
|
||||
private SerraInquisitors(final SerraInquisitors card) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class VeiledCrocodileStateTriggeredAbility extends StateTriggeredAbility {
|
|||
|
||||
public VeiledCrocodileStateTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new VeilCrocodileToken(), null, Duration.Custom));
|
||||
this.replaceRuleText = false;
|
||||
setTriggerPhrase("When a player has no cards in hand, if {this} is an enchantment, ");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public final class WormfangDrake extends CardImpl {
|
|||
this.addAbility(new EntersBattlefieldTriggeredAbility(
|
||||
new SacrificeSourceUnlessPaysEffect(new ExileTargetCost(new TargetControlledPermanent(filter))),
|
||||
false
|
||||
));
|
||||
).setReplaceRuleText(false));
|
||||
|
||||
// When Wormfang Drake leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false));
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public final class YuanShaosInfantry extends CardImpl {
|
|||
// Whenever Yuan Shao's Infantry attacks alone, Yuan Shao's Infantry can't be blocked this combat.
|
||||
Effect effect = new CantBeBlockedSourceEffect(Duration.EndOfCombat);
|
||||
effect.setText("{this} can't be blocked this combat");
|
||||
this.addAbility(new AttacksAloneSourceTriggeredAbility(effect));
|
||||
this.addAbility(new AttacksAloneSourceTriggeredAbility(effect).setReplaceRuleText(false));
|
||||
}
|
||||
|
||||
private YuanShaosInfantry(final YuanShaosInfantry card) {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ public interface TriggeredAbility extends Ability {
|
|||
|
||||
TriggeredAbility setTriggersOnceEachTurn(boolean triggersOnce);
|
||||
|
||||
TriggeredAbility setDoOnlyOnceEachTurn(boolean doOnlyOnce);
|
||||
|
||||
TriggeredAbility setReplaceRuleText(boolean replaceRuleText);
|
||||
|
||||
boolean checkInterveningIfClause(Game game);
|
||||
|
||||
boolean isOptional();
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
protected boolean leavesTheBattlefieldTrigger;
|
||||
private boolean triggersOnceEachTurn = false;
|
||||
private boolean doOnlyOnceEachTurn = false;
|
||||
protected boolean replaceRuleText = true;
|
||||
private GameEvent triggerEvent = null;
|
||||
private String triggerPhrase = null; // TODO: This could be changed to final if all constructors set a value
|
||||
private String triggerPhrase = null;
|
||||
|
||||
protected TriggeredAbilityImpl(Zone zone, Effect effect) {
|
||||
this(zone, effect, false);
|
||||
|
|
@ -54,6 +55,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
this.leavesTheBattlefieldTrigger = ability.leavesTheBattlefieldTrigger;
|
||||
this.triggersOnceEachTurn = ability.triggersOnceEachTurn;
|
||||
this.doOnlyOnceEachTurn = ability.doOnlyOnceEachTurn;
|
||||
this.replaceRuleText = ability.replaceRuleText;
|
||||
this.triggerEvent = ability.triggerEvent;
|
||||
this.triggerPhrase = ability.triggerPhrase;
|
||||
}
|
||||
|
|
@ -103,11 +105,6 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
return lastTurnTriggered == null || lastTurnTriggered != game.getTurnNum();
|
||||
}
|
||||
|
||||
public TriggeredAbility setTriggersOnceEachTurn(boolean triggersOnce) {
|
||||
this.triggersOnceEachTurn = triggersOnce;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkUsedAlready(Game game) {
|
||||
if (!doOnlyOnceEachTurn) {
|
||||
|
|
@ -119,12 +116,25 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
return lastTurnUsed != null && lastTurnUsed == game.getTurnNum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriggeredAbility setTriggersOnceEachTurn(boolean triggersOnce) {
|
||||
this.triggersOnceEachTurn = triggersOnce;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriggeredAbility setDoOnlyOnceEachTurn(boolean doOnlyOnce) {
|
||||
this.optional = true;
|
||||
this.doOnlyOnceEachTurn = doOnlyOnce;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriggeredAbility setReplaceRuleText(boolean replaceRuleText) {
|
||||
this.replaceRuleText = replaceRuleText;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkInterveningIfClause(Game game) {
|
||||
return true;
|
||||
|
|
@ -202,41 +212,25 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
}
|
||||
} else if (!ruleLow.startsWith("{this}")
|
||||
&& (this.getTargets().isEmpty()
|
||||
|| ruleLow.startsWith("attach")
|
||||
|| ruleLow.startsWith("change")
|
||||
|| ruleLow.startsWith("counter")
|
||||
|| ruleLow.startsWith("destroy")
|
||||
|| ruleLow.startsWith("distribute")
|
||||
|| ruleLow.startsWith("sacrifice")
|
||||
|| ruleLow.startsWith("exchange")
|
||||
|| ruleLow.startsWith("exile")
|
||||
|| ruleLow.startsWith("gain")
|
||||
|| ruleLow.startsWith("goad")
|
||||
|| ruleLow.startsWith("have")
|
||||
|| ruleLow.startsWith("move")
|
||||
|| ruleLow.startsWith("prevent")
|
||||
|| ruleLow.startsWith("put")
|
||||
|| ruleLow.startsWith("remove")
|
||||
|| ruleLow.startsWith("return")
|
||||
|| ruleLow.startsWith("shuffle")
|
||||
|| ruleLow.startsWith("turn")
|
||||
|| ruleLow.startsWith("tap")
|
||||
|| ruleLow.startsWith("untap"))) {
|
||||
|| startsWithVerb(ruleLow))) {
|
||||
sb.append("you may ");
|
||||
} else if (!ruleLow.startsWith("its controller may")) {
|
||||
sb.append("you may have ");
|
||||
superRule = superRule
|
||||
.replace(" becomes ", " become ")
|
||||
.replace(" blocks ", " block ")
|
||||
.replace(" deals ", " deal ")
|
||||
.replace(" discards ", " discard ")
|
||||
.replace(" gains ", " gain ")
|
||||
.replace(" gets ", " get ")
|
||||
.replace(" loses ", " lose ")
|
||||
.replace(" mills ", " mill ")
|
||||
.replace(" sacrifices ", " sacrifice ");
|
||||
superRule = ruleWithFixedVerbGrammar(superRule);
|
||||
}
|
||||
|
||||
}
|
||||
if (replaceRuleText
|
||||
&& triggerPhrase != null
|
||||
&& triggerPhrase.contains("{this}")
|
||||
&& !triggerPhrase.contains("other")
|
||||
&& !triggerPhrase.contains(" of a ")
|
||||
&& !triggerPhrase.contains(" by a ")
|
||||
&& !triggerPhrase.contains(" to a ")
|
||||
&& !triggerPhrase.contains(" blocks a ")
|
||||
&& (superRule.startsWith("{this}")
|
||||
|| superRule.startsWith("sacrifice {this}")
|
||||
)) {
|
||||
superRule = superRule.replace("{this} ", "it ");
|
||||
}
|
||||
sb.append(superRule);
|
||||
if (triggersOnceEachTurn) {
|
||||
|
|
@ -246,10 +240,44 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
sb.append(" Do this only once each turn.");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean startsWithVerb(String ruleLow) {
|
||||
return ruleLow.startsWith("attach")
|
||||
|| ruleLow.startsWith("change")
|
||||
|| ruleLow.startsWith("counter")
|
||||
|| ruleLow.startsWith("destroy")
|
||||
|| ruleLow.startsWith("distribute")
|
||||
|| ruleLow.startsWith("sacrifice")
|
||||
|| ruleLow.startsWith("exchange")
|
||||
|| ruleLow.startsWith("exile")
|
||||
|| ruleLow.startsWith("gain")
|
||||
|| ruleLow.startsWith("goad")
|
||||
|| ruleLow.startsWith("have")
|
||||
|| ruleLow.startsWith("move")
|
||||
|| ruleLow.startsWith("prevent")
|
||||
|| ruleLow.startsWith("put")
|
||||
|| ruleLow.startsWith("remove")
|
||||
|| ruleLow.startsWith("return")
|
||||
|| ruleLow.startsWith("shuffle")
|
||||
|| ruleLow.startsWith("turn")
|
||||
|| ruleLow.startsWith("tap")
|
||||
|| ruleLow.startsWith("untap");
|
||||
}
|
||||
|
||||
private static String ruleWithFixedVerbGrammar(String rule) {
|
||||
return rule.replace(" becomes ", " become ")
|
||||
.replace(" blocks ", " block ")
|
||||
.replace(" deals ", " deal ")
|
||||
.replace(" discards ", " discard ")
|
||||
.replace(" gains ", " gain ")
|
||||
.replace(" gets ", " get ")
|
||||
.replace(" loses ", " lose ")
|
||||
.replace(" mills ", " mill ")
|
||||
.replace(" sacrifices ", " sacrifice ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ public class BecomesBlockedByCreatureTriggeredAbility extends TriggeredAbilityIm
|
|||
public BecomesBlockedByCreatureTriggeredAbility(Effect effect, FilterCreaturePermanent filter, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
this.replaceRuleText = false;
|
||||
setTriggerPhrase("Whenever {this} becomes blocked by " + CardUtil.addArticle(filter.getMessage()) + ", ");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public class BlocksOrBecomesBlockedByOneOrMoreTriggeredAbility extends Triggered
|
|||
public BlocksOrBecomesBlockedByOneOrMoreTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional, String rule) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
this.replaceRuleText = false;
|
||||
this.rule = rule;
|
||||
setTriggerPhrase("Whenever {this} blocks or becomes blocked by one or more " + (filter != null ? filter.getMessage() : "creatures") + ", ");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ public class HeroicAbility extends TriggeredAbilityImpl {
|
|||
if (isHeroic) {
|
||||
this.setAbilityWord(AbilityWord.HEROIC);
|
||||
}
|
||||
this.replaceRuleText = false;
|
||||
setTriggerPhrase("Whenever you cast a spell that targets {this}, ");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ public class PackTacticsAbility extends TriggeredAbilityImpl {
|
|||
|
||||
public PackTacticsAbility(Effect effect) {
|
||||
super(Zone.BATTLEFIELD, effect, false);
|
||||
this.replaceRuleText = false;
|
||||
this.setAbilityWord(AbilityWord.PACK_TACTICS);
|
||||
setTriggerPhrase("Whenever {this} attacks, if you attacked with creatures with total power 6 or greater this combat, ");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public OrTriggeredAbility(Zone zone, Effect effect, boolean optional, String ruleTrigger, TriggeredAbility... abilities) {
|
||||
super(zone, effect, optional);
|
||||
this.ruleTrigger = ruleTrigger;
|
||||
this.replaceRuleText = false;
|
||||
Collections.addAll(this.triggeredAbilities, abilities);
|
||||
for (TriggeredAbility ability : triggeredAbilities) {
|
||||
//Remove useless data
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue