diff --git a/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java index cff66313247..dcc351e65fc 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java @@ -2,6 +2,7 @@ package forge.game.ability.effects; import forge.game.Game; import forge.game.GameActionUtil; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.*; @@ -10,6 +11,7 @@ import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; import forge.game.player.PlayerPredicates; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; import forge.util.Lang; @@ -22,8 +24,8 @@ import org.apache.commons.lang3.StringUtils; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import java.util.ArrayList; import java.util.List; +import java.util.Map; public class DiscardEffect extends SpellAbilityEffect { @@ -109,7 +111,7 @@ public class DiscardEffect extends SpellAbilityEffect { final Game game = source.getGame(); //final boolean anyNumber = sa.hasParam("AnyNumber"); - final List discarded = new ArrayList<>(); + final List discarded = Lists.newArrayList(); final List targets = getTargetPlayers(sa), discarders; Player firstTarget = null; @@ -127,6 +129,8 @@ public class DiscardEffect extends SpellAbilityEffect { final CardZoneTable table = new CardZoneTable(); for (final Player p : discarders) { + boolean firstDiscard = p.getNumDiscardedThisTurn() == 0; + final CardCollection discardedByPlayer = new CardCollection(); if ((mode.equals("RevealTgtChoose") && firstTarget != null) || !sa.usesTargeting() || p.canBeTargetedBy(sa)) { if (sa.hasParam("RememberDiscarder") && p.canDiscardBy(sa)) { source.addRemembered(p); @@ -149,35 +153,28 @@ public class DiscardEffect extends SpellAbilityEffect { for (final Card c : toDiscard) { if (p.discard(c, sa, table) != null) { discarded.add(c); - } - } - - if (sa.hasParam("RememberDiscarded")) { - for (final Card c : discarded) { - source.addRemembered(c); + discardedByPlayer.add(c); } } } - continue; } if (mode.equals("Hand")) { if (!p.canDiscardBy(sa)) { continue; } - boolean shouldRemember = sa.hasParam("RememberDiscarded"); - CardCollectionView toDiscard = new CardCollection(Lists.newArrayList(p.getCardsIn(ZoneType.Hand))); + CardCollectionView toDiscard = p.getCardsIn(ZoneType.Hand); if (toDiscard.size() > 1) { toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard); } - for(Card c : toDiscard) { // without copying will get concurrent modification exception - boolean hasDiscarded = p.discard(c, sa, table) != null; - if( hasDiscarded && shouldRemember ) - source.addRemembered(c); + for(Card c : Lists.newArrayList(toDiscard)) { // without copying will get concurrent modification exception + if (p.discard(c, sa, table) != null) { + discarded.add(c); + discardedByPlayer.add(c); + } } - continue; } if (mode.equals("NotRemembered")) { @@ -192,6 +189,7 @@ public class DiscardEffect extends SpellAbilityEffect { for (final Card c : dPHand) { if (p.discard(c, sa, table) != null) { discarded.add(c); + discardedByPlayer.add(c); } } } @@ -231,6 +229,7 @@ public class DiscardEffect extends SpellAbilityEffect { for (Card c : toDiscardView) { if (p.discard(c, sa, table) != null) { discarded.add(c); + discardedByPlayer.add(c); } } } @@ -249,7 +248,10 @@ public class DiscardEffect extends SpellAbilityEffect { } for (Card c : toDiscard) { - c.getController().discard(c, sa, table); + if (c.getController().discard(c, sa, table) != null) { + discarded.add(c); + discardedByPlayer.add(c); + } } } } @@ -282,6 +284,7 @@ public class DiscardEffect extends SpellAbilityEffect { for (final Card c : dPChHand) { if (p.discard(c, sa, table) != null) { discarded.add(c); + discardedByPlayer.add(c); } } } else if (mode.equals("RevealYouChoose") || mode.equals("RevealTgtChoose") || mode.equals("TgtChoose")) { @@ -332,11 +335,21 @@ public class DiscardEffect extends SpellAbilityEffect { if (card == null) { continue; } if (p.discard(card, sa, table) != null) { discarded.add(card); + discardedByPlayer.add(card); } } } } } + + if (!discardedByPlayer.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Player, p); + runParams.put(AbilityKey.Cards, discardedByPlayer); + runParams.put(AbilityKey.Cause, sa); + runParams.put(AbilityKey.FirstTime, firstDiscard); + game.getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false); + } } if (sa.hasParam("RememberDiscarded")) { diff --git a/forge-game/src/main/java/forge/game/card/CardZoneTable.java b/forge-game/src/main/java/forge/game/card/CardZoneTable.java index 53e95605713..177cd669ba8 100644 --- a/forge-game/src/main/java/forge/game/card/CardZoneTable.java +++ b/forge-game/src/main/java/forge/game/card/CardZoneTable.java @@ -42,7 +42,7 @@ public class CardZoneTable extends ForwardingTable. */ package forge.game.cost; +import java.util.Map; + +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; @@ -24,6 +27,7 @@ import forge.game.card.CardLists; import forge.game.card.CardPredicates; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; import forge.util.TextUtil; @@ -35,6 +39,8 @@ public class CostDiscard extends CostPartWithList { // Inputs + protected boolean firstTime = false; + /** * Serializables need a version ID. */ @@ -42,7 +48,7 @@ public class CostDiscard extends CostPartWithList { /** * Instantiates a new cost discard. - * + * * @param amount * the amount * @param type @@ -58,7 +64,7 @@ public class CostDiscard extends CostPartWithList { /* * (non-Javadoc) - * + * * @see forge.card.cost.CostPart#toString() */ @Override @@ -98,7 +104,7 @@ public class CostDiscard extends CostPartWithList { /* * (non-Javadoc) - * + * * @see * forge.card.cost.CostPart#canPay(forge.card.spellability.SpellAbility, * forge.Card, forge.Player, forge.card.cost.Cost) @@ -181,4 +187,23 @@ public class CostDiscard extends CostPartWithList { public T accept(ICostVisitor visitor) { return visitor.visit(this); } + + protected void handleBeforePayment(Player ai, SpellAbility ability, CardCollectionView targetCards) { + firstTime = ai.getNumDiscardedThisTurn() == 0; + } + + @Override + protected void handleChangeZoneTrigger(Player payer, SpellAbility ability, CardCollectionView targetCards) { + super.handleChangeZoneTrigger(payer, ability, targetCards); + + if (!targetCards.isEmpty()) + { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Player, payer); + runParams.put(AbilityKey.Cards, new CardCollection(targetCards)); + runParams.put(AbilityKey.Cause, ability); + runParams.put(AbilityKey.FirstTime, firstTime); + payer.getGame().getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false); + } + } } diff --git a/forge-game/src/main/java/forge/game/cost/CostPartWithList.java b/forge-game/src/main/java/forge/game/cost/CostPartWithList.java index a8dabcbc86f..9679d84e262 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPartWithList.java +++ b/forge-game/src/main/java/forge/game/cost/CostPartWithList.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -45,7 +45,7 @@ public abstract class CostPartWithList extends CostPart { public final CardCollectionView getLKIList() { return lkiList; } - + public final CardCollectionView getCardList() { return cardList; } @@ -61,13 +61,16 @@ public abstract class CostPartWithList extends CostPart { /** * Adds the list to hash. - * + * * @param sa * the sa * @param hash * the hash */ public final void reportPaidCardsTo(final SpellAbility sa) { + if (sa == null) { + return; + } final String lkiPaymentMethod = getHashForLKIList(); for (final Card card : lkiList) { sa.addCostToHashList(card, lkiPaymentMethod); @@ -77,18 +80,18 @@ public abstract class CostPartWithList extends CostPart { sa.addCostToHashList(card, cardPaymentMethod); } } - - // public abstract List getValidCards(); + + // public abstract List getValidCards(); /** * Instantiates a new cost part with list. */ public CostPartWithList() { } - + /** * Instantiates a new cost part with list. - * + * * @param amount * the amount * @param type @@ -121,19 +124,19 @@ public abstract class CostPartWithList extends CostPart { } // always returns true, made this to inline with return - public boolean executePayment(SpellAbility ability, CardCollectionView targetCards) { + protected boolean executePayment(Player payer, SpellAbility ability, CardCollectionView targetCards) { + handleBeforePayment(payer, ability, targetCards); if (canPayListAtOnce()) { // This is used by reveal. Without it when opponent would reveal hand, you'll get N message boxes. for (Card c: targetCards) { lkiList.add(CardUtil.getLKICopy(c)); } cardList.addAll(doListPayment(ability, targetCards)); - handleChangeZoneTrigger(ability); - return true; + } else { + for (Card c: targetCards) { + executePayment(ability, c); + } } - for (Card c: targetCards) { - executePayment(ability, c); - } - handleChangeZoneTrigger(ability); + handleChangeZoneTrigger(payer, ability, targetCards); return true; } @@ -154,15 +157,19 @@ public abstract class CostPartWithList extends CostPart { */ public abstract String getHashForLKIList(); public abstract String getHashForCardList(); - + @Override public boolean payAsDecided(Player ai, PaymentDecision decision, SpellAbility ability) { - executePayment(ability, decision.cards); + executePayment(ai, ability, decision.cards); reportPaidCardsTo(ability); return true; } - protected void handleChangeZoneTrigger(SpellAbility ability) { + protected void handleBeforePayment(Player ai, SpellAbility ability, CardCollectionView targetCards) { + + } + + protected void handleChangeZoneTrigger(Player payer, SpellAbility ability, CardCollectionView targetCards) { if (table.isEmpty()) { return; } @@ -170,7 +177,7 @@ public abstract class CostPartWithList extends CostPart { // copy table because the original get cleaned after the cost is done final CardZoneTable copyTable = new CardZoneTable(); copyTable.putAll(table); - copyTable.triggerChangesZoneAll(ability.getHostCard().getGame()); + copyTable.triggerChangesZoneAll(payer.getGame()); } } diff --git a/forge-game/src/main/java/forge/game/cost/CostPutCounter.java b/forge-game/src/main/java/forge/game/cost/CostPutCounter.java index 63c64457ea2..5ce5d63305d 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPutCounter.java +++ b/forge-game/src/main/java/forge/game/cost/CostPutCounter.java @@ -164,7 +164,7 @@ public class CostPutCounter extends CostPartWithList { if (this.payCostFromSource()) { executePayment(ability, ability.getHostCard()); } else { - executePayment(ability, decision.cards); + executePayment(ai, ability, decision.cards); } triggerCounterPutAll(ability); return true; diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java index 18f69184042..7e6d63f464f 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -59,7 +59,7 @@ import java.util.*; *

* Phase class. *

- * + * * @author Forge * @version $Id: PhaseHandler.java 13001 2012-01-08 12:25:25Z Sloth $ */ @@ -369,10 +369,23 @@ public class PhaseHandler implements java.io.Serializable { if (numDiscard > 0) { final CardZoneTable table = new CardZoneTable(); + final CardCollection discarded = new CardCollection(); + boolean firstDiscarded = playerTurn.getNumDiscardedThisTurn() == 0; for (Card c : playerTurn.getController().chooseCardsToDiscardToMaximumHandSize(numDiscard)){ - playerTurn.discard(c, null, table); + if (playerTurn.discard(c, null, table) != null) { + discarded.add(c); + } } table.triggerChangesZoneAll(game); + + if (!discarded.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Player, playerTurn); + runParams.put(AbilityKey.Cards, discarded); + runParams.put(AbilityKey.Cause, null); + runParams.put(AbilityKey.FirstTime, firstDiscarded); + game.getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false); + } } // Rule 514.2 @@ -387,7 +400,6 @@ public class PhaseHandler implements java.io.Serializable { game.getEndOfTurn().registerUntilEndCommand(playerTurn); for (Player player : game.getPlayers()) { - player.onCleanupPhase(); player.getController().autoPassCancel(); // autopass won't wrap to next turn } for (Player player : game.getLostPlayers()) { @@ -439,7 +451,7 @@ public class PhaseHandler implements java.io.Serializable { for (Player p : game.getPlayers()) { int burn = p.getManaPool().clearPool(true).size(); - + boolean manaBurns = game.getRules().hasManaBurn(); if (manaBurns) { p.loseLife(burn,true); @@ -488,6 +500,10 @@ public class PhaseHandler implements java.io.Serializable { case CLEANUP: bPreventCombatDamageThisTurn = false; if (!bRepeatCleanup) { + // only call onCleanupPhase when Cleanup is not repeated + for (Player player : game.getPlayers()) { + player.onCleanupPhase(); + } setPlayerTurn(handleNextTurn()); // "Trigger" for begin turn to get around a phase skipping final Map runParams = AbilityKey.newMap(); @@ -736,7 +752,7 @@ public class PhaseHandler implements java.io.Serializable { runParams.put(AbilityKey.DefendingPlayer, combat.getDefenderPlayerByAttacker(a)); game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false); } - + // Run this trigger once for each blocker for (final Card b : blockers) { @@ -836,7 +852,7 @@ public class PhaseHandler implements java.io.Serializable { if (nextPlayer.hasKeyword("Skip your next turn.")) { nextPlayer.removeKeyword("Skip your next turn.", false); - if (extraTurn == null) { + if (extraTurn == null) { setPlayerTurn(nextPlayer); } return getNextActivePlayer(); @@ -861,7 +877,7 @@ public class PhaseHandler implements java.io.Serializable { return getNextActivePlayer(); } } - + if (extraTurn != null) { if (extraTurn.isSkipUntap()) { nextPlayer.addKeyword("Skip the untap step of this turn."); @@ -1015,7 +1031,7 @@ public class PhaseHandler implements java.io.Serializable { triggerList.put(originZone.getZoneType(), currentZone.getZoneType(), saHost); triggerList.triggerChangesZoneAll(game); } - + } loopCount++; } while (loopCount < 999 || !pPlayerPriority.getController().isAI()); diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDiscardedAll.java b/forge-game/src/main/java/forge/game/trigger/TriggerDiscardedAll.java new file mode 100644 index 00000000000..cb2837e71d6 --- /dev/null +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDiscardedAll.java @@ -0,0 +1,61 @@ +package forge.game.trigger; + +import java.util.Map; + +import forge.game.ability.AbilityKey; +import forge.game.card.Card; +import forge.game.card.CardCollection; +import forge.game.spellability.SpellAbility; +import forge.util.Localizer; + +public class TriggerDiscardedAll extends Trigger { + + public TriggerDiscardedAll(Map params, Card host, boolean intrinsic) { + super(params, host, intrinsic); + } + + @Override + public boolean performTest(Map runParams) { + if (hasParam("ValidPlayer")) { + if (!matchesValid(runParams.get(AbilityKey.Player), getParam("ValidPlayer").split(","), + this.getHostCard())) { + return false; + } + } + + if (hasParam("ValidCause")) { + if (runParams.get(AbilityKey.Cause) == null) { + return false; + } + if (!matchesValid(runParams.get(AbilityKey.Cause), getParam("ValidCause").split(","), + this.getHostCard())) { + return false; + } + } + + if (hasParam("FirstTime")) { + if (!(boolean) runParams.get(AbilityKey.FirstTime)) { + return false; + } + } + return true; + } + + @Override + public void setTriggeringObjects(SpellAbility sa, Map runParams) { + final CardCollection cards = (CardCollection) runParams.get(AbilityKey.Cards); + + sa.setTriggeringObject(AbilityKey.Cards, cards); + sa.setTriggeringObject(AbilityKey.Amount, cards.size()); + sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player, AbilityKey.Cause); + } + + @Override + public String getImportantStackObjects(SpellAbility sa) { + StringBuilder sb = new StringBuilder(); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.Amount)); + return sb.toString(); + } + +} diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerType.java b/forge-game/src/main/java/forge/game/trigger/TriggerType.java index b0f82c1c153..0f90c9b72c3 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerType.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerType.java @@ -52,6 +52,7 @@ public enum TriggerType { Destroyed(TriggerDestroyed.class), Devoured(TriggerDevoured.class), Discarded(TriggerDiscarded.class), + DiscardedAll(TriggerDiscardedAll.class), Drawn(TriggerDrawn.class), Evolved(TriggerEvolved.class), Exerted(TriggerExerted.class), diff --git a/forge-gui/res/cardsfolder/upcoming/rielle_the_everwise.txt b/forge-gui/res/cardsfolder/upcoming/rielle_the_everwise.txt new file mode 100644 index 00000000000..0a8a829ca3f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/rielle_the_everwise.txt @@ -0,0 +1,10 @@ +Name:Rielle, the Everwise +ManaCost:1 U R +Types:Legendary Creature Human Wizard +PT:0/3 +S:Mode$ Continuous | EffectZone$ Battlefield | AddPower$ X | References$ X | Description$ CARDNAME gets +1/+0 for each instant and sorcery card in your graveyard. +SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn +T:Mode$ DiscardedAll | FirstTime$ True | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever you discard one or more cards for the first time each turn, draw that many cards. +SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ Y | References$ Y +SVar:Y:TriggerCount$Amount +Oracle:Rielle, the Everwise gets +1/+0 for each instant and sorcery card in your graveyard.\nWhenever you discard one or more cards for the first time each turn, draw that many cards. diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index 7ba91c575e5..207f901b27b 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -380,7 +380,7 @@ public class HumanPlay { return false; } CardCollectionView listmill = p.getCardsIn(ZoneType.Library, amount); - ((CostMill) part).executePayment(sourceAbility, listmill); + ((CostMill) part).payAsDecided(p, PaymentDecision.card(listmill), sourceAbility); } else if (part instanceof CostFlipCoin) { final int amount = getAmountFromPart(part, source, sourceAbility); @@ -488,7 +488,7 @@ public class HumanPlay { return false; } - costExile.executePayment(sourceAbility, p.getCardsIn(ZoneType.Graveyard)); + costExile.payAsDecided(p, PaymentDecision.card(p.getCardsIn(ZoneType.Graveyard)), sourceAbility); } else { from = costExile.getFrom(); @@ -502,7 +502,7 @@ public class HumanPlay { return false; } list = list.subList(0, nNeeded); - costExile.executePayment(sourceAbility, list); + costExile.payAsDecided(p, PaymentDecision.card(list), sourceAbility); } else { // replace this with input CardCollection newList = new CardCollection(); @@ -515,7 +515,7 @@ public class HumanPlay { list.remove(c); newList.add(c); } - costExile.executePayment(sourceAbility, newList); + costExile.payAsDecided(p, PaymentDecision.card(newList), sourceAbility); } } } @@ -567,7 +567,7 @@ public class HumanPlay { } } else { // Tainted Specter, Gurzigost, etc. - boolean hasPaid = payCostPart(controller, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblPutIntoLibrary") + orString); + boolean hasPaid = payCostPart(controller, p, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblPutIntoLibrary") + orString); if (!hasPaid) { return false; } @@ -584,13 +584,13 @@ public class HumanPlay { else if (part instanceof CostGainControl) { int amount = Integer.parseInt(part.getAmount()); CardCollectionView list = CardLists.getValidCards(p.getGame().getCardsIn(ZoneType.Battlefield), part.getType(), p, source); - boolean hasPaid = payCostPart(controller, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblGainControl") + orString); + boolean hasPaid = payCostPart(controller, p, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblGainControl") + orString); if (!hasPaid) { return false; } } else if (part instanceof CostReturn) { CardCollectionView list = CardLists.getValidCards(p.getCardsIn(ZoneType.Battlefield), part.getType(), p, source); int amount = getAmountFromPartX(part, source, sourceAbility); - boolean hasPaid = payCostPart(controller, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblReturnToHand") + orString); + boolean hasPaid = payCostPart(controller, p, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblReturnToHand") + orString); if (!hasPaid) { return false; } } else if (part instanceof CostDiscard) { @@ -599,11 +599,11 @@ public class HumanPlay { return false; } - ((CostDiscard)part).executePayment(sourceAbility, p.getCardsIn(ZoneType.Hand)); + ((CostDiscard)part).payAsDecided(p, PaymentDecision.card(p.getCardsIn(ZoneType.Hand)), sourceAbility); } else { CardCollectionView list = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), part.getType(), p, source); int amount = getAmountFromPartX(part, source, sourceAbility); - boolean hasPaid = payCostPart(controller, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lbldiscard") + orString); + boolean hasPaid = payCostPart(controller, p, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lbldiscard") + orString); if (!hasPaid) { return false; } } } @@ -611,14 +611,14 @@ public class HumanPlay { CostReveal costReveal = (CostReveal) part; CardCollectionView list = CardLists.getValidCards(p.getCardsIn(costReveal.getRevealFrom()), part.getType(), p, source); int amount = getAmountFromPartX(part, source, sourceAbility); - boolean hasPaid = payCostPart(controller, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblReveal") + orString); + boolean hasPaid = payCostPart(controller, p, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblReveal") + orString); if (!hasPaid) { return false; } } else if (part instanceof CostTapType) { CardCollectionView list = CardLists.getValidCards(p.getCardsIn(ZoneType.Battlefield), part.getType(), p, source); list = CardLists.filter(list, Presets.UNTAPPED); int amount = getAmountFromPartX(part, source, sourceAbility); - boolean hasPaid = payCostPart(controller, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblTap") + orString); + boolean hasPaid = payCostPart(controller, p, sourceAbility, (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lblTap") + orString); if (!hasPaid) { return false; } } else if (part instanceof CostPartMana) { @@ -677,7 +677,7 @@ public class HumanPlay { return paid; } - private static boolean payCostPart(final PlayerControllerHuman controller, SpellAbility sourceAbility, CostPartWithList cpl, int amount, CardCollectionView list, String actionName) { + private static boolean payCostPart(final PlayerControllerHuman controller, Player p, SpellAbility sourceAbility, CostPartWithList cpl, int amount, CardCollectionView list, String actionName) { if (list.size() < amount) { return false; } // unable to pay (not enough cards) InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, amount, amount, list, sourceAbility); @@ -689,11 +689,8 @@ public class HumanPlay { return false; } - cpl.executePayment(sourceAbility, new CardCollection(inp.getSelected())); + cpl.payAsDecided(p, PaymentDecision.card(inp.getSelected()), sourceAbility); - if (sourceAbility != null) { - cpl.reportPaidCardsTo(sourceAbility); - } return true; }