mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +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);
|
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)) {
|
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).
|
// 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();
|
c = hostCard.getEnchantingCard();
|
||||||
if (c == null && sa instanceof SpellAbility) {
|
if (c == null && sa instanceof SpellAbility) {
|
||||||
SpellAbility root = ((SpellAbility)sa).getRootAbility();
|
SpellAbility root = ((SpellAbility)sa).getRootAbility();
|
||||||
CardCollection sacrificed = root.getPaidList("Sacrificed");
|
CardCollection sacrificed = root.getPaidList("Sacrificed", true);
|
||||||
if (sacrificed != null && !sacrificed.isEmpty()) {
|
if (sacrificed != null && !sacrificed.isEmpty()) {
|
||||||
c = sacrificed.getFirst().getEnchantingCard();
|
c = sacrificed.getFirst().getEnchantingCard();
|
||||||
}
|
}
|
||||||
@@ -742,29 +742,29 @@ public class AbilityUtils {
|
|||||||
} else { // these ones only for handling lists
|
} else { // these ones only for handling lists
|
||||||
Iterable<Card> list = null;
|
Iterable<Card> list = null;
|
||||||
if (calcX[0].startsWith("Sacrificed")) {
|
if (calcX[0].startsWith("Sacrificed")) {
|
||||||
list = sa.getRootAbility().getPaidList("Sacrificed");
|
list = sa.getRootAbility().getPaidList("Sacrificed", true);
|
||||||
}
|
}
|
||||||
else if (calcX[0].startsWith("Discarded")) {
|
else if (calcX[0].startsWith("Discarded")) {
|
||||||
final SpellAbility root = sa.getRootAbility();
|
final SpellAbility root = sa.getRootAbility();
|
||||||
list = root.getPaidList("Discarded");
|
list = root.getPaidList("Discarded", true);
|
||||||
if (null == list && root.isTrigger()) {
|
if (null == list && root.isTrigger()) {
|
||||||
list = root.getHostCard().getSpellPermanent().getPaidList("Discarded");
|
list = root.getHostCard().getSpellPermanent().getPaidList("Discarded", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (calcX[0].startsWith("Exiled")) {
|
else if (calcX[0].startsWith("Exiled")) {
|
||||||
list = sa.getRootAbility().getPaidList("Exiled");
|
list = sa.getRootAbility().getPaidList("Exiled", true);
|
||||||
}
|
}
|
||||||
else if (calcX[0].startsWith("Milled")) {
|
else if (calcX[0].startsWith("Milled")) {
|
||||||
list = sa.getRootAbility().getPaidList("Milled");
|
list = sa.getRootAbility().getPaidList("Milled", true);
|
||||||
}
|
}
|
||||||
else if (calcX[0].startsWith("Tapped")) {
|
else if (calcX[0].startsWith("Tapped")) {
|
||||||
list = sa.getRootAbility().getPaidList("Tapped");
|
list = sa.getRootAbility().getPaidList("Tapped", true);
|
||||||
}
|
}
|
||||||
else if (calcX[0].startsWith("Revealed")) {
|
else if (calcX[0].startsWith("Revealed")) {
|
||||||
list = sa.getRootAbility().getPaidList("Revealed");
|
list = sa.getRootAbility().getPaidList("Revealed", true);
|
||||||
}
|
}
|
||||||
else if (calcX[0].startsWith("Returned")) {
|
else if (calcX[0].startsWith("Returned")) {
|
||||||
list = sa.getRootAbility().getPaidList("Returned");
|
list = sa.getRootAbility().getPaidList("Returned", true);
|
||||||
}
|
}
|
||||||
else if (calcX[0].startsWith("Targeted")) {
|
else if (calcX[0].startsWith("Targeted")) {
|
||||||
list = sa.findTargetedCards();
|
list = sa.findTargetedCards();
|
||||||
@@ -1606,40 +1606,40 @@ public class AbilityUtils {
|
|||||||
|
|
||||||
if (sa.hasParam("RememberCostCards") && !sa.getPaidHash().isEmpty()) {
|
if (sa.hasParam("RememberCostCards") && !sa.getPaidHash().isEmpty()) {
|
||||||
List <Card> noList = Lists.newArrayList();
|
List <Card> noList = Lists.newArrayList();
|
||||||
Map<String, CardCollection> paidLists = sa.getPaidHash();
|
Table<String, Boolean, CardCollection> paidLists = sa.getPaidHash();
|
||||||
if (sa.hasParam("RememberCostExcept")) {
|
if (sa.hasParam("RememberCostExcept")) {
|
||||||
noList.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("RememberCostExcept"), sa));
|
noList.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("RememberCostExcept"), sa));
|
||||||
}
|
}
|
||||||
if (paidLists.containsKey("Exiled")) {
|
if (paidLists.contains("Exiled", true)) {
|
||||||
final CardCollection paidListExiled = sa.getPaidList("Exiled");
|
final CardCollection paidListExiled = sa.getPaidList("Exiled", true);
|
||||||
for (final Card exiledAsCost : paidListExiled) {
|
for (final Card exiledAsCost : paidListExiled) {
|
||||||
if (!noList.contains(exiledAsCost)) {
|
if (!noList.contains(exiledAsCost)) {
|
||||||
host.addRemembered(exiledAsCost);
|
host.addRemembered(exiledAsCost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (paidLists.containsKey("Sacrificed")) {
|
} else if (paidLists.contains("Sacrificed", true)) {
|
||||||
final CardCollection paidListSacrificed = sa.getPaidList("Sacrificed");
|
final CardCollection paidListSacrificed = sa.getPaidList("Sacrificed", true);
|
||||||
for (final Card sacrificedAsCost : paidListSacrificed) {
|
for (final Card sacrificedAsCost : paidListSacrificed) {
|
||||||
if (!noList.contains(sacrificedAsCost)) {
|
if (!noList.contains(sacrificedAsCost)) {
|
||||||
host.addRemembered(sacrificedAsCost);
|
host.addRemembered(sacrificedAsCost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (paidLists.containsKey("Tapped")) {
|
} else if (paidLists.contains("Tapped", true)) {
|
||||||
final CardCollection paidListTapped = sa.getPaidList("Tapped");
|
final CardCollection paidListTapped = sa.getPaidList("Tapped", true);
|
||||||
for (final Card tappedAsCost : paidListTapped) {
|
for (final Card tappedAsCost : paidListTapped) {
|
||||||
if (!noList.contains(tappedAsCost)) {
|
if (!noList.contains(tappedAsCost)) {
|
||||||
host.addRemembered(tappedAsCost);
|
host.addRemembered(tappedAsCost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (paidLists.containsKey("Unattached")) {
|
} else if (paidLists.contains("Unattached", true)) {
|
||||||
final CardCollection paidListUnattached = sa.getPaidList("Unattached");
|
final CardCollection paidListUnattached = sa.getPaidList("Unattached", true);
|
||||||
for (final Card unattachedAsCost : paidListUnattached) {
|
for (final Card unattachedAsCost : paidListUnattached) {
|
||||||
if (!noList.contains(unattachedAsCost)) {
|
if (!noList.contains(unattachedAsCost)) {
|
||||||
host.addRemembered(unattachedAsCost);
|
host.addRemembered(unattachedAsCost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (paidLists.containsKey("Discarded")) {
|
} else if (paidLists.contains("Discarded", true)) {
|
||||||
final CardCollection paidListDiscarded = sa.getPaidList("Discarded");
|
final CardCollection paidListDiscarded = sa.getPaidList("Discarded", true);
|
||||||
for (final Card discardedAsCost : paidListDiscarded) {
|
for (final Card discardedAsCost : paidListDiscarded) {
|
||||||
if (!noList.contains(discardedAsCost)) {
|
if (!noList.contains(discardedAsCost)) {
|
||||||
host.addRemembered(discardedAsCost);
|
host.addRemembered(discardedAsCost);
|
||||||
@@ -3860,29 +3860,29 @@ public class AbilityUtils {
|
|||||||
SpellAbility root = ((SpellAbility)sa).getRootAbility();
|
SpellAbility root = ((SpellAbility)sa).getRootAbility();
|
||||||
// TODO do we really need these checks?
|
// TODO do we really need these checks?
|
||||||
if (defined.startsWith("SacrificedCards")) {
|
if (defined.startsWith("SacrificedCards")) {
|
||||||
list = root.getPaidList("SacrificedCards");
|
list = root.getPaidList("SacrificedCards", true);
|
||||||
} else if (defined.startsWith("Sacrificed")) {
|
} else if (defined.startsWith("Sacrificed")) {
|
||||||
list = root.getPaidList("Sacrificed");
|
list = root.getPaidList("Sacrificed", true);
|
||||||
} else if (defined.startsWith("Revealed")) {
|
} else if (defined.startsWith("Revealed")) {
|
||||||
list = root.getPaidList("Revealed");
|
list = root.getPaidList("Revealed", true);
|
||||||
} else if (defined.startsWith("DiscardedCards")) {
|
} else if (defined.startsWith("DiscardedCards")) {
|
||||||
list = root.getPaidList("DiscardedCards");
|
list = root.getPaidList("DiscardedCards", true);
|
||||||
} else if (defined.startsWith("Discarded")) {
|
} else if (defined.startsWith("Discarded")) {
|
||||||
list = root.getPaidList("Discarded");
|
list = root.getPaidList("Discarded", true);
|
||||||
} else if (defined.startsWith("ExiledCards")) {
|
} else if (defined.startsWith("ExiledCards")) {
|
||||||
list = root.getPaidList("ExiledCards");
|
list = root.getPaidList("ExiledCards", true);
|
||||||
} else if (defined.startsWith("Exiled")) {
|
} else if (defined.startsWith("Exiled")) {
|
||||||
list = root.getPaidList("Exiled");
|
list = root.getPaidList("Exiled", true);
|
||||||
} else if (defined.startsWith("Milled")) {
|
} else if (defined.startsWith("Milled")) {
|
||||||
list = root.getPaidList("Milled");
|
list = root.getPaidList("Milled", true);
|
||||||
} else if (defined.startsWith("TappedCards")) {
|
} else if (defined.startsWith("TappedCards")) {
|
||||||
list = root.getPaidList("TappedCards");
|
list = root.getPaidList("TappedCards", true);
|
||||||
} else if (defined.startsWith("Tapped")) {
|
} else if (defined.startsWith("Tapped")) {
|
||||||
list = root.getPaidList("Tapped");
|
list = root.getPaidList("Tapped", true);
|
||||||
} else if (defined.startsWith("UntappedCards")) {
|
} else if (defined.startsWith("UntappedCards")) {
|
||||||
list = root.getPaidList("UntappedCards");
|
list = root.getPaidList("UntappedCards", true);
|
||||||
} else if (defined.startsWith("Untapped")) {
|
} else if (defined.startsWith("Untapped")) {
|
||||||
list = root.getPaidList("Untapped");
|
list = root.getPaidList("Untapped", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
|
|||||||
@@ -696,7 +696,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
if (sa.isNinjutsu()) {
|
if (sa.isNinjutsu()) {
|
||||||
// Ninjutsu need to get the Defender of the Returned Creature
|
// 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);
|
final GameEntity defender = game.getCombat().getDefenderByAttacker(returned);
|
||||||
game.getCombat().addAttacker(movedCard, defender);
|
game.getCombat().addAttacker(movedCard, defender);
|
||||||
game.getCombat().getBandOfAttacker(movedCard).setBlocked(false);
|
game.getCombat().getBandOfAttacker(movedCard).setBlocked(false);
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
|||||||
abCost = new Cost(cost, false);
|
abCost = new Cost(cost, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
tgtSA = tgtSA.copyWithDefinedCost(abCost);
|
tgtSA = tgtSA.copyWithManaCostReplaced(tgtSA.getActivatingPlayer(), abCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!optional) {
|
if (!optional) {
|
||||||
|
|||||||
@@ -5847,7 +5847,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
timesCrewedThisTurn += 1;
|
timesCrewedThisTurn += 1;
|
||||||
Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||||
runParams.put(AbilityKey.Vehicle, this);
|
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);
|
game.getTriggerHandler().runTrigger(TriggerType.BecomesCrewed, runParams, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -866,9 +866,9 @@ public class CardProperty {
|
|||||||
} else if (restriction.equals("MovedToGrave")) {
|
} else if (restriction.equals("MovedToGrave")) {
|
||||||
if (!(spellAbility instanceof SpellAbility)) {
|
if (!(spellAbility instanceof SpellAbility)) {
|
||||||
final SpellAbility root = ((SpellAbility) spellAbility).getRootAbility();
|
final SpellAbility root = ((SpellAbility) spellAbility).getRootAbility();
|
||||||
if (root != null && (root.getPaidList("MovedToGrave") != null)
|
if (root != null && (root.getPaidList("MovedToGrave", true) != null)
|
||||||
&& !root.getPaidList("MovedToGrave").isEmpty()) {
|
&& !root.getPaidList("MovedToGrave", true).isEmpty()) {
|
||||||
final CardCollectionView cards = root.getPaidList("MovedToGrave");
|
final CardCollectionView cards = root.getPaidList("MovedToGrave", true);
|
||||||
for (final Card c : cards) {
|
for (final Card c : cards) {
|
||||||
String name = c.getName();
|
String name = c.getName();
|
||||||
if (StringUtils.isEmpty(name)) {
|
if (StringUtils.isEmpty(name)) {
|
||||||
|
|||||||
@@ -210,6 +210,10 @@ public class Cost implements Serializable {
|
|||||||
costParts.add(new CostPartMana(cost, null));
|
costParts.add(new CostPartMana(cost, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Cost(String parse, final boolean bAbility) {
|
||||||
|
this(parse, bAbility, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Constructor for Cost.
|
* Constructor for Cost.
|
||||||
@@ -219,7 +223,7 @@ public class Cost implements Serializable {
|
|||||||
* @param bAbility
|
* @param bAbility
|
||||||
* a boolean.
|
* a boolean.
|
||||||
*/
|
*/
|
||||||
public Cost(String parse, final boolean bAbility) {
|
public Cost(String parse, final boolean bAbility, final boolean intrinsic) {
|
||||||
this.isAbility = bAbility;
|
this.isAbility = bAbility;
|
||||||
// when adding new costs for cost string, place them here
|
// when adding new costs for cost string, place them here
|
||||||
|
|
||||||
@@ -249,6 +253,9 @@ public class Cost implements Serializable {
|
|||||||
if (cp instanceof CostPartMana) {
|
if (cp instanceof CostPartMana) {
|
||||||
parsedMana = (CostPartMana) cp;
|
parsedMana = (CostPartMana) cp;
|
||||||
} else {
|
} else {
|
||||||
|
if (cp instanceof CostPartWithList) {
|
||||||
|
((CostPartWithList)cp).setIntrinsic(intrinsic);
|
||||||
|
}
|
||||||
this.costParts.add(cp);
|
this.costParts.add(cp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ public class CostAdjustment {
|
|||||||
count = 1;
|
count = 1;
|
||||||
}
|
}
|
||||||
if (count > 0) {
|
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);
|
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) {
|
public final boolean payAsDecided(final Player ai, final PaymentDecision decision, SpellAbility ability, final boolean effect) {
|
||||||
Game game = ai.getGame();
|
Game game = ai.getGame();
|
||||||
for (final SpellAbility sa : decision.sp) {
|
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);
|
SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(sa);
|
||||||
if (si != null) {
|
if (si != null) {
|
||||||
game.getStack().remove(si);
|
game.getStack().remove(si);
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ public class CostMill extends CostPart {
|
|||||||
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||||
moveParams.put(AbilityKey.LastStateBattlefield, ai.getGame().getLastStateBattlefield());
|
moveParams.put(AbilityKey.LastStateBattlefield, ai.getGame().getLastStateBattlefield());
|
||||||
moveParams.put(AbilityKey.LastStateGraveyard, ai.getGame().getLastStateGraveyard());
|
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);
|
table.triggerChangesZoneAll(ai.getGame(), ability);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,9 +127,9 @@ public class CostPartMana extends CostPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ManaCost getManaCostFor(SpellAbility sa) {
|
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
|
// 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()) {
|
if (isEnchantedCreatureCost() && sa.getHostCard().isEnchantingCard()) {
|
||||||
return sa.getHostCard().getEnchantingCard().getManaCost();
|
return sa.getHostCard().getEnchantingCard().getManaCost();
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ public abstract class CostPartWithList extends CostPart {
|
|||||||
private final CardCollection lkiList = new CardCollection();
|
private final CardCollection lkiList = new CardCollection();
|
||||||
protected final CardCollection cardList = new CardCollection();
|
protected final CardCollection cardList = new CardCollection();
|
||||||
|
|
||||||
|
private boolean intrinsic = true;
|
||||||
|
|
||||||
protected final CardZoneTable table = new CardZoneTable();
|
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 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
|
||||||
@@ -50,6 +52,10 @@ public abstract class CostPartWithList extends CostPart {
|
|||||||
return cardList;
|
return cardList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void setIntrinsic(boolean b) {
|
||||||
|
intrinsic = b;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset list.
|
* Reset list.
|
||||||
*/
|
*/
|
||||||
@@ -71,11 +77,11 @@ public abstract class CostPartWithList extends CostPart {
|
|||||||
}
|
}
|
||||||
final String lkiPaymentMethod = getHashForLKIList();
|
final String lkiPaymentMethod = getHashForLKIList();
|
||||||
for (final Card card : lkiList) {
|
for (final Card card : lkiList) {
|
||||||
sa.addCostToHashList(card, lkiPaymentMethod);
|
sa.addCostToHashList(card, lkiPaymentMethod, intrinsic);
|
||||||
}
|
}
|
||||||
final String cardPaymentMethod = getHashForCardList();
|
final String cardPaymentMethod = getHashForCardList();
|
||||||
for (final Card card : cardList) {
|
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 List<SpellAbility> paidAbilities = Lists.newArrayList();
|
||||||
private Integer xManaCostPaid = null;
|
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();
|
private EnumMap<AbilityKey, Object> triggeringObjects = AbilityKey.newMap();
|
||||||
|
|
||||||
@@ -688,22 +688,29 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Combined PaidLists
|
// Combined PaidLists
|
||||||
public Map<String, CardCollection> getPaidHash() {
|
public TreeBasedTable<String, Boolean, CardCollection> getPaidHash() {
|
||||||
return paidLists;
|
return paidLists;
|
||||||
}
|
}
|
||||||
public void setPaidHash(final Map<String, CardCollection> hash) {
|
public void setPaidHash(final TreeBasedTable<String, Boolean, CardCollection> hash) {
|
||||||
paidLists = Maps.newHashMap(hash);
|
paidLists = TreeBasedTable.create(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CardCollection getPaidList(final String str) {
|
// use if it doesn't matter if payment was caused by extrinsic cost modifier
|
||||||
return paidLists.get(str);
|
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)) {
|
public CardCollection getPaidList(final String str, final boolean intrinsic) {
|
||||||
paidLists.put(str, new CardCollection());
|
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() {
|
public void resetPaidHash() {
|
||||||
paidLists.clear();
|
paidLists.clear();
|
||||||
}
|
}
|
||||||
@@ -1364,67 +1371,56 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
soFar += c.getNetPower();
|
soFar += c.getNetPower();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (soFar > tr.getMaxTotalPower(getHostCard(),this)) {
|
if (soFar > tr.getMaxTotalPower(getHostCard(), this)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tr.isSameController()) {
|
if (tr.isSameController() && entity instanceof Card) {
|
||||||
Player newController;
|
Player newController;
|
||||||
if (entity instanceof Card) {
|
|
||||||
newController = ((Card) entity).getController();
|
newController = ((Card) entity).getController();
|
||||||
for (final Card c : targetChosen.getTargetCards()) {
|
for (final Card c : targetChosen.getTargetCards()) {
|
||||||
if (entity != c && !c.getController().equals(newController))
|
if (entity != c && !c.getController().equals(newController))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (tr.isDifferentControllers()) {
|
if (tr.isDifferentControllers() && entity instanceof Card) {
|
||||||
Player newController;
|
Player newController;
|
||||||
if (entity instanceof Card) {
|
|
||||||
newController = ((Card) entity).getController();
|
newController = ((Card) entity).getController();
|
||||||
for (final Card c : targetChosen.getTargetCards()) {
|
for (final Card c : targetChosen.getTargetCards()) {
|
||||||
if (entity != c && c.getController().equals(newController))
|
if (entity != c && c.getController().equals(newController))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (tr.isWithoutSameCreatureType()) {
|
if (tr.isWithoutSameCreatureType() && entity instanceof Card) {
|
||||||
if (entity instanceof Card) {
|
|
||||||
for (final Card c : targetChosen.getTargetCards()) {
|
for (final Card c : targetChosen.getTargetCards()) {
|
||||||
if (entity != c && c.sharesCreatureTypeWith((Card) entity)) {
|
if (entity != c && c.sharesCreatureTypeWith((Card) entity)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (tr.isWithSameCreatureType()) {
|
if (tr.isWithSameCreatureType() && entity instanceof Card) {
|
||||||
if (entity instanceof Card) {
|
|
||||||
for (final Card c : targetChosen.getTargetCards()) {
|
for (final Card c : targetChosen.getTargetCards()) {
|
||||||
if (entity != c && !c.sharesCreatureTypeWith((Card) entity)) {
|
if (entity != c && !c.sharesCreatureTypeWith((Card) entity)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (tr.isWithSameCardType()) {
|
if (tr.isWithSameCardType() && entity instanceof Card) {
|
||||||
if (entity instanceof Card) {
|
|
||||||
for (final Card c : targetChosen.getTargetCards()) {
|
for (final Card c : targetChosen.getTargetCards()) {
|
||||||
if (entity != c && !c.sharesCardTypeWith((Card) entity)) {
|
if (entity != c && !c.sharesCardTypeWith((Card) entity)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (entity instanceof GameEntity) {
|
if (entity instanceof GameEntity) {
|
||||||
String[] validTgt = tr.getValidTgts();
|
|
||||||
GameEntity e = (GameEntity)entity;
|
GameEntity e = (GameEntity)entity;
|
||||||
if (!e.isValid(validTgt, getActivatingPlayer(), getHostCard(), this)) {
|
if (!e.isValid(tr.getValidTgts(), getActivatingPlayer(), getHostCard(), this)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (hasParam("TargetType") && !e.isValid(getParam("TargetType").split(","), getActivatingPlayer(), getHostCard(), this)) {
|
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.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.common.collect.TreeBasedTable;
|
||||||
|
|
||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.IIdentifiable;
|
import forge.game.IIdentifiable;
|
||||||
@@ -85,7 +86,7 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView {
|
|||||||
private Integer xManaPaid = null;
|
private Integer xManaPaid = null;
|
||||||
|
|
||||||
// Other Paid things
|
// Other Paid things
|
||||||
private final Map<String, CardCollection> paidHash;
|
private final TreeBasedTable<String, Boolean, CardCollection> paidHash;
|
||||||
|
|
||||||
// Additional info
|
// Additional info
|
||||||
// is Kicked, is Buyback
|
// is Kicked, is Buyback
|
||||||
@@ -108,7 +109,7 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView {
|
|||||||
activatingPlayer = sa.getActivatingPlayer();
|
activatingPlayer = sa.getActivatingPlayer();
|
||||||
|
|
||||||
// Payment info
|
// Payment info
|
||||||
paidHash = Maps.newHashMap(ability.getPaidHash());
|
paidHash = TreeBasedTable.create(ability.getPaidHash());
|
||||||
ability.resetPaidHash();
|
ability.resetPaidHash();
|
||||||
splicedCards = sa.getSplicedCards();
|
splicedCards = sa.getSplicedCards();
|
||||||
|
|
||||||
|
|||||||
@@ -961,7 +961,7 @@ public final class StaticAbilityContinuous {
|
|||||||
AbilityUtils.getDefinedPlayers(affectedCard, params.get("MayPlayPlayer"), stAb).get(0) :
|
AbilityUtils.getDefinedPlayers(affectedCard, params.get("MayPlayPlayer"), stAb).get(0) :
|
||||||
controller;
|
controller;
|
||||||
affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost,
|
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);
|
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
|
// 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.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
@@ -404,8 +405,7 @@ public abstract class Trigger extends TriggerReplacementBase {
|
|||||||
}
|
}
|
||||||
} else if ("Sacrificed".equals(condition)) {
|
} else if ("Sacrificed".equals(condition)) {
|
||||||
final SpellAbility trigSA = (SpellAbility) runParams.get(AbilityKey.CastSA);
|
final SpellAbility trigSA = (SpellAbility) runParams.get(AbilityKey.CastSA);
|
||||||
if (trigSA != null &&
|
if (trigSA != null && Iterables.isEmpty(trigSA.getPaidList("Sacrificed"))) {
|
||||||
(trigSA.getPaidList("Sacrificed") == null || trigSA.getPaidList("Sacrificed").isEmpty())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if ("AttackedPlayerWithMostLife".equals(condition)) {
|
} else if ("AttackedPlayerWithMostLife".equals(condition)) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.TreeBasedTable;
|
||||||
|
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
@@ -108,23 +109,23 @@ public class WrappedAbility extends Ability {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPaidHash(final Map<String, CardCollection> hash) {
|
public void setPaidHash(final TreeBasedTable<String, Boolean, CardCollection> hash) {
|
||||||
sa.setPaidHash(hash);
|
sa.setPaidHash(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, CardCollection> getPaidHash() {
|
public TreeBasedTable<String, Boolean, CardCollection> getPaidHash() {
|
||||||
return sa.getPaidHash();
|
return sa.getPaidHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CardCollection getPaidList(final String str) {
|
public CardCollection getPaidList(final String str, boolean intrinsic) {
|
||||||
return sa.getPaidList(str);
|
return sa.getPaidList(str, intrinsic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCostToHashList(final Card c, final String str) {
|
public void addCostToHashList(final Card c, final String str, final boolean intrinsic) {
|
||||||
sa.addCostToHashList(c, str);
|
sa.addCostToHashList(c, str, intrinsic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -362,7 +362,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
if (sp.hasParam("Crew")) {
|
if (sp.hasParam("Crew")) {
|
||||||
// Trigger crews!
|
// Trigger crews!
|
||||||
runParams.put(AbilityKey.Vehicle, sp.getHostCard());
|
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);
|
game.getTriggerHandler().runTrigger(TriggerType.Crewed, runParams, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1347,10 +1347,10 @@ public final class CMatchUI
|
|||||||
enchantedEntityView = enchantedEntity.getView();
|
enchantedEntityView = enchantedEntity.getView();
|
||||||
numSmallImages++;
|
numSmallImages++;
|
||||||
} else if ((sa.getRootAbility() != null)
|
} else if ((sa.getRootAbility() != null)
|
||||||
&& (sa.getRootAbility().getPaidList("Sacrificed") != null)
|
&& (sa.getRootAbility().getPaidList("Sacrificed", true) != null)
|
||||||
&& !sa.getRootAbility().getPaidList("Sacrificed").isEmpty()) {
|
&& !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"
|
// 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) {
|
if (enchantedEntity != null) {
|
||||||
enchantedEntityView = enchantedEntity.getView();
|
enchantedEntityView = enchantedEntity.getView();
|
||||||
numSmallImages++;
|
numSmallImages++;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
Name:Barrin's Spite
|
Name:Barrin's Spite
|
||||||
ManaCost:2 U B
|
ManaCost:2 U B
|
||||||
Types:Sorcery
|
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.
|
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 | DefinedCards$ Targeted | Defined$ TargetedController | ChoiceTitle$ Choose one to sacrifice | SubAbility$ DBSac | StackDescription$ None | AILogic$ WorstCard
|
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: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.
|
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