Add: ability to refer to Cards with which costs were payed (eg. discard, sacrifice) by actual card,

in addition to LKI.

Relevant for example if you want to exile a sacrificed card on resolution (as Sword of the Ages does).
Existing functionality is not affected, only adds more Defined-clauses.
This commit is contained in:
elcnesh
2014-06-27 19:45:16 +00:00
parent d4ff20a5e7
commit d7aa626c45
26 changed files with 215 additions and 107 deletions

View File

@@ -1261,12 +1261,12 @@ public class GameAction {
return true; return true;
} }
public final boolean sacrifice(final Card c, final SpellAbility source) { public final Card sacrifice(final Card c, final SpellAbility source) {
if (!c.canBeSacrificedBy(source)) { if (!c.canBeSacrificedBy(source)) {
return false; return null;
} }
this.sacrificeDestroy(c); final Card newCard = this.sacrificeDestroy(c);
// Play the Sacrifice sound // Play the Sacrifice sound
game.fireEvent(new GameEventCardSacrificed()); game.fireEvent(new GameEventCardSacrificed());
@@ -1276,7 +1276,7 @@ public class GameAction {
runParams.put("Card", c); runParams.put("Card", c);
runParams.put("Cause", source); runParams.put("Cause", source);
game.getTriggerHandler().runTrigger(TriggerType.Sacrificed, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Sacrificed, runParams, false);
return true; return newCard;
} }
/** /**
@@ -1358,7 +1358,8 @@ public class GameAction {
runParams.put("Causer", activator); runParams.put("Causer", activator);
game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false);
return this.sacrificeDestroy(c); final Card sacrificed = this.sacrificeDestroy(c);
return sacrificed != null;
} }
/** /**
@@ -1413,11 +1414,12 @@ public class GameAction {
* *
* @param c * @param c
* a {@link forge.game.card.Card} object. * a {@link forge.game.card.Card} object.
* @return a boolean. * @return the sacrificed Card in its new location, or {@code null} if the
* sacrifice wasn't successful.
*/ */
public final boolean sacrificeDestroy(final Card c) { public final Card sacrificeDestroy(final Card c) {
if (!c.isInPlay()) { if (!c.isInPlay()) {
return false; return null;
} }
boolean persist = (c.hasKeyword("Persist") && c.getCounters(CounterType.M1M1) == 0) && !c.isToken(); boolean persist = (c.hasKeyword("Persist") && c.getCounters(CounterType.M1M1) == 0) && !c.isToken();
@@ -1464,7 +1466,7 @@ public class GameAction {
game.getStack().addSimultaneousStackEntry(undyingAb); game.getStack().addSimultaneousStackEntry(undyingAb);
} }
return true; return newCard;
} // sacrificeDestroy() } // sacrificeDestroy()
public void reveal(Collection<Card> cards, Player cardOwner) { public void reveal(Collection<Card> cards, Player cardOwner) {

View File

@@ -241,22 +241,37 @@ public class AbilityUtils {
} }
} else { } else {
List<Card> list = null; List<Card> list = null;
if (defined.startsWith("Sacrificed")) { if (defined.startsWith("SacrificedCards")) {
list = sa.getRootAbility().getPaidList("SacrificedCards");
}
else if (defined.startsWith("Sacrificed")) {
list = sa.getRootAbility().getPaidList("Sacrificed"); list = sa.getRootAbility().getPaidList("Sacrificed");
} }
else if (defined.startsWith("DiscardedCards")) {
list = sa.getRootAbility().getPaidList("DiscardedCards");
}
else if (defined.startsWith("Discarded")) { else if (defined.startsWith("Discarded")) {
list = sa.getRootAbility().getPaidList("Discarded"); list = sa.getRootAbility().getPaidList("Discarded");
} }
else if (defined.startsWith("ExiledCards")) {
list = sa.getRootAbility().getPaidList("ExiledCards");
}
else if (defined.startsWith("Exiled")) { else if (defined.startsWith("Exiled")) {
list = sa.getRootAbility().getPaidList("Exiled"); list = sa.getRootAbility().getPaidList("Exiled");
} }
else if (defined.startsWith("TappedCards")) {
list = sa.getRootAbility().getPaidList("TappedCards");
}
else if (defined.startsWith("Tapped")) { else if (defined.startsWith("Tapped")) {
list = sa.getRootAbility().getPaidList("Tapped"); list = sa.getRootAbility().getPaidList("Tapped");
} }
else if (defined.startsWith("UntappedCards")) {
list = sa.getRootAbility().getPaidList("UntappedCards");
}
else if (defined.startsWith("Untapped")) { else if (defined.startsWith("Untapped")) {
list = sa.getRootAbility().getPaidList("Untapped"); list = sa.getRootAbility().getPaidList("Untapped");
} }

View File

@@ -96,7 +96,7 @@ public class DestroyEffect extends SpellAbilityEffect {
boolean destroyed = false; boolean destroyed = false;
final Card lki = CardUtil.getLKICopy(tgtC); final Card lki = CardUtil.getLKICopy(tgtC);
if (sac) { if (sac) {
destroyed = game.getAction().sacrifice(tgtC, sa); destroyed = game.getAction().sacrifice(tgtC, sa) != null;
} else if (noRegen) { } else if (noRegen) {
destroyed = game.getAction().destroyNoRegeneration(tgtC, sa); destroyed = game.getAction().destroyNoRegeneration(tgtC, sa);
} else { } else {
@@ -115,7 +115,7 @@ public class DestroyEffect extends SpellAbilityEffect {
if (unTgtC.isInPlay()) { if (unTgtC.isInPlay()) {
boolean destroyed = false; boolean destroyed = false;
if (sac) { if (sac) {
destroyed = game.getAction().sacrifice(unTgtC, sa); destroyed = game.getAction().sacrifice(unTgtC, sa) != null;
} else if (noRegen) { } else if (noRegen) {
destroyed = game.getAction().destroyNoRegeneration(unTgtC, sa); destroyed = game.getAction().destroyNoRegeneration(unTgtC, sa);
} else { } else {

View File

@@ -104,7 +104,7 @@ public class DiscardEffect extends SpellAbilityEffect {
if (runDiscard) { if (runDiscard) {
final List<Card> toDiscard = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa); final List<Card> toDiscard = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa);
for (final Card c : toDiscard) { for (final Card c : toDiscard) {
boolean hasDiscarded = p.discard(c, sa); boolean hasDiscarded = p.discard(c, sa) != null;
if (hasDiscarded) { if (hasDiscarded) {
discarded.add(c); discarded.add(c);
} }
@@ -122,7 +122,7 @@ public class DiscardEffect extends SpellAbilityEffect {
if (mode.equals("Hand")) { if (mode.equals("Hand")) {
boolean shouldRemember = sa.hasParam("RememberDiscarded"); boolean shouldRemember = sa.hasParam("RememberDiscarded");
for(Card c : Lists.newArrayList(p.getCardsIn(ZoneType.Hand))) { // without copying will get concurrent modification exception for(Card c : Lists.newArrayList(p.getCardsIn(ZoneType.Hand))) { // without copying will get concurrent modification exception
boolean hasDiscarded = p.discard(c, sa); boolean hasDiscarded = p.discard(c, sa) != null;
if( hasDiscarded && shouldRemember ) if( hasDiscarded && shouldRemember )
source.addRemembered(c); source.addRemembered(c);
} }
@@ -161,7 +161,7 @@ public class DiscardEffect extends SpellAbilityEffect {
break; break;
final Card disc = Aggregates.random(list); final Card disc = Aggregates.random(list);
if ( p.discard(disc, sa) ) if (p.discard(disc, sa) != null)
discarded.add(disc); discarded.add(disc);
list.remove(disc); list.remove(disc);
} }

View File

@@ -62,7 +62,7 @@ public class SacrificeAllEffect extends SpellAbilityEffect {
} }
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
if (game.getAction().sacrifice(list.get(i), sa) && remSacrificed) { if (game.getAction().sacrifice(list.get(i), sa) != null && remSacrificed) {
card.addRemembered(list.get(i)); card.addRemembered(list.get(i));
} }
} }

View File

@@ -64,7 +64,7 @@ public class SacrificeEffect extends SpellAbilityEffect {
if (valid.equals("Self")) { if (valid.equals("Self")) {
if (game.getZoneOf(card).is(ZoneType.Battlefield)) { if (game.getZoneOf(card).is(ZoneType.Battlefield)) {
if (game.getAction().sacrifice(card, sa) && remSacrificed) { if (game.getAction().sacrifice(card, sa) != null && remSacrificed) {
card.addRemembered(card); card.addRemembered(card);
} }
} }
@@ -89,7 +89,7 @@ public class SacrificeEffect extends SpellAbilityEffect {
for(Card sac : choosenToSacrifice) { for(Card sac : choosenToSacrifice) {
final Card lKICopy = CardUtil.getLKICopy(sac); final Card lKICopy = CardUtil.getLKICopy(sac);
boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa); boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa) != null;
boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa); boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa);
// Run Devour Trigger // Run Devour Trigger
if (devour) { if (devour) {

View File

@@ -150,17 +150,20 @@ public class CostDiscard extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.getController().discard(targetCard, ability); return targetCard.getController().discard(targetCard, ability);
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Discarded"; return "Discarded";
} }
public String getHashForCardList() {
return "DiscardedCards";
}
@Override @Override
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -194,23 +194,24 @@ public class CostExile extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
Game game = targetCard.getGame(); final Game game = targetCard.getGame();
return game.getAction().exile(targetCard);
game.getAction().exile(targetCard);
} }
public static final String HashListKey = "Exiled"; public static final String HashLKIListKey = "Exiled";
public static final String HashCardListKey = "ExiledCards";
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
// TODO Auto-generated method stub return HashLKIListKey;
return HashListKey; }
@Override
public String getHashForCardList() {
return HashCardListKey;
} }
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@@ -69,9 +69,13 @@ public class CostExiledMoveToGrave extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "MovedToGrave"; return "MovedToGrave";
} }
@Override
public String getHashForCardList() {
return "MovedToGraveCards";
}
/* /*
* (non-Javadoc) * (non-Javadoc)
@@ -107,8 +111,8 @@ public class CostExiledMoveToGrave extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.getGame().getAction().moveToGraveyard(targetCard); return targetCard.getGame().getAction().moveToGraveyard(targetCard);
} }
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -41,9 +41,13 @@ public class CostFlipCoin extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Flipped"; return "Flipped";
} }
@Override
public String getHashForCardList() {
return "FlippedCards";
}
/* /*
* (non-Javadoc) * (non-Javadoc)
@@ -66,10 +70,11 @@ public class CostFlipCoin extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
final Player activator = ability.getActivatingPlayer(); final Player activator = ability.getActivatingPlayer();
int i = FlipCoinEffect.getFilpMultiplier(activator); int i = FlipCoinEffect.getFilpMultiplier(activator);
FlipCoinEffect.flipCoinCall(activator, ability, i); FlipCoinEffect.flipCoinCall(activator, ability, i);
return targetCard;
} }
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -88,17 +88,22 @@ public class CostGainControl extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.setController(ability.getActivatingPlayer(), ability.getActivatingPlayer().getGame().getNextTimestamp()); targetCard.setController(ability.getActivatingPlayer(), ability.getActivatingPlayer().getGame().getNextTimestamp());
return targetCard;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "ControllGained"; // why the hell double "L"? return "ControllGained"; // why the hell double "L"?
} }
@Override
public String getHashForCardList() {
return "ControlGainedCards";
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@@ -45,9 +45,13 @@ public class CostMill extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Milled"; return "Milled";
} }
@Override
public String getHashForCardList() {
return "MilledCards";
}
/* /*
* (non-Javadoc) * (non-Javadoc)
@@ -106,8 +110,8 @@ public class CostMill extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.getGame().getAction().moveToGraveyard(targetCard); return targetCard.getGame().getAction().moveToGraveyard(targetCard);
} }
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -116,8 +116,8 @@ public class CostPartMana extends CostPart {
} }
public ManaCost getManaCostFor(SpellAbility sa) { public ManaCost getManaCostFor(SpellAbility sa) {
if ( isExiledCreatureCost() && !sa.getPaidList(CostExile.HashListKey).isEmpty()) // back from the brink if ( isExiledCreatureCost() && !sa.getPaidList(CostExile.HashLKIListKey).isEmpty()) // back from the brink
return sa.getPaidList(CostExile.HashListKey).get(0).getManaCost(); return sa.getPaidList(CostExile.HashLKIListKey).get(0).getManaCost();
else else
return getManaToPay(); return getManaToPay();
} }

View File

@@ -17,22 +17,25 @@
*/ */
package forge.game.cost; package forge.game.cost;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.Lists;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardUtil; import forge.game.card.CardUtil;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/** /**
* The Class CostPartWithList. * The Class CostPartWithList.
*/ */
public abstract class CostPartWithList extends CostPart { public abstract class CostPartWithList extends CostPart {
/** The list. */ /** The lists: one for LKI, one for the actual cards. */
private final List<Card> list = new ArrayList<Card>(); private final List<Card> lkiList = Lists.newArrayList(),
cardList = Lists.newArrayList();
// set is here because executePayment() adds card to list, while ai's decide payment does the same thing. // set is here because executePayment() adds card to list, while ai's decide payment does the same thing.
// set allows to avoid duplication // set allows to avoid duplication
@@ -41,19 +44,20 @@ public abstract class CostPartWithList extends CostPart {
* *
* @return the list * @return the list
*/ */
public final List<Card> getList() { public final List<Card> getLKIList() {
return this.list; return this.lkiList;
}
public final List<Card> getCardList() {
return this.cardList;
} }
/** /**
* Reset list. * Reset list.
*/ */
public final void resetList() { public final void resetLists() {
this.list.clear(); this.lkiList.clear();
} this.cardList.clear();
protected final void addToList(final Card c) {
this.list.add(c);
} }
/** /**
@@ -65,9 +69,13 @@ public abstract class CostPartWithList extends CostPart {
* the hash * the hash
*/ */
public final void reportPaidCardsTo(final SpellAbility sa) { public final void reportPaidCardsTo(final SpellAbility sa) {
final String paymentMethod = getHashForList(); final String lkiPaymentMethod = getHashForLKIList();
for (final Card card : this.list) { for (final Card card : this.lkiList) {
sa.addCostToHashList(card, paymentMethod); sa.addCostToHashList(card, lkiPaymentMethod);
}
final String cardPaymentMethod = getHashForCardList();
for (final Card card : this.cardList) {
sa.addCostToHashList(card, cardPaymentMethod);
} }
} }
@@ -94,16 +102,18 @@ public abstract class CostPartWithList extends CostPart {
} }
public final boolean executePayment(SpellAbility ability, Card targetCard) { public final boolean executePayment(SpellAbility ability, Card targetCard) {
this.list.add(CardUtil.getLKICopy(targetCard)); this.lkiList.add(CardUtil.getLKICopy(targetCard));
doPayment(ability, targetCard); final Card newCard = doPayment(ability, targetCard);
this.cardList.add(newCard);
return true; return true;
} }
// always returns true, made this to inline with return // always returns true, made this to inline with return
public final boolean executePayment(SpellAbility ability, Collection<Card> targetCards) { public final boolean executePayment(SpellAbility ability, Collection<Card> targetCards) {
if(canPayListAtOnce()) { // This is used by reveal. Without it when opponent would reveal hand, you'll get N message boxes. if(canPayListAtOnce()) { // This is used by reveal. Without it when opponent would reveal hand, you'll get N message boxes.
this.list.addAll(targetCards); this.lkiList.addAll(targetCards);
doListPayment(ability, targetCards); final Collection<Card> newCards = doListPayment(ability, targetCards);
this.cardList.addAll(newCards);
return true; return true;
} }
for(Card c: targetCards) for(Card c: targetCards)
@@ -111,16 +121,23 @@ public abstract class CostPartWithList extends CostPart {
return true; return true;
} }
protected abstract void doPayment(SpellAbility ability, Card targetCard); /**
* Do a payment with a single card.
* @param ability the {@link SpellAbility} to pay for.
* @param targetCard the {@link Card} to pay with.
* @return The physical card after the payment.
*/
protected abstract Card doPayment(SpellAbility ability, Card targetCard);
// Overload these two only together, set to true and perform payment on list // Overload these two only together, set to true and perform payment on list
protected boolean canPayListAtOnce() { return false; } protected boolean canPayListAtOnce() { return false; }
protected void doListPayment(SpellAbility ability, Collection<Card> targetCards) { }; protected Collection<Card> doListPayment(SpellAbility ability, Collection<Card> targetCards) { return Collections.emptyList(); };
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @return * @return
*/ */
public abstract String getHashForList(); public abstract String getHashForLKIList();
public abstract String getHashForCardList();
@Override @Override
public boolean payAsDecided(Player ai, PaymentDecision decision, SpellAbility ability) { public boolean payAsDecided(Player ai, PaymentDecision decision, SpellAbility ability) {

View File

@@ -144,7 +144,7 @@ public class CostPayment {
// this clears lists used for undo. // this clears lists used for undo.
for (final CostPart part1 : this.paidCostParts) { for (final CostPart part1 : this.paidCostParts) {
if (part1 instanceof CostPartWithList) { if (part1 instanceof CostPartWithList) {
((CostPartWithList) part1).resetList(); ((CostPartWithList) part1).resetLists();
} }
} }
return true; return true;
@@ -176,7 +176,7 @@ public class CostPayment {
} }
// abilities care what was used to pay for them // abilities care what was used to pay for them
if( part instanceof CostPartWithList ) { if( part instanceof CostPartWithList ) {
((CostPartWithList) part).resetList(); ((CostPartWithList) part).resetLists();
} }
} }
return true; return true;

View File

@@ -133,9 +133,13 @@ public class CostPutCardToLib extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "CardPutToLib"; return "CardPutToLib";
} }
@Override
public String getHashForCardList() {
return "CardPutToLibCards";
}
/* /*
* (non-Javadoc) * (non-Javadoc)
@@ -195,8 +199,8 @@ public class CostPutCardToLib extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.getGame().getAction().moveToLibrary(targetCard, Integer.parseInt(getLibPos())); return targetCard.getGame().getAction().moveToLibrary(targetCard, Integer.parseInt(getLibPos()));
} }

View File

@@ -112,7 +112,7 @@ public class CostPutCounter extends CostPartWithList {
if(this.payCostFromSource()) if(this.payCostFromSource())
source.subtractCounter(this.counter, this.lastPaidAmount); source.subtractCounter(this.counter, this.lastPaidAmount);
else else
for (final Card c : this.getList()) { for (final Card c : this.getCardList()) {
c.subtractCounter(this.counter, 1); c.subtractCounter(this.counter, 1);
} }
} }
@@ -177,8 +177,9 @@ public class CostPutCounter extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard){ protected Card doPayment(SpellAbility ability, Card targetCard){
targetCard.addCounter(this.getCounter(), 1, false); targetCard.addCounter(this.getCounter(), 1, false);
return targetCard;
} }
protected void executePayment(SpellAbility ability, Card targetCard, int c) { protected void executePayment(SpellAbility ability, Card targetCard, int c) {
@@ -196,9 +197,13 @@ public class CostPutCounter extends CostPartWithList {
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "CounterPut"; return "CounterPut";
} }
@Override
public String getHashForCardList() {
return "CounterPutCards";
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@@ -60,9 +60,13 @@ public class CostRemoveAnyCounter extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "CounterRemove"; return "CounterRemove";
} }
@Override
public String getHashForCardList() {
return "CounterRemoveCards";
}
/** /**
* Gets the counter. * Gets the counter.
@@ -146,8 +150,9 @@ public class CostRemoveAnyCounter extends CostPartWithList {
} }
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard){ protected Card doPayment(SpellAbility ability, Card targetCard){
targetCard.subtractCounter(this.getCounter(), 1); targetCard.subtractCounter(this.getCounter(), 1);
return targetCard;
} }
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -18,6 +18,7 @@
package forge.game.cost; package forge.game.cost;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CounterType; import forge.game.card.CounterType;
@@ -104,8 +105,8 @@ public class CostRemoveCounter extends CostPartWithList {
*/ */
@Override @Override
public final void refund(final Card source) { public final void refund(final Card source) {
int refund = this.getList().size() == 1 ? this.cntRemoved : 1; // is wrong for Ooze Flux and Novijen Sages int refund = this.getCardList().size() == 1 ? this.cntRemoved : 1; // is wrong for Ooze Flux and Novijen Sages
for (final Card c : this.getList()) { for (final Card c : this.getCardList()) {
c.addCounter(this.counter, refund, false); c.addCounter(this.counter, refund, false);
} }
} }
@@ -162,17 +163,22 @@ public class CostRemoveCounter extends CostPartWithList {
} }
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard){ protected Card doPayment(SpellAbility ability, Card targetCard){
targetCard.subtractCounter(this.counter, cntRemoved); targetCard.subtractCounter(this.counter, cntRemoved);
return targetCard;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "CounterRemove"; return "CounterRemove";
} }
@Override
public String getHashForCardList() {
return "CounterRemoveCards";
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@@ -110,17 +110,21 @@ public class CostReturn extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.getGame().getAction().moveToHand(targetCard); return targetCard.getGame().getAction().moveToHand(targetCard);
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Returned"; return "Returned";
} }
@Override
public String getHashForCardList() {
return "ReturnedCards";
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -19,6 +19,7 @@ package forge.game.cost;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.player.Player; import forge.game.player.Player;
@@ -147,24 +148,30 @@ public class CostReveal extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.getGame().getAction().reveal(Lists.newArrayList(targetCard), ability.getActivatingPlayer()); targetCard.getGame().getAction().reveal(Lists.newArrayList(targetCard), ability.getActivatingPlayer());
return targetCard;
} }
@Override protected boolean canPayListAtOnce() { return true; } @Override protected boolean canPayListAtOnce() { return true; }
@Override @Override
protected void doListPayment(SpellAbility ability, Collection<Card> targetCards) { protected Collection<Card> doListPayment(SpellAbility ability, Collection<Card> targetCards) {
ability.getActivatingPlayer().getGame().getAction().reveal(targetCards, ability.getActivatingPlayer()); ability.getActivatingPlayer().getGame().getAction().reveal(targetCards, ability.getActivatingPlayer());
return targetCards;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Revealed"; return "Revealed";
} }
@Override
public String getHashForCardList() {
return "RevealedCards";
}
// Inputs // Inputs
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -116,17 +116,21 @@ public class CostSacrifice extends CostPartWithList {
} }
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.getGame().getAction().sacrifice(targetCard, ability); return targetCard.getGame().getAction().sacrifice(targetCard, ability);
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Sacrificed"; return "Sacrificed";
} }
@Override
public String getHashForCardList() {
return "SacrificedCards";
}
// Inputs // Inputs
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -18,6 +18,7 @@
package forge.game.cost; package forge.game.cost;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
@@ -89,11 +90,11 @@ public class CostTapType extends CostPartWithList {
*/ */
@Override @Override
public final void refund(final Card source) { public final void refund(final Card source) {
for (final Card c : this.getList()) { for (final Card c : this.getCardList()) {
c.setTapped(false); c.setTapped(false);
} }
this.getList().clear(); this.getCardList().clear();
} }
/* /*
@@ -162,17 +163,22 @@ public class CostTapType extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.tap(); targetCard.tap();
return targetCard;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Tapped"; return "Tapped";
} }
@Override
public String getHashForCardList() {
return "TappedCards";
}
// Inputs // Inputs
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -110,14 +110,19 @@ public class CostUnattach extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.unEquipCard(targetCard.getEquipping().get(0)); targetCard.unEquipCard(targetCard.getEquipping().get(0));
return targetCard;
} }
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Unattached"; return "Unattached";
} }
@Override
public String getHashForCardList() {
return "UnattachedCards";
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {

View File

@@ -84,11 +84,11 @@ public class CostUntapType extends CostPartWithList {
*/ */
@Override @Override
public final void refund(final Card source) { public final void refund(final Card source) {
for (final Card c : this.getList()) { for (final Card c : this.getCardList()) {
c.setTapped(true); c.setTapped(true);
} }
this.getList().clear(); this.resetLists();
} }
/* /*
@@ -123,17 +123,22 @@ public class CostUntapType extends CostPartWithList {
* @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card) * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
*/ */
@Override @Override
protected void doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
targetCard.untap(); targetCard.untap();
return targetCard;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.cost.CostPartWithList#getHashForList() * @see forge.card.cost.CostPartWithList#getHashForList()
*/ */
@Override @Override
public String getHashForList() { public String getHashForLKIList() {
return "Untapped"; return "Untapped";
} }
@Override
public String getHashForCardList() {
return "UntappedCards";
}
public <T> T accept(ICostVisitor<T> visitor) { public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@@ -1591,9 +1591,9 @@ public class Player extends GameEntity implements Comparable<Player> {
* a {@link forge.game.card.Card} object. * a {@link forge.game.card.Card} object.
* @param sa * @param sa
* a {@link forge.game.spellability.SpellAbility} object. * a {@link forge.game.spellability.SpellAbility} object.
* @return a {@link forge.CardList} object. * @return the discarded {@link Card} in its new location.
*/ */
public final boolean discard(final Card c, final SpellAbility sa) { public final Card discard(final Card c, final SpellAbility sa) {
// TODO: This line should be moved inside CostPayment somehow // TODO: This line should be moved inside CostPayment somehow
/*if (sa != null) { /*if (sa != null) {
sa.addCostToHashList(c, "Discarded"); sa.addCostToHashList(c, "Discarded");
@@ -1608,19 +1608,20 @@ public class Player extends GameEntity implements Comparable<Player> {
repRunParams.put("Affected", this); repRunParams.put("Affected", this);
if (game.getReplacementHandler().run(repRunParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(repRunParams) != ReplacementResult.NotReplaced) {
return false; return null;
} }
boolean discardToTopOfLibrary = null != sa && sa.hasParam("DiscardToTopOfLibrary"); boolean discardToTopOfLibrary = null != sa && sa.hasParam("DiscardToTopOfLibrary");
boolean discardMadness = sa != null && sa.hasParam("Madness"); boolean discardMadness = sa != null && sa.hasParam("Madness");
final Card newCard;
if (discardToTopOfLibrary) { if (discardToTopOfLibrary) {
game.getAction().moveToLibrary(c, 0); newCard = game.getAction().moveToLibrary(c, 0);
// Play the Discard sound // Play the Discard sound
} else if (discardMadness) { } else if (discardMadness) {
game.getAction().exile(c); newCard = game.getAction().exile(c);
} else { } else {
game.getAction().moveToGraveyard(c); newCard = game.getAction().moveToGraveyard(c);
// Play the Discard sound // Play the Discard sound
} }
this.numDiscardedThisTurn++; this.numDiscardedThisTurn++;
@@ -1635,8 +1636,8 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("Cause", cause); runParams.put("Cause", cause);
runParams.put("IsMadness", (Boolean) discardMadness); runParams.put("IsMadness", (Boolean) discardMadness);
game.getTriggerHandler().runTrigger(TriggerType.Discarded, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Discarded, runParams, false);
return true;
return newCard;
} }
/** /**