Added framework method for copying a StackAbility without casting it.

Modified the effects doing so with the new method.
This commit is contained in:
emerald000 2016-04-17 23:55:11 -04:00
parent b9ab16d945
commit 8823839a42
34 changed files with 158 additions and 313 deletions

View file

@ -419,7 +419,9 @@ public class SimulatedPlayer2 extends ComputerPlayer {
if (options.isEmpty()) { if (options.isEmpty()) {
logger.debug("simulating -- triggered ability:" + ability); logger.debug("simulating -- triggered ability:" + ability);
game.getStack().push(new StackAbility(ability, playerId)); game.getStack().push(new StackAbility(ability, playerId));
ability.activate(game, false); if (ability.activate(game, false) && ability.isUsesStack()) {
game.fireEvent(new GameEvent(GameEvent.EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
}
game.applyEffects(); game.applyEffects();
game.getPlayers().resetPassed(); game.getPlayers().resetPassed();
} else { } else {
@ -439,7 +441,9 @@ public class SimulatedPlayer2 extends ComputerPlayer {
protected void addAbilityNode(SimulationNode2 parent, Ability ability, int depth, Game game) { protected void addAbilityNode(SimulationNode2 parent, Ability ability, int depth, Game game) {
Game sim = game.copy(); Game sim = game.copy();
sim.getStack().push(new StackAbility(ability, playerId)); sim.getStack().push(new StackAbility(ability, playerId));
ability.activate(sim, false); if (ability.activate(sim, false) && ability.isUsesStack()) {
game.fireEvent(new GameEvent(GameEvent.EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
}
sim.applyEffects(); sim.applyEffects();
SimulationNode2 newNode = new SimulationNode2(parent, sim, depth, playerId); SimulationNode2 newNode = new SimulationNode2(parent, sim, depth, playerId);
logger.debug("simulating -- node #:" + SimulationNode2.getCount() + " triggered ability option"); logger.debug("simulating -- node #:" + SimulationNode2.getCount() + " triggered ability option");

View file

@ -47,6 +47,7 @@ import mage.choices.Choice;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.game.Game; import mage.game.Game;
import mage.game.combat.CombatGroup; import mage.game.combat.CombatGroup;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.StackAbility; import mage.game.stack.StackAbility;
import mage.players.Player; import mage.players.Player;
@ -168,6 +169,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
if (ability.isUsesStack()) { if (ability.isUsesStack()) {
game.getStack().push(new StackAbility(ability, playerId)); game.getStack().push(new StackAbility(ability, playerId));
if (ability.activate(game, false)) { if (ability.activate(game, false)) {
game.fireEvent(new GameEvent(GameEvent.EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
actionCount++; actionCount++;
return true; return true;
} }

View file

@ -28,6 +28,8 @@
package mage.player.ai; package mage.player.ai;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
@ -42,9 +44,6 @@ import mage.game.stack.StackAbility;
import mage.target.Target; import mage.target.Target;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -239,7 +238,9 @@ public class SimulatedPlayer extends ComputerPlayer {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("simulating -- triggered ability:" + ability); logger.debug("simulating -- triggered ability:" + ability);
game.getStack().push(new StackAbility(ability, playerId)); game.getStack().push(new StackAbility(ability, playerId));
ability.activate(game, false); if (ability.activate(game, false) && ability.isUsesStack()) {
game.fireEvent(new GameEvent(GameEvent.EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
}
game.applyEffects(); game.applyEffects();
game.getPlayers().resetPassed(); game.getPlayers().resetPassed();
} }
@ -258,6 +259,9 @@ public class SimulatedPlayer extends ComputerPlayer {
Game sim = game.copy(); Game sim = game.copy();
sim.getStack().push(new StackAbility(ability, playerId)); sim.getStack().push(new StackAbility(ability, playerId));
ability.activate(sim, false); ability.activate(sim, false);
if (ability.activate(sim, false) && ability.isUsesStack()) {
game.fireEvent(new GameEvent(GameEvent.EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
}
sim.applyEffects(); sim.applyEffects();
SimulationNode newNode = new SimulationNode(parent, sim, playerId); SimulationNode newNode = new SimulationNode(parent, sim, playerId);
logger.debug(indent(newNode.getDepth()) + "simulating -- node #:" + SimulationNode.getCount() + " triggered ability option"); logger.debug(indent(newNode.getDepth()) + "simulating -- node #:" + SimulationNode.getCount() + " triggered ability option");

View file

@ -28,22 +28,18 @@
package mage.sets.alarareborn; package mage.sets.alarareborn;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CopyTargetSpellEffect;
import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DoIfCostPaid;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.filter.FilterSpell; import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.MulticoloredPredicate; import mage.filter.predicate.mageobject.MulticoloredPredicate;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.players.Player;
/** /**
* *
@ -65,8 +61,9 @@ public class ClovenCasting extends CardImpl {
this.expansionSetCode = "ARB"; this.expansionSetCode = "ARB";
// Whenever you cast a multicolored instant or sorcery spell, you may pay {1}. If you do, copy that spell. You may choose new targets for the copy. // Whenever you cast a multicolored instant or sorcery spell, you may pay {1}. If you do, copy that spell. You may choose new targets for the copy.
this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(new ClovenCastingEffect(), new GenericManaCost(1)), filter, true, true)); Effect effect = new CopyTargetSpellEffect();
effect.setText("copy that spell. You may choose new targets for the copy");
this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(effect, new GenericManaCost(1)), filter, true, true));
} }
public ClovenCasting(final ClovenCasting card) { public ClovenCasting(final ClovenCasting card) {
@ -78,38 +75,3 @@ public class ClovenCasting extends CardImpl {
return new ClovenCasting(this); return new ClovenCasting(this);
} }
} }
class ClovenCastingEffect extends OneShotEffect {
public ClovenCastingEffect() {
super(Outcome.Copy);
staticText = "copy that spell. You may choose new targets for the copy";
}
public ClovenCastingEffect(final ClovenCastingEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
if (spell != null) {
Spell copy = spell.copySpell(source.getControllerId());
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
Player player = game.getPlayer(source.getControllerId());
String activateMessage = copy.getActivatedMessage(game);
if (activateMessage.startsWith(" casts ")) {
activateMessage = activateMessage.substring(6);
}
game.informPlayers(player.getLogName() + " copies " + activateMessage);
return true;
}
return false;
}
@Override
public ClovenCastingEffect copy() {
return new ClovenCastingEffect(this);
}
}

View file

@ -196,7 +196,7 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
} }
} }
} }
game.fireEvent(new GameEvent(GameEvent.EventType.COPIED_STACKOBJECT, copy.getId(), spell.getId(), source.getControllerId()));
String activateMessage = copy.getActivatedMessage(game); String activateMessage = copy.getActivatedMessage(game);
if (activateMessage.startsWith(" casts ")) { if (activateMessage.startsWith(" casts ")) {
activateMessage = activateMessage.substring(6); activateMessage = activateMessage.substring(6);

View file

@ -29,17 +29,15 @@ package mage.sets.commander;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyTargetSpellEffect;
import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.PutTokenOntoBattlefieldCopyTargetEffect; import mage.abilities.effects.common.PutTokenOntoBattlefieldCopyTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.SetTargetPointer; import mage.constants.SetTargetPointer;
import mage.constants.Zone; import mage.constants.Zone;
@ -49,9 +47,6 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.AnotherPredicate;
import mage.filter.predicate.permanent.TokenPredicate; import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.players.Player;
/** /**
* *
@ -82,10 +77,12 @@ public class RikuOfTwoReflections extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Whenever you cast an instant or sorcery spell, you may pay {U}{R}. If you do, copy that spell. You may choose new targets for the copy. // Whenever you cast an instant or sorcery spell, you may pay {U}{R}. If you do, copy that spell. You may choose new targets for the copy.
this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(new RikuOfTwoReflectionsCopyEffect(), new ManaCostsImpl("{U}{R}")), filter, false, true)); Effect effect = new CopyTargetSpellEffect();
effect.setText("copy that spell. You may choose new targets for the copy");
this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(effect, new ManaCostsImpl("{U}{R}")), filter, false, true));
// Whenever another nontoken creature enters the battlefield under your control, you may pay {G}{U}. If you do, put a token that's a copy of that creature onto the battlefield. // Whenever another nontoken creature enters the battlefield under your control, you may pay {G}{U}. If you do, put a token that's a copy of that creature onto the battlefield.
Effect effect = new DoIfCostPaid(new PutTokenOntoBattlefieldCopyTargetEffect(), effect = new DoIfCostPaid(new PutTokenOntoBattlefieldCopyTargetEffect(),
new ManaCostsImpl("{G}{U}"), "Put a token that's a copy of that creature onto the battlefield?"); new ManaCostsImpl("{G}{U}"), "Put a token that's a copy of that creature onto the battlefield?");
effect.setText("you may pay {G}{U}. If you do, put a token that's a copy of that creature onto the battlefield"); effect.setText("you may pay {G}{U}. If you do, put a token that's a copy of that creature onto the battlefield");
this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, effect, filterPermanent, false, SetTargetPointer.PERMANENT, null)); this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, effect, filterPermanent, false, SetTargetPointer.PERMANENT, null));
@ -100,38 +97,3 @@ public class RikuOfTwoReflections extends CardImpl {
return new RikuOfTwoReflections(this); return new RikuOfTwoReflections(this);
} }
} }
class RikuOfTwoReflectionsCopyEffect extends OneShotEffect {
public RikuOfTwoReflectionsCopyEffect() {
super(Outcome.Copy);
staticText = "copy that spell. You may choose new targets for the copy";
}
public RikuOfTwoReflectionsCopyEffect(final RikuOfTwoReflectionsCopyEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
if (spell != null) {
Spell copy = spell.copySpell(source.getControllerId());;
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
Player player = game.getPlayer(source.getControllerId());
String activateMessage = copy.getActivatedMessage(game);
if (activateMessage.startsWith(" casts ")) {
activateMessage = activateMessage.substring(6);
}
game.informPlayers(player.getLogName() + " copies " + activateMessage);
return true;
}
return false;
}
@Override
public RikuOfTwoReflectionsCopyEffect copy() {
return new RikuOfTwoReflectionsCopyEffect(this);
}
}

View file

@ -28,18 +28,15 @@
package mage.sets.commander; package mage.sets.commander;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseNewTargetsTargetEffect;
import mage.abilities.effects.common.CopyTargetSpellEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.filter.FilterStackObject; import mage.filter.FilterStackObject;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetStackObject; import mage.target.TargetStackObject;
/** /**
@ -61,9 +58,11 @@ public class WildRicochet extends CardImpl {
this.expansionSetCode = "CMD"; this.expansionSetCode = "CMD";
// You may choose new targets for target instant or sorcery spell. Then copy that spell. You may choose new targets for the copy. // You may choose new targets for target instant or sorcery spell. Then copy that spell. You may choose new targets for the copy.
this.getSpellAbility().addEffect(new WildRicochetEffect()); this.getSpellAbility().addEffect(new ChooseNewTargetsTargetEffect());
Effect effect = new CopyTargetSpellEffect();
effect.setText("Then copy that spell. You may choose new targets for the copy");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetStackObject(filter)); this.getSpellAbility().addTarget(new TargetStackObject(filter));
} }
public WildRicochet(final WildRicochet card) { public WildRicochet(final WildRicochet card) {
@ -75,37 +74,3 @@ public class WildRicochet extends CardImpl {
return new WildRicochet(this); return new WildRicochet(this);
} }
} }
class WildRicochetEffect extends OneShotEffect {
public WildRicochetEffect() {
super(Outcome.Neutral);
staticText = "You may choose new targets for target instant or sorcery spell. Then copy that spell. You may choose new targets for the copy";
}
public WildRicochetEffect(final WildRicochetEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getStack().getSpell(source.getFirstTarget());
Player you = game.getPlayer(source.getControllerId());
if (spell != null && you != null && you.chooseUse(Outcome.Benefit, "Do you wish to choose new targets for " + spell.getName() + "?", source, game)) {
spell.chooseNewTargets(game, you.getId());
}
if (spell != null) {
Spell copy = spell.copySpell(source.getControllerId());;
game.getStack().push(copy);
if (you != null && you.chooseUse(Outcome.Benefit, "Do you wish to choose new targets for the copied " + spell.getName() + "?", source, game)) {
return copy.chooseNewTargets(game, you.getId());
}
}
return false;
}
@Override
public WildRicochetEffect copy() {
return new WildRicochetEffect(this);
}
}

View file

@ -45,6 +45,7 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
@ -106,14 +107,14 @@ class CopySourceSpellEffect extends OneShotEffect {
if (controller != null) { if (controller != null) {
Spell spell = game.getStack().getSpell(source.getSourceId()); Spell spell = game.getStack().getSpell(source.getSourceId());
if (spell != null) { if (spell != null) {
Spell spellCopy = spell.copySpell(source.getControllerId());; StackObject stackObjectCopy = spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(spellCopy); if (stackObjectCopy != null && stackObjectCopy instanceof Spell) {
spellCopy.chooseNewTargets(game, controller.getId()); String activateMessage = ((Spell) stackObjectCopy).getActivatedMessage(game);
String activateMessage = spellCopy.getActivatedMessage(game); if (activateMessage.startsWith(" casts ")) {
if (activateMessage.startsWith(" casts ")) { activateMessage = activateMessage.substring(6);
activateMessage = activateMessage.substring(6); }
game.informPlayers(controller.getLogName() + " copies " + activateMessage);
} }
game.informPlayers(controller.getLogName() + " copies " + activateMessage);
return true; return true;
} }
} }

View file

@ -151,9 +151,7 @@ class CurseOfEchoesEffect extends OneShotEffect {
if (!playerId.equals(spell.getControllerId())) { if (!playerId.equals(spell.getControllerId())) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if (player.chooseUse(Outcome.Copy, chooseMessage, source, game)) { if (player.chooseUse(Outcome.Copy, chooseMessage, source, game)) {
Spell copy = spell.copySpell(source.getControllerId()); spell.createCopyOnStack(game, source, player.getId(), true);
game.getStack().push(copy);
copy.chooseNewTargets(game, playerId);
} }
} }
} }

View file

@ -40,6 +40,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetSpell; import mage.target.TargetSpell;
@ -99,17 +100,17 @@ class IncreasingVengeanceEffect extends OneShotEffect {
if (controller != null) { if (controller != null) {
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
if (spell != null) { if (spell != null) {
Spell copy = spell.copySpell(source.getControllerId()); StackObject stackObjectCopy = spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy); if (stackObjectCopy != null && stackObjectCopy instanceof Spell) {
copy.chooseNewTargets(game, source.getControllerId()); game.informPlayers(new StringBuilder(controller.getLogName()).append(((Spell) stackObjectCopy).getActivatedMessage(game)).toString());
game.informPlayers(new StringBuilder(controller.getLogName()).append(copy.getActivatedMessage(game)).toString()); }
Spell sourceSpell = (Spell) game.getStack().getStackObject(source.getSourceId()); Spell sourceSpell = (Spell) game.getStack().getStackObject(source.getSourceId());
if (sourceSpell != null) { if (sourceSpell != null) {
if (sourceSpell.getFromZone() == Zone.GRAVEYARD) { if (sourceSpell.getFromZone() == Zone.GRAVEYARD) {
copy = spell.copySpell(source.getControllerId()); stackObjectCopy = spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy); if (stackObjectCopy != null && stackObjectCopy instanceof Spell) {
copy.chooseNewTargets(game, source.getControllerId()); game.informPlayers(new StringBuilder(controller.getLogName()).append(((Spell) stackObjectCopy).getActivatedMessage(game)).toString());
game.informPlayers(new StringBuilder(controller.getLogName()).append(copy.getActivatedMessage(game)).toString()); }
} }
} }
return true; return true;

View file

@ -31,10 +31,9 @@ import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyTargetSpellEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterSpell; import mage.filter.FilterSpell;
@ -43,9 +42,7 @@ import mage.filter.predicate.ObjectPlayerPredicate;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell;
import mage.game.stack.StackObject; import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetSpell; import mage.target.TargetSpell;
@ -56,7 +53,7 @@ import mage.target.TargetSpell;
*/ */
public class MirrorSheen extends CardImpl { public class MirrorSheen extends CardImpl {
private static final FilterSpell filter = new FilterSpell(); private static final FilterSpell filter = new FilterSpell("instant or sorcery spell that targets you");
static { static {
filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY))); filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY)));
@ -68,7 +65,7 @@ public class MirrorSheen extends CardImpl {
this.expansionSetCode = "EVE"; this.expansionSetCode = "EVE";
// {1}{UR}{UR}: Copy target instant or sorcery spell that targets you. You may choose new targets for the copy. // {1}{UR}{UR}: Copy target instant or sorcery spell that targets you. You may choose new targets for the copy.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MirrorSheenEffect(), new ManaCostsImpl("{1}{U/R}{U/R}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CopyTargetSpellEffect(), new ManaCostsImpl("{1}{U/R}{U/R}"));
ability.addTarget(new TargetSpell(filter)); ability.addTarget(new TargetSpell(filter));
this.addAbility(ability); this.addAbility(ability);
@ -84,41 +81,6 @@ public class MirrorSheen extends CardImpl {
} }
} }
class MirrorSheenEffect extends OneShotEffect {
public MirrorSheenEffect() {
super(Outcome.Copy);
staticText = "Copy target instant or sorcery spell that targets you. You may choose new targets for the copy";
}
public MirrorSheenEffect(final MirrorSheenEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getStack().getSpell(source.getFirstTarget());
if (spell != null) {
Spell copy = spell.copySpell(source.getControllerId());
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
Player player = game.getPlayer(source.getControllerId());
String activateMessage = copy.getActivatedMessage(game);
if (activateMessage.startsWith(" casts ")) {
activateMessage = activateMessage.substring(6);
}
game.informPlayers(player.getLogName() + " copies " + activateMessage);
return true;
}
return false;
}
@Override
public MirrorSheenEffect copy() {
return new MirrorSheenEffect(this);
}
}
class TargetYouPredicate implements ObjectPlayerPredicate<ObjectPlayer<StackObject>> { class TargetYouPredicate implements ObjectPlayerPredicate<ObjectPlayer<StackObject>> {
@Override @Override

View file

@ -102,7 +102,7 @@ class AbilityActivatedTriggeredAbility extends TriggeredAbilityImpl {
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId()); StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
if (!(stackAbility.getStackAbility() instanceof ManaAbility)) { if (!(stackAbility.getStackAbility() instanceof ManaAbility)) {
Effect effect = this.getEffects().get(0); Effect effect = this.getEffects().get(0);
effect.setValue("stackAbility", stackAbility.getStackAbility()); effect.setValue("stackAbility", stackAbility);
return true; return true;
} }
} }
@ -133,21 +133,11 @@ class CopyActivatedAbilityEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Ability ability = (Ability) getValue("stackAbility"); StackAbility ability = (StackAbility) getValue("stackAbility");
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (ability != null && controller != null && sourcePermanent != null) { if (ability != null && controller != null && sourcePermanent != null) {
Ability newAbility = ability.copy(); ability.createCopyOnStack(game, source, source.getControllerId(), true);
newAbility.newId();
game.getStack().push(new StackAbility(newAbility, source.getControllerId()));
if (newAbility.getTargets().size() > 0) {
if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) {
newAbility.getTargets().clearChosen();
if (newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), source.getControllerId(), newAbility, false, game) == false) {
return false;
}
}
}
game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString()); game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString());
return true; return true;
} }

View file

@ -106,10 +106,8 @@ class ChainLightningEffect extends OneShotEffect {
if (cost.pay(source, game, source.getSourceId(), affectedPlayer.getId(), false, null)) { if (cost.pay(source, game, source.getSourceId(), affectedPlayer.getId(), false, null)) {
Spell spell = game.getStack().getSpell(source.getSourceId()); Spell spell = game.getStack().getSpell(source.getSourceId());
if (spell != null) { if (spell != null) {
Spell copy = spell.copySpell(affectedPlayer.getId()); spell.createCopyOnStack(game, source, affectedPlayer.getId(), true);
game.getStack().push(copy); game.informPlayers(affectedPlayer.getLogName() + " copies " + spell.getName() + ".");
copy.chooseNewTargets(game, affectedPlayer.getId());
game.informPlayers(affectedPlayer.getLogName() + " copies " + copy.getName() + ".");
} }
} }
} }

View file

@ -39,6 +39,7 @@ import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetSpell; import mage.target.TargetSpell;
@ -96,6 +97,7 @@ class ForkEffect extends OneShotEffect {
copy.getColor(game).setRed(true); copy.getColor(game).setRed(true);
game.getStack().push(copy); game.getStack().push(copy);
copy.chooseNewTargets(game, controller.getId()); copy.chooseNewTargets(game, controller.getId());
game.fireEvent(new GameEvent(GameEvent.EventType.COPIED_STACKOBJECT, copy.getId(), spell.getId(), source.getControllerId()));
return true; return true;
} }
return false; return false;

View file

@ -96,7 +96,7 @@ class RingsOfBrighthearthTriggeredAbility extends TriggeredAbilityImpl {
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId()); StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
if (stackAbility != null && !(stackAbility.getStackAbility() instanceof ManaAbility)) { if (stackAbility != null && !(stackAbility.getStackAbility() instanceof ManaAbility)) {
Effect effect = this.getEffects().get(0); Effect effect = this.getEffects().get(0);
effect.setValue("stackAbility", stackAbility.getStackAbility()); effect.setValue("stackAbility", stackAbility);
return true; return true;
} }
} }
@ -132,21 +132,11 @@ class RingsOfBrighthearthEffect extends OneShotEffect {
if (player != null) { if (player != null) {
if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", source, game)) { if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", source, game)) {
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) {
Ability ability = (Ability) getValue("stackAbility"); StackAbility ability = (StackAbility) getValue("stackAbility");
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (ability != null && controller != null) { if (ability != null && controller != null) {
Ability newAbility = ability.copy(); ability.createCopyOnStack(game, source, source.getControllerId(), true);
newAbility.newId();
game.getStack().push(new StackAbility(newAbility, source.getControllerId()));
if (newAbility.getTargets().size() > 0) {
if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) {
newAbility.getTargets().clearChosen();
if (newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), source.getControllerId(), newAbility, false, game) == false) {
return false;
}
}
}
game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString()); game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString());
return true; return true;
} }

View file

@ -135,9 +135,7 @@ class HiveMindEffect extends OneShotEffect {
if (spell != null && player != null) { if (spell != null && player != null) {
for (UUID playerId : game.getState().getPlayersInRange(player.getId(), game)) { for (UUID playerId : game.getState().getPlayersInRange(player.getId(), game)) {
if (!playerId.equals(spell.getControllerId())) { if (!playerId.equals(spell.getControllerId())) {
Spell copy = spell.copySpell(playerId); spell.createCopyOnStack(game, source, playerId, true);
game.getStack().push(copy);
copy.chooseNewTargets(game, playerId);
} }
} }
return true; return true;

View file

@ -92,21 +92,10 @@ class StrionicResonatorEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(targetPointer.getFirst(game, source)); StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(targetPointer.getFirst(game, source));
if (stackAbility != null) { if (stackAbility != null) {
Ability ability = (Ability) stackAbility.getStackAbility();
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (ability != null && controller != null && sourcePermanent != null) { if (controller != null && sourcePermanent != null) {
Ability newAbility = ability.copy(); stackAbility.createCopyOnStack(game, source, source.getControllerId(), true);
newAbility.newId();
game.getStack().push(new StackAbility(newAbility, source.getControllerId()));
if (newAbility.getTargets().size() > 0) {
if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) {
newAbility.getTargets().clearChosen();
if (newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), source.getControllerId(), newAbility, false, game) == false) {
return false;
}
}
}
game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString()); game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString());
return true; return true;
} }

View file

@ -107,7 +107,7 @@ class KurkeshOnakkeAncientTriggeredAbility extends TriggeredAbilityImpl {
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId()); StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
if (!(stackAbility.getStackAbility() instanceof ManaAbility)) { if (!(stackAbility.getStackAbility() instanceof ManaAbility)) {
Effect effect = this.getEffects().get(0); Effect effect = this.getEffects().get(0);
effect.setValue("stackAbility", stackAbility.getStackAbility()); effect.setValue("stackAbility", stackAbility);
return true; return true;
} }
} }
@ -144,21 +144,11 @@ class KurkeshOnakkeAncientEffect extends OneShotEffect {
if (player != null) { if (player != null) {
if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", source, game)) { if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", source, game)) {
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) {
Ability ability = (Ability) getValue("stackAbility"); StackAbility ability = (StackAbility) getValue("stackAbility");
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (ability != null && controller != null) { if (ability != null && controller != null) {
Ability newAbility = ability.copy(); ability.createCopyOnStack(game, source, source.getControllerId(), true);
newAbility.newId();
game.getStack().push(new StackAbility(newAbility, source.getControllerId()));
if (newAbility.getTargets().size() > 0) {
if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) {
newAbility.getTargets().clearChosen();
if (newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), source.getControllerId(), newAbility, false, game) == false) {
return false;
}
}
}
game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString()); game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString());
return true; return true;
} }

View file

@ -104,22 +104,21 @@ class PsychicRebuttalEffect extends OneShotEffect {
if (controller == null) { if (controller == null) {
return false; return false;
} }
StackObject stackObject = game.getState().getStack().getStackObject(getTargetPointer().getFirst(game, source)); Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source));
if (stackObject != null) { if (spell != null) {
game.getStack().counter(stackObject.getId(), source.getSourceId(), game); game.getStack().counter(spell.getId(), source.getSourceId(), game);
if (SpellMasteryCondition.getInstance().apply(game, source) if (SpellMasteryCondition.getInstance().apply(game, source)
&& controller.chooseUse(Outcome.PlayForFree, "Copy " + stackObject.getName() + " (you may choose new targets for the copy)?", source, game)) { && controller.chooseUse(Outcome.PlayForFree, "Copy " + spell.getName() + " (you may choose new targets for the copy)?", source, game)) {
Spell copy = ((Spell) stackObject).copySpell(source.getControllerId()); StackObject newStackObject = spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy); if (newStackObject != null && newStackObject instanceof Spell) {
copy.chooseNewTargets(game, source.getControllerId()); String activateMessage = ((Spell) newStackObject).getActivatedMessage(game);
Player player = game.getPlayer(source.getControllerId()); if (activateMessage.startsWith(" casts ")) {
String activateMessage = copy.getActivatedMessage(game); activateMessage = activateMessage.substring(6);
if (activateMessage.startsWith(" casts ")) { }
activateMessage = activateMessage.substring(6); game.informPlayers(controller.getLogName() + activateMessage);
} }
game.informPlayers(player.getLogName() + activateMessage);
} }
return true; return true;

View file

@ -41,6 +41,7 @@ import mage.filter.common.FilterControlledLandPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetNonlandPermanent; import mage.target.common.TargetNonlandPermanent;
@ -103,14 +104,14 @@ class ChainOfVaporEffect extends OneShotEffect {
if (player.chooseUse(outcome, "Copy the spell?", source, game)) { if (player.chooseUse(outcome, "Copy the spell?", source, game)) {
Spell spell = game.getStack().getSpell(source.getSourceId()); Spell spell = game.getStack().getSpell(source.getSourceId());
if (spell != null) { if (spell != null) {
Spell copy = spell.copySpell(player.getId()); StackObject newStackObject = spell.createCopyOnStack(game, source, player.getId(), true);
game.getStack().push(copy); if (newStackObject != null && newStackObject instanceof Spell) {
copy.chooseNewTargets(game, player.getId()); String activateMessage = ((Spell) newStackObject).getActivatedMessage(game);
String activateMessage = copy.getActivatedMessage(game); if (activateMessage.startsWith(" casts ")) {
if (activateMessage.startsWith(" casts ")) { activateMessage = activateMessage.substring(6);
activateMessage = activateMessage.substring(6); }
game.informPlayers(player.getLogName() + " " + activateMessage);
} }
game.informPlayers(player.getLogName() + " " + activateMessage);
} }
} }
} }

View file

@ -130,11 +130,8 @@ class EchoMageEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
if (spell != null) { if (spell != null) {
for (int i = 0; i < 2; i++) { spell.createCopyOnStack(game, source, source.getControllerId(), true);
Spell copy = spell.copySpell(source.getControllerId()); spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
}
return true; return true;
} }
return false; return false;

View file

@ -44,6 +44,7 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetSpell; import mage.target.TargetSpell;
@ -104,15 +105,15 @@ class MeletisCharlatanCopyTargetSpellEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
if (spell != null) { if (spell != null) {
Spell copy = spell.copySpell(source.getControllerId()); StackObject newStackObject = spell.createCopyOnStack(game, source, spell.getControllerId(), true);
game.getStack().push(copy);
copy.chooseNewTargets(game, spell.getControllerId());
Player player = game.getPlayer(spell.getControllerId()); Player player = game.getPlayer(spell.getControllerId());
String activateMessage = copy.getActivatedMessage(game); if (player != null && newStackObject != null && newStackObject instanceof Spell) {
if (activateMessage.startsWith(" casts ")) { String activateMessage = ((Spell) newStackObject).getActivatedMessage(game);
activateMessage = activateMessage.substring(6); if (activateMessage.startsWith(" casts ")) {
activateMessage = activateMessage.substring(6);
}
game.informPlayers(player.getLogName() + " copies " + activateMessage);
} }
game.informPlayers(player.getLogName() + " copies " + activateMessage);;
return true; return true;
} }
return false; return false;

