mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
PaidLists now store if the CostPart source is linked to host
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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<Card> 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 <Card> noList = Lists.newArrayList();
|
||||
Map<String, CardCollection> paidLists = sa.getPaidHash();
|
||||
Table<String, Boolean, CardCollection> 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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -5847,7 +5847,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
timesCrewedThisTurn += 1;
|
||||
Map<AbilityKey, Object> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -94,7 +94,7 @@ public class CostMill extends CostPart {
|
||||
Map<AbilityKey, Object> 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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
private List<SpellAbility> paidAbilities = Lists.newArrayList();
|
||||
private Integer xManaCostPaid = null;
|
||||
|
||||
private HashMap<String, CardCollection> paidLists = Maps.newHashMap();
|
||||
private TreeBasedTable<String, Boolean, CardCollection> paidLists = TreeBasedTable.create();
|
||||
|
||||
private EnumMap<AbilityKey, Object> triggeringObjects = AbilityKey.newMap();
|
||||
|
||||
@@ -688,22 +688,29 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
|
||||
// Combined PaidLists
|
||||
public Map<String, CardCollection> getPaidHash() {
|
||||
public TreeBasedTable<String, Boolean, CardCollection> getPaidHash() {
|
||||
return paidLists;
|
||||
}
|
||||
public void setPaidHash(final Map<String, CardCollection> hash) {
|
||||
paidLists = Maps.newHashMap(hash);
|
||||
public void setPaidHash(final TreeBasedTable<String, Boolean, CardCollection> 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<Card> 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);
|
||||
}
|
||||
paidLists.get(str).add(c);
|
||||
|
||||
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, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tr.isWithoutSameCreatureType()) {
|
||||
if (entity instanceof Card) {
|
||||
if (tr.isWithoutSameCreatureType() && 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) {
|
||||
if (tr.isWithSameCreatureType() && 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) {
|
||||
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)) {
|
||||
|
||||
@@ -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<String, CardCollection> paidHash;
|
||||
private final TreeBasedTable<String, Boolean, CardCollection> 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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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<String, CardCollection> hash) {
|
||||
public void setPaidHash(final TreeBasedTable<String, Boolean, CardCollection> hash) {
|
||||
sa.setPaidHash(hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, CardCollection> getPaidHash() {
|
||||
public TreeBasedTable<String, Boolean, CardCollection> 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
|
||||
|
||||
@@ -362,7 +362,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
if (sp.hasParam("Crew")) {
|
||||
// Trigger crews!
|
||||
runParams.put(AbilityKey.Vehicle, sp.getHostCard());
|
||||
runParams.put(AbilityKey.Crew, sp.getPaidList("TappedCards"));
|
||||
runParams.put(AbilityKey.Crew, sp.getPaidList("TappedCards", true));
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Crewed, runParams, false);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1347,10 +1347,10 @@ public final class CMatchUI
|
||||
enchantedEntityView = enchantedEntity.getView();
|
||||
numSmallImages++;
|
||||
} else if ((sa.getRootAbility() != null)
|
||||
&& (sa.getRootAbility().getPaidList("Sacrificed") != null)
|
||||
&& !sa.getRootAbility().getPaidList("Sacrificed").isEmpty()) {
|
||||
&& (sa.getRootAbility().getPaidList("Sacrificed", true) != null)
|
||||
&& !sa.getRootAbility().getPaidList("Sacrificed", true).isEmpty()) {
|
||||
// If the player activated its ability by sacrificing the enchantment, the enchantment has not anything attached anymore and the ex-enchanted card has to be searched in other ways.. for example, the green enchantment "Carapace"
|
||||
enchantedEntity = sa.getRootAbility().getPaidList("Sacrificed").get(0).getEnchantingCard();
|
||||
enchantedEntity = sa.getRootAbility().getPaidList("Sacrificed", true).get(0).getEnchantingCard();
|
||||
if (enchantedEntity != null) {
|
||||
enchantedEntityView = enchantedEntity.getView();
|
||||
numSmallImages++;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
Name:Barrin's Spite
|
||||
ManaCost:2 U B
|
||||
Types:Sorcery
|
||||
A:SP$ Pump | Cost$ 2 U B | ValidTgts$ Creature | TgtPrompt$ Choose two target creatures controlled by the same player | TargetMin$ 2 | TargetMax$ 2 | TargetUnique$ True | TargetsWithSameController$ True | IsCurse$ True | SubAbility$ DBChooseSac | StackDescription$ SpellDescription | SpellDescription$ Choose two target creatures controlled by the same player. Their controller chooses and sacrifices one of them. Return the other to its owner's hand.
|
||||
SVar:DBChooseSac:DB$ ChooseCard | DefinedCards$ Targeted | Defined$ TargetedController | ChoiceTitle$ Choose one to sacrifice | SubAbility$ DBSac | StackDescription$ None | AILogic$ WorstCard
|
||||
A:SP$ Pump | Cost$ 2 U B | ValidTgts$ Creature | TgtPrompt$ Choose two target creatures controlled by the same player | TargetMin$ 2 | TargetMax$ 2 | TargetUnique$ True | TargetsWithSameController$ True | RememberTargets$ True | IsCurse$ True | SubAbility$ DBChooseSac | StackDescription$ SpellDescription | SpellDescription$ Choose two target creatures controlled by the same player. Their controller chooses and sacrifices one of them. Return the other to its owner's hand.
|
||||
SVar:DBChooseSac:DB$ ChooseCard | Choices$ Card.IsRemembered | Defined$ TargetedController | ChoiceTitle$ Choose one to sacrifice | ForgetChosen$ True | SubAbility$ DBSac | StackDescription$ None | AILogic$ WorstCard
|
||||
SVar:DBSac:DB$ Destroy | Defined$ ChosenCard | Sacrifice$ True | SubAbility$ DBBounce | StackDescription$ None
|
||||
SVar:DBBounce:DB$ ChangeZone | Defined$ Targeted | Origin$ Battlefield | Destination$ Hand | StackDescription$ None
|
||||
SVar:DBBounce:DB$ ChangeZone | Defined$ Remembered | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBCleanup | StackDescription$ None
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
Oracle:Choose two target creatures controlled by the same player. Their controller chooses and sacrifices one of them. Return the other to its owner's hand.
|
||||
|
||||
Reference in New Issue
Block a user