diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/mage/view/CardView.java
index 7216ba5c49..5be823cbe3 100644
--- a/Mage.Common/src/mage/view/CardView.java
+++ b/Mage.Common/src/mage/view/CardView.java
@@ -32,7 +32,7 @@ import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.ObjectColor;
-import mage.abilities.Modes;
+import mage.abilities.Mode;
import mage.abilities.SpellAbility;
import mage.abilities.costs.mana.ManaCosts;
import mage.cards.Card;
@@ -311,19 +311,16 @@ public class CardView extends SimpleCardView {
this.mageObjectType = MageObjectType.SPELL;
Spell spell = (Spell) card;
for (SpellAbility spellAbility : spell.getSpellAbilities()) {
- for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
- spellAbility.getModes().setActiveMode(modeId);
- if (spellAbility.getTargets().size() > 0) {
+ for (Mode mode : spellAbility.getModes().getSelectedModes()) {
+ if (mode.getTargets().size() > 0) {
setTargets(spellAbility.getTargets());
}
}
}
// show for modal spell, which mode was choosen
if (spell.getSpellAbility().isModal()) {
- Modes modes = spell.getSpellAbility().getModes();
- for (UUID modeId : modes.getSelectedModes()) {
- modes.setActiveMode(modeId);
- this.rules.add("Chosen mode: " + spell.getSpellAbility().getEffects().getText(modes.get(modeId)) + "");
+ for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
+ this.rules.add("Chosen mode: " + mode.getEffects().getText(mode) + "");
}
}
}
diff --git a/Mage.Common/src/mage/view/StackAbilityView.java b/Mage.Common/src/mage/view/StackAbilityView.java
index 6fb4d3c486..815c0ec13d 100644
--- a/Mage.Common/src/mage/view/StackAbilityView.java
+++ b/Mage.Common/src/mage/view/StackAbilityView.java
@@ -31,6 +31,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
+import mage.abilities.Mode;
import mage.abilities.Modes;
import mage.abilities.effects.Effect;
import mage.cards.Card;
@@ -98,13 +99,12 @@ public class StackAbilityView extends CardView {
private void updateTargets(Game game, StackAbility ability) {
List names = new ArrayList<>();
- for (UUID modeId : ability.getModes().getSelectedModes()) {
- ability.getModes().setActiveMode(modeId);
- if (ability.getTargets().size() > 0) {
- setTargets(ability.getTargets());
+ for (Mode mode : ability.getModes().getSelectedModes()) {
+ if (mode.getTargets().size() > 0) {
+ setTargets(mode.getTargets());
} else {
List targetList = new ArrayList<>();
- for (Effect effect : ability.getEffects()) {
+ for (Effect effect : mode.getEffects()) {
TargetPointer targetPointer = effect.getTargetPointer();
if (targetPointer instanceof FixedTarget) {
targetList.add(((FixedTarget) targetPointer).getTarget());
@@ -132,9 +132,8 @@ public class StackAbilityView extends CardView {
// show for modal ability, which mode was choosen
if (ability.isModal()) {
Modes modes = ability.getModes();
- for (UUID modeId : modes.getSelectedModes()) {
- modes.setActiveMode(modeId);
- this.rules.add("Chosen mode: " + ability.getEffects().getText(modes.get(modeId)) + "");
+ for (Mode mode : modes.getSelectedModes()) {
+ this.rules.add("Chosen mode: " + mode.getEffects().getText(mode) + "");
}
}
}
diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java
index d967799a0d..4fff0604db 100644
--- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java
+++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java
@@ -1568,9 +1568,14 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return modes.getMode();
}
//TODO: improve this;
+ AvailableMode:
for (Mode mode : modes.getAvailableModes(source, game)) {
- if (!modes.getSelectedModes().contains(mode.getId()) // select only modes not already selected
- && mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and where targets are available
+ for (Mode selectedMode : modes.getSelectedModes()) {
+ if (selectedMode.getId().equals(mode.getId())) {
+ continue AvailableMode;
+ }
+ }
+ if (mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and where targets are available
return mode;
}
}
diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java
index dd3830375a..a9c4cb6c6b 100644
--- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java
+++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java
@@ -64,7 +64,16 @@ import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.PlayerAction;
+import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_NO;
+import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_YES;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
+import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_TEXT_NO;
+import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_TEXT_YES;
+import static mage.constants.PlayerAction.RESET_AUTO_SELECT_REPLACEMENT_EFFECTS;
+import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_ABILITY_FIRST;
+import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_ABILITY_LAST;
+import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_NAME_FIRST;
+import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_NAME_LAST;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
@@ -1284,20 +1293,24 @@ public class HumanPlayer extends PlayerImpl {
if (modes.size() > 1) {
MageObject obj = game.getObject(source.getSourceId());
Map modeMap = new LinkedHashMap<>();
+ AvailableModes:
for (Mode mode : modes.getAvailableModes(source, game)) {
- if ((!modes.getSelectedModes().contains(mode.getId()) || modes.isEachModeMoreThanOnce())// show only modes not already selected if more than once is not allowed
- && mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and needed targets have to be available
+ int timesSelected = 0;
+ for (Mode selectedMode : modes.getSelectedModes()) {
+ if (mode.getId().equals(selectedMode.getId())) {
+ if (modes.isEachModeMoreThanOnce()) {
+ timesSelected++;
+ } else {
+ continue AvailableModes;
+ }
+ }
+ }
+ if (mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and needed targets have to be available
String modeText = mode.getEffects().getText(mode);
if (obj != null) {
modeText = modeText.replace("{source}", obj.getName()).replace("{this}", obj.getName());
}
if (modes.isEachModeMoreThanOnce()) {
- int timesSelected = 0;
- for (UUID selectedModeId : modes.getSelectedModes()) {
- if (mode.getId().equals(selectedModeId)) {
- timesSelected++;
- }
- }
if (timesSelected > 0) {
modeText = "(selected " + timesSelected + "x) " + modeText;
}
@@ -1327,6 +1340,7 @@ public class HumanPlayer extends PlayerImpl {
}
return null;
}
+
return modes.getMode();
}
diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/ZadaHedronGrinder.java b/Mage.Sets/src/mage/sets/battleforzendikar/ZadaHedronGrinder.java
index e34ac40666..48c1a77a9a 100644
--- a/Mage.Sets/src/mage/sets/battleforzendikar/ZadaHedronGrinder.java
+++ b/Mage.Sets/src/mage/sets/battleforzendikar/ZadaHedronGrinder.java
@@ -30,6 +30,7 @@ package mage.sets.battleforzendikar;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
+import mage.abilities.Mode;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
@@ -102,9 +103,8 @@ class ZadaHedronGrinderTriggeredAbility extends TriggeredAbilityImpl {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (isControlledInstantOrSorcery(spell)) {
boolean targetsSource = false;
- for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
- spell.getSpellAbility().getModes().setActiveMode(modeId);
- for (Target target : spell.getSpellAbility().getTargets()) {
+ for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
+ for (Target target : mode.getTargets()) {
for (UUID targetId : target.getTargets()) {
if (targetId.equals(getSourceId())) {
targetsSource = true;
@@ -161,9 +161,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
if (spell != null && controller != null) {
Target usedTarget = null;
setUsedTarget:
- for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
- spell.getSpellAbility().getModes().setActiveMode(modeId);
- for (Target target : spell.getSpellAbility().getTargets()) {
+ for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
+ for (Target target : mode.getTargets()) {
if (target.getFirstTarget().equals(source.getSourceId())) {
usedTarget = target.copy();
usedTarget.clearChosen();
@@ -178,9 +177,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
if (!creature.getId().equals(source.getSourceId()) && usedTarget.canTarget(source.getControllerId(), creature.getId(), source, game)) {
Spell copy = spell.copySpell();
setTarget:
- for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
- copy.getSpellAbility().getModes().setActiveMode(modeId);
- for (Target target : copy.getSpellAbility().getTargets()) {
+ for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
+ for (Target target : mode.getTargets()) {
if (target.getClass().equals(usedTarget.getClass()) && target.getMessage().equals(usedTarget.getMessage())) {
target.clearChosen();
target.add(creature.getId(), game);
diff --git a/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java b/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java
index 85fb229bf7..d5bd22552a 100644
--- a/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java
+++ b/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java
@@ -74,9 +74,9 @@ public class MogisGodOfSlaughter extends CardImpl {
// As long as your devotion to black and red is less than seven, Mogis isn't a creature.
Effect effect = new LoseCreatureTypeSourceEffect(new DevotionCount(ColoredManaSymbol.B, ColoredManaSymbol.R), 7);
effect.setText("As long as your devotion to black and red is less than seven, Mogis isn't a creature");
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
-
- // At the beginning of each opponent's upkeep, Mogis deals 2 damage to that player unless he or she sacrifices a creature.
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
+
+ // At the beginning of each opponent's upkeep, Mogis deals 2 damage to that player unless he or she sacrifices a creature.
effect = new DoUnlessTargetPaysCost(new DamageTargetEffect(2, false, "that player"), new SacrificeTargetCost(new TargetControlledCreaturePermanent()),
"Sacrifice a creature? (otherwise you get 2 damage)");
effect.setText("Mogis deals 2 damage to that player unless he or she sacrifices a creature");
@@ -95,6 +95,7 @@ public class MogisGodOfSlaughter extends CardImpl {
}
class DoUnlessTargetPaysCost extends OneShotEffect {
+
private final OneShotEffect executingEffect;
private final Cost cost;
private final String userMessage;
@@ -102,6 +103,7 @@ class DoUnlessTargetPaysCost extends OneShotEffect {
public DoUnlessTargetPaysCost(OneShotEffect effect, Cost cost) {
this(effect, cost, null);
}
+
public DoUnlessTargetPaysCost(OneShotEffect effect, Cost cost, String userMessage) {
super(Outcome.Benefit);
this.executingEffect = effect;
@@ -123,7 +125,7 @@ class DoUnlessTargetPaysCost extends OneShotEffect {
if (player != null && mageObject != null) {
String message = userMessage;
if (message == null) {
- message = new StringBuilder(getCostText()).append(" to prevent ").append(executingEffect.getText(source.getModes().getMode())).append("?").toString();
+ message = getCostText() + " to prevent " + executingEffect.getText(source.getModes().getMode()) + "?";
}
message = CardUtil.replaceSourceName(message, mageObject.getLogName());
cost.clearPaid();
@@ -132,8 +134,8 @@ class DoUnlessTargetPaysCost extends OneShotEffect {
}
if (!cost.isPaid()) {
executingEffect.setTargetPointer(this.targetPointer);
- return executingEffect.apply(game, source);
- }
+ return executingEffect.apply(game, source);
+ }
return true;
}
return false;
@@ -153,8 +155,8 @@ class DoUnlessTargetPaysCost extends OneShotEffect {
private String getCostText() {
StringBuilder sb = new StringBuilder();
String costText = cost.getText();
- if (costText != null &&
- !costText.toLowerCase().startsWith("discard")
+ if (costText != null
+ && !costText.toLowerCase().startsWith("discard")
&& !costText.toLowerCase().startsWith("sacrifice")
&& !costText.toLowerCase().startsWith("remove")) {
sb.append("pay ");
diff --git a/Mage.Sets/src/mage/sets/magicorigins/JaceTelepathUnbound.java b/Mage.Sets/src/mage/sets/magicorigins/JaceTelepathUnbound.java
index 7e87bf53d0..3e55cfbfbd 100644
--- a/Mage.Sets/src/mage/sets/magicorigins/JaceTelepathUnbound.java
+++ b/Mage.Sets/src/mage/sets/magicorigins/JaceTelepathUnbound.java
@@ -124,7 +124,7 @@ class JaceTelepathUnboundEffect extends OneShotEffect {
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
if (card != null) {
ContinuousEffect effect = new JaceTelepathUnboundCastFromGraveyardEffect();
- effect.setTargetPointer(new FixedTarget(card.getId()));
+ effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game)));
game.addEffect(effect, source);
effect = new JaceTelepathUnboundReplacementEffect(card.getId());
game.addEffect(effect, source);
diff --git a/Mage.Sets/src/mage/sets/magicorigins/PsychicRebuttal.java b/Mage.Sets/src/mage/sets/magicorigins/PsychicRebuttal.java
index cdc1ecbfb1..84aca36df0 100644
--- a/Mage.Sets/src/mage/sets/magicorigins/PsychicRebuttal.java
+++ b/Mage.Sets/src/mage/sets/magicorigins/PsychicRebuttal.java
@@ -29,6 +29,7 @@ package mage.sets.magicorigins;
import java.util.UUID;
import mage.abilities.Ability;
+import mage.abilities.Mode;
import mage.abilities.condition.common.SpellMasteryCondition;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
@@ -137,9 +138,8 @@ class PsychicRebuttalPredicate implements ObjectPlayerPredicate 2 && groups[2].startsWith("spellOnTopOfStack=")) {
-// String spellOnTopOFStack = groups[2].substring(18);
-// if (game.getStack().size() > 0) {
-// StackObject stackObject = game.getStack().getFirst();
-// if (stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack)) {
-// return true;
-// }
-// }
-// return false;
-// }
-// return true;
-// }
- private boolean addTargets(Ability ability, String[] groups, Game game) {
+ @Override
+ public boolean addTargets(Ability ability, Game game) {
+ if (groupsForTargetHandling == null) {
+ return true;
+ }
boolean result = true;
- for (int i = 1; i < groups.length; i++) {
- String group = groups[i];
+ for (int i = 1; i < groupsForTargetHandling.length; i++) {
+ String group = groupsForTargetHandling[i];
if (group.startsWith("spellOnStack") || group.startsWith("spellOnTopOfStack") || group.startsWith("!spellOnStack") || group.startsWith("target=null") || group.startsWith("manaInPool=")) {
break;
}
@@ -277,29 +270,36 @@ public class TestPlayer implements Player {
int index = 0;
int targetsSet = 0;
for (String targetName : targetList) {
+ Mode selectedMode = null;
if (targetName.startsWith("mode=")) {
int modeNr = Integer.parseInt(targetName.substring(5, 6));
if (modeNr == 0 || modeNr > ability.getModes().size()) {
throw new UnsupportedOperationException("Given mode number (" + modeNr + ") not available for " + ability.toString());
}
- int modeCounter = 1;
- for (Mode mode : ability.getModes().values()) {
- if (modeCounter == modeNr) {
- ability.getModes().setMode(mode);
+ UUID modeId = ability.getModes().getModeId(modeNr);
+
+ for (Mode mode : ability.getModes().getSelectedModes()) {
+ if (mode.getId().equals(modeId)) {
+ selectedMode = mode;
+ ability.getModes().setActiveMode(mode);
index = 0; // reset target index if mode changes
break;
}
- modeCounter++;
}
targetName = targetName.substring(6);
+ } else {
+ selectedMode = ability.getModes().getMode();
}
- if (ability.getTargets().size() == 0) {
+ if (selectedMode == null) {
+ throw new UnsupportedOperationException("Mode not available for " + ability.toString());
+ }
+ if (selectedMode.getTargets().size() == 0) {
throw new AssertionError("Ability has no targets. " + ability.toString());
}
- if (index >= ability.getTargets().size()) {
+ if (index >= selectedMode.getTargets().size()) {
break; // this can happen if targets should be set but can't be used because of hexproof e.g.
}
- Target currentTarget = ability.getTargets().get(index);
+ Target currentTarget = selectedMode.getTargets().get(index);
if (targetName.startsWith("targetPlayer=")) {
target = targetName.substring(targetName.indexOf("targetPlayer=") + 13);
for (Player player : game.getPlayers().values()) {
@@ -362,6 +362,7 @@ public class TestPlayer implements Player {
if (action.getAction().startsWith("activate:")) {
String command = action.getAction();
command = command.substring(command.indexOf("activate:") + 9);
+ groupsForTargetHandling = null;
String[] groups = command.split("\\$");
if (groups.length > 2 && !checkExecuteCondition(groups, game)) {
break;
@@ -371,13 +372,11 @@ public class TestPlayer implements Player {
int bookmark = game.bookmarkState();
Ability newAbility = ability.copy();
if (groups.length > 1 && !groups[1].equals("target=NO_TARGET")) {
- if (!addTargets(newAbility, groups, game)) {
- // targets could not be set -> try next priority
- break;
- }
+ groupsForTargetHandling = groups;
}
if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) {
actions.remove(action);
+ groupsForTargetHandling = null;
return true;
} else {
game.restoreState(bookmark, ability.getRule());
@@ -1913,6 +1912,7 @@ public class TestPlayer implements Player {
@Override
public boolean playMana(Ability ability, ManaCost unpaid, String promptText, Game game) {
+ groupsForTargetHandling = null;
return computerPlayer.playMana(ability, unpaid, promptText, game);
}
diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java
index a595b7478f..4efdb77684 100644
--- a/Mage/src/mage/abilities/AbilityImpl.java
+++ b/Mage/src/mage/abilities/AbilityImpl.java
@@ -155,7 +155,7 @@ public abstract class AbilityImpl implements Ability {
subAbilities.add(subAbility.copy());
}
}
- this.modes = ability.modes.copy();
+ this.modes = ability.getModes().copy();
this.ruleAtTheTop = ability.ruleAtTheTop;
this.ruleVisible = ability.ruleVisible;
this.ruleAdditionalCostsVisible = ability.ruleAdditionalCostsVisible;
@@ -196,6 +196,7 @@ public abstract class AbilityImpl implements Ability {
boolean result = true;
//20100716 - 117.12
if (checkIfClause(game)) {
+
for (Effect effect : getEffects()) {
if (effect instanceof OneShotEffect) {
boolean effectResult = effect.apply(game, this);
@@ -255,9 +256,14 @@ public abstract class AbilityImpl implements Ability {
/* 20130201 - 601.2b
* If the spell is modal the player announces the mode choice (see rule 700.2).
*/
- if (!modes.choose(game, this)) {
+ if (!getModes().choose(game, this)) {
return false;
}
+ if (controller.isTestMode()) {
+ if (!controller.addTargets(this, game)) {
+ return false;
+ }
+ }
getSourceObject(game);
@@ -274,9 +280,8 @@ public abstract class AbilityImpl implements Ability {
}
// TODO: Because all (non targeted) choices have to be done during resolution
// this has to be removed, if all using effects are changed
- for (UUID modeId : this.getModes().getSelectedModes()) {
- this.getModes().setActiveMode(modeId);
- if (getChoices().size() > 0 && getChoices().choose(game, this) == false) {
+ for (Mode mode : this.getModes().getSelectedModes()) {
+ if (mode.getChoices().size() > 0 && mode.getChoices().choose(game, this) == false) {
logger.debug("activate failed - choice");
return false;
}
@@ -313,8 +318,8 @@ public abstract class AbilityImpl implements Ability {
VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller);
String announceString = handleOtherXCosts(game, controller);
- for (UUID modeId : this.getModes().getSelectedModes()) {
- this.getModes().setActiveMode(modeId);
+ for (Mode mode : this.getModes().getSelectedModes()) {
+ this.getModes().setActiveMode(mode);
//20121001 - 601.2c
// 601.2c The player announces his or her choice of an appropriate player, object, or zone for
// each target the spell requires. A spell may require some targets only if an alternative or
@@ -335,7 +340,7 @@ public abstract class AbilityImpl implements Ability {
if (sourceObject != null && !this.getAbilityType().equals(AbilityType.TRIGGERED)) { // triggered abilities check this already in playerImpl.triggerAbility
sourceObject.adjustTargets(this, game);
}
- if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, noMana, game) == false) {
+ if (mode.getTargets().size() > 0 && mode.getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, noMana, game) == false) {
if ((variableManaCost != null || announceString != null) && !game.isSimulation()) {
game.informPlayer(controller, (sourceObject != null ? sourceObject.getIdName() : "") + ": no valid targets with this value of X");
}
@@ -408,7 +413,7 @@ public abstract class AbilityImpl implements Ability {
}
if (variableManaCost != null) {
int xValue = getManaCostsToPay().getX();
- game.informPlayers(new StringBuilder(controller.getLogName()).append(" announces a value of ").append(xValue).append(" for ").append(variableManaCost.getText()).toString());
+ game.informPlayers(controller.getLogName() + " announces a value of " + xValue + " for " + variableManaCost.getText());
}
}
activated = true;
@@ -681,7 +686,7 @@ public abstract class AbilityImpl implements Ability {
@Override
public Effects getEffects() {
- return modes.getMode().getEffects();
+ return getModes().getMode().getEffects();
}
@Override
@@ -706,7 +711,7 @@ public abstract class AbilityImpl implements Ability {
@Override
public Choices getChoices() {
- return modes.getMode().getChoices();
+ return getModes().getMode().getChoices();
}
@Override
@@ -781,7 +786,7 @@ public abstract class AbilityImpl implements Ability {
}
String ruleStart = sbRule.toString();
- String text = modes.getText();
+ String text = getModes().getText();
String rule;
if (!text.isEmpty()) {
if (ruleStart.length() > 1) {
@@ -873,7 +878,7 @@ public abstract class AbilityImpl implements Ability {
@Override
public Targets getTargets() {
- return modes.getMode().getTargets();
+ return getModes().getMode().getTargets();
}
@Override
@@ -883,12 +888,12 @@ public abstract class AbilityImpl implements Ability {
@Override
public boolean isModal() {
- return this.modes.size() > 1;
+ return getModes().size() > 1;
}
@Override
public void addMode(Mode mode) {
- this.modes.addMode(mode);
+ getModes().addMode(mode);
}
@Override
@@ -899,10 +904,10 @@ public abstract class AbilityImpl implements Ability {
@Override
public boolean canChooseTarget(Game game) {
int found = 0;
- for (Mode mode : modes.values()) {
+ for (Mode mode : getModes().values()) {
if (mode.getTargets().canChoose(sourceId, controllerId, game)) {
found++;
- if (modes.isEachModeMoreThanOnce()) {
+ if (getModes().isEachModeMoreThanOnce()) {
return true;
}
if (found >= getModes().getMinModes()) {
@@ -1037,7 +1042,7 @@ public abstract class AbilityImpl implements Ability {
logger.warn("Could get no object: " + this.toString());
}
return new StringBuilder(" activates: ")
- .append(object != null ? this.formatRule(modes.getText(), object.getLogName()) : modes.getText())
+ .append(object != null ? this.formatRule(getModes().getText(), object.getLogName()) : getModes().getText())
.append(" from ")
.append(getMessageText(game)).toString();
}
@@ -1106,14 +1111,13 @@ public abstract class AbilityImpl implements Ability {
}
} else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) {
Modes spellModes = ((Spell) object).getSpellAbility().getModes();
- for (UUID modeId : spellModes.getSelectedModes()) {
+ for (Mode selectedMode : spellModes.getSelectedModes()) {
int item = 0;
for (Mode mode : spellModes.values()) {
item++;
- if (mode.getId().equals(modeId)) {
- spellModes.setActiveMode(mode.getId());
+ if (mode.getId().equals(selectedMode.getId())) {
sb.append(" (mode ").append(item).append(")");
- sb.append(getTargetDescriptionForLog(getTargets(), game));
+ sb.append(getTargetDescriptionForLog(selectedMode.getTargets(), game));
break;
}
}
diff --git a/Mage/src/mage/abilities/Modes.java b/Mage/src/mage/abilities/Modes.java
index f17c787cb0..08a317f95c 100644
--- a/Mage/src/mage/abilities/Modes.java
+++ b/Mage/src/mage/abilities/Modes.java
@@ -49,8 +49,8 @@ import mage.util.CardUtil;
*/
public class Modes extends LinkedHashMap {
- private UUID modeId;
- private final ArrayList selectedModes = new ArrayList<>();
+ private Mode mode; // the current mode of the selected modes
+ private final ArrayList selectedModes = new ArrayList<>();
private int minModes;
private int maxModes;
private TargetController modeChooser;
@@ -58,25 +58,40 @@ public class Modes extends LinkedHashMap {
private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists
public Modes() {
- Mode mode = new Mode();
+ this.mode = new Mode();
this.put(mode.getId(), mode);
- this.modeId = mode.getId();
this.minModes = 1;
this.maxModes = 1;
- this.selectedModes.add(modeId);
+ this.selectedModes.add(mode);
this.modeChooser = TargetController.YOU;
this.eachModeOnlyOnce = false;
this.eachModeMoreThanOnce = false;
}
public Modes(final Modes modes) {
- this.modeId = modes.modeId;
for (Map.Entry entry : modes.entrySet()) {
this.put(entry.getKey(), entry.getValue().copy());
}
this.minModes = modes.minModes;
this.maxModes = modes.maxModes;
- this.selectedModes.addAll(modes.selectedModes);
+
+ if (modes.size() == 1) {
+ this.mode = values().iterator().next();
+ this.selectedModes.add(mode);
+ } else {
+ // probably there is still a problem with copying modes with the same mode selected multiple times.
+ for (Mode selectedMode : modes.getSelectedModes()) {
+ Mode copiedMode = selectedMode.copy();
+ this.selectedModes.add(copiedMode);
+ if (modes.getSelectedModes().size() == 1) {
+ this.mode = copiedMode;
+ } else {
+ if (selectedMode.equals(modes.getMode())) {
+ this.mode = copiedMode;
+ }
+ }
+ }
+ }
this.modeChooser = modes.modeChooser;
this.eachModeOnlyOnce = modes.eachModeOnlyOnce;
this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce;
@@ -87,10 +102,21 @@ public class Modes extends LinkedHashMap {
}
public Mode getMode() {
- return get(modeId);
+ return mode;
}
- public ArrayList getSelectedModes() {
+ public UUID getModeId(int index) {
+ int idx = 0;
+ for (Mode currentMode : this.values()) {
+ idx++;
+ if (idx == index) {
+ return currentMode.getId();
+ }
+ }
+ return null;
+ }
+
+ public ArrayList getSelectedModes() {
return selectedModes;
}
@@ -118,16 +144,9 @@ public class Modes extends LinkedHashMap {
return this.modeChooser;
}
- public void setActiveMode(UUID modeId) {
- if (selectedModes.contains(modeId)) {
- this.modeId = modeId;
- }
- }
-
- public void setMode(Mode mode) {
- if (this.containsKey(mode.getId())) {
- this.modeId = mode.getId();
- this.selectedModes.add(mode.getId());
+ public void setActiveMode(Mode mode) {
+ if (selectedModes.contains(mode)) {
+ this.mode = mode;
}
}
@@ -156,7 +175,7 @@ public class Modes extends LinkedHashMap {
for (Mode mode : this.values()) {
if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId()))
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) {
- this.selectedModes.add(mode.getId());
+ this.selectedModes.add(mode.copy());
}
}
if (isEachModeOnlyOnce()) {
@@ -184,6 +203,7 @@ public class Modes extends LinkedHashMap {
Player player = game.getPlayer(playerId);
// player chooses modes manually
+ this.mode = null;
while (this.selectedModes.size() < this.getMaxModes()) {
Mode choice = player.chooseMode(this, source, game);
if (choice == null) {
@@ -192,29 +212,38 @@ public class Modes extends LinkedHashMap {
}
return this.selectedModes.size() >= this.getMinModes();
}
- setMode(choice);
+ this.selectedModes.add(choice.copy());
+ if (mode == null) {
+ mode = choice;
+ }
}
if (isEachModeOnlyOnce()) {
setAlreadySelectedModes(selectedModes, source, game);
}
return true;
}
- this.modeId = this.values().iterator().next().getId();
- this.selectedModes.clear();
- this.selectedModes.add(modeId);
+ if (mode == null) {
+ this.selectedModes.clear();
+ Mode copiedMode = this.values().iterator().next().copy();
+ this.selectedModes.add(copiedMode);
+ this.setActiveMode(copiedMode);
+ }
if (isEachModeOnlyOnce()) {
setAlreadySelectedModes(selectedModes, source, game);
}
return true;
}
- private void setAlreadySelectedModes(ArrayList selectedModes, Ability source, Game game) {
+ private void setAlreadySelectedModes(ArrayList selectedModes, Ability source, Game game) {
String key = getKey(source, game);
Set onceSelectedModes = (Set) game.getState().getValue(key);
if (onceSelectedModes == null) {
onceSelectedModes = new HashSet<>();
}
- onceSelectedModes.addAll(selectedModes);
+ for (Mode mode : selectedModes) {
+ onceSelectedModes.add(mode.getId());
+ }
+
game.getState().setValue(key, onceSelectedModes);
}
diff --git a/Mage/src/mage/abilities/common/EntersBattlefieldTriggeredAbility.java b/Mage/src/mage/abilities/common/EntersBattlefieldTriggeredAbility.java
index ddaf6be2b8..528a8c65c1 100644
--- a/Mage/src/mage/abilities/common/EntersBattlefieldTriggeredAbility.java
+++ b/Mage/src/mage/abilities/common/EntersBattlefieldTriggeredAbility.java
@@ -27,9 +27,9 @@
*/
package mage.abilities.common;
-import mage.constants.Zone;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
+import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
@@ -73,7 +73,7 @@ public class EntersBattlefieldTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
- return event.getTargetId().equals(getSourceId());
+ return event.getTargetId().equals(getSourceId());
}
@Override
@@ -81,7 +81,7 @@ public class EntersBattlefieldTriggeredAbility extends TriggeredAbilityImpl {
if (noRule) {
return super.getRule();
}
- return (rulePrefix != null ? rulePrefix : "") + "When {this} enters the battlefield, "+ super.getRule();
+ return (rulePrefix != null ? rulePrefix : "") + "When {this} enters the battlefield, " + super.getRule();
}
@Override
diff --git a/Mage/src/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java b/Mage/src/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java
index e660cd1967..d332b7ac6c 100644
--- a/Mage/src/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java
+++ b/Mage/src/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java
@@ -8,6 +8,7 @@ package mage.abilities.effects.common;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
+import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
@@ -50,9 +51,8 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe
} else {
return false;
}
- for (UUID modeId : sourceAbility.getModes().getSelectedModes()) {
- sourceAbility.getModes().setActiveMode(modeId);
- targets.addAll(sourceAbility.getTargets());
+ for (Mode mode : sourceAbility.getModes().getSelectedModes()) {
+ targets.addAll(mode.getTargets());
}
boolean twoTimesTarget = false;
diff --git a/Mage/src/mage/abilities/effects/common/ExileTargetForSourceEffect.java b/Mage/src/mage/abilities/effects/common/ExileTargetForSourceEffect.java
index f909d0828e..697c07435a 100644
--- a/Mage/src/mage/abilities/effects/common/ExileTargetForSourceEffect.java
+++ b/Mage/src/mage/abilities/effects/common/ExileTargetForSourceEffect.java
@@ -1,43 +1,39 @@
/*
-* 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.
-*/
-
+ * 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.abilities.effects.common;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.Mode;
-import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
-import mage.constants.AbilityType;
import mage.constants.Outcome;
-import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@@ -49,7 +45,6 @@ import mage.util.CardUtil;
*/
public class ExileTargetForSourceEffect extends OneShotEffect {
-
public ExileTargetForSourceEffect() {
super(Outcome.Exile);
}
@@ -71,11 +66,11 @@ public class ExileTargetForSourceEffect extends OneShotEffect {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
if (permanent != null) {
- return controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true);
+ return controller.moveCardsToExile(permanent, source, game, true, exileId, sourceObject.getIdName());
} else {
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card != null) {
- return controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, game.getState().getZone(card.getId()), true);
+ return controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getIdName());
}
}
}
@@ -84,14 +79,14 @@ public class ExileTargetForSourceEffect extends OneShotEffect {
@Override
public String getText(Mode mode) {
- if(staticText != null && !staticText.isEmpty()) {
+ if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
if (mode.getTargets().isEmpty()) {
- return "Exile it";
+ return "exile it";
} else {
- return "Exile target " + mode.getTargets().get(0).getTargetName();
+ return "exile target " + mode.getTargets().get(0).getTargetName();
}
}
}
diff --git a/Mage/src/mage/abilities/effects/common/ReturnToHandTargetEffect.java b/Mage/src/mage/abilities/effects/common/ReturnToHandTargetEffect.java
index 7e6d25c147..f4af1e29b0 100644
--- a/Mage/src/mage/abilities/effects/common/ReturnToHandTargetEffect.java
+++ b/Mage/src/mage/abilities/effects/common/ReturnToHandTargetEffect.java
@@ -27,10 +27,14 @@
*/
package mage.abilities.effects.common;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.UUID;
+import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
-import mage.cards.CardsImpl;
+import mage.cards.Card;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
@@ -70,7 +74,14 @@ public class ReturnToHandTargetEffect extends OneShotEffect {
if (controller == null) {
return false;
}
- return controller.moveCards(new CardsImpl(targetPointer.getTargets(game, source)), null, Zone.HAND, source, game);
+ Set cards = new LinkedHashSet<>();
+ for (UUID targetId : targetPointer.getTargets(game, source)) {
+ MageObject mageObject = game.getObject(targetId);
+ if (mageObject instanceof Card) {
+ cards.add((Card) mageObject);
+ }
+ }
+ return controller.moveCards(cards, Zone.HAND, source, game);
}
@Override
diff --git a/Mage/src/mage/abilities/keyword/HeroicAbility.java b/Mage/src/mage/abilities/keyword/HeroicAbility.java
index 5b89f5d65b..2df1ea081c 100644
--- a/Mage/src/mage/abilities/keyword/HeroicAbility.java
+++ b/Mage/src/mage/abilities/keyword/HeroicAbility.java
@@ -1,34 +1,34 @@
/*
-* 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.
-*/
-
+ * 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.abilities.keyword;
import java.util.UUID;
+import mage.abilities.Mode;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
@@ -44,7 +44,6 @@ import mage.target.Target;
*
* @author LevelX2
*/
-
public class HeroicAbility extends TriggeredAbilityImpl {
public HeroicAbility(Effect effect) {
@@ -83,19 +82,19 @@ public class HeroicAbility extends TriggeredAbilityImpl {
private boolean checkSpell(Spell spell, Game game) {
if (spell != null) {
SpellAbility sa = spell.getSpellAbility();
- for(UUID modeId :sa.getModes().getSelectedModes()) {
- for (Target target : sa.getModes().get(modeId).getTargets()) {
+ for (Mode mode : sa.getModes().getSelectedModes()) {
+ for (Target target : mode.getTargets()) {
if (!target.isNotTarget() && target.getTargets().contains(this.getSourceId())) {
return true;
}
}
- for (Effect effect : sa.getModes().get(modeId).getEffects()) {
+ for (Effect effect : mode.getEffects()) {
for (UUID targetId : effect.getTargetPointer().getTargets(game, sa)) {
if (targetId.equals(this.getSourceId())) {
return true;
}
}
- }
+ }
}
}
return false;
diff --git a/Mage/src/mage/filter/predicate/mageobject/NumberOfTargetsPredicate.java b/Mage/src/mage/filter/predicate/mageobject/NumberOfTargetsPredicate.java
index 7284bd1943..6d40519920 100644
--- a/Mage/src/mage/filter/predicate/mageobject/NumberOfTargetsPredicate.java
+++ b/Mage/src/mage/filter/predicate/mageobject/NumberOfTargetsPredicate.java
@@ -27,7 +27,6 @@
*/
package mage.filter.predicate.mageobject;
-import java.util.UUID;
import mage.MageObject;
import mage.abilities.Mode;
import mage.filter.predicate.Predicate;
@@ -52,8 +51,7 @@ public class NumberOfTargetsPredicate implements Predicate {
Spell spell = game.getStack().getSpell(input.getId());
if (spell != null) {
int numberOfTargets = 0;
- for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
- Mode mode = spell.getSpellAbility().getModes().get(modeId);
+ for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
for (Target target : mode.getTargets()) {
numberOfTargets += target.getTargets().size();
}
diff --git a/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java
index 5471eae280..aad5bb551b 100644
--- a/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java
+++ b/Mage/src/mage/filter/predicate/other/TargetsPermanentPredicate.java
@@ -53,13 +53,12 @@ public class TargetsPermanentPredicate implements ObjectSourcePlayerPredicate input, Game game) {
StackObject object = game.getStack().getStackObject(input.getObject().getId());
- if(object != null) {
- for(UUID modeId : object.getStackAbility().getModes().getSelectedModes()) {
- Mode mode = object.getStackAbility().getModes().get(modeId);
- for(Target target : mode.getTargets()) {
- for(UUID targetId : target.getTargets()) {
+ if (object != null) {
+ for (Mode mode : object.getStackAbility().getModes().getSelectedModes()) {
+ for (Target target : mode.getTargets()) {
+ for (UUID targetId : target.getTargets()) {
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
- if(permanent != null && targetFilter.match(permanent, input.getSourceId(), input.getPlayerId(), game)) {
+ if (permanent != null && targetFilter.match(permanent, input.getSourceId(), input.getPlayerId(), game)) {
return true;
}
}
diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java
index 68f312ad7a..d2af936c84 100644
--- a/Mage/src/mage/game/GameState.java
+++ b/Mage/src/mage/game/GameState.java
@@ -309,7 +309,7 @@ public class GameState implements Serializable, Copyable {
for (StackObject spell : stack) {
sb.append(spell.getControllerId()).append(spell.getName());
sb.append(spell.getStackAbility().toString());
- for (Mode mode : spell.getStackAbility().getModes().values()) {
+ for (Mode mode : spell.getStackAbility().getModes().getSelectedModes()) {
if (!mode.getTargets().isEmpty()) {
sb.append("targets");
for (Target target : mode.getTargets()) {
@@ -367,7 +367,7 @@ public class GameState implements Serializable, Copyable {
for (StackObject spell : stack) {
sb.append(spell.getControllerId()).append(spell.getName());
sb.append(spell.getStackAbility().toString());
- for (Mode mode : spell.getStackAbility().getModes().values()) {
+ for (Mode mode : spell.getStackAbility().getModes().getSelectedModes()) {
if (!mode.getTargets().isEmpty()) {
sb.append("targets");
for (Target target : mode.getTargets()) {
@@ -709,7 +709,7 @@ public class GameState implements Serializable, Copyable {
public void addAbility(Ability ability, MageObject attachedTo) {
if (ability instanceof StaticAbility) {
- for (Mode mode : ability.getModes().values()) {
+ for (Mode mode : ability.getModes().getSelectedModes()) {
for (Effect effect : mode.getEffects()) {
if (effect instanceof ContinuousEffect) {
addEffect((ContinuousEffect) effect, ability);
@@ -731,7 +731,7 @@ public class GameState implements Serializable, Copyable {
*/
public void addAbility(Ability ability, UUID sourceId, Card attachedTo) {
if (ability instanceof StaticAbility) {
- for (Mode mode : ability.getModes().values()) {
+ for (Mode mode : ability.getModes().getSelectedModes()) {
for (Effect effect : mode.getEffects()) {
if (effect instanceof ContinuousEffect) {
addEffect((ContinuousEffect) effect, sourceId, ability);
diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java
index 79092da68a..d2efaaaf15 100644
--- a/Mage/src/mage/game/stack/Spell.java
+++ b/Mage/src/mage/game/stack/Spell.java
@@ -36,6 +36,7 @@ import mage.Mana;
import mage.ObjectColor;
import mage.abilities.Abilities;
import mage.abilities.Ability;
+import mage.abilities.Mode;
import mage.abilities.SpellAbility;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
@@ -195,9 +196,9 @@ public class Spell extends StackObjImpl implements Card {
if (notTargeted || legalParts) {
for (SpellAbility spellAbility : this.spellAbilities) {
if (spellAbilityHasLegalParts(spellAbility, game)) {
- for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
- spellAbility.getModes().setActiveMode(modeId);
- if (spellAbility.getTargets().stillLegal(spellAbility, game)) {
+ for (Mode mode : spellAbility.getModes().getSelectedModes()) {
+ spellAbility.getModes().setActiveMode(mode);
+ if (mode.getTargets().stillLegal(spellAbility, game)) {
if (!spellAbility.getSpellAbilityType().equals(SpellAbilityType.SPLICE)) {
updateOptionalCosts(index);
}
@@ -268,9 +269,8 @@ public class Spell extends StackObjImpl implements Card {
private boolean hasTargets(SpellAbility spellAbility, Game game) {
if (spellAbility.getModes().getSelectedModes().size() > 1) {
- for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
- spellAbility.getModes().setActiveMode(modeId);
- if (!spellAbility.getTargets().isEmpty()) {
+ for (Mode mode : spellAbility.getModes().getSelectedModes()) {
+ if (!mode.getTargets().isEmpty()) {
return true;
}
@@ -285,11 +285,10 @@ public class Spell extends StackObjImpl implements Card {
if (spellAbility.getModes().getSelectedModes().size() > 1) {
boolean targetedMode = false;
boolean legalTargetedMode = false;
- for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
- spellAbility.getModes().setActiveMode(modeId);
- if (spellAbility.getTargets().size() > 0) {
+ for (Mode mode : spellAbility.getModes().getSelectedModes()) {
+ if (mode.getTargets().size() > 0) {
targetedMode = true;
- if (spellAbility.getTargets().stillLegal(spellAbility, game)) {
+ if (mode.getTargets().stillLegal(spellAbility, game)) {
legalTargetedMode = true;
}
}
diff --git a/Mage/src/mage/game/stack/StackAbility.java b/Mage/src/mage/game/stack/StackAbility.java
index 6b689529d9..7215000ee4 100644
--- a/Mage/src/mage/game/stack/StackAbility.java
+++ b/Mage/src/mage/game/stack/StackAbility.java
@@ -86,14 +86,14 @@ public class StackAbility extends StackObjImpl implements Ability {
public StackAbility(Ability ability, UUID controllerId) {
this.ability = ability;
this.controllerId = controllerId;
- this.name = new StringBuilder("stack ability (").append(ability.getRule()).append(")").toString();
+ this.name = "stack ability (" + ability.getRule() + ")";
}
- public StackAbility(final StackAbility spell) {
- this.ability = spell.ability.copy();
- this.controllerId = spell.controllerId;
- this.name = spell.name;
- this.expansionSetCode = spell.expansionSetCode;
+ public StackAbility(final StackAbility stackAbility) {
+ this.ability = stackAbility.ability.copy();
+ this.controllerId = stackAbility.controllerId;
+ this.name = stackAbility.name;
+ this.expansionSetCode = stackAbility.expansionSetCode;
}
@Override
diff --git a/Mage/src/mage/game/stack/StackObjImpl.java b/Mage/src/mage/game/stack/StackObjImpl.java
index 6cf33e65ea..447b1a00c5 100644
--- a/Mage/src/mage/game/stack/StackObjImpl.java
+++ b/Mage/src/mage/game/stack/StackObjImpl.java
@@ -117,8 +117,8 @@ public abstract class StackObjImpl implements StackObject {
}
for (Ability ability : objectAbilities) {
// Some spells can have more than one mode
- for (UUID modeId : ability.getModes().getSelectedModes()) {
- Mode mode = ability.getModes().get(modeId);
+ for (Mode mode : ability.getModes().getSelectedModes()) {
+ ability.getModes().setActiveMode(mode);
oldTargetDescription.append(ability.getTargetDescription(mode.getTargets(), game));
for (Target target : mode.getTargets()) {
Target newTarget = chooseNewTarget(targetController, ability, mode, target, forceChange, filterNewTarget, game);
diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java
index 7cfa444437..3dae03761b 100644
--- a/Mage/src/mage/players/Player.java
+++ b/Mage/src/mage/players/Player.java
@@ -787,4 +787,13 @@ public interface Player extends MageItem, Copyable {
MatchPlayer getMatchPlayer();
boolean scry(int value, Ability source, Game game);
+
+ /**
+ * Only used for test player for pre-setting targets
+ *
+ * @param ability
+ * @param game
+ * @return
+ */
+ boolean addTargets(Ability ability, Game game);
}
diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java
index 4ad9cd64dd..d736afc3c7 100644
--- a/Mage/src/mage/players/PlayerImpl.java
+++ b/Mage/src/mage/players/PlayerImpl.java
@@ -2706,7 +2706,8 @@ public abstract class PlayerImpl implements Player, Serializable {
for (Mode mode : option.getModes().values()) {
Ability newOption = option.copy();
newOption.getModes().getSelectedModes().clear();
- newOption.getModes().setMode(mode);
+ newOption.getModes().getSelectedModes().add(mode);
+ newOption.getModes().setActiveMode(mode);
if (newOption.getTargets().getUnchosen().size() > 0) {
if (newOption.getManaCosts().getVariableCosts().size() > 0) {
addVariableXOptions(options, newOption, 0, game);
@@ -3448,4 +3449,10 @@ public abstract class PlayerImpl implements Player, Serializable {
return true;
}
+ @Override
+ public boolean addTargets(Ability ability, Game game) {
+ // only used for TestPlayer to preSet Targets
+ return true;
+ }
+
}
diff --git a/Mage/src/mage/util/TargetAddress.java b/Mage/src/mage/util/TargetAddress.java
index 4774fe21e1..e4e89d1832 100644
--- a/Mage/src/mage/util/TargetAddress.java
+++ b/Mage/src/mage/util/TargetAddress.java
@@ -36,11 +36,11 @@ import mage.cards.Card;
import mage.game.stack.Spell;
import mage.target.Target;
-
/**
* @author duncant
*/
public class TargetAddress {
+
protected int spellAbilityIndex;
protected UUID mode;
protected int targetIndex;
@@ -52,8 +52,9 @@ public class TargetAddress {
}
protected static class TargetAddressIterable implements Iterable {
+
protected final Card card;
-
+
public TargetAddressIterable(Card card) {
this.card = card;
}
@@ -64,9 +65,10 @@ public class TargetAddress {
}
protected static class TargetAddressIterator implements Iterator {
+
protected Iterator spellAbilityIterator;
protected Integer lastSpellAbilityIndex = null;
- protected Iterator modeIterator = null;
+ protected Iterator modeIterator = null;
protected Modes modes = null;
protected UUID lastMode = null;
protected Iterator targetIterator = null;
@@ -88,14 +90,14 @@ public class TargetAddress {
public boolean hasNext() {
return lastTargetIndex != null;
}
-
+
public TargetAddress next() {
TargetAddress ret = new TargetAddress(lastSpellAbilityIndex,
- lastMode,
- lastTargetIndex);
+ lastMode,
+ lastTargetIndex);
calcNext();
return ret;
-
+
}
public void remove() {
@@ -118,9 +120,9 @@ public class TargetAddress {
return;
}
}
-
+
if (modeIterator != null && modeIterator.hasNext()) {
- lastMode = modeIterator.next();
+ lastMode = modeIterator.next().getId();
targetIterator = modes.get(lastMode).getTargets().iterator();
} else {
lastMode = null;
@@ -145,7 +147,6 @@ public class TargetAddress {
}
}
-
public static Iterable walk(Card card) {
return new TargetAddressIterable(card);
}
@@ -179,8 +180,8 @@ public class TargetAddress {
public boolean equals(TargetAddress other) {
return spellAbilityIndex == other.spellAbilityIndex
- && mode.equals(other.mode)
- && targetIndex == other.targetIndex;
+ && mode.equals(other.mode)
+ && targetIndex == other.targetIndex;
}
@Override