diff --git a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java index 625eac69eec..6d9f1305da9 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java @@ -172,7 +172,7 @@ public class PlayAi extends SpellAbilityAi { abCost = new Cost(sa.getParam("PlayCost"), false); } - spell = (Spell) spell.copyWithDefinedCost(abCost); + spell = (Spell) spell.copyWithManaCostReplaced(spell.getActivatingPlayer(), abCost); } if (AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlayFromEffectAI(spell, !(isOptional || sa.hasParam("Optional")), true)) { // Before accepting, see if the spell has a valid number of targets (it should at this point). diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 341024825be..5fce377cdf4 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -144,7 +144,7 @@ public class AbilityUtils { c = hostCard.getEnchantingCard(); if (c == null && sa instanceof SpellAbility) { SpellAbility root = ((SpellAbility)sa).getRootAbility(); - CardCollection sacrificed = root.getPaidList("Sacrificed"); + CardCollection sacrificed = root.getPaidList("Sacrificed", true); if (sacrificed != null && !sacrificed.isEmpty()) { c = sacrificed.getFirst().getEnchantingCard(); } @@ -742,29 +742,29 @@ public class AbilityUtils { } else { // these ones only for handling lists Iterable list = null; if (calcX[0].startsWith("Sacrificed")) { - list = sa.getRootAbility().getPaidList("Sacrificed"); + list = sa.getRootAbility().getPaidList("Sacrificed", true); } else if (calcX[0].startsWith("Discarded")) { final SpellAbility root = sa.getRootAbility(); - list = root.getPaidList("Discarded"); + list = root.getPaidList("Discarded", true); if (null == list && root.isTrigger()) { - list = root.getHostCard().getSpellPermanent().getPaidList("Discarded"); + list = root.getHostCard().getSpellPermanent().getPaidList("Discarded", true); } } else if (calcX[0].startsWith("Exiled")) { - list = sa.getRootAbility().getPaidList("Exiled"); + list = sa.getRootAbility().getPaidList("Exiled", true); } else if (calcX[0].startsWith("Milled")) { - list = sa.getRootAbility().getPaidList("Milled"); + list = sa.getRootAbility().getPaidList("Milled", true); } else if (calcX[0].startsWith("Tapped")) { - list = sa.getRootAbility().getPaidList("Tapped"); + list = sa.getRootAbility().getPaidList("Tapped", true); } else if (calcX[0].startsWith("Revealed")) { - list = sa.getRootAbility().getPaidList("Revealed"); + list = sa.getRootAbility().getPaidList("Revealed", true); } else if (calcX[0].startsWith("Returned")) { - list = sa.getRootAbility().getPaidList("Returned"); + list = sa.getRootAbility().getPaidList("Returned", true); } else if (calcX[0].startsWith("Targeted")) { list = sa.findTargetedCards(); @@ -1606,40 +1606,40 @@ public class AbilityUtils { if (sa.hasParam("RememberCostCards") && !sa.getPaidHash().isEmpty()) { List noList = Lists.newArrayList(); - Map paidLists = sa.getPaidHash(); + Table paidLists = sa.getPaidHash(); if (sa.hasParam("RememberCostExcept")) { noList.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("RememberCostExcept"), sa)); } - if (paidLists.containsKey("Exiled")) { - final CardCollection paidListExiled = sa.getPaidList("Exiled"); + if (paidLists.contains("Exiled", true)) { + final CardCollection paidListExiled = sa.getPaidList("Exiled", true); for (final Card exiledAsCost : paidListExiled) { if (!noList.contains(exiledAsCost)) { host.addRemembered(exiledAsCost); } } - } else if (paidLists.containsKey("Sacrificed")) { - final CardCollection paidListSacrificed = sa.getPaidList("Sacrificed"); + } else if (paidLists.contains("Sacrificed", true)) { + final CardCollection paidListSacrificed = sa.getPaidList("Sacrificed", true); for (final Card sacrificedAsCost : paidListSacrificed) { if (!noList.contains(sacrificedAsCost)) { host.addRemembered(sacrificedAsCost); } } - } else if (paidLists.containsKey("Tapped")) { - final CardCollection paidListTapped = sa.getPaidList("Tapped"); + } else if (paidLists.contains("Tapped", true)) { + final CardCollection paidListTapped = sa.getPaidList("Tapped", true); for (final Card tappedAsCost : paidListTapped) { if (!noList.contains(tappedAsCost)) { host.addRemembered(tappedAsCost); } } - } else if (paidLists.containsKey("Unattached")) { - final CardCollection paidListUnattached = sa.getPaidList("Unattached"); + } else if (paidLists.contains("Unattached", true)) { + final CardCollection paidListUnattached = sa.getPaidList("Unattached", true); for (final Card unattachedAsCost : paidListUnattached) { if (!noList.contains(unattachedAsCost)) { host.addRemembered(unattachedAsCost); } } - } else if (paidLists.containsKey("Discarded")) { - final CardCollection paidListDiscarded = sa.getPaidList("Discarded"); + } else if (paidLists.contains("Discarded", true)) { + final CardCollection paidListDiscarded = sa.getPaidList("Discarded", true); for (final Card discardedAsCost : paidListDiscarded) { if (!noList.contains(discardedAsCost)) { host.addRemembered(discardedAsCost); @@ -3860,29 +3860,29 @@ public class AbilityUtils { SpellAbility root = ((SpellAbility)sa).getRootAbility(); // TODO do we really need these checks? if (defined.startsWith("SacrificedCards")) { - list = root.getPaidList("SacrificedCards"); + list = root.getPaidList("SacrificedCards", true); } else if (defined.startsWith("Sacrificed")) { - list = root.getPaidList("Sacrificed"); + list = root.getPaidList("Sacrificed", true); } else if (defined.startsWith("Revealed")) { - list = root.getPaidList("Revealed"); + list = root.getPaidList("Revealed", true); } else if (defined.startsWith("DiscardedCards")) { - list = root.getPaidList("DiscardedCards"); + list = root.getPaidList("DiscardedCards", true); } else if (defined.startsWith("Discarded")) { - list = root.getPaidList("Discarded"); + list = root.getPaidList("Discarded", true); } else if (defined.startsWith("ExiledCards")) { - list = root.getPaidList("ExiledCards"); + list = root.getPaidList("ExiledCards", true); } else if (defined.startsWith("Exiled")) { - list = root.getPaidList("Exiled"); + list = root.getPaidList("Exiled", true); } else if (defined.startsWith("Milled")) { - list = root.getPaidList("Milled"); + list = root.getPaidList("Milled", true); } else if (defined.startsWith("TappedCards")) { - list = root.getPaidList("TappedCards"); + list = root.getPaidList("TappedCards", true); } else if (defined.startsWith("Tapped")) { - list = root.getPaidList("Tapped"); + list = root.getPaidList("Tapped", true); } else if (defined.startsWith("UntappedCards")) { - list = root.getPaidList("UntappedCards"); + list = root.getPaidList("UntappedCards", true); } else if (defined.startsWith("Untapped")) { - list = root.getPaidList("Untapped"); + list = root.getPaidList("Untapped", true); } } return list; diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 05849f13f90..5151cba7bd9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -696,7 +696,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } if (sa.isNinjutsu()) { // Ninjutsu need to get the Defender of the Returned Creature - final Card returned = sa.getPaidList("Returned").getFirst(); + final Card returned = sa.getPaidList("Returned", true).getFirst(); final GameEntity defender = game.getCombat().getDefenderByAttacker(returned); game.getCombat().addAttacker(movedCard, defender); game.getCombat().getBandOfAttacker(movedCard).setBlocked(false); diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index 6d88ba2795f..1863b2564d1 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -371,7 +371,7 @@ public class PlayEffect extends SpellAbilityEffect { abCost = new Cost(cost, false); } - tgtSA = tgtSA.copyWithDefinedCost(abCost); + tgtSA = tgtSA.copyWithManaCostReplaced(tgtSA.getActivatingPlayer(), abCost); } if (!optional) { diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 984f8e3174a..67abd8f9e15 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -5847,7 +5847,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { timesCrewedThisTurn += 1; Map runParams = AbilityKey.newMap(); runParams.put(AbilityKey.Vehicle, this); - runParams.put(AbilityKey.Crew, sa.getPaidList("TappedCards")); + runParams.put(AbilityKey.Crew, sa.getPaidList("TappedCards", true)); game.getTriggerHandler().runTrigger(TriggerType.BecomesCrewed, runParams, false); } diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index e184ad6b358..3d2d41bb368 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -866,9 +866,9 @@ public class CardProperty { } else if (restriction.equals("MovedToGrave")) { if (!(spellAbility instanceof SpellAbility)) { final SpellAbility root = ((SpellAbility) spellAbility).getRootAbility(); - if (root != null && (root.getPaidList("MovedToGrave") != null) - && !root.getPaidList("MovedToGrave").isEmpty()) { - final CardCollectionView cards = root.getPaidList("MovedToGrave"); + if (root != null && (root.getPaidList("MovedToGrave", true) != null) + && !root.getPaidList("MovedToGrave", true).isEmpty()) { + final CardCollectionView cards = root.getPaidList("MovedToGrave", true); for (final Card c : cards) { String name = c.getName(); if (StringUtils.isEmpty(name)) { diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java index 27037e37814..9c8db14b398 100644 --- a/forge-game/src/main/java/forge/game/cost/Cost.java +++ b/forge-game/src/main/java/forge/game/cost/Cost.java @@ -210,6 +210,10 @@ public class Cost implements Serializable { costParts.add(new CostPartMana(cost, null)); } + public Cost(String parse, final boolean bAbility) { + this(parse, bAbility, true); + } + /** *

* Constructor for Cost. @@ -219,7 +223,7 @@ public class Cost implements Serializable { * @param bAbility * a boolean. */ - public Cost(String parse, final boolean bAbility) { + public Cost(String parse, final boolean bAbility, final boolean intrinsic) { this.isAbility = bAbility; // when adding new costs for cost string, place them here @@ -249,6 +253,9 @@ public class Cost implements Serializable { if (cp instanceof CostPartMana) { parsedMana = (CostPartMana) cp; } else { + if (cp instanceof CostPartWithList) { + ((CostPartWithList)cp).setIntrinsic(intrinsic); + } this.costParts.add(cp); } else diff --git a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java index e60806b2c6d..98e03914cd9 100644 --- a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java +++ b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java @@ -161,7 +161,7 @@ public class CostAdjustment { count = 1; } if (count > 0) { - Cost part = new Cost(scost, sa.isAbility()); + Cost part = new Cost(scost, sa.isAbility(), sa.getHostCard().equals(hostCard)); cost.mergeTo(part, count); } } diff --git a/forge-game/src/main/java/forge/game/cost/CostExileFromStack.java b/forge-game/src/main/java/forge/game/cost/CostExileFromStack.java index 22c81129328..98ae0998eee 100644 --- a/forge-game/src/main/java/forge/game/cost/CostExileFromStack.java +++ b/forge-game/src/main/java/forge/game/cost/CostExileFromStack.java @@ -105,7 +105,7 @@ public class CostExileFromStack extends CostPart { public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) { Game game = ai.getGame(); for (final SpellAbility sa : decision.sp) { - ability.addCostToHashList(CardUtil.getLKICopy(sa.getHostCard()), "Exiled"); + ability.addCostToHashList(CardUtil.getLKICopy(sa.getHostCard()), "Exiled", true); SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(sa); if (si != null) { game.getStack().remove(si); diff --git a/forge-game/src/main/java/forge/game/cost/CostMill.java b/forge-game/src/main/java/forge/game/cost/CostMill.java index 16c8dad0747..328319c02ae 100644 --- a/forge-game/src/main/java/forge/game/cost/CostMill.java +++ b/forge-game/src/main/java/forge/game/cost/CostMill.java @@ -94,7 +94,7 @@ public class CostMill extends CostPart { Map moveParams = AbilityKey.newMap(); moveParams.put(AbilityKey.LastStateBattlefield, ai.getGame().getLastStateBattlefield()); moveParams.put(AbilityKey.LastStateGraveyard, ai.getGame().getLastStateGraveyard()); - ability.getPaidHash().put("Milled", (CardCollection) ai.mill(decision.c, ZoneType.Graveyard, false, ability, table, moveParams)); + ability.getPaidHash().put("Milled", true, (CardCollection) ai.mill(decision.c, ZoneType.Graveyard, false, ability, table, moveParams)); table.triggerChangesZoneAll(ai.getGame(), ability); return true; } diff --git a/forge-game/src/main/java/forge/game/cost/CostPartMana.java b/forge-game/src/main/java/forge/game/cost/CostPartMana.java index 47562d35ea7..3004e99030f 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPartMana.java +++ b/forge-game/src/main/java/forge/game/cost/CostPartMana.java @@ -127,9 +127,9 @@ public class CostPartMana extends CostPart { } public ManaCost getManaCostFor(SpellAbility sa) { - if (isExiledCreatureCost() && sa.getPaidList(CostExile.HashLKIListKey)!= null && !sa.getPaidList(CostExile.HashLKIListKey).isEmpty()) { + if (isExiledCreatureCost() && sa.getPaidList(CostExile.HashLKIListKey, true)!= null && !sa.getPaidList(CostExile.HashLKIListKey, true).isEmpty()) { // back from the brink - return sa.getPaidList(CostExile.HashLKIListKey).get(0).getManaCost(); + return sa.getPaidList(CostExile.HashLKIListKey, true).get(0).getManaCost(); } if (isEnchantedCreatureCost() && sa.getHostCard().isEnchantingCard()) { return sa.getHostCard().getEnchantingCard().getManaCost(); 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 cc5265b62d8..8eedbe26a73 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPartWithList.java +++ b/forge-game/src/main/java/forge/game/cost/CostPartWithList.java @@ -38,6 +38,8 @@ public abstract class CostPartWithList extends CostPart { private final CardCollection lkiList = new CardCollection(); protected final CardCollection cardList = new CardCollection(); + private boolean intrinsic = true; + protected final CardZoneTable table = new CardZoneTable(); // set is here because executePayment() adds card to list, while ai's decide payment does the same thing. // set allows to avoid duplication @@ -50,6 +52,10 @@ public abstract class CostPartWithList extends CostPart { return cardList; } + public final void setIntrinsic(boolean b) { + intrinsic = b; + } + /** * Reset list. */ @@ -71,11 +77,11 @@ public abstract class CostPartWithList extends CostPart { } final String lkiPaymentMethod = getHashForLKIList(); for (final Card card : lkiList) { - sa.addCostToHashList(card, lkiPaymentMethod); + sa.addCostToHashList(card, lkiPaymentMethod, intrinsic); } final String cardPaymentMethod = getHashForCardList(); for (final Card card : cardList) { - sa.addCostToHashList(card, cardPaymentMethod); + sa.addCostToHashList(card, cardPaymentMethod, intrinsic); } } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 61a52200332..1a4563b0a76 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -147,7 +147,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit private List paidAbilities = Lists.newArrayList(); private Integer xManaCostPaid = null; - private HashMap paidLists = Maps.newHashMap(); + private TreeBasedTable paidLists = TreeBasedTable.create(); private EnumMap triggeringObjects = AbilityKey.newMap(); @@ -688,22 +688,29 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit } // Combined PaidLists - public Map getPaidHash() { + public TreeBasedTable getPaidHash() { return paidLists; } - public void setPaidHash(final Map hash) { - paidLists = Maps.newHashMap(hash); + public void setPaidHash(final TreeBasedTable hash) { + paidLists = TreeBasedTable.create(hash); } - public CardCollection getPaidList(final String str) { - return paidLists.get(str); + // use if it doesn't matter if payment was caused by extrinsic cost modifier + public Iterable getPaidList(final String str) { + return Iterables.concat(paidLists.row(str).values()); } - public void addCostToHashList(final Card c, final String str) { - if (!paidLists.containsKey(str)) { - paidLists.put(str, new CardCollection()); + + public CardCollection getPaidList(final String str, final boolean intrinsic) { + return paidLists.get(str, intrinsic); + } + + public void addCostToHashList(final Card c, final String str, final boolean intrinsic) { + if (!paidLists.contains(str, intrinsic)) { + paidLists.put(str, intrinsic, new CardCollection()); } - paidLists.get(str).add(c); + paidLists.get(str, intrinsic).add(c); } + public void resetPaidHash() { paidLists.clear(); } @@ -1364,67 +1371,56 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit soFar += c.getNetPower(); } - if (soFar > tr.getMaxTotalPower(getHostCard(),this)) { + if (soFar > tr.getMaxTotalPower(getHostCard(), this)) { return false; } } - if (tr.isSameController()) { + if (tr.isSameController() && entity instanceof Card) { Player newController; - if (entity instanceof Card) { - newController = ((Card) entity).getController(); - for (final Card c : targetChosen.getTargetCards()) { - if (entity != c && !c.getController().equals(newController)) - return false; - } + newController = ((Card) entity).getController(); + for (final Card c : targetChosen.getTargetCards()) { + if (entity != c && !c.getController().equals(newController)) + return false; } } - if (tr.isDifferentControllers()) { + if (tr.isDifferentControllers() && entity instanceof Card) { Player newController; - if (entity instanceof Card) { - newController = ((Card) entity).getController(); - for (final Card c : targetChosen.getTargetCards()) { - if (entity != c && c.getController().equals(newController)) - return false; + newController = ((Card) entity).getController(); + for (final Card c : targetChosen.getTargetCards()) { + if (entity != c && c.getController().equals(newController)) + return false; + } + } + + if (tr.isWithoutSameCreatureType() && entity instanceof Card) { + for (final Card c : targetChosen.getTargetCards()) { + if (entity != c && c.sharesCreatureTypeWith((Card) entity)) { + return false; } } } - if (tr.isWithoutSameCreatureType()) { - if (entity instanceof Card) { - for (final Card c : targetChosen.getTargetCards()) { - if (entity != c && c.sharesCreatureTypeWith((Card) entity)) { - return false; - } + if (tr.isWithSameCreatureType() && entity instanceof Card) { + for (final Card c : targetChosen.getTargetCards()) { + if (entity != c && !c.sharesCreatureTypeWith((Card) entity)) { + return false; } } } - if (tr.isWithSameCreatureType()) { - if (entity instanceof Card) { - for (final Card c : targetChosen.getTargetCards()) { - if (entity != c && !c.sharesCreatureTypeWith((Card) entity)) { - return false; - } - } - } - } - - if (tr.isWithSameCardType()) { - if (entity instanceof Card) { - for (final Card c : targetChosen.getTargetCards()) { - if (entity != c && !c.sharesCardTypeWith((Card) entity)) { - return false; - } + if (tr.isWithSameCardType() && entity instanceof Card) { + for (final Card c : targetChosen.getTargetCards()) { + if (entity != c && !c.sharesCardTypeWith((Card) entity)) { + return false; } } } if (entity instanceof GameEntity) { - String[] validTgt = tr.getValidTgts(); GameEntity e = (GameEntity)entity; - if (!e.isValid(validTgt, getActivatingPlayer(), getHostCard(), this)) { + if (!e.isValid(tr.getValidTgts(), getActivatingPlayer(), getHostCard(), this)) { return false; } if (hasParam("TargetType") && !e.isValid(getParam("TargetType").split(","), getActivatingPlayer(), getHostCard(), this)) { diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityStackInstance.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityStackInstance.java index 297f541acf1..9acc3182347 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityStackInstance.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityStackInstance.java @@ -27,6 +27,7 @@ import org.apache.commons.lang3.StringUtils; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.common.collect.TreeBasedTable; import forge.game.GameObject; import forge.game.IIdentifiable; @@ -85,7 +86,7 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView { private Integer xManaPaid = null; // Other Paid things - private final Map paidHash; + private final TreeBasedTable paidHash; // Additional info // is Kicked, is Buyback @@ -108,7 +109,7 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView { activatingPlayer = sa.getActivatingPlayer(); // Payment info - paidHash = Maps.newHashMap(ability.getPaidHash()); + paidHash = TreeBasedTable.create(ability.getPaidHash()); ability.resetPaidHash(); splicedCards = sa.getSplicedCards(); diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index 254141be1ca..e48be012c71 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -961,7 +961,7 @@ public final class StaticAbilityContinuous { AbilityUtils.getDefinedPlayers(affectedCard, params.get("MayPlayPlayer"), stAb).get(0) : controller; affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost, - mayPlayAltCost != null ? new Cost(mayPlayAltCost, false) : null, additional, mayPlayWithFlash, + mayPlayAltCost != null ? new Cost(mayPlayAltCost, false, affectedCard.equals(hostCard)) : null, additional, mayPlayWithFlash, mayPlayGrantZonePermissions, stAb); // If the MayPlay effect only affected itself, check if it is in graveyard and give other player who cast Shaman's Trance MayPlay diff --git a/forge-game/src/main/java/forge/game/trigger/Trigger.java b/forge-game/src/main/java/forge/game/trigger/Trigger.java index d9d9e999f0f..a6ffb80ed22 100644 --- a/forge-game/src/main/java/forge/game/trigger/Trigger.java +++ b/forge-game/src/main/java/forge/game/trigger/Trigger.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -404,8 +405,7 @@ public abstract class Trigger extends TriggerReplacementBase { } } else if ("Sacrificed".equals(condition)) { final SpellAbility trigSA = (SpellAbility) runParams.get(AbilityKey.CastSA); - if (trigSA != null && - (trigSA.getPaidList("Sacrificed") == null || trigSA.getPaidList("Sacrificed").isEmpty())) { + if (trigSA != null && Iterables.isEmpty(trigSA.getPaidList("Sacrificed"))) { return false; } } else if ("AttackedPlayerWithMostLife".equals(condition)) { diff --git a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java index fa2e9d1b6df..ccf8c4533be 100644 --- a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java +++ b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java @@ -7,6 +7,7 @@ import java.util.Set; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; +import com.google.common.collect.TreeBasedTable; import forge.card.mana.ManaCost; import forge.game.Game; @@ -108,23 +109,23 @@ public class WrappedAbility extends Ability { } @Override - public void setPaidHash(final Map hash) { + public void setPaidHash(final TreeBasedTable hash) { sa.setPaidHash(hash); } @Override - public Map getPaidHash() { + public TreeBasedTable getPaidHash() { return sa.getPaidHash(); } @Override - public CardCollection getPaidList(final String str) { - return sa.getPaidList(str); + public CardCollection getPaidList(final String str, boolean intrinsic) { + return sa.getPaidList(str, intrinsic); } @Override - public void addCostToHashList(final Card c, final String str) { - sa.addCostToHashList(c, str); + public void addCostToHashList(final Card c, final String str, final boolean intrinsic) { + sa.addCostToHashList(c, str, intrinsic); } @Override diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index 2dd330f274f..1ab877cf45d 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -362,7 +362,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable