InputSelectTargets moved to separate class,

SpellAbilityRequirements - all options are passed as parameters to fillRequirements
This commit is contained in:
Maxmtg
2013-04-01 14:47:38 +00:00
parent 26ca62653c
commit 0700036b96
5 changed files with 258 additions and 292 deletions

1
.gitattributes vendored
View File

@@ -13847,6 +13847,7 @@ src/main/java/forge/control/input/InputSelectCards.java -text
src/main/java/forge/control/input/InputSelectCardsFromList.java -text src/main/java/forge/control/input/InputSelectCardsFromList.java -text
src/main/java/forge/control/input/InputSelectMany.java -text src/main/java/forge/control/input/InputSelectMany.java -text
src/main/java/forge/control/input/InputSelectManyBase.java -text src/main/java/forge/control/input/InputSelectManyBase.java -text
src/main/java/forge/control/input/InputSelectTargets.java -text
src/main/java/forge/control/input/InputSynchronized.java -text src/main/java/forge/control/input/InputSynchronized.java -text
src/main/java/forge/control/input/InputSyncronizedBase.java -text src/main/java/forge/control/input/InputSyncronizedBase.java -text
src/main/java/forge/control/input/package-info.java svneol=native#text/plain src/main/java/forge/control/input/package-info.java svneol=native#text/plain

View File

