mirror of
https://github.com/correl/mage.git
synced 2024-11-24 19:19:56 +00:00
Changed ability handling of modal spells to be able to select the same mode multiple times with different targets.
This commit is contained in:
parent
b18cae5100
commit
4711e0cf99
40 changed files with 488 additions and 421 deletions
|
@ -32,7 +32,7 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Modes;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.costs.mana.ManaCosts;
|
import mage.abilities.costs.mana.ManaCosts;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
@ -311,19 +311,16 @@ public class CardView extends SimpleCardView {
|
||||||
this.mageObjectType = MageObjectType.SPELL;
|
this.mageObjectType = MageObjectType.SPELL;
|
||||||
Spell spell = (Spell) card;
|
Spell spell = (Spell) card;
|
||||||
for (SpellAbility spellAbility : spell.getSpellAbilities()) {
|
for (SpellAbility spellAbility : spell.getSpellAbilities()) {
|
||||||
for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
|
for (Mode mode : spellAbility.getModes().getSelectedModes()) {
|
||||||
spellAbility.getModes().setActiveMode(modeId);
|
if (mode.getTargets().size() > 0) {
|
||||||
if (spellAbility.getTargets().size() > 0) {
|
|
||||||
setTargets(spellAbility.getTargets());
|
setTargets(spellAbility.getTargets());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// show for modal spell, which mode was choosen
|
// show for modal spell, which mode was choosen
|
||||||
if (spell.getSpellAbility().isModal()) {
|
if (spell.getSpellAbility().isModal()) {
|
||||||
Modes modes = spell.getSpellAbility().getModes();
|
for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
|
||||||
for (UUID modeId : modes.getSelectedModes()) {
|
this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>");
|
||||||
modes.setActiveMode(modeId);
|
|
||||||
this.rules.add("<span color='green'><i>Chosen mode: " + spell.getSpellAbility().getEffects().getText(modes.get(modeId)) + "</i></span>");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.Modes;
|
import mage.abilities.Modes;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
@ -98,13 +99,12 @@ public class StackAbilityView extends CardView {
|
||||||
|
|
||||||
private void updateTargets(Game game, StackAbility ability) {
|
private void updateTargets(Game game, StackAbility ability) {
|
||||||
List<String> names = new ArrayList<>();
|
List<String> names = new ArrayList<>();
|
||||||
for (UUID modeId : ability.getModes().getSelectedModes()) {
|
for (Mode mode : ability.getModes().getSelectedModes()) {
|
||||||
ability.getModes().setActiveMode(modeId);
|
if (mode.getTargets().size() > 0) {
|
||||||
if (ability.getTargets().size() > 0) {
|
setTargets(mode.getTargets());
|
||||||
setTargets(ability.getTargets());
|
|
||||||
} else {
|
} else {
|
||||||
List<UUID> targetList = new ArrayList<>();
|
List<UUID> targetList = new ArrayList<>();
|
||||||
for (Effect effect : ability.getEffects()) {
|
for (Effect effect : mode.getEffects()) {
|
||||||
TargetPointer targetPointer = effect.getTargetPointer();
|
TargetPointer targetPointer = effect.getTargetPointer();
|
||||||
if (targetPointer instanceof FixedTarget) {
|
if (targetPointer instanceof FixedTarget) {
|
||||||
targetList.add(((FixedTarget) targetPointer).getTarget());
|
targetList.add(((FixedTarget) targetPointer).getTarget());
|
||||||
|
@ -132,9 +132,8 @@ public class StackAbilityView extends CardView {
|
||||||
// show for modal ability, which mode was choosen
|
// show for modal ability, which mode was choosen
|
||||||
if (ability.isModal()) {
|
if (ability.isModal()) {
|
||||||
Modes modes = ability.getModes();
|
Modes modes = ability.getModes();
|
||||||
for (UUID modeId : modes.getSelectedModes()) {
|
for (Mode mode : modes.getSelectedModes()) {
|
||||||
modes.setActiveMode(modeId);
|
this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>");
|
||||||
this.rules.add("<span color='green'><i>Chosen mode: " + ability.getEffects().getText(modes.get(modeId)) + "</i></span>");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1568,9 +1568,14 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
return modes.getMode();
|
return modes.getMode();
|
||||||
}
|
}
|
||||||
//TODO: improve this;
|
//TODO: improve this;
|
||||||
|
AvailableMode:
|
||||||
for (Mode mode : modes.getAvailableModes(source, game)) {
|
for (Mode mode : modes.getAvailableModes(source, game)) {
|
||||||
if (!modes.getSelectedModes().contains(mode.getId()) // select only modes not already selected
|
for (Mode selectedMode : modes.getSelectedModes()) {
|
||||||
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and where targets are available
|
if (selectedMode.getId().equals(mode.getId())) {
|
||||||
|
continue AvailableMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and where targets are available
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,16 @@ import mage.constants.ManaType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.PlayerAction;
|
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_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 static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
|
||||||
import mage.constants.RangeOfInfluence;
|
import mage.constants.RangeOfInfluence;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
@ -1284,20 +1293,24 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
if (modes.size() > 1) {
|
if (modes.size() > 1) {
|
||||||
MageObject obj = game.getObject(source.getSourceId());
|
MageObject obj = game.getObject(source.getSourceId());
|
||||||
Map<UUID, String> modeMap = new LinkedHashMap<>();
|
Map<UUID, String> modeMap = new LinkedHashMap<>();
|
||||||
|
AvailableModes:
|
||||||
for (Mode mode : modes.getAvailableModes(source, game)) {
|
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
|
int timesSelected = 0;
|
||||||
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and needed targets have to be available
|
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);
|
String modeText = mode.getEffects().getText(mode);
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
modeText = modeText.replace("{source}", obj.getName()).replace("{this}", obj.getName());
|
modeText = modeText.replace("{source}", obj.getName()).replace("{this}", obj.getName());
|
||||||
}
|
}
|
||||||
if (modes.isEachModeMoreThanOnce()) {
|
if (modes.isEachModeMoreThanOnce()) {
|
||||||
int timesSelected = 0;
|
|
||||||
for (UUID selectedModeId : modes.getSelectedModes()) {
|
|
||||||
if (mode.getId().equals(selectedModeId)) {
|
|
||||||
timesSelected++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (timesSelected > 0) {
|
if (timesSelected > 0) {
|
||||||
modeText = "(selected " + timesSelected + "x) " + modeText;
|
modeText = "(selected " + timesSelected + "x) " + modeText;
|
||||||
}
|
}
|
||||||
|
@ -1327,6 +1340,7 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return modes.getMode();
|
return modes.getMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ package mage.sets.battleforzendikar;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -102,9 +103,8 @@ class ZadaHedronGrinderTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||||
if (isControlledInstantOrSorcery(spell)) {
|
if (isControlledInstantOrSorcery(spell)) {
|
||||||
boolean targetsSource = false;
|
boolean targetsSource = false;
|
||||||
for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
|
for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
|
||||||
spell.getSpellAbility().getModes().setActiveMode(modeId);
|
for (Target target : mode.getTargets()) {
|
||||||
for (Target target : spell.getSpellAbility().getTargets()) {
|
|
||||||
for (UUID targetId : target.getTargets()) {
|
for (UUID targetId : target.getTargets()) {
|
||||||
if (targetId.equals(getSourceId())) {
|
if (targetId.equals(getSourceId())) {
|
||||||
targetsSource = true;
|
targetsSource = true;
|
||||||
|
@ -161,9 +161,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
|
||||||
if (spell != null && controller != null) {
|
if (spell != null && controller != null) {
|
||||||
Target usedTarget = null;
|
Target usedTarget = null;
|
||||||
setUsedTarget:
|
setUsedTarget:
|
||||||
for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
|
for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
|
||||||
spell.getSpellAbility().getModes().setActiveMode(modeId);
|
for (Target target : mode.getTargets()) {
|
||||||
for (Target target : spell.getSpellAbility().getTargets()) {
|
|
||||||
if (target.getFirstTarget().equals(source.getSourceId())) {
|
if (target.getFirstTarget().equals(source.getSourceId())) {
|
||||||
usedTarget = target.copy();
|
usedTarget = target.copy();
|
||||||
usedTarget.clearChosen();
|
usedTarget.clearChosen();
|
||||||
|
@ -178,9 +177,8 @@ class ZadaHedronGrinderEffect extends OneShotEffect {
|
||||||
if (!creature.getId().equals(source.getSourceId()) && usedTarget.canTarget(source.getControllerId(), creature.getId(), source, game)) {
|
if (!creature.getId().equals(source.getSourceId()) && usedTarget.canTarget(source.getControllerId(), creature.getId(), source, game)) {
|
||||||
Spell copy = spell.copySpell();
|
Spell copy = spell.copySpell();
|
||||||
setTarget:
|
setTarget:
|
||||||
for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
|
for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
|
||||||
copy.getSpellAbility().getModes().setActiveMode(modeId);
|
for (Target target : mode.getTargets()) {
|
||||||
for (Target target : copy.getSpellAbility().getTargets()) {
|
|
||||||
if (target.getClass().equals(usedTarget.getClass()) && target.getMessage().equals(usedTarget.getMessage())) {
|
if (target.getClass().equals(usedTarget.getClass()) && target.getMessage().equals(usedTarget.getMessage())) {
|
||||||
target.clearChosen();
|
target.clearChosen();
|
||||||
target.add(creature.getId(), game);
|
target.add(creature.getId(), game);
|
||||||
|
|
|
@ -95,6 +95,7 @@ public class MogisGodOfSlaughter extends CardImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DoUnlessTargetPaysCost extends OneShotEffect {
|
class DoUnlessTargetPaysCost extends OneShotEffect {
|
||||||
|
|
||||||
private final OneShotEffect executingEffect;
|
private final OneShotEffect executingEffect;
|
||||||
private final Cost cost;
|
private final Cost cost;
|
||||||
private final String userMessage;
|
private final String userMessage;
|
||||||
|
@ -102,6 +103,7 @@ class DoUnlessTargetPaysCost extends OneShotEffect {
|
||||||
public DoUnlessTargetPaysCost(OneShotEffect effect, Cost cost) {
|
public DoUnlessTargetPaysCost(OneShotEffect effect, Cost cost) {
|
||||||
this(effect, cost, null);
|
this(effect, cost, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DoUnlessTargetPaysCost(OneShotEffect effect, Cost cost, String userMessage) {
|
public DoUnlessTargetPaysCost(OneShotEffect effect, Cost cost, String userMessage) {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
this.executingEffect = effect;
|
this.executingEffect = effect;
|
||||||
|
@ -123,7 +125,7 @@ class DoUnlessTargetPaysCost extends OneShotEffect {
|
||||||
if (player != null && mageObject != null) {
|
if (player != null && mageObject != null) {
|
||||||
String message = userMessage;
|
String message = userMessage;
|
||||||
if (message == null) {
|
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());
|
message = CardUtil.replaceSourceName(message, mageObject.getLogName());
|
||||||
cost.clearPaid();
|
cost.clearPaid();
|
||||||
|
@ -153,8 +155,8 @@ class DoUnlessTargetPaysCost extends OneShotEffect {
|
||||||
private String getCostText() {
|
private String getCostText() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
String costText = cost.getText();
|
String costText = cost.getText();
|
||||||
if (costText != null &&
|
if (costText != null
|
||||||
!costText.toLowerCase().startsWith("discard")
|
&& !costText.toLowerCase().startsWith("discard")
|
||||||
&& !costText.toLowerCase().startsWith("sacrifice")
|
&& !costText.toLowerCase().startsWith("sacrifice")
|
||||||
&& !costText.toLowerCase().startsWith("remove")) {
|
&& !costText.toLowerCase().startsWith("remove")) {
|
||||||
sb.append("pay ");
|
sb.append("pay ");
|
||||||
|
|
|
@ -124,7 +124,7 @@ class JaceTelepathUnboundEffect extends OneShotEffect {
|
||||||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
ContinuousEffect effect = new JaceTelepathUnboundCastFromGraveyardEffect();
|
ContinuousEffect effect = new JaceTelepathUnboundCastFromGraveyardEffect();
|
||||||
effect.setTargetPointer(new FixedTarget(card.getId()));
|
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game)));
|
||||||
game.addEffect(effect, source);
|
game.addEffect(effect, source);
|
||||||
effect = new JaceTelepathUnboundReplacementEffect(card.getId());
|
effect = new JaceTelepathUnboundReplacementEffect(card.getId());
|
||||||
game.addEffect(effect, source);
|
game.addEffect(effect, source);
|
||||||
|
|
|
@ -29,6 +29,7 @@ package mage.sets.magicorigins;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.condition.common.SpellMasteryCondition;
|
import mage.abilities.condition.common.SpellMasteryCondition;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -137,9 +138,8 @@ class PsychicRebuttalPredicate implements ObjectPlayerPredicate<ObjectPlayer<Sta
|
||||||
if (controllerId == null) {
|
if (controllerId == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (UUID modeId : input.getObject().getStackAbility().getModes().getSelectedModes()) {
|
for (Mode mode : input.getObject().getStackAbility().getModes().getSelectedModes()) {
|
||||||
input.getObject().getStackAbility().getModes().setActiveMode(modeId);
|
for (Target target : mode.getTargets()) {
|
||||||
for (Target target : input.getObject().getStackAbility().getTargets()) {
|
|
||||||
for (UUID targetId : target.getTargets()) {
|
for (UUID targetId : target.getTargets()) {
|
||||||
if (controllerId.equals(targetId)) {
|
if (controllerId.equals(targetId)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -28,11 +28,12 @@
|
||||||
package mage.sets.shardsofalara;
|
package mage.sets.shardsofalara;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
import mage.abilities.Mode;
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.abilities.effects.common.CounterTargetEffect;
|
import mage.abilities.effects.common.CounterTargetEffect;
|
||||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
import mage.filter.FilterSpell;
|
import mage.filter.FilterSpell;
|
||||||
import mage.filter.predicate.ObjectPlayer;
|
import mage.filter.predicate.ObjectPlayer;
|
||||||
import mage.filter.predicate.ObjectPlayerPredicate;
|
import mage.filter.predicate.ObjectPlayerPredicate;
|
||||||
|
@ -58,7 +59,6 @@ public class HinderingLight extends CardImpl {
|
||||||
super(ownerId, 173, "Hindering Light", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{W}{U}");
|
super(ownerId, 173, "Hindering Light", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{W}{U}");
|
||||||
this.expansionSetCode = "ALA";
|
this.expansionSetCode = "ALA";
|
||||||
|
|
||||||
|
|
||||||
// Counter target spell that targets you or a permanent you control.
|
// Counter target spell that targets you or a permanent you control.
|
||||||
this.getSpellAbility().addEffect(new CounterTargetEffect());
|
this.getSpellAbility().addEffect(new CounterTargetEffect());
|
||||||
this.getSpellAbility().addTarget(new TargetSpell(filter));
|
this.getSpellAbility().addTarget(new TargetSpell(filter));
|
||||||
|
@ -84,9 +84,8 @@ class HinderingLightPredicate implements ObjectPlayerPredicate<ObjectPlayer<Stac
|
||||||
if (controllerId == null) {
|
if (controllerId == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (UUID modeId :input.getObject().getStackAbility().getModes().getSelectedModes()) {
|
for (Mode mode : input.getObject().getStackAbility().getModes().getSelectedModes()) {
|
||||||
input.getObject().getStackAbility().getModes().setActiveMode(modeId);
|
for (Target target : mode.getTargets()) {
|
||||||
for (Target target : input.getObject().getStackAbility().getTargets()) {
|
|
||||||
for (UUID targetId : target.getTargets()) {
|
for (UUID targetId : target.getTargets()) {
|
||||||
if (controllerId.equals(targetId)) {
|
if (controllerId.equals(targetId)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -29,6 +29,7 @@ package mage.sets.vintagemasters;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||||
|
@ -44,14 +45,13 @@ import mage.constants.Rarity;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
import mage.target.Targets;
|
|
||||||
import mage.target.common.TargetCreatureOrPlayer;
|
import mage.target.common.TargetCreatureOrPlayer;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LoneFox
|
* @author LoneFox
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class KaerveksTorch extends CardImpl {
|
public class KaerveksTorch extends CardImpl {
|
||||||
|
|
||||||
|
@ -95,13 +95,11 @@ class KaerveksTorchCostIncreaseEffect extends CostModificationEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||||
if(abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility)
|
if (abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility) {
|
||||||
{
|
for (Mode mode : abilityToModify.getModes().getSelectedModes()) {
|
||||||
for(UUID modeId: abilityToModify.getModes().getSelectedModes()) {
|
for (Target target : mode.getTargets()) {
|
||||||
abilityToModify.getModes().setActiveMode(modeId);
|
for (UUID targetId : target.getTargets()) {
|
||||||
for(Target target: abilityToModify.getTargets()) {
|
if (targetId.equals(source.getSourceObject(game).getId())) {
|
||||||
for(UUID id: target.getTargets()) {
|
|
||||||
if(id.equals(source.getSourceObject(game).getId())) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,19 +25,18 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of maurer.it_at_googlemail.com.
|
* or implied, of maurer.it_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.sets.zendikar;
|
package mage.sets.zendikar;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
|
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.effects.common.ExileTargetForSourceEffect;
|
import mage.abilities.effects.common.ExileTargetForSourceEffect;
|
||||||
import mage.abilities.effects.common.ReturnFromExileForSourceEffect;
|
import mage.abilities.effects.common.ReturnFromExileForSourceEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterCreaturePermanent;
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
import mage.filter.predicate.permanent.AnotherPredicate;
|
import mage.filter.predicate.permanent.AnotherPredicate;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
|
@ -53,7 +52,6 @@ public class JourneyToNowhere extends CardImpl {
|
||||||
super(ownerId, 14, "Journey to Nowhere", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}");
|
super(ownerId, 14, "Journey to Nowhere", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}");
|
||||||
this.expansionSetCode = "ZEN";
|
this.expansionSetCode = "ZEN";
|
||||||
|
|
||||||
|
|
||||||
// When Journey to Nowhere enters the battlefield, exile target creature.
|
// When Journey to Nowhere enters the battlefield, exile target creature.
|
||||||
FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
||||||
filter.add(new AnotherPredicate());
|
filter.add(new AnotherPredicate());
|
||||||
|
|
|
@ -45,11 +45,13 @@ public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
|
||||||
@Test
|
@Test
|
||||||
public void testOrzhovCharm() {
|
public void testOrzhovCharm() {
|
||||||
// Choose one -
|
// Choose one -
|
||||||
// Return target creature you control and all Auras you control attached to it to their owner's hand;
|
// - Return target creature you control and all Auras you control attached to it to their owner's hand;
|
||||||
// or destroy target creature and you lose life equal to its toughness;
|
// - Destroy target creature and you lose life equal to its toughness;
|
||||||
// or return target creature card with converted mana cost 1 or less from your graveyard to the battlefield.
|
// - Return target creature card with converted mana cost 1 or less from your graveyard to the battlefield.
|
||||||
addCard(Zone.HAND, playerA, "Orzhov Charm"); // {W}{B}
|
addCard(Zone.HAND, playerA, "Orzhov Charm"); // {W}{B}
|
||||||
|
|
||||||
|
// {T}: Add {1} to your mana pool.
|
||||||
|
// {T} {W/B}, {T}: Add {W}{W}, {W}{B}, or {B}{B} to your mana pool.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Fetid Heath", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Fetid Heath", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,11 @@ public class ReturnToHandTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
|
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3);
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3);
|
||||||
addCard(Zone.HAND, playerB, "Bone Splinters");
|
|
||||||
|
|
||||||
// As an additional cost to cast Bone Splinters, sacrifice a creature.
|
// As an additional cost to cast Bone Splinters, sacrifice a creature.
|
||||||
// Destroy target creature.
|
// Destroy target creature.
|
||||||
|
addCard(Zone.HAND, playerB, "Bone Splinters");
|
||||||
|
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Bone Splinters", "Pillarfield Ox");
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Bone Splinters", "Pillarfield Ox");
|
||||||
setChoice(playerB, "Skarrgan Firebird");
|
setChoice(playerB, "Skarrgan Firebird");
|
||||||
|
|
||||||
|
@ -126,7 +127,7 @@ public class ReturnToHandTest extends CardTestPlayerBase {
|
||||||
// Devoid
|
// Devoid
|
||||||
// Choose one or both
|
// Choose one or both
|
||||||
// - Return target spell or creature to its owner's hand;
|
// - Return target spell or creature to its owner's hand;
|
||||||
// or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead.
|
// - Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead.
|
||||||
addCard(Zone.HAND, playerA, "Brutal Expulsion"); // {2}{U}{R}
|
addCard(Zone.HAND, playerA, "Brutal Expulsion"); // {2}{U}{R}
|
||||||
|
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Plains", 4);
|
addCard(Zone.BATTLEFIELD, playerB, "Plains", 4);
|
||||||
|
@ -135,6 +136,8 @@ public class ReturnToHandTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Pillarfield Ox");
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Pillarfield Ox");
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Brutal Expulsion", "mode=1Pillarfield Ox^mode=2Silvercoat Lion", "Pillarfield Ox");
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Brutal Expulsion", "mode=1Pillarfield Ox^mode=2Silvercoat Lion", "Pillarfield Ox");
|
||||||
|
setModeChoice(playerA, "1");
|
||||||
|
setModeChoice(playerA, "2");
|
||||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||||
|
|
||||||
execute();
|
execute();
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class DeathtouchTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Marath, Will of the Wild");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Marath, Will of the Wild");
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {2}", "Marath, Will of the Wild");
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {2}", "Marath, Will of the Wild", "Marath, Will of the Wild", StackClause.WHILE_NOT_ON_STACK);
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{X},Remove X +1/+1 counters from Marath", "Archangel of Thune");
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{X},Remove X +1/+1 counters from Marath", "Archangel of Thune");
|
||||||
setChoice(playerA, "X=3");
|
setChoice(playerA, "X=3");
|
||||||
|
|
|
@ -36,15 +36,14 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class HeroicTest extends CardTestPlayerBase {
|
public class HeroicTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When casting Dromoka's Command targeting two of my own Heroic creatures, only one of them triggers.
|
* When casting Dromoka's Command targeting two of my own Heroic creatures,
|
||||||
* It appears to be the one targeted with mode 4 (fight) rather than the one targeted with mode 3 (+1/+1 counter).
|
* only one of them triggers. It appears to be the one targeted with mode 4
|
||||||
|
* (fight) rather than the one targeted with mode 3 (+1/+1 counter).
|
||||||
* Screenshot attached. Reproducible.
|
* Screenshot attached. Reproducible.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeroicWithModal() {
|
public void testHeroicWithModal() {
|
||||||
// Heroic - Whenever you cast a spell that targets Favored Hoplite, put a +1/+1 counter on Favored Hoplite and prevent all damage that would be dealt to it this turn.
|
// Heroic - Whenever you cast a spell that targets Favored Hoplite, put a +1/+1 counter on Favored Hoplite and prevent all damage that would be dealt to it this turn.
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.mage.test.cards.abilities.oneshot.counterspell;
|
package org.mage.test.cards.abilities.oneshot.counterspell;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
|
@ -34,17 +33,17 @@ import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cryptic Command
|
* Cryptic Command Instant, 1UUU Choose two — Counter target spell; or return
|
||||||
* Instant, 1UUU
|
* target permanent to its owner's hand; or tap all creatures your opponents
|
||||||
* Choose two — Counter target spell; or return target permanent to its owner's hand; or tap all creatures your opponents control; or draw a card.
|
* control; or draw a card.
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class CrypticCommandTest extends CardTestPlayerBase {
|
public class CrypticCommandTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that if command has only one target and that targets is not valid on resolution, Cryptic Command fizzeles
|
* Test that if command has only one target and that targets is not valid on
|
||||||
* The player does not draw a card
|
* resolution, Cryptic Command fizzeles The player does not draw a card
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCommand() {
|
public void testCommand() {
|
||||||
|
@ -80,12 +79,14 @@ public class CrypticCommandTest extends CardTestPlayerBase {
|
||||||
assertHandCount(playerB, 0); // Because Cryptic Command has no legal target playerB does not draw a card and has 0 cards in hand
|
assertHandCount(playerB, 0); // Because Cryptic Command has no legal target playerB does not draw a card and has 0 cards in hand
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game is not letting me play Ricochet Trap targetting oponent's Cryptic Command,
|
* Game is not letting me play Ricochet Trap targetting oponent's Cryptic
|
||||||
* modes 1 and 4. It only has one target and should be allowed
|
* Command, modes 1 and 4. It only has one target and should be allowed
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCommandChangeTarget() {
|
public void testCommandChangeTarget() {
|
||||||
|
// Target player reveals his or her hand. You choose a nonland card from it. That player discards that card. You lose 2 life.
|
||||||
addCard(Zone.HAND, playerA, "Thoughtseize");
|
addCard(Zone.HAND, playerA, "Thoughtseize");
|
||||||
// Counter target spell. If that spell is countered this way, put it into its owner's hand instead of into that player's graveyard.
|
// Counter target spell. If that spell is countered this way, put it into its owner's hand instead of into that player's graveyard.
|
||||||
// Draw a card.
|
// Draw a card.
|
||||||
|
@ -99,11 +100,11 @@ public class CrypticCommandTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thoughtseize", playerB);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thoughtseize", playerB);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cryptic Command", "Thoughtseize");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cryptic Command", "mode=1Thoughtseize", "Thoughtseize", StackClause.WHILE_ON_STACK);
|
||||||
setModeChoice(playerB, "1"); // Counter target spell
|
setModeChoice(playerB, "1"); // Counter target spell
|
||||||
setModeChoice(playerB, "4"); // Draw a card
|
setModeChoice(playerB, "4"); // Draw a card
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ricochet Trap", "Cryptic Command");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ricochet Trap", "Cryptic Command", "Cryptic Command", StackClause.WHILE_ON_STACK);
|
||||||
addTarget(playerA, "Lightning Bolt");
|
addTarget(playerA, "Lightning Bolt");
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.CLEANUP);
|
setStopAt(1, PhaseStep.CLEANUP);
|
||||||
|
|
|
@ -63,6 +63,7 @@ public class NotOfThisWorldTest extends CardTestPlayerBase {
|
||||||
setStopAt(2, PhaseStep.PRECOMBAT_MAIN);
|
setStopAt(2, PhaseStep.PRECOMBAT_MAIN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
|
assertHandCount(playerB, "Not of This World", 0);
|
||||||
assertGraveyardCount(playerB, "Not of This World", 1);
|
assertGraveyardCount(playerB, "Not of This World", 1);
|
||||||
assertPermanentCount(playerB, "Ruhan of the Fomori", 1);
|
assertPermanentCount(playerB, "Ruhan of the Fomori", 1);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ public class GainControlTargetEffectTest extends CardTestPlayerBase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testPermanentControlEffect() {
|
public void testPermanentControlEffect() {
|
||||||
|
// When Smelt-Ward Gatekeepers enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. That creature gains haste until end of turn.
|
||||||
addCard(Zone.HAND, playerA, "Smelt-Ward Gatekeepers", 1);
|
addCard(Zone.HAND, playerA, "Smelt-Ward Gatekeepers", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Boros Guildgate", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Boros Guildgate", 2);
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class AbattoirGhoulTest extends CardTestPlayerBase{
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAbattoirGhoulEffect() {
|
public void testAbattoirGhoulEffect() {
|
||||||
|
// Whenever a creature dealt damage by Abattoir Ghoul this turn dies, you gain life equal to that creature's toughness.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Abattoir Ghoul", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Abattoir Ghoul", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1);
|
addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Shivan Dragon", 1);
|
addCard(Zone.BATTLEFIELD, playerB, "Shivan Dragon", 1);
|
||||||
|
|
|
@ -36,7 +36,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
*
|
*
|
||||||
* @author LeveX2
|
* @author LeveX2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class JourneyToNowhereTest extends CardTestPlayerBase {
|
public class JourneyToNowhereTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -47,7 +46,6 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
||||||
10/1/2009: If Journey to Nowhere leaves the battlefield before its first ability has resolved, its second ability will
|
10/1/2009: If Journey to Nowhere leaves the battlefield before its first ability has resolved, its second ability will
|
||||||
trigger and do nothing. Then its first ability will resolve and exile the targeted creature forever.
|
trigger and do nothing. Then its first ability will resolve and exile the targeted creature forever.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTargetGetsExiled() {
|
public void testTargetGetsExiled() {
|
||||||
addCard(Zone.HAND, playerA, "Journey to Nowhere");
|
addCard(Zone.HAND, playerA, "Journey to Nowhere");
|
||||||
|
@ -64,7 +62,6 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
||||||
assertExileCount("Silvercoat Lion", 1);
|
assertExileCount("Silvercoat Lion", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTargetGetsExiledAndReturns() {
|
public void testTargetGetsExiledAndReturns() {
|
||||||
addCard(Zone.HAND, playerA, "Journey to Nowhere");
|
addCard(Zone.HAND, playerA, "Journey to Nowhere");
|
||||||
|
@ -133,7 +130,7 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere");
|
||||||
addTarget(playerA, "Silvercoat Lion");
|
addTarget(playerA, "Silvercoat Lion");
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Journey to Nowhere");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Journey to Nowhere", "Journey to Nowhere", StackClause.WHILE_NOT_ON_STACK);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Journey to Nowhere");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Journey to Nowhere");
|
||||||
addTarget(playerA, "Pillarfield Ox");
|
addTarget(playerA, "Pillarfield Ox");
|
||||||
|
|
|
@ -94,12 +94,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Stormfront Riders", 1);
|
assertPermanentCount(playerA, "Stormfront Riders", 1);
|
||||||
assertPermanentCount(playerA, "Rat", 0);
|
|
||||||
assertHandCount(playerA, "Silvercoat Lion", 2);
|
assertHandCount(playerA, "Silvercoat Lion", 2);
|
||||||
assertGraveyardCount(playerA, "Lab Rats", 1);
|
assertGraveyardCount(playerA, "Lab Rats", 1);
|
||||||
assertGraveyardCount(playerB, "Boomerang", 1);
|
assertGraveyardCount(playerB, "Boomerang", 1);
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Soldier", 3);
|
assertPermanentCount(playerA, "Soldier", 3);
|
||||||
|
assertPermanentCount(playerA, "Rat", 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,10 +123,10 @@ public class SpellskiteTest extends CardTestPlayerBase {
|
||||||
public void testSpellskite() {
|
public void testSpellskite() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||||
// Choose two -
|
// Choose two -
|
||||||
// Counter target spell;
|
// - Counter target spell;
|
||||||
// or return target permanent to its owner's hand;
|
// - return target permanent to its owner's hand;
|
||||||
// or tap all creatures your opponents control;
|
// - tap all creatures your opponents control;
|
||||||
// or draw a card.
|
// - draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Cryptic Command");
|
addCard(Zone.HAND, playerA, "Cryptic Command");
|
||||||
|
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1);
|
addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1);
|
||||||
|
@ -141,7 +141,7 @@ public class SpellskiteTest extends CardTestPlayerBase {
|
||||||
setModeChoice(playerA, "1"); // Counter target spell
|
setModeChoice(playerA, "1"); // Counter target spell
|
||||||
setModeChoice(playerA, "2"); // return target permanent to its owner's hand
|
setModeChoice(playerA, "2"); // return target permanent to its owner's hand
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Cryptic Command");
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Cryptic Command", "Cryptic Command");
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
execute();
|
execute();
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.mage.test.lki;
|
package org.mage.test.lki;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
|
@ -21,9 +20,9 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
||||||
* see here for more information
|
* see here for more information
|
||||||
* http://www.slightlymagic.net/forum/viewtopic.php?f=116&t=14516
|
* http://www.slightlymagic.net/forum/viewtopic.php?f=116&t=14516
|
||||||
*
|
*
|
||||||
* Tests Safehold Elite with persist returns to battlefield with -1/-1 counter
|
* Tests Safehold Elite with persist returns to battlefield with -1/-1
|
||||||
* Murder Investigation has to put 2 tokens onto battlefield because enchanted Safehold Elite
|
* counter Murder Investigation has to put 2 tokens onto battlefield because
|
||||||
* was 2/2
|
* enchanted Safehold Elite was 2/2
|
||||||
*
|
*
|
||||||
* @author LevelX
|
* @author LevelX
|
||||||
*/
|
*/
|
||||||
|
@ -64,11 +63,14 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Here we test that Trostani's first ability checks the toughness on resolve.
|
* Here we test that Trostani's first ability checks the toughness on
|
||||||
|
* resolve.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testTrostaniSelesnyasVoice1() {
|
public void testTrostaniSelesnyasVoice1() {
|
||||||
|
// Whenever another creature enters the battlefield under your control, you gain life equal to that creature's toughness.
|
||||||
|
// {1}{G}{W}, {T}: Populate. (Put a token onto the battlefield that's a copy of a creature token you control.)
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Trostani, Selesnya's Voice");
|
addCard(Zone.BATTLEFIELD, playerA, "Trostani, Selesnya's Voice");
|
||||||
|
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||||
|
@ -76,20 +78,21 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears", "Grizzly Bears", StackClause.WHILE_NOT_ON_STACK);
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, "Giant Growth", 1);
|
||||||
assertPermanentCount(playerA, "Grizzly Bears", 1);
|
assertPermanentCount(playerA, "Grizzly Bears", 1);
|
||||||
assertLife(playerA, 25);
|
assertLife(playerA, 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Here we test correct spell interaction by playing Cloudshift BEFORE Giant Growth resolves.
|
* Here we test correct spell interaction by playing Cloudshift BEFORE Giant
|
||||||
* Cloudshift will remove 2/2 creature and it will return as 2/2.
|
* Growth resolves. Cloudshift will remove 2/2 creature and it will return
|
||||||
* Giant Growth will be fizzled.
|
* as 2/2. Giant Growth will be fizzled. That means that player should gain
|
||||||
* That means that player should gain 2 + 2 life.
|
* 2 + 2 life.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testTrostaniSelesnyasVoice2() {
|
public void testTrostaniSelesnyasVoice2() {
|
||||||
|
@ -102,7 +105,7 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears", "Grizzly Bears", StackClause.WHILE_NOT_ON_STACK);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloudshift", "Grizzly Bears", "Giant Growth",
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloudshift", "Grizzly Bears", "Giant Growth",
|
||||||
StackClause.WHILE_ON_STACK);
|
StackClause.WHILE_ON_STACK);
|
||||||
|
|
||||||
|
@ -114,8 +117,8 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Here we test actual use of LKI by playing Cloudshift AFTER Giant Growth resolves.
|
* Here we test actual use of LKI by playing Cloudshift AFTER Giant Growth
|
||||||
* Cloudshift will remove 5/5 creature and it will return as 2/2.
|
* resolves. Cloudshift will remove 5/5 creature and it will return as 2/2.
|
||||||
* That means that player should gain 5 + 2 life.
|
* That means that player should gain 5 + 2 life.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -130,7 +133,7 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears", "Grizzly Bears", StackClause.WHILE_NOT_ON_STACK);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloudshift", "Grizzly Bears", "Giant Growth",
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloudshift", "Grizzly Bears", "Giant Growth",
|
||||||
StackClause.WHILE_NOT_ON_STACK);
|
StackClause.WHILE_NOT_ON_STACK);
|
||||||
|
|
||||||
|
@ -142,5 +145,4 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,8 @@ public class TestPlayer implements Player {
|
||||||
|
|
||||||
private final ComputerPlayer computerPlayer;
|
private final ComputerPlayer computerPlayer;
|
||||||
|
|
||||||
|
private String[] groupsForTargetHandling = null;
|
||||||
|
|
||||||
public TestPlayer(ComputerPlayer computerPlayer) {
|
public TestPlayer(ComputerPlayer computerPlayer) {
|
||||||
this.computerPlayer = computerPlayer;
|
this.computerPlayer = computerPlayer;
|
||||||
AIPlayer = false;
|
AIPlayer = false;
|
||||||
|
@ -204,23 +206,14 @@ public class TestPlayer implements Player {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private boolean checkSpellOnTopOfStackCondition(String[] groups, Game game) {
|
@Override
|
||||||
// if (groups.length > 2 && groups[2].startsWith("spellOnTopOfStack=")) {
|
public boolean addTargets(Ability ability, Game game) {
|
||||||
// String spellOnTopOFStack = groups[2].substring(18);
|
if (groupsForTargetHandling == null) {
|
||||||
// if (game.getStack().size() > 0) {
|
return true;
|
||||||
// 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) {
|
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
for (int i = 1; i < groups.length; i++) {
|
for (int i = 1; i < groupsForTargetHandling.length; i++) {
|
||||||
String group = groups[i];
|
String group = groupsForTargetHandling[i];
|
||||||
if (group.startsWith("spellOnStack") || group.startsWith("spellOnTopOfStack") || group.startsWith("!spellOnStack") || group.startsWith("target=null") || group.startsWith("manaInPool=")) {
|
if (group.startsWith("spellOnStack") || group.startsWith("spellOnTopOfStack") || group.startsWith("!spellOnStack") || group.startsWith("target=null") || group.startsWith("manaInPool=")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -277,29 +270,36 @@ public class TestPlayer implements Player {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int targetsSet = 0;
|
int targetsSet = 0;
|
||||||
for (String targetName : targetList) {
|
for (String targetName : targetList) {
|
||||||
|
Mode selectedMode = null;
|
||||||
if (targetName.startsWith("mode=")) {
|
if (targetName.startsWith("mode=")) {
|
||||||
int modeNr = Integer.parseInt(targetName.substring(5, 6));
|
int modeNr = Integer.parseInt(targetName.substring(5, 6));
|
||||||
if (modeNr == 0 || modeNr > ability.getModes().size()) {
|
if (modeNr == 0 || modeNr > ability.getModes().size()) {
|
||||||
throw new UnsupportedOperationException("Given mode number (" + modeNr + ") not available for " + ability.toString());
|
throw new UnsupportedOperationException("Given mode number (" + modeNr + ") not available for " + ability.toString());
|
||||||
}
|
}
|
||||||
int modeCounter = 1;
|
UUID modeId = ability.getModes().getModeId(modeNr);
|
||||||
for (Mode mode : ability.getModes().values()) {
|
|
||||||
if (modeCounter == modeNr) {
|
for (Mode mode : ability.getModes().getSelectedModes()) {
|
||||||
ability.getModes().setMode(mode);
|
if (mode.getId().equals(modeId)) {
|
||||||
|
selectedMode = mode;
|
||||||
|
ability.getModes().setActiveMode(mode);
|
||||||
index = 0; // reset target index if mode changes
|
index = 0; // reset target index if mode changes
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
modeCounter++;
|
|
||||||
}
|
}
|
||||||
targetName = targetName.substring(6);
|
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());
|
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.
|
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=")) {
|
if (targetName.startsWith("targetPlayer=")) {
|
||||||
target = targetName.substring(targetName.indexOf("targetPlayer=") + 13);
|
target = targetName.substring(targetName.indexOf("targetPlayer=") + 13);
|
||||||
for (Player player : game.getPlayers().values()) {
|
for (Player player : game.getPlayers().values()) {
|
||||||
|
@ -362,6 +362,7 @@ public class TestPlayer implements Player {
|
||||||
if (action.getAction().startsWith("activate:")) {
|
if (action.getAction().startsWith("activate:")) {
|
||||||
String command = action.getAction();
|
String command = action.getAction();
|
||||||
command = command.substring(command.indexOf("activate:") + 9);
|
command = command.substring(command.indexOf("activate:") + 9);
|
||||||
|
groupsForTargetHandling = null;
|
||||||
String[] groups = command.split("\\$");
|
String[] groups = command.split("\\$");
|
||||||
if (groups.length > 2 && !checkExecuteCondition(groups, game)) {
|
if (groups.length > 2 && !checkExecuteCondition(groups, game)) {
|
||||||
break;
|
break;
|
||||||
|
@ -371,13 +372,11 @@ public class TestPlayer implements Player {
|
||||||
int bookmark = game.bookmarkState();
|
int bookmark = game.bookmarkState();
|
||||||
Ability newAbility = ability.copy();
|
Ability newAbility = ability.copy();
|
||||||
if (groups.length > 1 && !groups[1].equals("target=NO_TARGET")) {
|
if (groups.length > 1 && !groups[1].equals("target=NO_TARGET")) {
|
||||||
if (!addTargets(newAbility, groups, game)) {
|
groupsForTargetHandling = groups;
|
||||||
// targets could not be set -> try next priority
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) {
|
if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) {
|
||||||
actions.remove(action);
|
actions.remove(action);
|
||||||
|
groupsForTargetHandling = null;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
game.restoreState(bookmark, ability.getRule());
|
game.restoreState(bookmark, ability.getRule());
|
||||||
|
@ -1913,6 +1912,7 @@ public class TestPlayer implements Player {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playMana(Ability ability, ManaCost unpaid, String promptText, Game game) {
|
public boolean playMana(Ability ability, ManaCost unpaid, String promptText, Game game) {
|
||||||
|
groupsForTargetHandling = null;
|
||||||
return computerPlayer.playMana(ability, unpaid, promptText, game);
|
return computerPlayer.playMana(ability, unpaid, promptText, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
subAbilities.add(subAbility.copy());
|
subAbilities.add(subAbility.copy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.modes = ability.modes.copy();
|
this.modes = ability.getModes().copy();
|
||||||
this.ruleAtTheTop = ability.ruleAtTheTop;
|
this.ruleAtTheTop = ability.ruleAtTheTop;
|
||||||
this.ruleVisible = ability.ruleVisible;
|
this.ruleVisible = ability.ruleVisible;
|
||||||
this.ruleAdditionalCostsVisible = ability.ruleAdditionalCostsVisible;
|
this.ruleAdditionalCostsVisible = ability.ruleAdditionalCostsVisible;
|
||||||
|
@ -196,6 +196,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
//20100716 - 117.12
|
//20100716 - 117.12
|
||||||
if (checkIfClause(game)) {
|
if (checkIfClause(game)) {
|
||||||
|
|
||||||
for (Effect effect : getEffects()) {
|
for (Effect effect : getEffects()) {
|
||||||
if (effect instanceof OneShotEffect) {
|
if (effect instanceof OneShotEffect) {
|
||||||
boolean effectResult = effect.apply(game, this);
|
boolean effectResult = effect.apply(game, this);
|
||||||
|
@ -255,9 +256,14 @@ public abstract class AbilityImpl implements Ability {
|
||||||
/* 20130201 - 601.2b
|
/* 20130201 - 601.2b
|
||||||
* If the spell is modal the player announces the mode choice (see rule 700.2).
|
* 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (controller.isTestMode()) {
|
||||||
|
if (!controller.addTargets(this, game)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getSourceObject(game);
|
getSourceObject(game);
|
||||||
|
|
||||||
|
@ -274,9 +280,8 @@ public abstract class AbilityImpl implements Ability {
|
||||||
}
|
}
|
||||||
// TODO: Because all (non targeted) choices have to be done during resolution
|
// TODO: Because all (non targeted) choices have to be done during resolution
|
||||||
// this has to be removed, if all using effects are changed
|
// this has to be removed, if all using effects are changed
|
||||||
for (UUID modeId : this.getModes().getSelectedModes()) {
|
for (Mode mode : this.getModes().getSelectedModes()) {
|
||||||
this.getModes().setActiveMode(modeId);
|
if (mode.getChoices().size() > 0 && mode.getChoices().choose(game, this) == false) {
|
||||||
if (getChoices().size() > 0 && getChoices().choose(game, this) == false) {
|
|
||||||
logger.debug("activate failed - choice");
|
logger.debug("activate failed - choice");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -313,8 +318,8 @@ public abstract class AbilityImpl implements Ability {
|
||||||
VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller);
|
VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller);
|
||||||
String announceString = handleOtherXCosts(game, controller);
|
String announceString = handleOtherXCosts(game, controller);
|
||||||
|
|
||||||
for (UUID modeId : this.getModes().getSelectedModes()) {
|
for (Mode mode : this.getModes().getSelectedModes()) {
|
||||||
this.getModes().setActiveMode(modeId);
|
this.getModes().setActiveMode(mode);
|
||||||
//20121001 - 601.2c
|
//20121001 - 601.2c
|
||||||
// 601.2c The player announces his or her choice of an appropriate player, object, or zone for
|
// 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
|
// 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
|
if (sourceObject != null && !this.getAbilityType().equals(AbilityType.TRIGGERED)) { // triggered abilities check this already in playerImpl.triggerAbility
|
||||||
sourceObject.adjustTargets(this, game);
|
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()) {
|
if ((variableManaCost != null || announceString != null) && !game.isSimulation()) {
|
||||||
game.informPlayer(controller, (sourceObject != null ? sourceObject.getIdName() : "") + ": no valid targets with this value of X");
|
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) {
|
if (variableManaCost != null) {
|
||||||
int xValue = getManaCostsToPay().getX();
|
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;
|
activated = true;
|
||||||
|
@ -681,7 +686,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Effects getEffects() {
|
public Effects getEffects() {
|
||||||
return modes.getMode().getEffects();
|
return getModes().getMode().getEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -706,7 +711,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Choices getChoices() {
|
public Choices getChoices() {
|
||||||
return modes.getMode().getChoices();
|
return getModes().getMode().getChoices();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -781,7 +786,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
}
|
}
|
||||||
|
|
||||||
String ruleStart = sbRule.toString();
|
String ruleStart = sbRule.toString();
|
||||||
String text = modes.getText();
|
String text = getModes().getText();
|
||||||
String rule;
|
String rule;
|
||||||
if (!text.isEmpty()) {
|
if (!text.isEmpty()) {
|
||||||
if (ruleStart.length() > 1) {
|
if (ruleStart.length() > 1) {
|
||||||
|
@ -873,7 +878,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Targets getTargets() {
|
public Targets getTargets() {
|
||||||
return modes.getMode().getTargets();
|
return getModes().getMode().getTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -883,12 +888,12 @@ public abstract class AbilityImpl implements Ability {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isModal() {
|
public boolean isModal() {
|
||||||
return this.modes.size() > 1;
|
return getModes().size() > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMode(Mode mode) {
|
public void addMode(Mode mode) {
|
||||||
this.modes.addMode(mode);
|
getModes().addMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -899,10 +904,10 @@ public abstract class AbilityImpl implements Ability {
|
||||||
@Override
|
@Override
|
||||||
public boolean canChooseTarget(Game game) {
|
public boolean canChooseTarget(Game game) {
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for (Mode mode : modes.values()) {
|
for (Mode mode : getModes().values()) {
|
||||||
if (mode.getTargets().canChoose(sourceId, controllerId, game)) {
|
if (mode.getTargets().canChoose(sourceId, controllerId, game)) {
|
||||||
found++;
|
found++;
|
||||||
if (modes.isEachModeMoreThanOnce()) {
|
if (getModes().isEachModeMoreThanOnce()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (found >= getModes().getMinModes()) {
|
if (found >= getModes().getMinModes()) {
|
||||||
|
@ -1037,7 +1042,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
logger.warn("Could get no object: " + this.toString());
|
logger.warn("Could get no object: " + this.toString());
|
||||||
}
|
}
|
||||||
return new StringBuilder(" activates: ")
|
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(" from ")
|
||||||
.append(getMessageText(game)).toString();
|
.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) {
|
} else if (object instanceof Spell && ((Spell) object).getSpellAbility().getModes().size() > 1) {
|
||||||
Modes spellModes = ((Spell) object).getSpellAbility().getModes();
|
Modes spellModes = ((Spell) object).getSpellAbility().getModes();
|
||||||
for (UUID modeId : spellModes.getSelectedModes()) {
|
for (Mode selectedMode : spellModes.getSelectedModes()) {
|
||||||
int item = 0;
|
int item = 0;
|
||||||
for (Mode mode : spellModes.values()) {
|
for (Mode mode : spellModes.values()) {
|
||||||
item++;
|
item++;
|
||||||
if (mode.getId().equals(modeId)) {
|
if (mode.getId().equals(selectedMode.getId())) {
|
||||||
spellModes.setActiveMode(mode.getId());
|
|
||||||
sb.append(" (mode ").append(item).append(")");
|
sb.append(" (mode ").append(item).append(")");
|
||||||
sb.append(getTargetDescriptionForLog(getTargets(), game));
|
sb.append(getTargetDescriptionForLog(selectedMode.getTargets(), game));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,8 @@ import mage.util.CardUtil;
|
||||||
*/
|
*/
|
||||||
public class Modes extends LinkedHashMap<UUID, Mode> {
|
public class Modes extends LinkedHashMap<UUID, Mode> {
|
||||||
|
|
||||||
private UUID modeId;
|
private Mode mode; // the current mode of the selected modes
|
||||||
private final ArrayList<UUID> selectedModes = new ArrayList<>();
|
private final ArrayList<Mode> selectedModes = new ArrayList<>();
|
||||||
private int minModes;
|
private int minModes;
|
||||||
private int maxModes;
|
private int maxModes;
|
||||||
private TargetController modeChooser;
|
private TargetController modeChooser;
|
||||||
|
@ -58,25 +58,40 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
||||||
private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists
|
private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists
|
||||||
|
|
||||||
public Modes() {
|
public Modes() {
|
||||||
Mode mode = new Mode();
|
this.mode = new Mode();
|
||||||
this.put(mode.getId(), mode);
|
this.put(mode.getId(), mode);
|
||||||
this.modeId = mode.getId();
|
|
||||||
this.minModes = 1;
|
this.minModes = 1;
|
||||||
this.maxModes = 1;
|
this.maxModes = 1;
|
||||||
this.selectedModes.add(modeId);
|
this.selectedModes.add(mode);
|
||||||
this.modeChooser = TargetController.YOU;
|
this.modeChooser = TargetController.YOU;
|
||||||
this.eachModeOnlyOnce = false;
|
this.eachModeOnlyOnce = false;
|
||||||
this.eachModeMoreThanOnce = false;
|
this.eachModeMoreThanOnce = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Modes(final Modes modes) {
|
public Modes(final Modes modes) {
|
||||||
this.modeId = modes.modeId;
|
|
||||||
for (Map.Entry<UUID, Mode> entry : modes.entrySet()) {
|
for (Map.Entry<UUID, Mode> entry : modes.entrySet()) {
|
||||||
this.put(entry.getKey(), entry.getValue().copy());
|
this.put(entry.getKey(), entry.getValue().copy());
|
||||||
}
|
}
|
||||||
this.minModes = modes.minModes;
|
this.minModes = modes.minModes;
|
||||||
this.maxModes = modes.maxModes;
|
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.modeChooser = modes.modeChooser;
|
||||||
this.eachModeOnlyOnce = modes.eachModeOnlyOnce;
|
this.eachModeOnlyOnce = modes.eachModeOnlyOnce;
|
||||||
this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce;
|
this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce;
|
||||||
|
@ -87,10 +102,21 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mode getMode() {
|
public Mode getMode() {
|
||||||
return get(modeId);
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<UUID> 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<Mode> getSelectedModes() {
|
||||||
return selectedModes;
|
return selectedModes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,16 +144,9 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
||||||
return this.modeChooser;
|
return this.modeChooser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setActiveMode(UUID modeId) {
|
public void setActiveMode(Mode mode) {
|
||||||
if (selectedModes.contains(modeId)) {
|
if (selectedModes.contains(mode)) {
|
||||||
this.modeId = modeId;
|
this.mode = mode;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMode(Mode mode) {
|
|
||||||
if (this.containsKey(mode.getId())) {
|
|
||||||
this.modeId = mode.getId();
|
|
||||||
this.selectedModes.add(mode.getId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +175,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
||||||
for (Mode mode : this.values()) {
|
for (Mode mode : this.values()) {
|
||||||
if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId()))
|
if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId()))
|
||||||
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) {
|
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) {
|
||||||
this.selectedModes.add(mode.getId());
|
this.selectedModes.add(mode.copy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isEachModeOnlyOnce()) {
|
if (isEachModeOnlyOnce()) {
|
||||||
|
@ -184,6 +203,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
||||||
Player player = game.getPlayer(playerId);
|
Player player = game.getPlayer(playerId);
|
||||||
|
|
||||||
// player chooses modes manually
|
// player chooses modes manually
|
||||||
|
this.mode = null;
|
||||||
while (this.selectedModes.size() < this.getMaxModes()) {
|
while (this.selectedModes.size() < this.getMaxModes()) {
|
||||||
Mode choice = player.chooseMode(this, source, game);
|
Mode choice = player.chooseMode(this, source, game);
|
||||||
if (choice == null) {
|
if (choice == null) {
|
||||||
|
@ -192,29 +212,38 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
||||||
}
|
}
|
||||||
return this.selectedModes.size() >= this.getMinModes();
|
return this.selectedModes.size() >= this.getMinModes();
|
||||||
}
|
}
|
||||||
setMode(choice);
|
this.selectedModes.add(choice.copy());
|
||||||
|
if (mode == null) {
|
||||||
|
mode = choice;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isEachModeOnlyOnce()) {
|
if (isEachModeOnlyOnce()) {
|
||||||
setAlreadySelectedModes(selectedModes, source, game);
|
setAlreadySelectedModes(selectedModes, source, game);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this.modeId = this.values().iterator().next().getId();
|
if (mode == null) {
|
||||||
this.selectedModes.clear();
|
this.selectedModes.clear();
|
||||||
this.selectedModes.add(modeId);
|
Mode copiedMode = this.values().iterator().next().copy();
|
||||||
|
this.selectedModes.add(copiedMode);
|
||||||
|
this.setActiveMode(copiedMode);
|
||||||
|
}
|
||||||
if (isEachModeOnlyOnce()) {
|
if (isEachModeOnlyOnce()) {
|
||||||
setAlreadySelectedModes(selectedModes, source, game);
|
setAlreadySelectedModes(selectedModes, source, game);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAlreadySelectedModes(ArrayList<UUID> selectedModes, Ability source, Game game) {
|
private void setAlreadySelectedModes(ArrayList<Mode> selectedModes, Ability source, Game game) {
|
||||||
String key = getKey(source, game);
|
String key = getKey(source, game);
|
||||||
Set<UUID> onceSelectedModes = (Set<UUID>) game.getState().getValue(key);
|
Set<UUID> onceSelectedModes = (Set<UUID>) game.getState().getValue(key);
|
||||||
if (onceSelectedModes == null) {
|
if (onceSelectedModes == null) {
|
||||||
onceSelectedModes = new HashSet<>();
|
onceSelectedModes = new HashSet<>();
|
||||||
}
|
}
|
||||||
onceSelectedModes.addAll(selectedModes);
|
for (Mode mode : selectedModes) {
|
||||||
|
onceSelectedModes.add(mode.getId());
|
||||||
|
}
|
||||||
|
|
||||||
game.getState().setValue(key, onceSelectedModes);
|
game.getState().setValue(key, onceSelectedModes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,9 @@
|
||||||
*/
|
*/
|
||||||
package mage.abilities.common;
|
package mage.abilities.common;
|
||||||
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ package mage.abilities.effects.common;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
@ -50,9 +51,8 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (UUID modeId : sourceAbility.getModes().getSelectedModes()) {
|
for (Mode mode : sourceAbility.getModes().getSelectedModes()) {
|
||||||
sourceAbility.getModes().setActiveMode(modeId);
|
targets.addAll(mode.getTargets());
|
||||||
targets.addAll(sourceAbility.getTargets());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean twoTimesTarget = false;
|
boolean twoTimesTarget = false;
|
||||||
|
|
|
@ -25,19 +25,15 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.abilities.effects.common;
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.constants.AbilityType;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
@ -49,7 +45,6 @@ import mage.util.CardUtil;
|
||||||
*/
|
*/
|
||||||
public class ExileTargetForSourceEffect extends OneShotEffect {
|
public class ExileTargetForSourceEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
|
||||||
public ExileTargetForSourceEffect() {
|
public ExileTargetForSourceEffect() {
|
||||||
super(Outcome.Exile);
|
super(Outcome.Exile);
|
||||||
}
|
}
|
||||||
|
@ -71,11 +66,11 @@ public class ExileTargetForSourceEffect extends OneShotEffect {
|
||||||
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||||
if (permanent != null) {
|
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 {
|
} else {
|
||||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||||
if (card != null) {
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,9 +84,9 @@ public class ExileTargetForSourceEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.getTargets().isEmpty()) {
|
if (mode.getTargets().isEmpty()) {
|
||||||
return "Exile it";
|
return "exile it";
|
||||||
} else {
|
} else {
|
||||||
return "Exile target " + mode.getTargets().get(0).getTargetName();
|
return "exile target " + mode.getTargets().get(0).getTargetName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,14 @@
|
||||||
*/
|
*/
|
||||||
package mage.abilities.effects.common;
|
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.Ability;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.CardsImpl;
|
import mage.cards.Card;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
@ -70,7 +74,14 @@ public class ReturnToHandTargetEffect extends OneShotEffect {
|
||||||
if (controller == null) {
|
if (controller == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return controller.moveCards(new CardsImpl(targetPointer.getTargets(game, source)), null, Zone.HAND, source, game);
|
Set<Card> 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
|
@Override
|
||||||
|
|
|
@ -25,10 +25,10 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.abilities.keyword;
|
package mage.abilities.keyword;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
|
@ -44,7 +44,6 @@ import mage.target.Target;
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class HeroicAbility extends TriggeredAbilityImpl {
|
public class HeroicAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
public HeroicAbility(Effect effect) {
|
public HeroicAbility(Effect effect) {
|
||||||
|
@ -83,13 +82,13 @@ public class HeroicAbility extends TriggeredAbilityImpl {
|
||||||
private boolean checkSpell(Spell spell, Game game) {
|
private boolean checkSpell(Spell spell, Game game) {
|
||||||
if (spell != null) {
|
if (spell != null) {
|
||||||
SpellAbility sa = spell.getSpellAbility();
|
SpellAbility sa = spell.getSpellAbility();
|
||||||
for(UUID modeId :sa.getModes().getSelectedModes()) {
|
for (Mode mode : sa.getModes().getSelectedModes()) {
|
||||||
for (Target target : sa.getModes().get(modeId).getTargets()) {
|
for (Target target : mode.getTargets()) {
|
||||||
if (!target.isNotTarget() && target.getTargets().contains(this.getSourceId())) {
|
if (!target.isNotTarget() && target.getTargets().contains(this.getSourceId())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Effect effect : sa.getModes().get(modeId).getEffects()) {
|
for (Effect effect : mode.getEffects()) {
|
||||||
for (UUID targetId : effect.getTargetPointer().getTargets(game, sa)) {
|
for (UUID targetId : effect.getTargetPointer().getTargets(game, sa)) {
|
||||||
if (targetId.equals(this.getSourceId())) {
|
if (targetId.equals(this.getSourceId())) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
*/
|
*/
|
||||||
package mage.filter.predicate.mageobject;
|
package mage.filter.predicate.mageobject;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.filter.predicate.Predicate;
|
import mage.filter.predicate.Predicate;
|
||||||
|
@ -52,8 +51,7 @@ public class NumberOfTargetsPredicate implements Predicate<MageObject> {
|
||||||
Spell spell = game.getStack().getSpell(input.getId());
|
Spell spell = game.getStack().getSpell(input.getId());
|
||||||
if (spell != null) {
|
if (spell != null) {
|
||||||
int numberOfTargets = 0;
|
int numberOfTargets = 0;
|
||||||
for (UUID modeId : spell.getSpellAbility().getModes().getSelectedModes()) {
|
for (Mode mode : spell.getSpellAbility().getModes().getSelectedModes()) {
|
||||||
Mode mode = spell.getSpellAbility().getModes().get(modeId);
|
|
||||||
for (Target target : mode.getTargets()) {
|
for (Target target : mode.getTargets()) {
|
||||||
numberOfTargets += target.getTargets().size();
|
numberOfTargets += target.getTargets().size();
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,7 @@ public class TargetsPermanentPredicate implements ObjectSourcePlayerPredicate<Ob
|
||||||
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
|
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
|
||||||
StackObject object = game.getStack().getStackObject(input.getObject().getId());
|
StackObject object = game.getStack().getStackObject(input.getObject().getId());
|
||||||
if (object != null) {
|
if (object != null) {
|
||||||
for(UUID modeId : object.getStackAbility().getModes().getSelectedModes()) {
|
for (Mode mode : object.getStackAbility().getModes().getSelectedModes()) {
|
||||||
Mode mode = object.getStackAbility().getModes().get(modeId);
|
|
||||||
for (Target target : mode.getTargets()) {
|
for (Target target : mode.getTargets()) {
|
||||||
for (UUID targetId : target.getTargets()) {
|
for (UUID targetId : target.getTargets()) {
|
||||||
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
|
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
|
||||||
|
|
|
@ -309,7 +309,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
for (StackObject spell : stack) {
|
for (StackObject spell : stack) {
|
||||||
sb.append(spell.getControllerId()).append(spell.getName());
|
sb.append(spell.getControllerId()).append(spell.getName());
|
||||||
sb.append(spell.getStackAbility().toString());
|
sb.append(spell.getStackAbility().toString());
|
||||||
for (Mode mode : spell.getStackAbility().getModes().values()) {
|
for (Mode mode : spell.getStackAbility().getModes().getSelectedModes()) {
|
||||||
if (!mode.getTargets().isEmpty()) {
|
if (!mode.getTargets().isEmpty()) {
|
||||||
sb.append("targets");
|
sb.append("targets");
|
||||||
for (Target target : mode.getTargets()) {
|
for (Target target : mode.getTargets()) {
|
||||||
|
@ -367,7 +367,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
for (StackObject spell : stack) {
|
for (StackObject spell : stack) {
|
||||||
sb.append(spell.getControllerId()).append(spell.getName());
|
sb.append(spell.getControllerId()).append(spell.getName());
|
||||||
sb.append(spell.getStackAbility().toString());
|
sb.append(spell.getStackAbility().toString());
|
||||||
for (Mode mode : spell.getStackAbility().getModes().values()) {
|
for (Mode mode : spell.getStackAbility().getModes().getSelectedModes()) {
|
||||||
if (!mode.getTargets().isEmpty()) {
|
if (!mode.getTargets().isEmpty()) {
|
||||||
sb.append("targets");
|
sb.append("targets");
|
||||||
for (Target target : mode.getTargets()) {
|
for (Target target : mode.getTargets()) {
|
||||||
|
@ -709,7 +709,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
|
|
||||||
public void addAbility(Ability ability, MageObject attachedTo) {
|
public void addAbility(Ability ability, MageObject attachedTo) {
|
||||||
if (ability instanceof StaticAbility) {
|
if (ability instanceof StaticAbility) {
|
||||||
for (Mode mode : ability.getModes().values()) {
|
for (Mode mode : ability.getModes().getSelectedModes()) {
|
||||||
for (Effect effect : mode.getEffects()) {
|
for (Effect effect : mode.getEffects()) {
|
||||||
if (effect instanceof ContinuousEffect) {
|
if (effect instanceof ContinuousEffect) {
|
||||||
addEffect((ContinuousEffect) effect, ability);
|
addEffect((ContinuousEffect) effect, ability);
|
||||||
|
@ -731,7 +731,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
*/
|
*/
|
||||||
public void addAbility(Ability ability, UUID sourceId, Card attachedTo) {
|
public void addAbility(Ability ability, UUID sourceId, Card attachedTo) {
|
||||||
if (ability instanceof StaticAbility) {
|
if (ability instanceof StaticAbility) {
|
||||||
for (Mode mode : ability.getModes().values()) {
|
for (Mode mode : ability.getModes().getSelectedModes()) {
|
||||||
for (Effect effect : mode.getEffects()) {
|
for (Effect effect : mode.getEffects()) {
|
||||||
if (effect instanceof ContinuousEffect) {
|
if (effect instanceof ContinuousEffect) {
|
||||||
addEffect((ContinuousEffect) effect, sourceId, ability);
|
addEffect((ContinuousEffect) effect, sourceId, ability);
|
||||||
|
|
|
@ -36,6 +36,7 @@ import mage.Mana;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Abilities;
|
import mage.abilities.Abilities;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.costs.AlternativeSourceCosts;
|
import mage.abilities.costs.AlternativeSourceCosts;
|
||||||
import mage.abilities.costs.Cost;
|
import mage.abilities.costs.Cost;
|
||||||
|
@ -195,9 +196,9 @@ public class Spell extends StackObjImpl implements Card {
|
||||||
if (notTargeted || legalParts) {
|
if (notTargeted || legalParts) {
|
||||||
for (SpellAbility spellAbility : this.spellAbilities) {
|
for (SpellAbility spellAbility : this.spellAbilities) {
|
||||||
if (spellAbilityHasLegalParts(spellAbility, game)) {
|
if (spellAbilityHasLegalParts(spellAbility, game)) {
|
||||||
for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
|
for (Mode mode : spellAbility.getModes().getSelectedModes()) {
|
||||||
spellAbility.getModes().setActiveMode(modeId);
|
spellAbility.getModes().setActiveMode(mode);
|
||||||
if (spellAbility.getTargets().stillLegal(spellAbility, game)) {
|
if (mode.getTargets().stillLegal(spellAbility, game)) {
|
||||||
if (!spellAbility.getSpellAbilityType().equals(SpellAbilityType.SPLICE)) {
|
if (!spellAbility.getSpellAbilityType().equals(SpellAbilityType.SPLICE)) {
|
||||||
updateOptionalCosts(index);
|
updateOptionalCosts(index);
|
||||||
}
|
}
|
||||||
|
@ -268,9 +269,8 @@ public class Spell extends StackObjImpl implements Card {
|
||||||
|
|
||||||
private boolean hasTargets(SpellAbility spellAbility, Game game) {
|
private boolean hasTargets(SpellAbility spellAbility, Game game) {
|
||||||
if (spellAbility.getModes().getSelectedModes().size() > 1) {
|
if (spellAbility.getModes().getSelectedModes().size() > 1) {
|
||||||
for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
|
for (Mode mode : spellAbility.getModes().getSelectedModes()) {
|
||||||
spellAbility.getModes().setActiveMode(modeId);
|
if (!mode.getTargets().isEmpty()) {
|
||||||
if (!spellAbility.getTargets().isEmpty()) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,11 +285,10 @@ public class Spell extends StackObjImpl implements Card {
|
||||||
if (spellAbility.getModes().getSelectedModes().size() > 1) {
|
if (spellAbility.getModes().getSelectedModes().size() > 1) {
|
||||||
boolean targetedMode = false;
|
boolean targetedMode = false;
|
||||||
boolean legalTargetedMode = false;
|
boolean legalTargetedMode = false;
|
||||||
for (UUID modeId : spellAbility.getModes().getSelectedModes()) {
|
for (Mode mode : spellAbility.getModes().getSelectedModes()) {
|
||||||
spellAbility.getModes().setActiveMode(modeId);
|
if (mode.getTargets().size() > 0) {
|
||||||
if (spellAbility.getTargets().size() > 0) {
|
|
||||||
targetedMode = true;
|
targetedMode = true;
|
||||||
if (spellAbility.getTargets().stillLegal(spellAbility, game)) {
|
if (mode.getTargets().stillLegal(spellAbility, game)) {
|
||||||
legalTargetedMode = true;
|
legalTargetedMode = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,14 +86,14 @@ public class StackAbility extends StackObjImpl implements Ability {
|
||||||
public StackAbility(Ability ability, UUID controllerId) {
|
public StackAbility(Ability ability, UUID controllerId) {
|
||||||
this.ability = ability;
|
this.ability = ability;
|
||||||
this.controllerId = controllerId;
|
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) {
|
public StackAbility(final StackAbility stackAbility) {
|
||||||
this.ability = spell.ability.copy();
|
this.ability = stackAbility.ability.copy();
|
||||||
this.controllerId = spell.controllerId;
|
this.controllerId = stackAbility.controllerId;
|
||||||
this.name = spell.name;
|
this.name = stackAbility.name;
|
||||||
this.expansionSetCode = spell.expansionSetCode;
|
this.expansionSetCode = stackAbility.expansionSetCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -117,8 +117,8 @@ public abstract class StackObjImpl implements StackObject {
|
||||||
}
|
}
|
||||||
for (Ability ability : objectAbilities) {
|
for (Ability ability : objectAbilities) {
|
||||||
// Some spells can have more than one mode
|
// Some spells can have more than one mode
|
||||||
for (UUID modeId : ability.getModes().getSelectedModes()) {
|
for (Mode mode : ability.getModes().getSelectedModes()) {
|
||||||
Mode mode = ability.getModes().get(modeId);
|
ability.getModes().setActiveMode(mode);
|
||||||
oldTargetDescription.append(ability.getTargetDescription(mode.getTargets(), game));
|
oldTargetDescription.append(ability.getTargetDescription(mode.getTargets(), game));
|
||||||
for (Target target : mode.getTargets()) {
|
for (Target target : mode.getTargets()) {
|
||||||
Target newTarget = chooseNewTarget(targetController, ability, mode, target, forceChange, filterNewTarget, game);
|
Target newTarget = chooseNewTarget(targetController, ability, mode, target, forceChange, filterNewTarget, game);
|
||||||
|
|
|
@ -787,4 +787,13 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
MatchPlayer getMatchPlayer();
|
MatchPlayer getMatchPlayer();
|
||||||
|
|
||||||
boolean scry(int value, Ability source, Game game);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2706,7 +2706,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
for (Mode mode : option.getModes().values()) {
|
for (Mode mode : option.getModes().values()) {
|
||||||
Ability newOption = option.copy();
|
Ability newOption = option.copy();
|
||||||
newOption.getModes().getSelectedModes().clear();
|
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.getTargets().getUnchosen().size() > 0) {
|
||||||
if (newOption.getManaCosts().getVariableCosts().size() > 0) {
|
if (newOption.getManaCosts().getVariableCosts().size() > 0) {
|
||||||
addVariableXOptions(options, newOption, 0, game);
|
addVariableXOptions(options, newOption, 0, game);
|
||||||
|
@ -3448,4 +3449,10 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addTargets(Ability ability, Game game) {
|
||||||
|
// only used for TestPlayer to preSet Targets
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,11 @@ import mage.cards.Card;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author duncant
|
* @author duncant
|
||||||
*/
|
*/
|
||||||
public class TargetAddress {
|
public class TargetAddress {
|
||||||
|
|
||||||
protected int spellAbilityIndex;
|
protected int spellAbilityIndex;
|
||||||
protected UUID mode;
|
protected UUID mode;
|
||||||
protected int targetIndex;
|
protected int targetIndex;
|
||||||
|
@ -52,6 +52,7 @@ public class TargetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class TargetAddressIterable implements Iterable<TargetAddress> {
|
protected static class TargetAddressIterable implements Iterable<TargetAddress> {
|
||||||
|
|
||||||
protected final Card card;
|
protected final Card card;
|
||||||
|
|
||||||
public TargetAddressIterable(Card card) {
|
public TargetAddressIterable(Card card) {
|
||||||
|
@ -64,9 +65,10 @@ public class TargetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class TargetAddressIterator implements Iterator<TargetAddress> {
|
protected static class TargetAddressIterator implements Iterator<TargetAddress> {
|
||||||
|
|
||||||
protected Iterator<SpellAbility> spellAbilityIterator;
|
protected Iterator<SpellAbility> spellAbilityIterator;
|
||||||
protected Integer lastSpellAbilityIndex = null;
|
protected Integer lastSpellAbilityIndex = null;
|
||||||
protected Iterator<UUID> modeIterator = null;
|
protected Iterator<Mode> modeIterator = null;
|
||||||
protected Modes modes = null;
|
protected Modes modes = null;
|
||||||
protected UUID lastMode = null;
|
protected UUID lastMode = null;
|
||||||
protected Iterator<Target> targetIterator = null;
|
protected Iterator<Target> targetIterator = null;
|
||||||
|
@ -120,7 +122,7 @@ public class TargetAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modeIterator != null && modeIterator.hasNext()) {
|
if (modeIterator != null && modeIterator.hasNext()) {
|
||||||
lastMode = modeIterator.next();
|
lastMode = modeIterator.next().getId();
|
||||||
targetIterator = modes.get(lastMode).getTargets().iterator();
|
targetIterator = modes.get(lastMode).getTargets().iterator();
|
||||||
} else {
|
} else {
|
||||||
lastMode = null;
|
lastMode = null;
|
||||||
|
@ -145,7 +147,6 @@ public class TargetAddress {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Iterable<TargetAddress> walk(Card card) {
|
public static Iterable<TargetAddress> walk(Card card) {
|
||||||
return new TargetAddressIterable(card);
|
return new TargetAddressIterable(card);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue