master #6

Merged
Failure merged 49 commits from External/mage:master into master 2024-12-02 20:41:31 -08:00
325 changed files with 3029 additions and 710 deletions

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-client</artifactId>

View file

@ -265,7 +265,7 @@ public class ChatPanelBasic extends javax.swing.JPanel {
}
String cachedProfanityFilterValue = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0");
boolean isContainsSwearing = !containsSwearing(messageToTest, cachedProfanityFilterValue);
boolean isContainsSwearing = containsSwearing(messageToTest, cachedProfanityFilterValue);
boolean isUserInfoOrGameOrStatus = messageType == MessageType.USER_INFO || messageType == MessageType.GAME || messageType == MessageType.STATUS;
if (isUserInfoOrGameOrStatus || cachedProfanityFilterValue.equals("0") || (!cachedProfanityFilterValue.equals("0") && !isContainsSwearing)) {
if (username != null && !username.isEmpty()) {

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-common</artifactId>

View file

@ -17,8 +17,8 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
// * launcher gives priority to 1.4.48 instead 1.4.48-any-text, so don't use empty release info
public static final int MAGE_VERSION_MAJOR = 1;
public static final int MAGE_VERSION_MINOR = 4;
public static final int MAGE_VERSION_RELEASE = 54;
public static final String MAGE_VERSION_RELEASE_INFO = "V3"; // V1, V1a, V1b for releases; V1-beta3, V1-beta4 for betas
public static final int MAGE_VERSION_RELEASE = 55;
public static final String MAGE_VERSION_RELEASE_INFO = "V2"; // V1, V1a, V1b for releases; V1-beta3, V1-beta4 for betas
// strict mode
// Each update requires a strict version

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-counter-plugin</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-plugins</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-reports</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-server-console</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-deck-constructed</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-deck-limited</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-brawlduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-brawlfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-canadianhighlanderduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-commanderduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-commanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-custompillaroftheparunsduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-freeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-freeformcommanderduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-freeformunlimitedcommander</artifactId>
@ -23,7 +23,7 @@
<dependency>
<groupId>org.mage</groupId>
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
<scope>compile</scope>
</dependency>
</dependencies>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-momirduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-momirfreeforall</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-oathbreakerduel</artifactId>
@ -22,7 +22,7 @@
<dependency>
<groupId>org.mage</groupId>
<artifactId>mage-game-oathbreakerfreeforall</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
<scope>compile</scope>
</dependency>
</dependencies>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-oathbreakerfreeforall</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-pennydreadfulcommanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-tinyleadersduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-game-twoplayerduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-player-ai-draftbot</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-player-ai-ma</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-player-ai</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-player-ai-mcts</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-player-human</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-tournament-boosterdraft</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-tournament-constructed</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-tournament-sealed</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-server-plugins</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-server</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.54</version>
<version>1.4.55</version>
</parent>
<artifactId>mage-sets</artifactId>

View file

@ -43,7 +43,7 @@ public final class AbzanCharm extends CardImpl {
this.getSpellAbility().addMode(mode);
// *Distribute two +1/+1 counters among one or two target creatures.
mode = new Mode(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures"));
mode = new Mode(new DistributeCountersEffect(2, "one or two target creatures"));
mode.addTarget(new TargetCreaturePermanentAmount(2));
this.getSpellAbility().addMode(mode);

View file

@ -37,7 +37,7 @@ public final class AetherGust extends CardImpl {
// Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(true).setText(
"choose target spell or permanent that's red or green. " +
"Its owner puts it on the top or bottom of their library"
"Its owner puts it on their choice of the top or bottom of their library"
));
this.getSpellAbility().addTarget(new TargetSpellOrPermanent(filter));
}

View file

@ -125,7 +125,6 @@ class AirtightAlibiReplacementEffect extends ReplacementEffectImpl {
public boolean applies(GameEvent event, Ability source, Game game) {
return Optional
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.filter(Objects::nonNull)
.map(Permanent::getAttachedTo)
.map(event.getTargetId()::equals)
.orElse(false);

View file

@ -38,7 +38,7 @@ public final class AjaniMentorOfHeroes extends CardImpl {
this.setStartingLoyalty(4);
// +1: Distribute three +1/+1 counters among one, two, or three target creatures you control
Ability ability = new LoyaltyAbility(new DistributeCountersEffect(CounterType.P1P1, 3, false, "one, two, or three target creatures you control"), 1);
Ability ability = new LoyaltyAbility(new DistributeCountersEffect(3, "one, two, or three target creatures you control"), 1);
ability.addTarget(new TargetCreaturePermanentAmount(3, StaticFilters.FILTER_CONTROLLED_CREATURES));
this.addAbility(ability);

View file

@ -42,7 +42,7 @@ public final class AjaniSleeperAgent extends CardImpl {
this.addAbility(new LoyaltyAbility(new AjaniSleeperAgentEffect(), 1));
// 3: Distribute three +1/+1 counters among up to three target creatures. They gain vigilance until end of turn.
Ability ability = new LoyaltyAbility(new DistributeCountersEffect(CounterType.P1P1, 3, false, "up to three target creatures"), -3);
Ability ability = new LoyaltyAbility(new DistributeCountersEffect(3, "up to three target creatures"), -3);
ability.addEffect(new GainAbilityTargetEffect(VigilanceAbility.getInstance()).setText("They gain vigilance until end of turn"));
Target target = new TargetCreaturePermanentAmount(3);
target.setMinNumberOfTargets(0);

View file

@ -1,6 +1,8 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.DiscardedByOpponentTriggeredAbility;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
@ -63,6 +65,7 @@ class AjanisLastStandTriggeredAbility extends TriggeredAbilityImpl {
new CreateTokenEffect(new AvatarToken2()),
new SacrificeSourceCost()
), false);
setLeavesTheBattlefieldTrigger(true);
}
private AjanisLastStandTriggeredAbility(final AjanisLastStandTriggeredAbility ability) {
@ -98,4 +101,9 @@ class AjanisLastStandTriggeredAbility extends TriggeredAbilityImpl {
+ "you may sacrifice {this}. "
+ "If you do, create a 4/4 white Avatar creature token with flying.";
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -82,8 +82,8 @@ enum AleshaWhoLaughsAtFatePredicate implements ObjectSourcePlayerPredicate<Card>
public boolean apply(ObjectSourcePlayer<Card> input, Game game) {
return Optional
.ofNullable(input.getSource().getSourcePermanentOrLKI(game))
.map(MageObject::getManaValue)
.map(p -> input.getObject().getManaValue() <= p)
.map(MageObject::getPower)
.map(p -> input.getObject().getManaValue() <= p.getValue())
.orElse(false);
}
}

View file

@ -44,7 +44,7 @@ public final class AnaraWolvidFamiliar extends CardImpl {
new GainAbilityControlledEffect(
IndestructibleAbility.getInstance(),
Duration.WhileOnBattlefield, filter
), MyTurnCondition.instance, "as long as it's your turn, " +
), MyTurnCondition.instance, "during your turn, " +
"commanders you control have indestructible"
)));

View file

@ -28,7 +28,7 @@ public final class ArmamentCorps extends CardImpl {
this.toughness = new MageInt(4);
// When Armament Corps enters the battlefield, distribute two +1/+1 counters among one or two target creatures you control.
Ability ability = new EntersBattlefieldTriggeredAbility(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures you control"), false);
Ability ability = new EntersBattlefieldTriggeredAbility(new DistributeCountersEffect(2, "one or two target creatures you control"), false);
ability.addTarget(new TargetCreaturePermanentAmount(2, StaticFilters.FILTER_CONTROLLED_CREATURES));
this.addAbility(ability);
}

View file

@ -76,11 +76,9 @@ class AssaultIntercessorEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
return Optional
.ofNullable(getValue("creatureDied"))
.filter(Objects::nonNull)
.map(Permanent.class::cast)
.map(Controllable::getControllerId)
.map(game::getPlayer)
.filter(Objects::nonNull)
.map(player -> player.loseLife(2, game, source, false) > 0)
.orElse(false);
}

View file

@ -34,7 +34,7 @@ public final class AtKnifepoint extends CardImpl {
// As long as it's your turn, outlaws you control have first strike.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter),
MyTurnCondition.instance, "as long as it's your turn, outlaws you control have first strike"
MyTurnCondition.instance, "during your turn, outlaws you control have first strike"
)));
// Whenever you commit a crime, create a 1/1 red Mercenary creature token with "{T}: Target creature you control gets +1/+0 until end of turn. Activate only as a sorcery." This ability triggers only once each turn.

View file

@ -1,6 +1,7 @@
package mage.cards.a;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
@ -122,6 +123,7 @@ class AthreosDiesCreatureTriggeredAbility extends TriggeredAbilityImpl {
super(Zone.BATTLEFIELD, effect, optional);
this.filter = filter;
setTriggerPhrase("Whenever " + filter.getMessage() + " dies, ");
setLeavesTheBattlefieldTrigger(true);
}
private AthreosDiesCreatureTriggeredAbility(AthreosDiesCreatureTriggeredAbility ability) {
@ -153,4 +155,9 @@ class AthreosDiesCreatureTriggeredAbility extends TriggeredAbilityImpl {
}
return true;
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -80,6 +80,7 @@ class AthreosShroudVeiledTriggeredAbility extends TriggeredAbilityImpl {
AthreosShroudVeiledTriggeredAbility() {
super(Zone.BATTLEFIELD, null, false);
setLeavesTheBattlefieldTrigger(true);
}
private AthreosShroudVeiledTriggeredAbility(final AthreosShroudVeiledTriggeredAbility ability) {

View file

@ -1,6 +1,7 @@
package mage.cards.a;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
@ -60,6 +61,7 @@ class AvacynsCollarTriggeredAbility extends TriggeredAbilityImpl {
public AvacynsCollarTriggeredAbility() {
super(Zone.BATTLEFIELD, new CreateTokenEffect(new SpiritWhiteToken()));
setLeavesTheBattlefieldTrigger(true);
}
private AvacynsCollarTriggeredAbility(final AvacynsCollarTriggeredAbility ability) {
@ -91,4 +93,9 @@ class AvacynsCollarTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() {
return "Whenever equipped creature dies, if it was a Human, create a 1/1 white Spirit creature token with flying.";
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -47,7 +47,7 @@ public final class BayekOfSiwa extends CardImpl {
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilityControlledEffect(
DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter, true
), MyTurnCondition.instance, "as long as it's your turn, " +
), MyTurnCondition.instance, "during your turn, " +
"other historic creatures you control have double strike"
)));

View file

@ -1,6 +1,8 @@
package mage.cards.b;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.discard.DiscardTargetEffect;
import mage.cards.CardImpl;
@ -41,6 +43,7 @@ class BereavementTriggeredAbility extends TriggeredAbilityImpl {
BereavementTriggeredAbility() {
super(Zone.BATTLEFIELD, new DiscardTargetEffect(1));
setLeavesTheBattlefieldTrigger(true);
}
private BereavementTriggeredAbility(final BereavementTriggeredAbility ability) {
@ -73,4 +76,9 @@ class BereavementTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() {
return "Whenever a green creature dies, its controller discards a card.";
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -39,7 +39,7 @@ public final class BilbosRing extends CardImpl {
// As long as it's your turn, equipped creature has hexproof and can't be blocked.
Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilityAttachedEffect(HexproofAbility.getInstance(), AttachmentType.EQUIPMENT),
MyTurnCondition.instance, "as long as it's your turn, equipped creature has hexproof"
MyTurnCondition.instance, "during your turn, equipped creature has hexproof"
));
ability.addEffect(new ConditionalRestrictionEffect(
new CantBeBlockedAttachedEffect(AttachmentType.EQUIPMENT),

View file

@ -27,7 +27,7 @@ public final class BiogenicUpgrade extends CardImpl {
// Distribute three +1/+1 counters among one, two, or three target creatures, then double the number of +1/+1 counters on each of those creatures.
this.getSpellAbility().addEffect(new DistributeCountersEffect(
CounterType.P1P1, 3, false,
3,
"one, two, or three target creatures"
));
this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(3));
@ -75,4 +75,4 @@ class BiogenicUpgradeEffect extends OneShotEffect {
}
return true;
}
}
}

View file

@ -19,7 +19,7 @@ public final class BlessingsOfNature extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}");
// Distribute four +1/+1 counters among any number of target creatures.
this.getSpellAbility().addEffect(new DistributeCountersEffect(CounterType.P1P1, 4, false, "any number of target creatures"));
this.getSpellAbility().addEffect(new DistributeCountersEffect(4, "any number of target creatures"));
this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(4));
this.addAbility(new MiracleAbility("{G}"));

View file

@ -35,9 +35,9 @@ public final class BountyOfTheHunt extends CardImpl {
// Distribute three +1/+1 counters among one, two, or three target creatures. For each +1/+1 counter you put on a creature this way, remove a +1/+1 counter from that creature at the beginning of the next cleanup step.
this.getSpellAbility().addEffect(new DistributeCountersEffect(
CounterType.P1P1, 3, true,
3,
"one, two, or three target creatures"
));
).withRemoveAtEndOfTurn());
this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(3));
}

