mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
Unbound Flourishing's X doubling should be a triggered ability (and related refactors) (#12597)
Complete rework of Unbound Flourishing, removing the multiplier code for casting X spells. Adds ActivateAbilityTriggeredAbility, NotManaAbilityPredicate, AbilitySourceAttachedPredicate CopyStackObjectEffect now uses a MOR. OrTriggeredAbility now works with target pointer setting abilities.
This commit is contained in:
parent
9d83381326
commit
b70638acc9
36 changed files with 399 additions and 547 deletions
|
|
@ -2,7 +2,6 @@ package mage.player.ai;
|
|||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.AbilityImpl;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.common.PassAbility;
|
||||
|
|
@ -154,12 +153,8 @@ public final class SimulatedPlayer2 extends ComputerPlayer {
|
|||
}
|
||||
}
|
||||
// find real X value after replace events
|
||||
int xMultiplier = 1;
|
||||
if (newAbility instanceof AbilityImpl) {
|
||||
xMultiplier = ((AbilityImpl) newAbility).handleManaXMultiplier(game, xMultiplier);
|
||||
}
|
||||
newAbility.addManaCostsToPay(new ManaCostsImpl<>(new StringBuilder("{").append(xAnnounceValue).append('}').toString()));
|
||||
newAbility.getManaCostsToPay().setX(xAnnounceValue * xMultiplier, xAnnounceValue * xInstancesCount);
|
||||
newAbility.getManaCostsToPay().setX(xAnnounceValue, xAnnounceValue * xInstancesCount);
|
||||
if (varCost != null) {
|
||||
varCost.setPaid();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1921,20 +1921,18 @@ public class ComputerPlayer extends PlayerImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int announceXMana(int min, int max, int multiplier, String message, Game game, Ability ability) {
|
||||
public int announceXMana(int min, int max, String message, Game game, Ability ability) {
|
||||
log.debug("announceXMana");
|
||||
//TODO: improve this
|
||||
int xMin = min * multiplier;
|
||||
int xMax = (max == Integer.MAX_VALUE ? max : max * multiplier);
|
||||
int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().manaValue();
|
||||
if (numAvailable < 0) {
|
||||
numAvailable = 0;
|
||||
} else {
|
||||
if (numAvailable < xMin) {
|
||||
numAvailable = xMin;
|
||||
if (numAvailable < min) {
|
||||
numAvailable = min;
|
||||
}
|
||||
if (numAvailable > xMax) {
|
||||
numAvailable = xMax;
|
||||
if (numAvailable > max) {
|
||||
numAvailable = max;
|
||||
}
|
||||
}
|
||||
return numAvailable;
|
||||
|
|
|
|||
|
|
@ -1668,24 +1668,22 @@ public class HumanPlayer extends PlayerImpl {
|
|||
*
|
||||
* @param min
|
||||
* @param max
|
||||
* @param multiplier - X multiplier after replace events
|
||||
* @param message
|
||||
* @param ability
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int announceXMana(int min, int max, int multiplier, String message, Game game, Ability ability) {
|
||||
public int announceXMana(int min, int max, String message, Game game, Ability ability) {
|
||||
if (gameInCheckPlayableState(game)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xValue = 0;
|
||||
String extraMessage = (multiplier == 1 ? "" : ", X will be increased by " + multiplier + " times");
|
||||
while (canRespond()) {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetAmountEvent(playerId, message + extraMessage + CardUtil.getSourceLogName(game, ability), min, max);
|
||||
game.fireGetAmountEvent(playerId, message + CardUtil.getSourceLogName(game, ability), min, max);
|
||||
}
|
||||
waitForResponse(game);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -92,8 +93,7 @@ class AbolethSpawnTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (triggerEvent.getSourceId() != permanent.getId()) {
|
||||
return false; // only triggered abilities of that creature
|
||||
}
|
||||
// CopyStackObjectEffect needs value set
|
||||
getEffects().setValue("stackObject", stackObject);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -53,6 +54,8 @@ class AshnodTheUncaringTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
AshnodTheUncaringTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new CopyStackObjectEffect(), true);
|
||||
setTriggerPhrase("Whenever you activate an ability of an artifact or creature that isn't a mana ability, " +
|
||||
"if one or more permanents were sacrificed to activate it, ");
|
||||
}
|
||||
|
||||
private AshnodTheUncaringTriggeredAbility(final AshnodTheUncaringTriggeredAbility ability) {
|
||||
|
|
@ -88,14 +91,7 @@ class AshnodTheUncaringTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (permanent == null || (!permanent.isArtifact(game) && !permanent.isCreature(game))) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you activate an ability of an artifact or creature that isn't a mana ability, " +
|
||||
"if one or more permanents were sacrificed to activate it, " +
|
||||
"you may copy that ability. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package mage.cards.b;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.ActivateAbilityTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
|
|
@ -11,10 +11,10 @@ import mage.abilities.keyword.HasteAbility;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.common.FilterActivatedOrTriggeredAbility;
|
||||
import mage.filter.predicate.other.AbilitySourceAttachedPredicate;
|
||||
import mage.filter.predicate.other.NotManaAbilityPredicate;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -24,6 +24,13 @@ import java.util.UUID;
|
|||
*/
|
||||
public final class BattlemagesBracers extends CardImpl {
|
||||
|
||||
private static final FilterStackObject filter = new FilterActivatedOrTriggeredAbility("an ability of equipped creature");
|
||||
|
||||
static {
|
||||
filter.add(NotManaAbilityPredicate.instance);
|
||||
filter.add(AbilitySourceAttachedPredicate.instance);
|
||||
}
|
||||
|
||||
public BattlemagesBracers(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}");
|
||||
|
||||
|
|
@ -35,7 +42,8 @@ public final class BattlemagesBracers extends CardImpl {
|
|||
)));
|
||||
|
||||
// Whenever an ability of equipped creature is activated, if it isn't a mana ability, you may pay {1}. If you do, copy that ability. You may choose new targets for the copy.
|
||||
this.addAbility(new BattlemagesBracersTriggeredAbility());
|
||||
this.addAbility(new ActivateAbilityTriggeredAbility(new DoIfCostPaid(new CopyStackObjectEffect(), new GenericManaCost(1)), filter, SetTargetPointer.SPELL)
|
||||
.setTriggerPhrase("Whenever an ability of equipped creature is activated, if it isn't a mana ability, "));
|
||||
|
||||
// Equip {2}
|
||||
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2), new TargetControlledCreaturePermanent(), false));
|
||||
|
|
@ -50,44 +58,3 @@ public final class BattlemagesBracers extends CardImpl {
|
|||
return new BattlemagesBracers(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BattlemagesBracersTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
BattlemagesBracersTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new DoIfCostPaid(new CopyStackObjectEffect(), new GenericManaCost(1)));
|
||||
}
|
||||
|
||||
private BattlemagesBracersTriggeredAbility(final BattlemagesBracersTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BattlemagesBracersTriggeredAbility copy() {
|
||||
return new BattlemagesBracersTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent equipment = game.getPermanent(this.getSourceId());
|
||||
if (equipment == null || !equipment.isAttachedTo(event.getSourceId())) {
|
||||
return false;
|
||||
}
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility == null || stackAbility.getStackAbility().isManaActivatedAbility()) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setValue("stackObject", stackAbility);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever an ability of equipped creature is activated, if it isn't a mana ability, you may pay {1}. " +
|
||||
"If you do, copy that ability. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import mage.game.Game;
|
|||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetAnyTarget;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
|
@ -87,7 +88,7 @@ class BreechesTheBlastmakerEffect extends OneShotEffect {
|
|||
if (player.flipCoin(source, game, true)) {
|
||||
Effect effect = new CopyStackObjectEffect();
|
||||
effect.setText("copy that spell. You may choose new targets for the copy");
|
||||
effect.setValue("stackObject", spell);
|
||||
effect.setTargetPointer(new FixedTarget(spell.getId(), game));
|
||||
ability = new ReflexiveTriggeredAbility(effect, false);
|
||||
} else {
|
||||
int mv = Optional
|
||||
|
|
|
|||
|
|
@ -8,18 +8,18 @@ import mage.abilities.costs.common.DiscardTargetCost;
|
|||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -44,7 +44,9 @@ public final class ChandrasRegulator extends CardImpl {
|
|||
this.supertype.add(SuperType.LEGENDARY);
|
||||
|
||||
// Whenever you activate a loyalty ability of a Chandra planeswalker, you may pay {1}. If you do, copy that ability. You may choose new targets for the copy.
|
||||
this.addAbility(new ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(new ChandrasRegulatorEffect(), SubType.CHANDRA));
|
||||
this.addAbility(new ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(
|
||||
new DoIfCostPaid(new CopyStackObjectEffect(), new ManaCostsImpl<>("{1}")),
|
||||
SubType.CHANDRA, SetTargetPointer.SPELL));
|
||||
|
||||
// {1}, {T}, Discard a Mountain card or a red card: Draw a card.
|
||||
Ability ability = new SimpleActivatedAbility(
|
||||
|
|
@ -64,45 +66,3 @@ public final class ChandrasRegulator extends CardImpl {
|
|||
return new ChandrasRegulator(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ChandrasRegulatorEffect extends OneShotEffect {
|
||||
|
||||
ChandrasRegulatorEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "you may pay {1}. If you do, copy that ability. You may choose new targets for the copy";
|
||||
}
|
||||
|
||||
private ChandrasRegulatorEffect(final ChandrasRegulatorEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChandrasRegulatorEffect copy() {
|
||||
return new ChandrasRegulatorEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
ManaCostsImpl cost = new ManaCostsImpl<>("{1}");
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
if (!cost.canPay(source, source, player.getId(), game)
|
||||
|| !player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() +
|
||||
"? If you do, copy that ability. You may choose new targets for the copy.", source, game)) {
|
||||
return true;
|
||||
}
|
||||
if (!cost.pay(source, game, source, source.getControllerId(), false, null)) {
|
||||
return true;
|
||||
}
|
||||
StackAbility ability = (StackAbility) getValue("stackObject");
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
if (ability == null || controller == null || sourcePermanent == null) {
|
||||
return false;
|
||||
}
|
||||
ability.createCopyOnStack(game, source, source.getControllerId(), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.watchers.common.ManaPaidSourceWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -91,6 +92,7 @@ class DynaheirInvokerAdeptTriggeredAbility extends DelayedTriggeredAbility {
|
|||
|
||||
DynaheirInvokerAdeptTriggeredAbility() {
|
||||
super(new CopyStackObjectEffect(), Duration.EndOfTurn, true);
|
||||
setTriggerPhrase("When you next activate an ability that isn't a mana ability this turn by spending four or more mana to activate it, ");
|
||||
}
|
||||
|
||||
private DynaheirInvokerAdeptTriggeredAbility(final DynaheirInvokerAdeptTriggeredAbility ability) {
|
||||
|
|
@ -118,13 +120,7 @@ class DynaheirInvokerAdeptTriggeredAbility extends DelayedTriggeredAbility {
|
|||
|| ManaPaidSourceWatcher.getTotalPaid(stackAbility.getId(), game) < 4) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "When you next activate an ability that isn't a mana ability this turn by spending four or more mana to activate it, " +
|
||||
"copy that ability. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,15 +14,12 @@ import mage.constants.Zone;
|
|||
import mage.filter.FilterPlayer;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||
import mage.filter.predicate.mageobject.TargetsPermanentOrPlayerPredicate;
|
||||
import mage.filter.predicate.mageobject.TargetsPermanentPredicate;
|
||||
import mage.filter.predicate.mageobject.TargetsPlayerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.token.MercenaryToken;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -94,7 +91,7 @@ class ErthaJoFrontierMentorTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return false;
|
||||
}
|
||||
// For the copy effect to find.
|
||||
this.getEffects().setValue("stackObject", stackObject);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package mage.cards.i;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.ActivateAbilityTriggeredAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
import mage.abilities.keyword.EquipAbility;
|
||||
|
|
@ -8,12 +8,12 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.common.FilterActivatedOrTriggeredAbility;
|
||||
import mage.filter.predicate.other.AbilitySourceAttachedPredicate;
|
||||
import mage.filter.predicate.other.NotManaAbilityPredicate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -22,12 +22,19 @@ import java.util.UUID;
|
|||
*/
|
||||
public final class IllusionistsBracers extends CardImpl {
|
||||
|
||||
private static final FilterStackObject filter = new FilterActivatedOrTriggeredAbility("an ability of equipped creature");
|
||||
|
||||
static {
|
||||
filter.add(NotManaAbilityPredicate.instance);
|
||||
filter.add(AbilitySourceAttachedPredicate.instance);
|
||||
}
|
||||
public IllusionistsBracers(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
|
||||
this.subtype.add(SubType.EQUIPMENT);
|
||||
|
||||
// Whenever an ability of equipped creature is activated, if it isn't a mana ability, copy that ability. You may choose new targets for the copy.
|
||||
this.addAbility(new IllusionistsBracersTriggeredAbility());
|
||||
this.addAbility(new ActivateAbilityTriggeredAbility(new CopyStackObjectEffect(), filter, SetTargetPointer.SPELL)
|
||||
.setTriggerPhrase("Whenever an ability of equipped creature is activated, if it isn't a mana ability, "));
|
||||
|
||||
// Equip 3
|
||||
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(3), false));
|
||||
|
|
@ -42,44 +49,3 @@ public final class IllusionistsBracers extends CardImpl {
|
|||
return new IllusionistsBracers(this);
|
||||
}
|
||||
}
|
||||
|
||||
class IllusionistsBracersTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
IllusionistsBracersTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new CopyStackObjectEffect());
|
||||
}
|
||||
|
||||
private IllusionistsBracersTriggeredAbility(final IllusionistsBracersTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IllusionistsBracersTriggeredAbility copy() {
|
||||
return new IllusionistsBracersTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent equipment = game.getPermanent(this.getSourceId());
|
||||
if (equipment == null || !equipment.isAttachedTo(event.getSourceId())) {
|
||||
return false;
|
||||
}
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility == null || stackAbility.getStackAbility().isManaActivatedAbility()) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever an ability of equipped creature is activated, if it isn't a mana ability, " +
|
||||
"copy that ability. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import mage.abilities.effects.common.DamagePlayersEffect;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
|
||||
|
|
@ -19,14 +20,15 @@ public final class KeralKeepDisciples extends CardImpl {
|
|||
|
||||
public KeralKeepDisciples(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}");
|
||||
|
||||
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.MONK);
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Whenever you activate a loyalty ability of a Chandra planeswalker, Keral Keep Disciples deals 1 damage to each opponent.
|
||||
this.addAbility(new ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(new DamagePlayersEffect(1, TargetController.OPPONENT), SubType.CHANDRA));
|
||||
this.addAbility(new ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(
|
||||
new DamagePlayersEffect(1, TargetController.OPPONENT), SubType.CHANDRA, SetTargetPointer.NONE));
|
||||
}
|
||||
|
||||
private KeralKeepDisciples(final KeralKeepDisciples card) {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
package mage.cards.k;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.ActivateAbilityTriggeredAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.common.FilterActivatedOrTriggeredAbility;
|
||||
import mage.filter.predicate.other.ArtifactSourcePredicate;
|
||||
import mage.filter.predicate.other.NotManaAbilityPredicate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -22,6 +22,12 @@ import java.util.UUID;
|
|||
* @author emerald000
|
||||
*/
|
||||
public final class KurkeshOnakkeAncient extends CardImpl {
|
||||
private static final FilterStackObject filter = new FilterActivatedOrTriggeredAbility("an ability of an artifact, if it isn't a mana ability");
|
||||
|
||||
static {
|
||||
filter.add(NotManaAbilityPredicate.instance);
|
||||
filter.add(ArtifactSourcePredicate.instance);
|
||||
}
|
||||
|
||||
public KurkeshOnakkeAncient(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}");
|
||||
|
|
@ -33,7 +39,7 @@ public final class KurkeshOnakkeAncient extends CardImpl {
|
|||
this.toughness = new MageInt(3);
|
||||
|
||||
// Whenever you activate an ability of an artifact, if it isn't a mana ability, you may pay {R}. If you do, copy that ability. You may choose new targets for the copy.
|
||||
this.addAbility(new KurkeshOnakkeAncientTriggeredAbility());
|
||||
this.addAbility(new ActivateAbilityTriggeredAbility(new DoIfCostPaid(new CopyStackObjectEffect(), new ManaCostsImpl<>("{R}")), filter, SetTargetPointer.SPELL));
|
||||
}
|
||||
|
||||
private KurkeshOnakkeAncient(final KurkeshOnakkeAncient card) {
|
||||
|
|
@ -45,42 +51,3 @@ public final class KurkeshOnakkeAncient extends CardImpl {
|
|||
return new KurkeshOnakkeAncient(this);
|
||||
}
|
||||
}
|
||||
|
||||
class KurkeshOnakkeAncientTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
KurkeshOnakkeAncientTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new DoIfCostPaid(new CopyStackObjectEffect(), new ManaCostsImpl<>("{R}")));
|
||||
setTriggerPhrase("Whenever you activate an ability of an artifact, if it isn't a mana ability, ");
|
||||
}
|
||||
|
||||
private KurkeshOnakkeAncientTriggeredAbility(final KurkeshOnakkeAncientTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KurkeshOnakkeAncientTriggeredAbility copy() {
|
||||
return new KurkeshOnakkeAncientTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getPlayerId().equals(getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
Card source = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||
if (source == null || !source.isArtifact(game)) {
|
||||
return false;
|
||||
}
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility == null || stackAbility.getStackAbility().isManaActivatedAbility()) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -114,6 +115,7 @@ class LeoriSparktouchedHunterTriggeredAbility extends DelayedTriggeredAbility {
|
|||
super(new CopyStackObjectEffect(), Duration.EndOfTurn, false);
|
||||
this.subType = subType;
|
||||
this.addHint(new StaticHint("Chosen Subtype: " + subType));
|
||||
setTriggerPhrase("Whenever you activate an ability of a planeswalker of the chosen type, ");
|
||||
}
|
||||
|
||||
private LeoriSparktouchedHunterTriggeredAbility(final LeoriSparktouchedHunterTriggeredAbility ability) {
|
||||
|
|
@ -146,13 +148,7 @@ class LeoriSparktouchedHunterTriggeredAbility extends DelayedTriggeredAbility {
|
|||
if (permanent == null || !permanent.isPlaneswalker(game) || !permanent.hasSubtype(subType, game)) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you activate an ability of a planeswalker of the chosen type, copy that ability. " +
|
||||
"You may choose new targets for the copies.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package mage.cards.l;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.ActivateAbilityTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
|
|
@ -10,11 +10,12 @@ import mage.cards.Card;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.common.FilterActivatedOrTriggeredAbility;
|
||||
import mage.filter.predicate.other.NotManaAbilityPredicate;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -23,7 +24,11 @@ import java.util.UUID;
|
|||
* @author TheElk801
|
||||
*/
|
||||
public final class LocusOfEnlightenment extends CardImpl {
|
||||
private static final FilterStackObject filter = new FilterActivatedOrTriggeredAbility("an ability that isn't a mana ability");
|
||||
|
||||
static {
|
||||
filter.add(NotManaAbilityPredicate.instance);
|
||||
}
|
||||
public LocusOfEnlightenment(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "");
|
||||
|
||||
|
|
@ -35,7 +40,7 @@ public final class LocusOfEnlightenment extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new LocusOfEnlightenmentEffect()));
|
||||
|
||||
// Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy.
|
||||
this.addAbility(new LocusOfEnlightenmentTriggeredAbility());
|
||||
this.addAbility(new ActivateAbilityTriggeredAbility(new CopyStackObjectEffect("it"), filter, SetTargetPointer.SPELL));
|
||||
}
|
||||
|
||||
private LocusOfEnlightenment(final LocusOfEnlightenment card) {
|
||||
|
|
@ -91,38 +96,3 @@ class LocusOfEnlightenmentEffect extends ContinuousEffectImpl {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class LocusOfEnlightenmentTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
LocusOfEnlightenmentTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new CopyStackObjectEffect().setText("copy it. You may choose new targets for the copy"));
|
||||
this.setTriggerPhrase("Whenever you activate an ability that isn't a mana ability, ");
|
||||
}
|
||||
|
||||
private LocusOfEnlightenmentTriggeredAbility(final LocusOfEnlightenmentTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocusOfEnlightenmentTriggeredAbility copy() {
|
||||
return new LocusOfEnlightenmentTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getPlayerId().equals(getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility == null || stackAbility.isManaAbility()) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -65,7 +65,9 @@ public final class MagusLuceaKane extends CardImpl {
|
|||
class MagusLuceaKaneTriggeredAbility extends DelayedTriggeredAbility {
|
||||
|
||||
MagusLuceaKaneTriggeredAbility() {
|
||||
super(new CopyStackObjectEffect(), Duration.EndOfTurn, true, false);
|
||||
super(new CopyStackObjectEffect("that spell or ability"), Duration.EndOfTurn, true, false);
|
||||
setTriggerPhrase("When you next cast a spell with {X} in its mana cost " +
|
||||
"or activate an ability with {X} in its activation cost this turn, ");
|
||||
}
|
||||
|
||||
private MagusLuceaKaneTriggeredAbility(final MagusLuceaKaneTriggeredAbility ability) {
|
||||
|
|
@ -92,9 +94,9 @@ class MagusLuceaKaneTriggeredAbility extends DelayedTriggeredAbility {
|
|||
// activated ability
|
||||
if (event.getType() == GameEvent.EventType.ACTIVATED_ABILITY) {
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility != null && !stackAbility.getStackAbility().isManaActivatedAbility()) {
|
||||
if (stackAbility != null) {
|
||||
if (stackAbility.getManaCostsToPay().containsX()) {
|
||||
this.getEffects().setValue("stackObject", (StackObject) stackAbility);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -104,16 +106,10 @@ class MagusLuceaKaneTriggeredAbility extends DelayedTriggeredAbility {
|
|||
if (event.getType() == GameEvent.EventType.SPELL_CAST) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
if (spell != null && spell.getSpellAbility().getManaCostsToPay().containsX()) {
|
||||
this.getEffects().setValue("stackObject", (StackObject) spell);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "When you next cast a spell with {X} in its mana cost or activate an ability with {X} in its "
|
||||
+ "activation cost this turn, copy that spell or ability. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -79,7 +80,7 @@ class MirrorShieldHopliteTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (permanent == null || !permanent.isCreature(game) || !permanent.isControlledBy(this.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", sourceObject);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getSourceId(), game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
package mage.cards.r;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.common.ActivateAbilityTriggeredAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.common.FilterActivatedOrTriggeredAbility;
|
||||
import mage.filter.predicate.other.NotManaAbilityPredicate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -18,12 +18,17 @@ import java.util.UUID;
|
|||
* @author LevelX2
|
||||
*/
|
||||
public final class RingsOfBrighthearth extends CardImpl {
|
||||
private static final FilterStackObject filter = new FilterActivatedOrTriggeredAbility("an ability, if it isn't a mana ability");
|
||||
|
||||
static {
|
||||
filter.add(NotManaAbilityPredicate.instance);
|
||||
}
|
||||
|
||||
public RingsOfBrighthearth(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
|
||||
|
||||
// Whenever you activate an ability, if it isn't a mana ability, you may pay {2}. If you do, copy that ability. You may choose new targets for the copy.
|
||||
this.addAbility(new RingsOfBrighthearthTriggeredAbility());
|
||||
this.addAbility(new ActivateAbilityTriggeredAbility(new DoIfCostPaid(new CopyStackObjectEffect(), new ManaCostsImpl<>("{2}")), filter, SetTargetPointer.SPELL));
|
||||
}
|
||||
|
||||
private RingsOfBrighthearth(final RingsOfBrighthearth card) {
|
||||
|
|
@ -35,43 +40,3 @@ public final class RingsOfBrighthearth extends CardImpl {
|
|||
return new RingsOfBrighthearth(this);
|
||||
}
|
||||
}
|
||||
|
||||
class RingsOfBrighthearthTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
RingsOfBrighthearthTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new DoIfCostPaid(new CopyStackObjectEffect(), new GenericManaCost(2)));
|
||||
}
|
||||
|
||||
private RingsOfBrighthearthTriggeredAbility(final RingsOfBrighthearthTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RingsOfBrighthearthTriggeredAbility copy() {
|
||||
return new RingsOfBrighthearthTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getPlayerId().equals(getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility == null || stackAbility.getStackAbility().isManaActivatedAbility()) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you activate an ability, if it isn't a mana ability, you may pay {2}. " +
|
||||
"If you do, copy that ability. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import mage.game.stack.StackObject;
|
|||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.target.common.TargetPlaneswalkerPermanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -72,6 +73,7 @@ class RowansTalentTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
RowansTalentTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new CopyStackObjectEffect());
|
||||
setTriggerPhrase("Whenever you activate a loyalty ability of enchanted planeswalker, ");
|
||||
}
|
||||
|
||||
private RowansTalentTriggeredAbility(final RowansTalentTriggeredAbility ability) {
|
||||
|
|
@ -100,13 +102,7 @@ class RowansTalentTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (stackObject == null || !(stackObject.getStackAbility() instanceof LoyaltyAbility)) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackObject);
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you activate a loyalty ability of enchanted planeswalker, " +
|
||||
"copy that ability. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,31 @@
|
|||
package mage.cards.u;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.common.ActivateAbilityTriggeredAbility;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
import mage.abilities.meta.OrTriggeredAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.common.FilterActivatedOrTriggeredAbility;
|
||||
import mage.filter.common.FilterInstantOrSorcerySpell;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.filter.predicate.mageobject.PermanentPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
|
@ -26,18 +33,33 @@ import java.util.UUID;
|
|||
*/
|
||||
public final class UnboundFlourishing extends CardImpl {
|
||||
|
||||
final static String needPrefix = "_UnboundFlourishing_NeedCopy";
|
||||
private static final FilterSpell filterPermanent = new FilterSpell("a permanent spell with a mana cost that contains {X}");
|
||||
private static final FilterSpell filterInstantSorcery = new FilterInstantOrSorcerySpell("an instant or sorcery spell with a mana cost that contains {X}");
|
||||
private static final FilterStackObject filterAbility = new FilterActivatedOrTriggeredAbility("an activated ability with an activation cost that contains {X}");
|
||||
|
||||
static {
|
||||
filterPermanent.add(PermanentPredicate.instance);
|
||||
filterPermanent.add(UnboundFlourishingCostContainsXPredicate.instance);
|
||||
filterInstantSorcery.add(UnboundFlourishingCostContainsXPredicate.instance);
|
||||
filterAbility.add(UnboundFlourishingCostContainsXPredicate.instance);
|
||||
}
|
||||
|
||||
public UnboundFlourishing(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
|
||||
|
||||
// Whenever you cast a permanent spell with a mana cost that contains {X}, double the value of X.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new UnboundFlourishingDoubleXEffect()));
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(new UnboundFlourishingDoubleXEffect(), filterPermanent, false, SetTargetPointer.SPELL));
|
||||
|
||||
// Whenever you cast an instant or sorcery spell or activate an ability,
|
||||
// if that spell’s mana cost or that ability’s activation cost contains {X}, copy that spell or ability.
|
||||
// You may choose new targets for the copy.
|
||||
this.addAbility(new UnboundFlourishingCopyAbility());
|
||||
this.addAbility(new OrTriggeredAbility(Zone.BATTLEFIELD,
|
||||
new CopyStackObjectEffect("that spell or ability"), false,
|
||||
"Whenever you cast an instant or sorcery spell or activate an ability, " +
|
||||
"if that spell's mana cost or that ability's activation cost contains {X}, ",
|
||||
new SpellCastControllerTriggeredAbility(null, filterInstantSorcery, false, SetTargetPointer.SPELL),
|
||||
new ActivateAbilityTriggeredAbility(null, filterAbility, SetTargetPointer.SPELL)
|
||||
));
|
||||
}
|
||||
|
||||
private UnboundFlourishing(final UnboundFlourishing card) {
|
||||
|
|
@ -50,130 +72,53 @@ public final class UnboundFlourishing extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class UnboundFlourishingDoubleXEffect extends ReplacementEffectImpl {
|
||||
enum UnboundFlourishingCostContainsXPredicate implements Predicate<StackObject> {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(StackObject input, Game game) {
|
||||
if (input instanceof Spell) {
|
||||
return ((Spell) input).getSpellAbility().getManaCostsToPay().containsX();
|
||||
} else if (input instanceof StackAbility) {
|
||||
return input.getStackAbility().getManaCostsToPay().containsX();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Contains {X}";
|
||||
}
|
||||
}
|
||||
|
||||
class UnboundFlourishingDoubleXEffect extends OneShotEffect {
|
||||
|
||||
UnboundFlourishingDoubleXEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Benefit, false);
|
||||
staticText = "Whenever you cast a permanent spell with a mana cost that contains {X}, double the value of X";
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "double the value of X";
|
||||
}
|
||||
|
||||
private UnboundFlourishingDoubleXEffect(final UnboundFlourishingDoubleXEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
event.setAmount(CardUtil.overflowMultiply(event.getAmount(), 2));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.X_MANA_ANNOUNCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Spell spell = game.getSpell(event.getTargetId());
|
||||
return spell != null && spell.isPermanent(game) && spell.isControlledBy(source.getControllerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnboundFlourishingDoubleXEffect copy() {
|
||||
return new UnboundFlourishingDoubleXEffect(this);
|
||||
}
|
||||
}
|
||||
|
||||
class UnboundFlourishingCopyAbility extends TriggeredAbilityImpl {
|
||||
|
||||
UnboundFlourishingCopyAbility() {
|
||||
super(Zone.BATTLEFIELD, new UnboundFlourishingCopyEffect(), false);
|
||||
setTriggerPhrase("Whenever you cast an instant or sorcery spell or activate an ability, " +
|
||||
"if that spell's mana cost or that ability's activation cost contains {X}");
|
||||
}
|
||||
|
||||
private UnboundFlourishingCopyAbility(final UnboundFlourishingCopyAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnboundFlourishingCopyAbility copy() {
|
||||
return new UnboundFlourishingCopyAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY
|
||||
|| event.getType() == GameEvent.EventType.SPELL_CAST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getPlayerId().equals(getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// activated ability
|
||||
if (event.getType() == GameEvent.EventType.ACTIVATED_ABILITY) {
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility != null && !stackAbility.getStackAbility().isManaActivatedAbility()) {
|
||||
if (stackAbility.getManaCostsToPay().containsX()) {
|
||||
game.getState().setValue(this.getSourceId() + UnboundFlourishing.needPrefix, stackAbility);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spell
|
||||
if (event.getType() == GameEvent.EventType.SPELL_CAST) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
if (spell != null && spell.isInstantOrSorcery(game)) {
|
||||
if (spell.getSpellAbility().getManaCostsToPay().containsX()) {
|
||||
game.getState().setValue(this.getSourceId() + UnboundFlourishing.needPrefix, spell);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class UnboundFlourishingCopyEffect extends OneShotEffect {
|
||||
|
||||
UnboundFlourishingCopyEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = ", copy that spell or ability. You may choose new targets for the copy";
|
||||
}
|
||||
|
||||
private UnboundFlourishingCopyEffect(final UnboundFlourishingCopyEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnboundFlourishingCopyEffect copy() {
|
||||
return new UnboundFlourishingCopyEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && controller != null) {
|
||||
Object needObject = game.getState().getValue(source.getSourceId() + UnboundFlourishing.needPrefix);
|
||||
|
||||
// copy ability
|
||||
if (needObject instanceof StackAbility) {
|
||||
StackAbility stackAbility = (StackAbility) needObject;
|
||||
stackAbility.createCopyOnStack(game, source, source.getControllerId(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// copy spell
|
||||
if (needObject instanceof Spell) {
|
||||
Spell spell = (Spell) needObject;
|
||||
spell.createCopyOnStack(game, source, source.getControllerId(), true);
|
||||
return true;
|
||||
Spell needObject = game.getSpell(getTargetPointer().getFirst(game, source));
|
||||
if (needObject != null) {
|
||||
Map<String, Object> tagsMap = CardUtil.getSourceCostsTagsMap(game, needObject.getSpellAbility());
|
||||
if (tagsMap.containsKey("X")) {
|
||||
tagsMap.put("X", ((int) tagsMap.get("X")) * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import mage.constants.Zone;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -96,7 +97,7 @@ class VerrakWarpedSengirTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (lifePaid > 0) {
|
||||
this.getEffects().clear();
|
||||
this.addEffect(new DoIfCostPaid(new CopyStackObjectEffect(), new PayLifeCost(lifePaid)));
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ public class UnboundFlourishingTest extends CardTestPlayerBase {
|
|||
addCard(Zone.HAND, playerA, "Endless One", 1); // {X}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
|
||||
// cast with X=3, but double it
|
||||
// cast with X=3, but double it twice
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Endless One");
|
||||
setChoice(playerA, "Unbound Flourishing"); // choose replacement effects
|
||||
setChoice(playerA, "X=3");
|
||||
setChoice(playerA, ""); //stack triggers
|
||||
checkPermanentCounters("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Endless One", CounterType.P1P1, 3 * 2 * 2);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
|
@ -163,6 +163,36 @@ public class UnboundFlourishingTest extends CardTestPlayerBase {
|
|||
execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_OnActivatedAbility_MustCopy2Counter() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Unbound Flourishing", 1);
|
||||
//
|
||||
// {X}{R}, {T}, Sacrifice Cinder Elemental: It deals X damage to any target.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Cinder Elemental", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
//
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 1);
|
||||
addCard(Zone.HAND, playerB, "Stifle", 1);
|
||||
|
||||
// activate with X=3 and make copy with another target, not double X
|
||||
checkLife("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 20);
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{X}{R}", playerA);
|
||||
setChoice(playerA, "X=3");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Stifle"); //Counter the original ability, copy must still work
|
||||
addTarget(playerB, "stack ability ({X}{R}, {T}, Sacrifice");
|
||||
|
||||
setChoice(playerA, true); // change target
|
||||
addTarget(playerA, playerB); // change to B
|
||||
checkLife("after", 1, PhaseStep.BEGIN_COMBAT, playerA, 20); // original damage is countered
|
||||
checkLife("after", 1, PhaseStep.BEGIN_COMBAT, playerB, 20 - 3); // copy damage
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_VariableManaCost() {
|
||||
// VariableManaCost contains:
|
||||
|
|
|
|||
|
|
@ -2816,7 +2816,7 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int announceXMana(int min, int max, int multiplier, String message, Game game, Ability ability) {
|
||||
public int announceXMana(int min, int max, String message, Game game, Ability ability) {
|
||||
assertAliasSupportInChoices(false);
|
||||
if (!choices.isEmpty()) {
|
||||
for (String choice : choices) {
|
||||
|
|
@ -2830,7 +2830,7 @@ public class TestPlayer implements Player {
|
|||
|
||||
this.chooseStrictModeFailed("choice", game, getInfo(ability, game)
|
||||
+ "\nMessage: " + message);
|
||||
return computerPlayer.announceXMana(min, max, multiplier, message, game, ability);
|
||||
return computerPlayer.announceXMana(min, max, message, game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -278,8 +278,6 @@ public abstract class AbilityImpl implements Ability {
|
|||
int xValue = CardUtil.getSourceCostsTag(game, this, "X", 0);
|
||||
this.clearManaCostsToPay();
|
||||
VariableManaCost xCosts = new VariableManaCost(VariableCostType.ADDITIONAL);
|
||||
// no x events - rules from Unbound Flourishing:
|
||||
// - Spells with additional costs that include X won't be affected by Unbound Flourishing. X must be in the spell's mana cost.
|
||||
xCosts.setAmount(xValue, xValue, false);
|
||||
addManaCostsToPay(xCosts);
|
||||
} else {
|
||||
|
|
@ -617,8 +615,6 @@ public abstract class AbilityImpl implements Ability {
|
|||
Cost fixedCost = variableCost.getFixedCostsFromAnnouncedValue(xValue);
|
||||
addCost(fixedCost);
|
||||
// set the xcosts to paid
|
||||
// no x events - rules from Unbound Flourishing:
|
||||
// - Spells with additional costs that include X won't be affected by Unbound Flourishing. X must be in the spell's mana cost.
|
||||
variableCost.setAmount(xValue, xValue, false);
|
||||
((Cost) variableCost).setPaid();
|
||||
String message = controller.getLogName() + " announces a value of " + xValue + " (" + variableCost.getActionText() + ')'
|
||||
|
|
@ -653,13 +649,6 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
|
||||
public int handleManaXMultiplier(Game game, int value) {
|
||||
// some spells can change X value without new pays (Unbound Flourishing doubles X)
|
||||
GameEvent xEvent = GameEvent.getEvent(GameEvent.EventType.X_MANA_ANNOUNCE, this.getId(), this, getControllerId(), value);
|
||||
game.replaceEvent(xEvent, this);
|
||||
return xEvent.getAmount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles X mana costs and sets manaCostsToPay.
|
||||
*
|
||||
|
|
@ -695,9 +684,8 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (variableManaCost != null) {
|
||||
if (!variableManaCost.isPaid()) { // should only happen for human players
|
||||
int xValue;
|
||||
int xValueMultiplier = handleManaXMultiplier(game, 1);
|
||||
if (!noMana || variableManaCost.getCostType().canUseAnnounceOnFreeCast()) {
|
||||
xValue = controller.announceXMana(variableManaCost.getMinX(), variableManaCost.getMaxX(), xValueMultiplier,
|
||||
xValue = controller.announceXMana(variableManaCost.getMinX(), variableManaCost.getMaxX(),
|
||||
"Announce the value for " + variableManaCost.getText(), game, this);
|
||||
int amountMana = xValue * variableManaCost.getXInstancesCount();
|
||||
StringBuilder manaString = threadLocalBuilder.get();
|
||||
|
|
@ -728,8 +716,8 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
addManaCostsToPay(new ManaCostsImpl<>(manaString.toString()));
|
||||
getManaCostsToPay().setX(xValue * xValueMultiplier, amountMana);
|
||||
setCostsTag("X", xValue * xValueMultiplier);
|
||||
getManaCostsToPay().setX(xValue, amountMana);
|
||||
setCostsTag("X", xValue);
|
||||
}
|
||||
variableManaCost.setPaid();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
public class ActivateAbilityTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterStackObject filter;
|
||||
protected final SetTargetPointer setTargetPointer;
|
||||
|
||||
public ActivateAbilityTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer) {
|
||||
this(Zone.BATTLEFIELD, effect, filter, setTargetPointer);
|
||||
}
|
||||
|
||||
public ActivateAbilityTriggeredAbility(Zone zone, Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer) {
|
||||
super(zone, effect, false);
|
||||
this.filter = filter;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("Whenever you activate " + filter.getMessage() + ", ");
|
||||
}
|
||||
|
||||
private ActivateAbilityTriggeredAbility(final ActivateAbilityTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivateAbilityTriggeredAbility copy() {
|
||||
return new ActivateAbilityTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getPlayerId().equals(getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getTargetId());
|
||||
if (stackAbility == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!filter.match(stackAbility, event.getPlayerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (setTargetPointer) {
|
||||
case NONE:
|
||||
break;
|
||||
case PLAYER:
|
||||
getAllEffects().setTargetPointer(new FixedTarget(getControllerId(), game));
|
||||
break;
|
||||
case SPELL:
|
||||
getAllEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unexpected setTargetPointer in ActivateAbilityTriggeredAbility: " + setTargetPointer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,26 +3,31 @@ package mage.abilities.common;
|
|||
import mage.abilities.LoyaltyAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
public class ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final SubType planeswalkerSubType;
|
||||
protected final SetTargetPointer setTargetPointer;
|
||||
|
||||
public ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(Effect effect, SubType planeswalkerSubType) {
|
||||
public ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(Effect effect, SubType planeswalkerSubType, SetTargetPointer setTargetPointer) {
|
||||
super(Zone.BATTLEFIELD, effect, false);
|
||||
this.planeswalkerSubType = planeswalkerSubType;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("Whenever you activate a loyalty ability of a " + planeswalkerSubType.getDescription() + " planeswalker, ");
|
||||
}
|
||||
|
||||
private ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(final ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.planeswalkerSubType = ability.planeswalkerSubType;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -49,7 +54,22 @@ public class ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility extends Triggere
|
|||
|| !permanent.hasSubtype(planeswalkerSubType, game)) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
|
||||
switch (setTargetPointer) {
|
||||
case NONE:
|
||||
break;
|
||||
case PLAYER:
|
||||
getAllEffects().setTargetPointer(new FixedTarget(getControllerId(), game));
|
||||
break;
|
||||
case SPELL:
|
||||
getAllEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
break;
|
||||
case PERMANENT:
|
||||
getAllEffects().setTargetPointer(new FixedTarget(event.getSourceId(), game));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unexpected setTargetPointer in ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility: " + setTargetPointer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,7 +418,6 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
game.undo(playerId);
|
||||
this.clearPaid();
|
||||
|
||||
// TODO: checks Word of Command with Unbound Flourishing's X multiplier
|
||||
// TODO: checks Word of Command with {X}{X} cards
|
||||
int amount = 0;
|
||||
List<VariableCost> variableCosts = getVariableCosts();
|
||||
|
|
|
|||
|
|
@ -3,18 +3,25 @@ package mage.abilities.effects.common;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CopyStackObjectEffect extends OneShotEffect {
|
||||
|
||||
public CopyStackObjectEffect() {
|
||||
this("that ability");
|
||||
}
|
||||
|
||||
public CopyStackObjectEffect(String name) {
|
||||
super(Outcome.Copy);
|
||||
staticText = "copy that ability. You may choose new targets for the copy";
|
||||
staticText = "copy "+ name + ". You may choose new targets for the copy";
|
||||
}
|
||||
|
||||
private CopyStackObjectEffect(final CopyStackObjectEffect effect) {
|
||||
|
|
@ -29,11 +36,15 @@ public class CopyStackObjectEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
StackObject ability = (StackObject) getValue("stackObject");
|
||||
if (controller == null || ability == null) {
|
||||
UUID id = getTargetPointer().getFirst(game, source);
|
||||
StackObject object = game.getStack().getStackObject(id);
|
||||
if (object == null) {
|
||||
object = (StackObject) game.getLastKnownInformation(id, Zone.STACK);
|
||||
}
|
||||
if (controller == null || object == null) {
|
||||
return false;
|
||||
}
|
||||
ability.createCopyOnStack(game, source, source.getControllerId(), true);
|
||||
object.createCopyOnStack(game, source, source.getControllerId(), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,9 +72,13 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
boolean toRet = false;
|
||||
for (TriggeredAbility ability : triggeredAbilities) {
|
||||
for (Effect e : getEffects()) { //Add effects to the sub-abilities so that they can set target pointers
|
||||
ability.addEffect(e);
|
||||
}
|
||||
if (ability.checkEventType(event, game) && ability.checkTrigger(event, game)) {
|
||||
toRet = true;
|
||||
}
|
||||
ability.getEffects().clear(); //Remove afterwards, ensures that they remain synced even with copying
|
||||
}
|
||||
return toRet;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package mage.filter.predicate.other;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.game.stack.StackObject;
|
||||
|
||||
/**
|
||||
* @author notgreat
|
||||
*/
|
||||
public enum AbilitySourceAttachedPredicate implements ObjectSourcePlayerPredicate<StackObject> {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(ObjectSourcePlayer<StackObject> input, Game game) {
|
||||
MageObject obj = input.getObject();
|
||||
Ability source = input.getSource();
|
||||
|
||||
return obj instanceof StackAbility
|
||||
&& ((StackAbility) obj).getSourceId().equals(source.getSourcePermanentOrLKI(game).getAttachedTo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Attached activated/triggered";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package mage.filter.predicate.other;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.StackObject;
|
||||
|
||||
/**
|
||||
* @author notgreat
|
||||
*/
|
||||
public enum NotManaAbilityPredicate implements Predicate<StackObject> {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(StackObject input, Game game) {
|
||||
if (!(input instanceof Ability)) {
|
||||
return false;
|
||||
}
|
||||
return !((Ability) input).isManaAbility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "isn't a mana ability";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,28 @@
|
|||
package mage.game.command.emblems;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.ActivateAbilityTriggeredAbility;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.common.FilterActivatedOrTriggeredAbility;
|
||||
import mage.filter.predicate.other.NotManaAbilityPredicate;
|
||||
import mage.game.command.Emblem;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackAbility;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class RowanKenrithEmblem extends Emblem {
|
||||
// Target player gets an emblem with "Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy."
|
||||
private static final FilterStackObject filter = new FilterActivatedOrTriggeredAbility("an ability that isn't a mana ability");
|
||||
|
||||
static {
|
||||
filter.add(NotManaAbilityPredicate.instance);
|
||||
}
|
||||
|
||||
public RowanKenrithEmblem() {
|
||||
super("Emblem Rowan Kenrith");
|
||||
this.getAbilities().add(new RowanKenrithEmblemTriggeredAbility());
|
||||
this.getAbilities().add(new ActivateAbilityTriggeredAbility(Zone.COMMAND, new CopyStackObjectEffect("it"), filter, SetTargetPointer.SPELL));
|
||||
}
|
||||
|
||||
private RowanKenrithEmblem(final RowanKenrithEmblem card) {
|
||||
|
|
@ -28,42 +34,3 @@ public final class RowanKenrithEmblem extends Emblem {
|
|||
return new RowanKenrithEmblem(this);
|
||||
}
|
||||
}
|
||||
|
||||
class RowanKenrithEmblemTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
RowanKenrithEmblemTriggeredAbility() {
|
||||
super(Zone.COMMAND, new CopyStackObjectEffect(), false);
|
||||
}
|
||||
|
||||
private RowanKenrithEmblemTriggeredAbility(final RowanKenrithEmblemTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowanKenrithEmblemTriggeredAbility copy() {
|
||||
return new RowanKenrithEmblemTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getPlayerId().equals(getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility == null || stackAbility.getStackAbility().isManaActivatedAbility()) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("stackObject", stackAbility);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,13 +219,6 @@ public class GameEvent implements Serializable {
|
|||
sourceId sourceId of the mount
|
||||
playerId the id of the controlling player
|
||||
*/
|
||||
X_MANA_ANNOUNCE,
|
||||
/* X_MANA_ANNOUNCE
|
||||
mana x-costs announced by players (X value can be changed by replace events like Unbound Flourishing)
|
||||
targetId id of the spell that's cast
|
||||
playerId player that casts the spell or ability
|
||||
amount X multiplier to change X value, default 1
|
||||
*/
|
||||
CAST_SPELL,
|
||||
CAST_SPELL_LATE,
|
||||
/* SPELL_CAST, CAST_SPELL_LATE
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
|
||||
package mage.game.stack;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.PutCards;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.util.CardUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -82,6 +83,7 @@ public class SpellStack extends ArrayDeque<StackObject> {
|
|||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, source, stackObject.getControllerId()))) {
|
||||
if (!(stackObject instanceof Spell)) { // spells are removed from stack by the card movement
|
||||
this.remove(stackObject, game);
|
||||
game.rememberLKI(Zone.STACK, stackObject);
|
||||
}
|
||||
stackObject.counter(source, game, putCard);
|
||||
if (!game.isSimulation()) {
|
||||
|
|
|
|||
|
|
@ -731,11 +731,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
boolean shuffleCardsToLibrary(Card card, Game game, Ability source);
|
||||
|
||||
// set the value for X mana spells and abilities
|
||||
default int announceXMana(int min, int max, String message, Game game, Ability ability) {
|
||||
return announceXMana(min, max, 1, message, game, ability);
|
||||
}
|
||||
|
||||
int announceXMana(int min, int max, int multiplier, String message, Game game, Ability ability);
|
||||
int announceXMana(int min, int max, String message, Game game, Ability ability);
|
||||
|
||||
// set the value for non mana X costs
|
||||
int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost);
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ public class StubPlayer extends PlayerImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int announceXMana(int min, int max, int multiplier, String message, Game game, Ability ability) {
|
||||
public int announceXMana(int min, int max, String message, Game game, Ability ability) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue