Merge origin/master

This commit is contained in:
fireshoes 2016-04-18 01:25:52 -05:00
commit 194c817c11
35 changed files with 331 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

@ -0,0 +1,173 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.scourge;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.stack.StackObject;
import mage.target.Target;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author emerald000
*/
public class GripOfChaos extends CardImpl {
public GripOfChaos(UUID ownerId) {
super(ownerId, 98, "Grip of Chaos", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}{R}");
this.expansionSetCode = "SCG";
// Whenever a spell or ability is put onto the stack, if it has a single target, reselect its target at random.
this.addAbility(new GripOfChaosTriggeredAbility());
}
public GripOfChaos(final GripOfChaos card) {
super(card);
}
@Override
public GripOfChaos copy() {
return new GripOfChaos(this);
}
}
class GripOfChaosTriggeredAbility extends TriggeredAbilityImpl {
GripOfChaosTriggeredAbility() {
super(Zone.BATTLEFIELD, new GripOfChaosEffect());
}
GripOfChaosTriggeredAbility(final GripOfChaosTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.SPELL_CAST
|| event.getType() == EventType.ACTIVATED_ABILITY
|| event.getType() == EventType.TRIGGERED_ABILITY
|| event.getType() == EventType.COPIED_STACKOBJECT;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
return true;
}
return false;
}
@Override
public boolean checkInterveningIfClause(Game game) {
StackObject stackObject = null;
for (Effect effect : this.getEffects()) {
stackObject = game.getStack().getStackObject(effect.getTargetPointer().getFirst(game, this));
}
if (stackObject != null) {
int numberOfTargets = 0;
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) {
for (Target target : mode.getTargets()) {
numberOfTargets += target.getTargets().size();
}
}
return numberOfTargets == 1;
}
return false;
}
@Override
public String getRule() {
return "Whenever a spell or ability is put onto the stack, if it has a single target, reselect its target at random.";
}
@Override
public GripOfChaosTriggeredAbility copy() {
return new GripOfChaosTriggeredAbility(this);
}
}
class GripOfChaosEffect extends OneShotEffect {
GripOfChaosEffect() {
super(Outcome.Neutral);
this.staticText = "reselect its target at random";
}
GripOfChaosEffect(final GripOfChaosEffect effect) {
super(effect);
}
@Override
public GripOfChaosEffect copy() {
return new GripOfChaosEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
StackObject stackObject = game.getStack().getStackObject(this.getTargetPointer().getFirst(game, source));
if (stackObject != null) {
for (Mode mode : stackObject.getStackAbility().getModes().getSelectedModes()) {
for (Target target : mode.getTargets()) {
UUID oldTargetId = target.getFirstTarget();
Set<UUID> possibleTargets = target.possibleTargets(source.getSourceId(), source.getControllerId(), game);
if (possibleTargets.size() > 0) {
int i = 0;
int rnd = new Random().nextInt(possibleTargets.size());
Iterator<UUID> it = possibleTargets.iterator();
while (i < rnd) {
it.next();
i++;
}
UUID newTargetId = it.next();
target.remove(oldTargetId);
target.add(newTargetId, game);
}
}
}
return true;
}
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

@ -51,6 +51,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;
} }