@@ -39,24 +39,15 @@ import forge.game.zone.Zone;
*/ */
public class SpellAbilityRequirements { public class SpellAbilityRequirements {
private final SpellAbility ability; private final SpellAbility ability;
private final TargetChooser select;
private final CostPayment payment; private final CostPayment payment;
private boolean isFree;
private boolean skipStack = false;
private boolean isAlreadyTargeted = false;
public void setAlreadyTargeted() { isAlreadyTargeted = true; }
public final void setSkipStack() { this.skipStack = true; }
public void setFree() { this.isFree = true; }
public SpellAbilityRequirements(final SpellAbility sa, final CostPayment cp) { public SpellAbilityRequirements(final SpellAbility sa, final CostPayment cp) {
this.ability = sa; this.ability = sa;
this.select = new TargetChooser(sa);
this.payment = cp; this.payment = cp;
} }
public final void fillRequirements() { public final void fillRequirements(boolean isAlreadyTargeted, boolean isFree, boolean skipStack) {
final GameState game = Singletons.getModel().getGame(); final GameState game = Singletons.getModel().getGame();
// used to rollback // used to rollback
@@ -75,26 +66,26 @@ public class SpellAbilityRequirements {
// Announce things like how many times you want to Multikick or the value of X // Announce things like how many times you want to Multikick or the value of X
if (!this.announceRequirements()) { if (!this.announceRequirements()) {
this.select.setCancel(true); rollbackAbility(fromZone, zonePosition, null);
rollbackAbility(fromZone, zonePosition);
return; return;
} }
final TargetChooser select = new TargetChooser(ability);
// Skip to paying if parent ability doesn't target and has no // Skip to paying if parent ability doesn't target and has no
// subAbilities. // subAbilities.
// (or trigger case where its already targeted) // (or trigger case where its already targeted)
boolean acceptsTargets = this.select.doesTarget() || this.ability.getSubAbility() != null; boolean acceptsTargets = select.doesTarget() || this.ability.getSubAbility() != null;
if (!isAlreadyTargeted && acceptsTargets) { if (!isAlreadyTargeted && acceptsTargets) {
this.select.clearTargets(); select.clearTargets();
this.select.chooseTargets(); select.chooseTargets();
if (this.select.isCanceled()) { if (select.isCanceled()) {
rollbackAbility(fromZone, zonePosition); rollbackAbility(fromZone, zonePosition, select);
return; return;
} }
} }
// Payment // Payment
boolean paymentMade = this.isFree; boolean paymentMade = isFree;
if (!paymentMade) { if (!paymentMade) {
this.payment.changeCost(); this.payment.changeCost();
@@ -102,12 +93,12 @@ public class SpellAbilityRequirements {
} }
if (!paymentMade) { if (!paymentMade) {
rollbackAbility(fromZone, zonePosition); rollbackAbility(fromZone, zonePosition, select);
return; return;
} }
else if (this.isFree || this.payment.isFullyPaid()) { else if (isFree || this.payment.isFullyPaid()) {
if (this.skipStack) { if (skipStack) {
AbilityUtils.resolve(this.ability, false); AbilityUtils.resolve(this.ability, false);
} else { } else {
@@ -116,13 +107,13 @@ public class SpellAbilityRequirements {
game.getStack().addAndUnfreeze(this.ability); game.getStack().addAndUnfreeze(this.ability);
} }
// Warning about this - resolution may come in another thread, and it would still need its targets // no worries here. The same thread must resolve, and by this moment ability will have been resolved already
this.select.clearTargets(); select.clearTargets();
game.getAction().checkStateEffects(); game.getAction().checkStateEffects();
} }
} }
private void rollbackAbility(Zone fromZone, int zonePosition) { private void rollbackAbility(Zone fromZone, int zonePosition, TargetChooser select) {
// cancel ability during target choosing // cancel ability during target choosing
final Card c = this.ability.getSourceCard(); final Card c = this.ability.getSourceCard();
@@ -136,8 +127,8 @@ public class SpellAbilityRequirements {
Singletons.getModel().getGame().getAction().moveTo(fromZone, c, zonePosition >= 0 ? Integer.valueOf(zonePosition) : null); Singletons.getModel().getGame().getAction().moveTo(fromZone, c, zonePosition >= 0 ? Integer.valueOf(zonePosition) : null);
} }
if (this.select != null) { if (select != null) {
this.select.clearTargets(); select.clearTargets();
} }
this.ability.resetOnceResolved(); this.ability.resetOnceResolved();
@@ -147,7 +138,7 @@ public class SpellAbilityRequirements {
} }
public boolean announceRequirements() { private boolean announceRequirements() {
// Announcing Requirements like Choosing X or Multikicker // Announcing Requirements like Choosing X or Multikicker
// SA Params as comma delimited list // SA Params as comma delimited list
String announce = ability.getParam("Announce"); String announce = ability.getParam("Announce");

View File

@@ -20,24 +20,19 @@ package forge.card.spellability;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.Card; import forge.Card;
import forge.CardLists; import forge.CardLists;
import forge.FThreads; import forge.FThreads;
import forge.GameEntity;
import forge.card.ability.AbilityUtils; import forge.card.ability.AbilityUtils;
import forge.card.ability.ApiType; import forge.control.input.InputSelectTargets;
import forge.control.input.InputSyncronizedBase;
import forge.game.GameState; import forge.game.GameState;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.Zone; import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiChoose; import forge.gui.GuiChoose;
import forge.view.ButtonUtil;
/** /**
* <p> * <p>
@@ -48,249 +43,18 @@ import forge.view.ButtonUtil;
* @version $Id$ * @version $Id$
*/ */
public class TargetChooser { public class TargetChooser {
/**
* TODO: Write javadoc for this type.
*
*/
public static final class InputSelectTargets extends InputSyncronizedBase {
private final List<Card> choices;
// some cards can be targeted several times (eg: distribute damage as you choose)
private final Map<GameEntity, Integer> targetDepth = new HashMap<GameEntity, Integer>();
private final Target tgt;
private final SpellAbility sa;
private boolean bCancel = false;
private boolean bOk = false;
private final boolean mandatory;
private static final long serialVersionUID = -1091595663541356356L;
public final boolean hasCancelled() { return bCancel; }
public final boolean hasPressedOk() { return bOk; }
/**
* TODO: Write javadoc for Constructor.
* @param select
* @param choices
* @param req
* @param alreadyTargeted
* @param targeted
* @param tgt
* @param sa
* @param mandatory
*/
public InputSelectTargets(List<Card> choices, SpellAbility sa, boolean mandatory) {
super(sa.getActivatingPlayer());
this.choices = choices;
this.tgt = sa.getTarget();
this.sa = sa;
this.mandatory = mandatory;
}
@Override
public void showMessage() {
final StringBuilder sb = new StringBuilder();
sb.append("Targeted:\n");
for (final Entry<GameEntity, Integer> o : targetDepth.entrySet()) {
sb.append(o.getKey());
if( o.getValue() > 1 )
sb.append(" (").append(o.getValue()).append(" times)");
sb.append("\n");
}
//sb.append(tgt.getTargetedString()).append("\n");
sb.append(tgt.getVTSelection());
showMessage(sb.toString());
// If reached Minimum targets, enable OK button
if (!tgt.isMinTargetsChosen(sa.getSourceCard(), sa) || tgt.isDividedAsYouChoose()) {
if (mandatory && tgt.hasCandidates(sa, true)) {
// Player has to click on a target
ButtonUtil.disableAll();
} else {
ButtonUtil.enableOnlyCancel();
}
} else {
if (mandatory && tgt.hasCandidates(sa, true)) {
// Player has to click on a target or ok
ButtonUtil.enableOnlyOk();
} else {
ButtonUtil.enableAllFocusOk();
}
}
}
@Override
public void selectButtonCancel() {
bCancel = true;
this.done();
}
@Override
public void selectButtonOK() {
bOk = true;
this.done();
}
@Override
public void selectCard(final Card card) {
if (!tgt.isUniqueTargets() && targetDepth.containsKey(card)) {
return;
}
// leave this in temporarily, there some seriously wrong things going on here
if (!card.canBeTargetedBy(sa)) {
showMessage("Cannot target this card (Shroud? Protection? Restrictions?).");
return;
}
if (!choices.contains(card)) {
showMessage("This card is not a valid choice for some other reason besides (Shroud? Protection? Restrictions?).");
return;
}
if (tgt.isDividedAsYouChoose()) {
final int stillToDivide = tgt.getStillToDivide();
int allocatedPortion = 0;
// allow allocation only if the max targets isn't reached and there are more candidates
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
final Integer[] choices = new Integer[stillToDivide];
for (int i = 1; i <= stillToDivide; i++) {
choices[i - 1] = i;
}
String apiBasedMessage = "Distribute how much to ";
if (sa.getApi() == ApiType.DealDamage) {
apiBasedMessage = "Select how much damage to deal to ";
} else if (sa.getApi() == ApiType.PreventDamage) {
apiBasedMessage = "Select how much damage to prevent to ";
} else if (sa.getApi() == ApiType.PutCounter) {
apiBasedMessage = "Select how many counters to distribute to ";
}
final StringBuilder sb = new StringBuilder();
sb.append(apiBasedMessage);
sb.append(card.toString());
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
if (null == chosen) {
return;
}
allocatedPortion = chosen;
} else { // otherwise assign the rest of the damage/protection
allocatedPortion = stillToDivide;
}
tgt.setStillToDivide(stillToDivide - allocatedPortion);
tgt.addDividedAllocation(card, allocatedPortion);
}
addTarget(card);
} // selectCard()
@Override
public void selectPlayer(final Player player) {
if (!tgt.isUniqueTargets() && targetDepth.containsKey(player)) {
return;
}
if (!sa.canTarget(player)) {
showMessage("Cannot target this player (Hexproof? Protection? Restrictions?).");
return;
}
if (tgt.isDividedAsYouChoose()) {
final int stillToDivide = tgt.getStillToDivide();
int allocatedPortion = 0;
// allow allocation only if the max targets isn't reached and there are more candidates
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa)) && (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
final Integer[] choices = new Integer[stillToDivide];
for (int i = 1; i <= stillToDivide; i++) {
choices[i - 1] = i;
}
String apiBasedMessage = "Distribute how much to ";
if (sa.getApi() == ApiType.DealDamage) {
apiBasedMessage = "Select how much damage to deal to ";
} else if (sa.getApi() == ApiType.PreventDamage) {
apiBasedMessage = "Select how much damage to prevent to ";
}
final StringBuilder sb = new StringBuilder();
sb.append(apiBasedMessage);
sb.append(player.getName());
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
if (null == chosen) {
return;
}
allocatedPortion = chosen;
} else { // otherwise assign the rest of the damage/protection
allocatedPortion = stillToDivide;
}
tgt.setStillToDivide(stillToDivide - allocatedPortion);
tgt.addDividedAllocation(player, allocatedPortion);
}
addTarget(player);
}
void addTarget(GameEntity ge) {
tgt.addTarget(ge);
Integer val = targetDepth.get(ge);
targetDepth.put(ge, val == null ? Integer.valueOf(1) : Integer.valueOf(val.intValue() + 1) );
if(hasAllTargets()) {
bOk = true;
this.done();
}
else
this.showMessage();
}
void done() {
this.stop();
}
boolean hasAllTargets() {
return tgt.isMaxTargetsChosen(sa.getSourceCard(), sa);
}
}
private final SpellAbility ability; private final SpellAbility ability;
/**
* <p>
* Constructor for Target_Selection.
* </p>
*
* @param tgt
* a {@link forge.card.spellability.Target} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
*/
public TargetChooser(final SpellAbility sa) { public TargetChooser(final SpellAbility sa) {
this.ability = sa; this.ability = sa;
} }
/** private final Target getTgt() {
* <p>
* getTgt.
* </p>
*
* @return a {@link forge.card.spellability.Target} object.
*/
public final Target getTgt() {
return this.ability.getTarget(); return this.ability.getTarget();
} }
/** private final Card getCard() {
* <p>
* Getter for the field <code>ability</code>.
* </p>
*
* @return a {@link forge.card.spellability.SpellAbility} object.
*/
public final SpellAbility getAbility() {
return this.ability;
}
/**
* <p>
* Getter for the field <code>card</code>.
* </p>
*
* @return a {@link forge.Card} object.
*/
public final Card getCard() {
return this.ability.getSourceCard(); return this.ability.getSourceCard();
} }
@@ -342,7 +106,7 @@ public class TargetChooser {
public final boolean chooseTargets() { public final boolean chooseTargets() {
Target tgt = getTgt(); Target tgt = getTgt();
final boolean canTarget = tgt == null ? false : tgt.doesTarget(); final boolean canTarget = doesTarget();
final int minTargets = canTarget ? tgt.getMinTargets(getCard(), ability) : 0; final int minTargets = canTarget ? tgt.getMinTargets(getCard(), ability) : 0;
final int maxTargets = canTarget ? tgt.getMaxTargets(getCard(), ability) : 0; final int maxTargets = canTarget ? tgt.getMaxTargets(getCard(), ability) : 0;
final int numTargeted = canTarget ? tgt.getNumTargeted() : 0; final int numTargeted = canTarget ? tgt.getNumTargeted() : 0;

View File

@@ -0,0 +1,212 @@
package forge.control.input;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import forge.Card;
import forge.GameEntity;
import forge.card.ability.ApiType;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.player.Player;
import forge.gui.GuiChoose;
import forge.view.ButtonUtil;
/**
* TODO: Write javadoc for this type.
*
*/
public final class InputSelectTargets extends InputSyncronizedBase {
private final List<Card> choices;
// some cards can be targeted several times (eg: distribute damage as you choose)
private final Map<GameEntity, Integer> targetDepth = new HashMap<GameEntity, Integer>();
private final Target tgt;
private final SpellAbility sa;
private boolean bCancel = false;
private boolean bOk = false;
private final boolean mandatory;
private static final long serialVersionUID = -1091595663541356356L;
public final boolean hasCancelled() { return bCancel; }
public final boolean hasPressedOk() { return bOk; }
/**
* TODO: Write javadoc for Constructor.
* @param select
* @param choices
* @param req
* @param alreadyTargeted
* @param targeted
* @param tgt
* @param sa
* @param mandatory
*/
public InputSelectTargets(List<Card> choices, SpellAbility sa, boolean mandatory) {
super(sa.getActivatingPlayer());
this.choices = choices;
this.tgt = sa.getTarget();
this.sa = sa;
this.mandatory = mandatory;
}
@Override
public void showMessage() {
final StringBuilder sb = new StringBuilder();
sb.append("Targeted:\n");
for (final Entry<GameEntity, Integer> o : targetDepth.entrySet()) {
sb.append(o.getKey());
if( o.getValue() > 1 )
sb.append(" (").append(o.getValue()).append(" times)");
sb.append("\n");
}
//sb.append(tgt.getTargetedString()).append("\n");
sb.append(tgt.getVTSelection());
showMessage(sb.toString());
// If reached Minimum targets, enable OK button
if (!tgt.isMinTargetsChosen(sa.getSourceCard(), sa) || tgt.isDividedAsYouChoose()) {
if (mandatory && tgt.hasCandidates(sa, true)) {
// Player has to click on a target
ButtonUtil.disableAll();
} else {
ButtonUtil.enableOnlyCancel();
}
} else {
if (mandatory && tgt.hasCandidates(sa, true)) {
// Player has to click on a target or ok
ButtonUtil.enableOnlyOk();
} else {
ButtonUtil.enableAllFocusOk();
}
}
}
@Override
public void selectButtonCancel() {
bCancel = true;
this.done();
}
@Override
public void selectButtonOK() {
bOk = true;
this.done();
}
@Override
public void selectCard(final Card card) {
if (!tgt.isUniqueTargets() && targetDepth.containsKey(card)) {
return;
}
// leave this in temporarily, there some seriously wrong things going on here
if (!card.canBeTargetedBy(sa)) {
showMessage("Cannot target this card (Shroud? Protection? Restrictions?).");
return;
}
if (!choices.contains(card)) {
showMessage("This card is not a valid choice for some other reason besides (Shroud? Protection? Restrictions?).");
return;
}
if (tgt.isDividedAsYouChoose()) {
final int stillToDivide = tgt.getStillToDivide();
int allocatedPortion = 0;
// allow allocation only if the max targets isn't reached and there are more candidates
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
final Integer[] choices = new Integer[stillToDivide];
for (int i = 1; i <= stillToDivide; i++) {
choices[i - 1] = i;
}
String apiBasedMessage = "Distribute how much to ";
if (sa.getApi() == ApiType.DealDamage) {
apiBasedMessage = "Select how much damage to deal to ";
} else if (sa.getApi() == ApiType.PreventDamage) {
apiBasedMessage = "Select how much damage to prevent to ";
} else if (sa.getApi() == ApiType.PutCounter) {
apiBasedMessage = "Select how many counters to distribute to ";
}
final StringBuilder sb = new StringBuilder();
sb.append(apiBasedMessage);
sb.append(card.toString());
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
if (null == chosen) {
return;
}
allocatedPortion = chosen;
} else { // otherwise assign the rest of the damage/protection
allocatedPortion = stillToDivide;
}
tgt.setStillToDivide(stillToDivide - allocatedPortion);
tgt.addDividedAllocation(card, allocatedPortion);
}
addTarget(card);
} // selectCard()
@Override
public void selectPlayer(final Player player) {
if (!tgt.isUniqueTargets() && targetDepth.containsKey(player)) {
return;
}
if (!sa.canTarget(player)) {
showMessage("Cannot target this player (Hexproof? Protection? Restrictions?).");
return;
}
if (tgt.isDividedAsYouChoose()) {
final int stillToDivide = tgt.getStillToDivide();
int allocatedPortion = 0;
// allow allocation only if the max targets isn't reached and there are more candidates
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa)) && (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
final Integer[] choices = new Integer[stillToDivide];
for (int i = 1; i <= stillToDivide; i++) {
choices[i - 1] = i;
}
String apiBasedMessage = "Distribute how much to ";
if (sa.getApi() == ApiType.DealDamage) {
apiBasedMessage = "Select how much damage to deal to ";
} else if (sa.getApi() == ApiType.PreventDamage) {
apiBasedMessage = "Select how much damage to prevent to ";
}
final StringBuilder sb = new StringBuilder();
sb.append(apiBasedMessage);
sb.append(player.getName());
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
if (null == chosen) {
return;
}
allocatedPortion = chosen;
} else { // otherwise assign the rest of the damage/protection
allocatedPortion = stillToDivide;
}
tgt.setStillToDivide(stillToDivide - allocatedPortion);
tgt.addDividedAllocation(player, allocatedPortion);
}
addTarget(player);
}
void addTarget(GameEntity ge) {
tgt.addTarget(ge);
Integer val = targetDepth.get(ge);
targetDepth.put(ge, val == null ? Integer.valueOf(1) : Integer.valueOf(val.intValue() + 1) );
if(hasAllTargets()) {
bOk = true;
this.done();
}
else
this.showMessage();
}
void done() {
this.stop();
}
boolean hasAllTargets() {
return tgt.isMaxTargetsChosen(sa.getSourceCard(), sa);
}
}

View File

@@ -66,7 +66,9 @@ public class GameActionPlay {
public final void playSpellAbilityWithoutPayingManaCost(final SpellAbility sa) { public final void playSpellAbilityWithoutPayingManaCost(final SpellAbility sa) {
FThreads.checkEDT("GameActionPlay.playSpellAbilityWithoutPayingManaCost", false); FThreads.checkEDT("GameActionPlay.playSpellAbilityWithoutPayingManaCost", false);
final Card source = sa.getSourceCard(); final Card source = sa.getSourceCard();
setSplitCardState(source, sa); // Split card support
if( source.isSplitCard())
setSplitCardState(source, sa);
if (sa.getPayCosts() != null) { if (sa.getPayCosts() != null) {
if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) { if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) {
@@ -75,8 +77,7 @@ public class GameActionPlay {
final CostPayment payment = new CostPayment(sa.getPayCosts(), sa); final CostPayment payment = new CostPayment(sa.getPayCosts(), sa);
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment); final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment);
req.setFree(); req.fillRequirements(false, true, false);
req.fillRequirements();
} else { } else {
if (sa.isSpell()) { if (sa.isSpell()) {
final Card c = sa.getSourceCard(); final Card c = sa.getSourceCard();
@@ -356,8 +357,8 @@ public class GameActionPlay {
final Card source = sa.getSourceCard(); final Card source = sa.getSourceCard();
// Split card support if(source.isSplitCard())
setSplitCardState(source, sa); setSplitCardState(source, sa);
if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) { if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) {
CharmEffect.makeChoices(sa); CharmEffect.makeChoices(sa);
@@ -389,7 +390,7 @@ public class GameActionPlay {
} }
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment); final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment);
req.fillRequirements(); req.fillRequirements(false, false, false);
} else { } else {
ManaCostBeingPaid manaCost = new ManaCostBeingPaid(sa.getManaCost()); ManaCostBeingPaid manaCost = new ManaCostBeingPaid(sa.getManaCost());
if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) { if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) {
@@ -437,10 +438,8 @@ public class GameActionPlay {
} }
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment); final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment);
if( useOldTargets )
req.setAlreadyTargeted(); req.fillRequirements(useOldTargets, false, true);
req.setSkipStack();
req.fillRequirements();
} else { } else {
ManaCostBeingPaid manaCost = new ManaCostBeingPaid(sa.getManaCost()); ManaCostBeingPaid manaCost = new ManaCostBeingPaid(sa.getManaCost());
if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) { if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) {
@@ -492,21 +491,20 @@ public class GameActionPlay {
private void setSplitCardState(final Card source, SpellAbility sa) { private void setSplitCardState(final Card source, SpellAbility sa) {
// Split card support // Split card support
if (source.isSplitCard()) { List<SpellAbility> leftSplitAbilities = source.getState(CardCharacteristicName.LeftSplit).getSpellAbility();
List<SpellAbility> leftSplitAbilities = source.getState(CardCharacteristicName.LeftSplit).getSpellAbility(); List<SpellAbility> rightSplitAbilities = source.getState(CardCharacteristicName.RightSplit).getSpellAbility();
List<SpellAbility> rightSplitAbilities = source.getState(CardCharacteristicName.RightSplit).getSpellAbility(); for (SpellAbility a : leftSplitAbilities) {
for (SpellAbility a : leftSplitAbilities) { if (sa == a || sa.getDescription().equals(String.format("%s (without paying its mana cost)", a.getDescription()))) {
if (sa == a || sa.getDescription().equals(String.format("%s (without paying its mana cost)", a.getDescription()))) { source.setState(CardCharacteristicName.LeftSplit);
source.setState(CardCharacteristicName.LeftSplit); return;
break;
}
}
for (SpellAbility a : rightSplitAbilities) {
if (sa == a || sa.getDescription().equals(String.format("%s (without paying its mana cost)", a.getDescription()))) {
source.setState(CardCharacteristicName.RightSplit);
break;
}
} }
} }
for (SpellAbility a : rightSplitAbilities) {
if (sa == a || sa.getDescription().equals(String.format("%s (without paying its mana cost)", a.getDescription()))) {
source.setState(CardCharacteristicName.RightSplit);
return;
}
}
throw new RuntimeException("Not found which part to choose for ability " + sa + " from card " + source);
} }
} }