View file

@ -48,6 +48,7 @@ import mage.constants.Outcome;
import mage.constants.RangeOfInfluence; import mage.constants.RangeOfInfluence;
import mage.game.Game; import mage.game.Game;
import mage.game.combat.CombatGroup; import mage.game.combat.CombatGroup;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.StackAbility; import mage.game.stack.StackAbility;
import mage.player.ai.ComputerPlayer; import mage.player.ai.ComputerPlayer;
@ -173,6 +174,7 @@ public class RandomPlayer extends ComputerPlayer {
if (ability.isUsesStack()) { if (ability.isUsesStack()) {
game.getStack().push(new StackAbility(ability, playerId)); game.getStack().push(new StackAbility(ability, playerId));
if (ability.activate(game, false)) { if (ability.activate(game, false)) {
game.fireEvent(new GameEvent(GameEvent.EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
actionCount++; actionCount++;
return true; return true;
} }

View file

@ -34,6 +34,7 @@ import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
/** /**
@ -57,16 +58,16 @@ public class CopyTargetSpellEffect extends OneShotEffect {
spell = (Spell) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK); spell = (Spell) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK);
} }
if (spell != null) { if (spell != null) {
Spell copy = spell.copySpell(source.getControllerId());; StackObject newStackObject = spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
String activateMessage = copy.getActivatedMessage(game); if (player != null && newStackObject != null && newStackObject instanceof Spell) {
if (activateMessage.startsWith(" casts ")) { String activateMessage = ((Spell) newStackObject).getActivatedMessage(game);
activateMessage = activateMessage.substring(6); if (activateMessage.startsWith(" casts ")) {
} activateMessage = activateMessage.substring(6);
if (!game.isSimulation()) { }
game.informPlayers(player.getLogName() + activateMessage); if (!game.isSimulation()) {
game.informPlayers(player.getLogName() + activateMessage);
}
} }
return true; return true;
} }

View file

@ -140,10 +140,7 @@ class EpicPushEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
if (spell != null) { if (spell != null) {
// don't change the targets of the in the origin copied spell spell.createCopyOnStack(game, source, source.getControllerId(), true);
Spell copySpell = spell.copy();
game.getStack().push(copySpell);
copySpell.chooseNewTargets(game, source.getControllerId());
return true; return true;
} }

View file

@ -52,6 +52,7 @@ import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
@ -292,11 +293,9 @@ class ConspireEffect extends OneShotEffect {
if (controller != null && conspiredSpell != null) { if (controller != null && conspiredSpell != null) {
Card card = game.getCard(conspiredSpell.getSourceId()); Card card = game.getCard(conspiredSpell.getSourceId());
if (card != null) { if (card != null) {
Spell copy = conspiredSpell.copySpell(source.getControllerId()); StackObject newStackObject = conspiredSpell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy); if (newStackObject != null && newStackObject instanceof Spell && !game.isSimulation()) {
copy.chooseNewTargets(game, source.getControllerId()); game.informPlayers(controller.getLogName() + ((Spell) newStackObject).getActivatedMessage(game));
if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + copy.getActivatedMessage(game));
} }
return true; return true;
} }

View file

@ -109,9 +109,7 @@ class GravestormEffect extends OneShotEffect {
game.informPlayers("Gravestorm: " + spell.getName() + " will be copied " + gravestormCount + " time" + (gravestormCount > 1 ? "s" : "")); game.informPlayers("Gravestorm: " + spell.getName() + " will be copied " + gravestormCount + " time" + (gravestormCount > 1 ? "s" : ""));
} }
for (int i = 0; i < gravestormCount; i++) { for (int i = 0; i < gravestormCount; i++) {
Spell copy = spell.copySpell(source.getControllerId()); spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
} }
} }
} }

View file

@ -247,11 +247,9 @@ class ReplicateCopyEffect extends OneShotEffect {
} }
// create the copies // create the copies
for (int i = 0; i < replicateCount; i++) { for (int i = 0; i < replicateCount; i++) {
Spell copy = spell.copySpell(source.getControllerId()); StackObject newStackObject = spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy); if (newStackObject != null && newStackObject instanceof Spell && !game.isSimulation()) {
copy.chooseNewTargets(game, source.getControllerId()); game.informPlayers(controller.getLogName() + ((Spell) newStackObject).getActivatedMessage(game));
if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + copy.getActivatedMessage(game));
} }
} }
return true; return true;

View file

@ -109,9 +109,7 @@ class StormEffect extends OneShotEffect {
game.informPlayers("Storm: " + spell.getLogName() + " will be copied " + stormCount + " time" + (stormCount > 1 ? "s" : "")); game.informPlayers("Storm: " + spell.getLogName() + " will be copied " + stormCount + " time" + (stormCount > 1 ? "s" : ""));
} }
for (int i = 0; i < stormCount; i++) { for (int i = 0; i < stormCount; i++) {
Spell copy = spell.copySpell(source.getControllerId()); spell.createCopyOnStack(game, source, source.getControllerId(), true);
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
} }
} }
} }

View file

@ -125,6 +125,8 @@ public class GameEvent implements Serializable {
*/ */
SPELL_CAST, SPELL_CAST,
ACTIVATE_ABILITY, ACTIVATED_ABILITY, ACTIVATE_ABILITY, ACTIVATED_ABILITY,
TRIGGERED_ABILITY,
COPIED_STACKOBJECT,
/* ADD_MANA /* ADD_MANA
targetId id of the ability that added the mana targetId id of the ability that added the mana
sourceId sourceId of the ability that added the mana sourceId sourceId of the ability that added the mana

View file

@ -56,6 +56,8 @@ import mage.constants.ZoneDetail;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.Counters; import mage.counters.Counters;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent; import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard; import mage.game.permanent.PermanentCard;
@ -873,4 +875,14 @@ public class Spell extends StackObjImpl implements Card {
throw new UnsupportedOperationException("Not supported for Spell"); throw new UnsupportedOperationException("Not supported for Spell");
} }
@Override
public StackObject createCopyOnStack(Game game, Ability source, UUID newControllerId, boolean chooseNewTargets) {
Spell copy = this.copySpell(newControllerId);
game.getStack().push(copy);
if (chooseNewTargets) {
copy.chooseNewTargets(game, newControllerId);
}
game.fireEvent(new GameEvent(EventType.COPIED_STACKOBJECT, copy.getId(), this.getId(), newControllerId));
return copy;
}
} }

View file

@ -580,4 +580,21 @@ public class StackAbility extends StackObjImpl implements Ability {
public void setCanFizzle(boolean canFizzle) { public void setCanFizzle(boolean canFizzle) {
throw new UnsupportedOperationException("Not supported."); throw new UnsupportedOperationException("Not supported.");
} }
@Override
public StackObject createCopyOnStack(Game game, Ability source, UUID newControllerId, boolean chooseNewTargets) {
Ability newAbility = this.copy();
newAbility.newId();
StackAbility newStackAbility = new StackAbility(newAbility, newControllerId);
game.getStack().push(newStackAbility);
if (chooseNewTargets && newAbility.getTargets().size() > 0) {
Player controller = game.getPlayer(newControllerId);
if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) {
newAbility.getTargets().clearChosen();
newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), newControllerId, newAbility, false, game);
}
}
game.fireEvent(new GameEvent(GameEvent.EventType.COPIED_STACKOBJECT, newStackAbility.getId(), this.getId(), newControllerId));
return newStackAbility;
}
} }

View file

@ -50,6 +50,8 @@ public interface StackObject extends MageObject, Controllable {
// int getConvertedManaCost(); // int getConvertedManaCost();
boolean chooseNewTargets(Game game, UUID playerId, boolean forceChange, boolean onlyOneTarget, FilterPermanent filterNewTarget); boolean chooseNewTargets(Game game, UUID playerId, boolean forceChange, boolean onlyOneTarget, FilterPermanent filterNewTarget);
StackObject createCopyOnStack(Game game, Ability source, UUID newControllerId, boolean chooseNewTargets);
@Override @Override
StackObject copy(); StackObject copy();

View file

@ -1239,6 +1239,9 @@ public abstract class PlayerImpl implements Player, Serializable {
if (!ability.isUsesStack()) { if (!ability.isUsesStack()) {
ability.resolve(game); ability.resolve(game);
} }
else {
game.fireEvent(new GameEvent(EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
}
game.removeBookmark(bookmark); game.removeBookmark(bookmark);
return true; return true;
} }