diff --git a/Mage.Sets/src/mage/cards/s/Spellskite.java b/Mage.Sets/src/mage/cards/s/Spellskite.java index 58ae3c060a..08340c9b3a 100644 --- a/Mage.Sets/src/mage/cards/s/Spellskite.java +++ b/Mage.Sets/src/mage/cards/s/Spellskite.java @@ -29,15 +29,25 @@ package mage.cards.s; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ChangeATargetOfTargetSpellAbilityToSourceEffect; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.Zone; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.game.stack.StackAbility; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; import mage.target.TargetStackObject; +import mage.target.Targets; /** * @@ -46,13 +56,13 @@ import mage.target.TargetStackObject; public class Spellskite extends CardImpl { public Spellskite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); this.subtype.add("Horror"); this.power = new MageInt(0); this.toughness = new MageInt(4); // {UP}: Change a target of target spell or ability to Spellskite. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ChangeATargetOfTargetSpellAbilityToSourceEffect(), new ManaCostsImpl("{UP}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SpellskiteEffect(), new ManaCostsImpl("{UP}")); ability.addTarget(new TargetStackObject()); this.addAbility(ability); } @@ -66,3 +76,114 @@ public class Spellskite extends CardImpl { return new Spellskite(this); } } + +class SpellskiteEffect extends OneShotEffect { + + public SpellskiteEffect() { + super(Outcome.Neutral); + staticText = "Change a target of target spell or ability to {this}"; + } + + public SpellskiteEffect(final SpellskiteEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (stackObject != null && sourceObject != null) { + Targets targets = new Targets(); + Ability sourceAbility; + String oldTargetName = null; + if (stackObject instanceof Spell) { + Spell spell = (Spell) stackObject; + sourceAbility = spell.getSpellAbility(); + } else if (stackObject instanceof StackAbility) { + StackAbility stackAbility = (StackAbility) stackObject; + sourceAbility = stackAbility; + } else { + return false; + } + for (UUID modeId : sourceAbility.getModes().getSelectedModes()) { + Mode mode = sourceAbility.getModes().get(modeId); + targets.addAll(mode.getTargets()); + } + + boolean twoTimesTarget = false; + if (targets.size() == 1 && targets.get(0).getTargets().size() == 1) { + Target target = targets.get(0); + if (target.getFirstTarget().equals(source.getSourceId())) { + return true; // Target was already the same source, so no change / target event to create + } + if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { + oldTargetName = getTargetName(targets.getFirstTarget(), game); + target.clearChosen(); + // The source is still the spell on the stack + target.addTarget(source.getSourceId(), stackObject.getStackAbility(), game); + } + } else { //needed for targeted source's with multiple targets + Player controller = game.getPlayer(source.getControllerId()); + boolean validTargets = false; + do { + for (Target target : targets) { + for (UUID targetId : target.getTargets()) { + String name = getTargetName(targetId, game); + if (!targetId.equals(source.getSourceId()) && target.getTargets().contains(source.getSourceId())) { + // you can't change this target to source because the source is already another targetId of that target. + twoTimesTarget = true; + continue; + } + if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { + validTargets = true; + if (name != null + && controller.chooseUse(Outcome.Neutral, "Change target from " + name + " to " + sourceObject.getLogName() + '?', source, game)) { + oldTargetName = getTargetName(targetId, game); + int damageAmount = target.getTargetAmount(targetId); + target.remove(targetId); + // The source is still the spell on the stack + // add the source permanent id and set the damage if any + target.addTarget(source.getSourceId(), stackObject.getStackAbility(), game); + target.setTargetAmount(source.getSourceId(), damageAmount, game); + break; + } + } + } + if (oldTargetName != null) { + break; + } + } + if (oldTargetName == null) { + game.informPlayer(controller, "You have to select at least one target to change to " + sourceObject.getIdName() + '!'); + } + } while (validTargets && oldTargetName == null); + } + if (oldTargetName != null) { + game.informPlayers(sourceObject.getLogName() + ": Changed target of " + stackObject.getLogName() + " from " + oldTargetName + " to " + sourceObject.getLogName()); + } else if (twoTimesTarget) { + game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its not valid to target it twice for " + stackObject.getLogName()); + } else { + game.informPlayers(sourceObject.getLogName() + ": Target not changed to " + sourceObject.getLogName() + " because its no valid target for " + stackObject.getLogName()); + } + return true; + } + return false; + } + + @Override + public SpellskiteEffect copy() { + return new SpellskiteEffect(this); + } + + private String getTargetName(UUID objectId, Game game) { + MageObject object = game.getObject(objectId); + if (object != null) { + return object.getLogName(); + } + Player player = game.getPlayer(objectId); + if (player != null) { + return player.getLogName(); + } + return null; + } +} diff --git a/Mage/src/main/java/mage/target/Target.java b/Mage/src/main/java/mage/target/Target.java index 307c5a46d6..647c6281e7 100644 --- a/Mage/src/main/java/mage/target/Target.java +++ b/Mage/src/main/java/mage/target/Target.java @@ -53,7 +53,7 @@ public interface Target extends Serializable { boolean isNotTarget(); /** - * controlls if it will be checked, if the target can be targeted from + * controls if it will be checked, if the target can be targeted from * source * * @param notTarget true = do not check for protection, false = check for @@ -157,4 +157,8 @@ public interface Target extends Serializable { void setTargetTag(int tag); Target getOriginalTarget(); + + // used for cards like Spellskite + void setTargetAmount(UUID targetId, int amount, Game game); + } diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index 88c29215ac..546bafd5ad 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -544,7 +544,7 @@ public abstract class TargetImpl implements Target { } /** - * Is used to be able to check, that another target is slected within the + * Is used to be able to check, that another target is selected within the * group of targets of the ability with a target tag > 0. * * @param targetTag @@ -559,4 +559,10 @@ public abstract class TargetImpl implements Target { return this; } + @Override + public void setTargetAmount(UUID targetId, int amount, Game game) { + targets.put(targetId, amount); + rememberZoneChangeCounter(targetId, game); + } + }