View file

@ -67,7 +67,6 @@ enum BrassKnucklesCondition implements Condition {
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.map(Permanent::getAttachedTo)
.map(game::getPermanent)
.filter(Objects::nonNull)
.map(Permanent::getAttachments)
.map(Collection::stream)
.map(stream -> stream.map(game::getPermanent))

View file

@ -65,6 +65,7 @@ class BridgeFromBelowAbility extends TriggeredAbilityImpl {
this.filter = filter;
this.withInterveningIf(SourceInGraveyardCondition.instance);
setTriggerPhrase(filter.getMessage());
setLeavesTheBattlefieldTrigger(true); // it's not required for Bridge from Below, but better to keep same code style and verify pass
}
private BridgeFromBelowAbility(final BridgeFromBelowAbility ability) {

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import java.util.UUID;
@ -39,6 +38,7 @@ public final class CallerOfTheClaw extends CardImpl {
// Flash
this.addAbility(FlashAbility.getInstance());
// When Caller of the Claw enters the battlefield, create a 2/2 green Bear creature token for each nontoken creature put into your graveyard from the battlefield this turn.
this.getSpellAbility().addWatcher(new CallerOfTheClawWatcher());
Effect effect = new CreateTokenEffect(new BearToken(), new CallerOfTheClawDynamicValue());

View file

@ -58,6 +58,7 @@ class CarthTheLionTriggeredAbility extends TriggeredAbilityImpl {
super(Zone.BATTLEFIELD, new LookLibraryAndPickControllerEffect(
7, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM));
setTriggerPhrase("Whenever {this} enters or a planeswalker you control dies, ");
setLeavesTheBattlefieldTrigger(true);
}
private CarthTheLionTriggeredAbility(final CarthTheLionTriggeredAbility ability) {

View file

@ -40,7 +40,7 @@ public final class CaseOfTheTrampledGarden extends CardImpl {
this.subtype.add(SubType.CASE);
// When this Case enters the battlefield, distribute two +1/+1 counters among one or two target creatures you control.
Ability initialAbility = new EntersBattlefieldTriggeredAbility(new DistributeCountersEffect(CounterType.P1P1, 2,
Ability initialAbility = new EntersBattlefieldTriggeredAbility(new DistributeCountersEffect(2,
"one or two target creatures you control"));
TargetPermanentAmount target = new TargetPermanentAmount(2, StaticFilters.FILTER_CONTROLLED_CREATURES);
target.setMinNumberOfTargets(1);

View file

@ -122,10 +122,10 @@ class ChainerNightmareAdeptWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.SPELL_CAST) {
if (event.getAdditionalReference() == null) {
if (event.getApprovingObject() == null) {
return;
}
morMap.computeIfAbsent(event.getAdditionalReference().getApprovingMageObjectReference(), m -> new HashMap<>())
morMap.computeIfAbsent(event.getApprovingObject().getApprovingMageObjectReference(), m -> new HashMap<>())
.compute(event.getPlayerId(), (u, i) -> i == null ? 0 : Integer.sum(i, -1));
}
}

View file

@ -150,10 +150,10 @@ class ChandraHopesBeaconWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.SPELL_CAST
|| event.getAdditionalReference() == null) {
|| event.getApprovingObject() == null) {
return;
}
MageObjectReference mor = event.getAdditionalReference().getApprovingMageObjectReference();
MageObjectReference mor = event.getApprovingObject().getApprovingMageObjectReference();
Spell spell = game.getSpell(event.getTargetId());
if (mor == null || spell == null) {
return;

View file

@ -194,10 +194,10 @@ class ChissGoriaForgeTyrantWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.SPELL_CAST || event.getAdditionalReference() == null) {
if (event.getType() != GameEvent.EventType.SPELL_CAST || event.getApprovingObject() == null) {
return;
}
MageObjectReference mor = event.getAdditionalReference().getApprovingMageObjectReference();
MageObjectReference mor = event.getApprovingObject().getApprovingMageObjectReference();
Spell spell = game.getSpell(event.getTargetId());
if (mor == null || spell == null) {
return;

View file

@ -33,7 +33,7 @@ public final class Chronozoa extends CardImpl {
// Vanishing 3 (This permanent enters the battlefield with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.)
this.addAbility(new VanishingAbility(3));
// When Chronozoa is put into a graveyard from play, if it had no time counters on it, create two tokens that are copies of it.
// When Chronozoa dies, if it had no time counters on it, create two tokens that are copies of it.
Effect effect = new CreateTokenCopySourceEffect(2);
effect.setText("create two tokens that are copies of it");
this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DiesSourceTriggeredAbility(effect, false),

View file

@ -44,7 +44,7 @@ class CircleOfTheMoonDruidBearEffect extends ContinuousEffectImpl {
CircleOfTheMoonDruidBearEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "as long as it's your turn, {this} is a Bear with base power and toughness 4/2";
staticText = "during your turn, {this} is a Bear with base power and toughness 4/2";
}
private CircleOfTheMoonDruidBearEffect(final CircleOfTheMoonDruidBearEffect effect) {

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import java.util.UUID;
@ -26,7 +25,8 @@ public final class ClipWings extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}");
// Each opponent sacrifices a creature with flying.
this.getSpellAbility().addEffect(new SacrificeOpponentsEffect(filter));
this.getSpellAbility().addEffect(new SacrificeOpponentsEffect(filter)
.setText("each opponent sacrifices a creature of their choice with flying"));
}
private ClipWings(final ClipWings card) {

View file

@ -114,7 +114,6 @@ class ConquerorsFlailEffect extends ContinuousRuleModifyingEffectImpl {
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.map(Permanent::getAttachedTo)
.map(game::getPermanent)
.filter(Objects::nonNull)
.map(permanent -> permanent.isCreature(game))
.orElse(false);
}

View file

@ -39,7 +39,7 @@ public final class Contagion extends CardImpl {
// Distribute two -2/-1 counters among one or two target creatures.
this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(2));
this.getSpellAbility().addEffect(new DistributeCountersEffect(
CounterType.M2M1, 2, false,
CounterType.M2M1, 2,
"one or two target creatures"
));
}

View file

@ -237,15 +237,15 @@ class CoramTheUndertakerWatcher extends Watcher {
cardsAllowedToBePlayedOrCast.add(new MageObjectReference(mainCard, game));
return;
}
if (event.getAdditionalReference() == null
|| !MageIdentifier.CoramTheUndertakerWatcher.equals(event.getAdditionalReference().getApprovingAbility().getIdentifier())) {
if (event.getApprovingObject() == null
|| !MageIdentifier.CoramTheUndertakerWatcher.equals(event.getApprovingObject().getApprovingAbility().getIdentifier())) {
return;
}
if (event.getType() == GameEvent.EventType.LAND_PLAYED) {
landPlayedForSource.add(event.getAdditionalReference().getApprovingMageObjectReference());
landPlayedForSource.add(event.getApprovingObject().getApprovingMageObjectReference());
}
if (event.getType() == GameEvent.EventType.SPELL_CAST) {
spellCastForSource.add(event.getAdditionalReference().getApprovingMageObjectReference());
spellCastForSource.add(event.getApprovingObject().getApprovingMageObjectReference());
}
}

View file

@ -33,7 +33,7 @@ public final class CourtOfGarenbrig extends CardImpl {
// At the beginning of your upkeep, distribute two +1/+1 counters among up to two target creatures. Then if you're the monarch, double the number of +1/+1 counters on each creature you control.
Ability ability = new BeginningOfUpkeepTriggeredAbility(
new DistributeCountersEffect(
CounterType.P1P1, 2, false, "up to two target creatures"
2, "up to two target creatures"
)
);
TargetCreaturePermanentAmount target = new TargetCreaturePermanentAmount(2);

View file

@ -226,7 +226,7 @@ class CourtOfLocthwainWatcher extends Watcher {
&& event.getPlayerId() != null) {
decrementCastAvailable(
event.getPlayerId(),
event.getAdditionalReference().getApprovingMageObjectReference()
event.getApprovingObject().getApprovingMageObjectReference()
);
}
}

View file

@ -39,7 +39,7 @@ public final class DapperShieldmate extends CardImpl {
// As long as it's your turn, Dapper Shieldmate gets +2/+0.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new BoostSourceEffect(2, 0, Duration.WhileOnBattlefield),
MyTurnCondition.instance, "as long as it's your turn, {this} gets +2/+0"
MyTurnCondition.instance, "during your turn, {this} gets +2/+0"
)));
}

View file

@ -54,6 +54,7 @@ class DaxosBlessedByTheSunAbility extends TriggeredAbilityImpl {
DaxosBlessedByTheSunAbility() {
super(Zone.BATTLEFIELD, new GainLifeEffect(1));
setLeavesTheBattlefieldTrigger(true);
}
private DaxosBlessedByTheSunAbility(DaxosBlessedByTheSunAbility ability) {

View file

@ -62,6 +62,7 @@ class DeathTyrantTriggeredAbility extends TriggeredAbilityImpl {
DeathTyrantTriggeredAbility() {
super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken()));
setTriggerPhrase("Whenever an attacking creature you control or a blocking creature an opponent controls dies, ");
setLeavesTheBattlefieldTrigger(true);
}
private DeathTyrantTriggeredAbility(final DeathTyrantTriggeredAbility ability) {
@ -94,7 +95,7 @@ class DeathTyrantTriggeredAbility extends TriggeredAbilityImpl {
}
@Override
public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game);
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -1,8 +1,8 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl;
@ -25,7 +25,6 @@ public final class DeathsPresence extends CardImpl {
public DeathsPresence(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{5}{G}");
// Whenever a creature you control dies, put X +1/+1 counters on target creature you control, where X is the power of the creature that died.
this.addAbility(new DeathsPresenceTriggeredAbility());
}
@ -44,6 +43,7 @@ class DeathsPresenceTriggeredAbility extends TriggeredAbilityImpl {
public DeathsPresenceTriggeredAbility() {
super(Zone.BATTLEFIELD, null);
setLeavesTheBattlefieldTrigger(true);
}
private DeathsPresenceTriggeredAbility(final DeathsPresenceTriggeredAbility ability) {
@ -80,4 +80,9 @@ class DeathsPresenceTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() {
return "Whenever a creature you control dies, put X +1/+1 counters on target creature you control, where X is the power of the creature that died.";
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -20,7 +20,7 @@ public final class DefendTheCelestus extends CardImpl {
// Distribute three +1/+1 counters among one, two, or three target creatures you control.
this.getSpellAbility().addEffect(new DistributeCountersEffect(
CounterType.P1P1, 3, false,
3,
"one, two, or three target creatures you control"
));
this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(

View file

@ -1,6 +1,8 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
@ -91,6 +93,7 @@ class DiabolicServitudeCreatureDiesTriggeredAbility extends TriggeredAbilityImpl
public DiabolicServitudeCreatureDiesTriggeredAbility() {
super(Zone.BATTLEFIELD, new DiabolicServitudeExileCreatureEffect(), false);
setLeavesTheBattlefieldTrigger(true);
}
private DiabolicServitudeCreatureDiesTriggeredAbility(final DiabolicServitudeCreatureDiesTriggeredAbility ability) {
@ -123,6 +126,11 @@ class DiabolicServitudeCreatureDiesTriggeredAbility extends TriggeredAbilityImpl
public String getRule() {
return "When the creature put onto the battlefield with {this} dies, exile it and return {this} to its owner's hand.";
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}
class DiabolicServitudeExileCreatureEffect extends OneShotEffect {

View file

@ -1,6 +1,7 @@
package mage.cards.d;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.LoseLifeTargetEffect;
@ -67,6 +68,7 @@ class DiregrafCaptainTriggeredAbility extends TriggeredAbilityImpl {
public DiregrafCaptainTriggeredAbility() {
super(Zone.BATTLEFIELD, new LoseLifeTargetEffect(1), false);
this.addTarget(new TargetOpponent());
this.setLeavesTheBattlefieldTrigger(true);
}
private DiregrafCaptainTriggeredAbility(final DiregrafCaptainTriggeredAbility ability) {
@ -99,4 +101,9 @@ class DiregrafCaptainTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() {
return "Whenever another Zombie you control dies, target opponent loses 1 life.";
}
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -24,7 +24,7 @@ public final class Discontinuity extends CardImpl {
// As long as it's your turn, this spell costs {2}{U}{U} less to cast.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(
new ManaCostsImpl<>("{2}{U}{U}"), MyTurnCondition.instance
).setText("as long as it's your turn, this spell costs {2}{U}{U} less to cast"))
).setText("during your turn, this spell costs {2}{U}{U} less to cast"))
.setRuleAtTheTop(true)
.addHint(MyTurnHint.instance));

View file

@ -53,6 +53,7 @@ class DreadhoundTriggeredAbility extends TriggeredAbilityImpl {
public DreadhoundTriggeredAbility() {
super(Zone.BATTLEFIELD, new LoseLifeOpponentsEffect(1));
setTriggerPhrase("Whenever a creature dies or a creature card is put into a graveyard from a library, ");
setLeavesTheBattlefieldTrigger(true);
}
private DreadhoundTriggeredAbility(final DreadhoundTriggeredAbility ability) {

View file

@ -34,7 +34,7 @@ public final class DuelistOfDeepFaith extends CardImpl {
// As long as it's your turn, Duelist of Deep Faith has first strike.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()),
MyTurnCondition.instance, "as long as it's your turn, {this} has first strike"
MyTurnCondition.instance, "during your turn, {this} has first strike"
)).addHint(MyTurnHint.instance));
}

View file

@ -90,7 +90,6 @@ class ElspethsTalentTriggeredAbility extends TriggeredAbilityImpl {
&& event.getSourceId().equals(permanent.getAttachedTo())
&& isControlledBy(event.getPlayerId())
&& Optional.ofNullable(game.getStack().getStackObject(event.getSourceId()))
.filter(Objects::nonNull)
.map(StackObject::getStackAbility)
.map(LoyaltyAbility.class::isInstance)
.orElse(false);

View file

@ -38,7 +38,7 @@ public final class ElusiveOtter extends AdventureCard {
// Grove's Bounty
// Distribute X +1/+1 counters among any number of target creatures you control.
this.getSpellCard().getSpellAbility().addEffect(new DistributeCountersEffect(
CounterType.P1P1, GetXValue.instance, false,
CounterType.P1P1, GetXValue.instance,
"any number of target creatures you control"
));
Target target = new TargetCreaturePermanentAmount(GetXValue.instance, StaticFilters.FILTER_CONTROLLED_CREATURES);

View file

@ -19,7 +19,7 @@ public final class ElvenRite extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{G}");
// Distribute two +1/+1 counters among one or two target creatures.
this.getSpellAbility().addEffect(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures"));
this.getSpellAbility().addEffect(new DistributeCountersEffect(2, "one or two target creatures"));
this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(2));
}

View file

@ -69,7 +69,6 @@ enum EmergentWoodwurmPredicate implements ObjectSourcePlayerPredicate<Card> {
.of(input)
.map(ObjectSourcePlayer::getSource)
.map(ability -> ability.getSourcePermanentOrLKI(game))
.filter(Objects::nonNull)
.map(MageObject::getPower)
.map(MageInt::getValue)
.map(i -> input.getObject().getManaValue() <= i)

View file

@ -1,5 +1,6 @@
package mage.cards.e;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
@ -97,6 +98,7 @@ class EndlessEvilBounceAbility extends TriggeredAbilityImpl {
public EndlessEvilBounceAbility() {
super(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(false, true));
setLeavesTheBattlefieldTrigger(true);
}
private EndlessEvilBounceAbility(final EndlessEvilBounceAbility effect) {
@ -126,4 +128,9 @@ class EndlessEvilBounceAbility extends TriggeredAbilityImpl {
public String getRule() {
return "When enchanted creature dies, if that creature was a Horror, return {this} to its owner's hand.";
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -3,6 +3,7 @@ package mage.cards.e;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
@ -65,6 +66,7 @@ class EnigmaSphinxTriggeredAbility extends TriggeredAbilityImpl {
public EnigmaSphinxTriggeredAbility(Effect effect, boolean optional) {
super(Zone.ALL, effect, optional);
setTriggerPhrase("When {this} is put into your graveyard from the battlefield, ");
setLeavesTheBattlefieldTrigger(true);
}
private EnigmaSphinxTriggeredAbility(final EnigmaSphinxTriggeredAbility ability) {
@ -94,6 +96,11 @@ class EnigmaSphinxTriggeredAbility extends TriggeredAbilityImpl {
}
return false;
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}
class EnigmaSphinxEffect extends OneShotEffect {

View file

@ -201,9 +201,9 @@ class EvelynTheCovetousWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if ((event.getType() == GameEvent.EventType.SPELL_CAST || event.getType() == GameEvent.EventType.LAND_PLAYED)
&& event.getAdditionalReference() != null) {
&& event.getApprovingObject() != null) {
usedMap.computeIfAbsent(
event.getAdditionalReference()
event.getApprovingObject()
.getApprovingMageObjectReference(),
x -> new HashSet<>()
).add(event.getPlayerId());

View file

@ -37,7 +37,7 @@ public final class FaithfulPikemaster extends CardImpl {
// As long as it's your turn, Faithful Pikemaster has first strike.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield),
MyTurnCondition.instance, "as long as it's your turn, {this} has first strike."
MyTurnCondition.instance, "during your turn, {this} has first strike."
)).addHint(MyTurnHint.instance));
}

View file

@ -1,6 +1,8 @@
package mage.cards.f;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.AbilityImpl;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.LoseLifeTargetEffect;
@ -51,6 +53,7 @@ class FalkenrathNobleTriggeredAbility extends TriggeredAbilityImpl {
super(Zone.BATTLEFIELD, new LoseLifeTargetEffect(1), false);
this.addEffect(new GainLifeEffect(1));
this.addTarget(new TargetPlayer());
setLeavesTheBattlefieldTrigger(true);
}
private FalkenrathNobleTriggeredAbility(final FalkenrathNobleTriggeredAbility ability) {
@ -87,4 +90,9 @@ class FalkenrathNobleTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() {
return "Whenever {this} or another creature dies, target player loses 1 life and you gain 1 life.";
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -0,0 +1,125 @@
package mage.cards.f;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.costs.common.ExileTargetCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.util.CardUtil;
/**
* @author Cguy7777
*/
public final class FearOfAbduction extends CardImpl {
public FearOfAbduction(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{4}{W}{W}");
this.subtype.add(SubType.NIGHTMARE);
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// As an additional cost to cast this spell, exile a creature you control.
this.getSpellAbility().addCost(
new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE)));
// Flying
this.addAbility(FlyingAbility.getInstance());
// When Fear of Abduction enters, exile target creature an opponent controls.
Ability ability = new EntersBattlefieldTriggeredAbility(new FearOfAbductionExileEffect());
ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE));
this.addAbility(ability);
// When Fear of Abduction leaves the battlefield, put each card exiled with it into its owner's hand.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new FearOfAbductionReturnEffect()));
}
private FearOfAbduction(final FearOfAbduction card) {
super(card);
}
@Override
public FearOfAbduction copy() {
return new FearOfAbduction(this);
}
}
class FearOfAbductionExileEffect extends OneShotEffect {
FearOfAbductionExileEffect() {
super(Outcome.Benefit);
this.staticText = "exile target creature an opponent controls";
}
private FearOfAbductionExileEffect(final FearOfAbductionExileEffect effect) {
super(effect);
}
@Override
public FearOfAbductionExileEffect copy() {
return new FearOfAbductionExileEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
MageObject sourceObject = source.getSourceObject(game);
if (sourceObject != null) {
return new ExileTargetEffect(
// Offset -1 so that opponent's creature is exiled to the same exile zone as your creature
CardUtil.getExileZoneId(game, source, -1),
CardUtil.getSourceName(game, source))
.apply(game, source);
}
return false;
}
}
class FearOfAbductionReturnEffect extends OneShotEffect {
FearOfAbductionReturnEffect() {
super(Outcome.Neutral);
this.staticText = "put each card exiled with it into its owner's hand";
}
private FearOfAbductionReturnEffect(final FearOfAbductionReturnEffect effect) {
super(effect);
}
@Override
public FearOfAbductionReturnEffect copy() {
return new FearOfAbductionReturnEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
// Offset -2 since Fear of Abduction has left the battlefield since last time
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, -2));
if (exileZone != null) {
controller.moveCards(exileZone, Zone.HAND, source, game);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,92 @@
package mage.cards.f;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.abilityword.EerieAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author Grath
*/
public final class FearOfSleepParalysis extends CardImpl {
public FearOfSleepParalysis(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{5}{U}");
this.subtype.add(SubType.NIGHTMARE);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Eerie -- Whenever Fear of Sleep Paralysis or another enchantment you control enters and whenever you fully unlock a Room, tap up to one target creature and put a stun counter on it.
Ability ability = new EerieAbility(new TapTargetEffect());
ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()).setText("and put a stun counter on it"));
ability.addTarget(new TargetCreaturePermanent(0, 1));
this.addAbility(ability);
// Stun counters can't be removed from permanents your opponents control.
this.addAbility(new SimpleStaticAbility(new FearOfSleepParalysisEffect()));
}
private FearOfSleepParalysis(final FearOfSleepParalysis card) {
super(card);
}
@Override
public FearOfSleepParalysis copy() {
return new FearOfSleepParalysis(this);
}
}
class FearOfSleepParalysisEffect extends ReplacementEffectImpl {
FearOfSleepParalysisEffect() {
super(Duration.WhileOnBattlefield, Outcome.PreventDamage);
staticText = "Stun counters can't be removed from permanents your opponents control";
}
private FearOfSleepParalysisEffect(final FearOfSleepParalysisEffect effect) {
super(effect);
}
@Override
public FearOfSleepParalysisEffect copy() {
return new FearOfSleepParalysisEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.REMOVE_COUNTERS;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent target = game.getPermanent(event.getTargetId());
return target != null && event.getData().equals(CounterType.STUN.getName()) && !target.getControllerId().equals(source.getControllerId());
}
}

View file

@ -0,0 +1,201 @@
package mage.cards.f;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* @author RobertFrosty, xenohedron
*/
public final class FirestormPhoenix extends CardImpl {
public FirestormPhoenix(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}");
this.subtype.add(SubType.PHOENIX);
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// Flying
this.addAbility(FlyingAbility.getInstance());
// If Firestorm Phoenix would die, return Firestorm Phoenix to its owner's hand instead.
// Until that player's next turn, that player plays with that card revealed in their hand and can't play it.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new FirestormPhoenixEffect()));
}
private FirestormPhoenix(final FirestormPhoenix card) {
super(card);
}
@Override
public FirestormPhoenix copy() {
return new FirestormPhoenix(this);
}
}
class FirestormPhoenixEffect extends ReplacementEffectImpl {
FirestormPhoenixEffect() {
super(Duration.Custom, Outcome.ReturnToHand);
staticText = "If {this} would die, return {this} to its owner's hand instead. " +
"Until that player's next turn, that player plays with that card revealed in their hand and can't play it";
}
private FirestormPhoenixEffect(final FirestormPhoenixEffect effect) {
super(effect);
}
@Override
public FirestormPhoenixEffect copy() {
return new FirestormPhoenixEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = ((ZoneChangeEvent) event).getTarget();
if (controller == null || permanent == null) {
return false;
}
controller.moveCards(permanent, Zone.HAND, source, game);
Card card = game.getCard(permanent.getId());
if (card == null) {
return true;
}
game.addEffect(new FirestormPhoenixRevealEffect().setTargetPointer(new FixedTarget(card, game)), source);
game.addEffect(new FirestormPhoenixRestrictEffect().setTargetPointer(new FixedTarget(card, game)), source);
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return source.getSourceId().equals(event.getTargetId())
&& ((ZoneChangeEvent) event).isDiesEvent();
}
}
class FirestormPhoenixRevealEffect extends ContinuousEffectImpl {
private int startingTurnNum;
FirestormPhoenixRevealEffect() {
super(Duration.Custom, Layer.PlayerEffects, SubLayer.NA, Outcome.Detriment);
}
private FirestormPhoenixRevealEffect(final FirestormPhoenixRevealEffect effect) {
super(effect);
this.startingTurnNum = effect.startingTurnNum;
}
@Override
public FirestormPhoenixRevealEffect copy() {
return new FirestormPhoenixRevealEffect(this);
}
@Override
public void init(Ability source, Game game) {
super.init(source, game);
startingTurnNum = game.getTurnNum();
}
@Override
public boolean isInactive(Ability source, Game game) {
if (game.getCard(getTargetPointer().getFirst(game, source)) == null) {
return true;
}
return game.isActivePlayer(game.getOwnerId(getTargetPointer().getFirst(game, source)))
&& game.getTurnNum() > startingTurnNum;
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card == null) {
discard();
return false;
}
Player player = game.getPlayer(card.getOwnerId());
if (player != null) {
player.revealCards(card.getIdName(), new CardsImpl(card), game, false);
}
return true;
}
}
class FirestormPhoenixRestrictEffect extends ContinuousRuleModifyingEffectImpl {
private int startingTurnNum;
FirestormPhoenixRestrictEffect() {
super(Duration.Custom, Outcome.Detriment);
}
private FirestormPhoenixRestrictEffect(final FirestormPhoenixRestrictEffect effect) {
super(effect);
this.startingTurnNum = effect.startingTurnNum;
}
@Override
public FirestormPhoenixRestrictEffect copy() {
return new FirestormPhoenixRestrictEffect(this);
}
@Override
public void init(Ability source, Game game) {
super.init(source, game);
startingTurnNum = game.getTurnNum();
}
@Override
public boolean isInactive(Ability source, Game game) {
if (game.getCard(getTargetPointer().getFirst(game, source)) == null) {
return true;
}
return game.isActivePlayer(game.getOwnerId(getTargetPointer().getFirst(game, source)))
&& game.getTurnNum() > startingTurnNum;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL_LATE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Card cardInHand = game.getCard(getTargetPointer().getFirst(game, source));
SpellAbility spellAbility = SpellAbility.getSpellAbilityFromEvent(event, game);
if (cardInHand == null || spellAbility == null) {
return false;
}
Card cardToCast = spellAbility.getCharacteristics(game);
return cardToCast != null && cardToCast.getId().equals(cardInHand.getId());
}
}

View file

@ -1,7 +1,6 @@
package mage.cards.f;
import mage.MageInt;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.CantBlockAbility;
@ -132,10 +131,10 @@ class FlameskullWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.SPELL_CAST
|| event.getAdditionalReference() == null) {
|| event.getApprovingObject() == null) {
return;
}
MageObjectReference mor = event.getAdditionalReference().getApprovingMageObjectReference();
MageObjectReference mor = event.getApprovingObject().getApprovingMageObjectReference();
Spell spell = game.getSpell(event.getTargetId());
if (mor == null || spell == null) {
return;

View file

@ -47,7 +47,7 @@ public class ForgeAnew extends CardImpl {
//As long as its your turn, you may activate equip abilities any time you could cast an instant.
this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect(
new ActivateAbilitiesAnyTimeYouCouldCastInstantEffect(EquipAbility.class, "equip abilities"), MyTurnCondition.instance
).setText("as long as it's your turn, you may activate equip abilities any time you could cast an instant."))
).setText("during your turn, you may activate equip abilities any time you could cast an instant."))
);
//You may pay {0} rather than pay the equip cost of the first equip ability you activate during each of your turns.
@ -144,4 +144,4 @@ class ForgeAnewWatcher extends Watcher {
ForgeAnewWatcher watcher = game.getState().getWatcher(ForgeAnewWatcher.class);
return watcher != null && watcher.equippedThisTurn.contains(playerId);
}
}
}

View file

@ -50,7 +50,7 @@ public final class FrodoDeterminedHero extends CardImpl {
// As long as it's your turn, prevent all damage that would be dealt to Frodo.
this.addAbility(new SimpleStaticAbility(new ConditionalPreventionEffect(
new PreventAllDamageToSourceEffect(Duration.WhileOnBattlefield), MyTurnCondition.instance,
"as long as it's your turn, prevent all damage that would be dealt to {this}"
"during your turn, prevent all damage that would be dealt to {this}"
)));
}

View file

@ -91,7 +91,7 @@ class GaleaKindlerOfHopeTriggeredAbility extends TriggeredAbilityImpl {
if (!isControlledBy(event.getPlayerId())
|| event.getZone() != Zone.LIBRARY
|| !event
.getAdditionalReference()
.getApprovingObject()
.getApprovingMageObjectReference()
.refersTo(this.getSourceObject(game), game)) {
return false;

Some files were not shown because too many files have changed in this diff Show more