Merge branch '1842-panharmonicon-trigger-lingering' into 'master'

Resolve "Panharmonicon trigger lingering"

Closes #1842

See merge request core-developers/forge!4708
This commit is contained in:
Michael Kamensky
2021-06-12 12:57:51 +00:00
30 changed files with 164 additions and 121 deletions

View File

@@ -1880,7 +1880,7 @@ public class ComputerUtilMana {
final Card offering = sa.getSacrificedAsOffering(); final Card offering = sa.getSacrificedAsOffering();
offering.setUsedToPay(false); offering.setUsedToPay(false);
if (costIsPaid && !test) { if (costIsPaid && !test) {
sa.getHostCard().getGame().getAction().sacrifice(offering, sa, null); sa.getHostCard().getGame().getAction().sacrifice(offering, sa, null, null);
} }
sa.resetSacrificedAsOffering(); sa.resetSacrificedAsOffering();
} }
@@ -1888,7 +1888,7 @@ public class ComputerUtilMana {
final Card emerge = sa.getSacrificedAsEmerge(); final Card emerge = sa.getSacrificedAsEmerge();
emerge.setUsedToPay(false); emerge.setUsedToPay(false);
if (costIsPaid && !test) { if (costIsPaid && !test) {
sa.getHostCard().getGame().getAction().sacrifice(emerge, sa, null); sa.getHostCard().getGame().getAction().sacrifice(emerge, sa, null, null);
} }
sa.resetSacrificedAsEmerge(); sa.resetSacrificedAsEmerge();
} }

View File

@@ -24,7 +24,7 @@ import forge.game.zone.ZoneType;
public class DestroyAi extends SpellAbilityAi { public class DestroyAi extends SpellAbilityAi {
@Override @Override
public boolean chkAIDrawback(SpellAbility sa, Player ai) { public boolean chkAIDrawback(SpellAbility sa, Player ai) {
return canPlayAI(ai, sa); return checkApiLogic(ai, sa);
} }
@Override @Override

View File

@@ -488,7 +488,32 @@ public class PumpAi extends PumpAiBase {
// each player sacrifices one permanent, e.g. Vaevictis, Asmadi the Dire - grab the worst for allied and // each player sacrifices one permanent, e.g. Vaevictis, Asmadi the Dire - grab the worst for allied and
// the best for opponents // the best for opponents
return SacrificeAi.doSacOneEachLogic(ai, sa); return SacrificeAi.doSacOneEachLogic(ai, sa);
} else if (sa.getParam("AILogic").equals("Destroy")) {
List<Card> tgts = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa);
if (tgts.isEmpty()) {
return false;
} }
List<Card> alliedTgts = CardLists.filter(tgts, Predicates.or(CardPredicates.isControlledByAnyOf(ai.getAllies()), CardPredicates.isController(ai)));
List<Card> oppTgts = CardLists.filter(tgts, CardPredicates.isControlledByAnyOf(ai.getRegisteredOpponents()));
Card destroyTgt = null;
if (!oppTgts.isEmpty()) {
destroyTgt = ComputerUtilCard.getBestAI(oppTgts);
} else {
// TODO: somehow limit this so that the AI doesn't always destroy own stuff when able?
destroyTgt = ComputerUtilCard.getWorstAI(alliedTgts);
}
if (destroyTgt != null) {
sa.resetTargets();
sa.getTargets().add(destroyTgt);
return true;
}
return false;
}
if (isFight) { if (isFight) {
return FightAi.canFightAi(ai, sa, attack, defense); return FightAi.canFightAi(ai, sa, attack, defense);
} }

View File

@@ -197,6 +197,15 @@ public class Game {
} }
} }
public CardCollectionView copyLastStateBattlefield() {
CardCollection result = new CardCollection();
Map<Integer, Card> cachedMap = Maps.newHashMap();
for (final Player p : getPlayers()) {
result.addAll(p.getZone(ZoneType.Battlefield).getLKICopy(cachedMap));
}
return result;
}
public void updateLastStateForCard(Card c) { public void updateLastStateForCard(Card c) {
if (c == null || c.getZone() == null) { if (c == null || c.getZone() == null) {
return; return;

View File

@@ -1278,7 +1278,7 @@ public class GameAction {
orderedNoRegCreats = true; orderedNoRegCreats = true;
} }
for (Card c : noRegCreats) { for (Card c : noRegCreats) {
sacrificeDestroy(c, null, table); sacrificeDestroy(c, null, table, null);
} }
} }
if (desCreats != null) { if (desCreats != null) {
@@ -1290,7 +1290,7 @@ public class GameAction {
orderedDesCreats = true; orderedDesCreats = true;
} }
for (Card c : desCreats) { for (Card c : desCreats) {
destroy(c, null, true, table); destroy(c, null, true, table, null);
} }
} }
setHoldCheckingStaticAbilities(false); setHoldCheckingStaticAbilities(false);
@@ -1376,7 +1376,7 @@ public class GameAction {
return false; return false;
} }
if (!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) { if (!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) {
sacrifice(c, null, table); sacrifice(c, null, table, null);
checkAgain = true; checkAgain = true;
} }
return checkAgain; return checkAgain;
@@ -1404,7 +1404,7 @@ public class GameAction {
// cleanup aura // cleanup aura
if (c.isAura() && c.isInPlay() && !c.isEnchanting()) { if (c.isAura() && c.isInPlay() && !c.isEnchanting()) {
sacrificeDestroy(c, null, table); sacrificeDestroy(c, null, table, null);
checkAgain = true; checkAgain = true;
} }
return checkAgain; return checkAgain;
@@ -1556,7 +1556,7 @@ public class GameAction {
for (Card c : list) { for (Card c : list) {
if (c.getCounters(CounterEnumType.LOYALTY) <= 0) { if (c.getCounters(CounterEnumType.LOYALTY) <= 0) {
sacrificeDestroy(c, null, table); sacrificeDestroy(c, null, table, null);
// Play the Destroy sound // Play the Destroy sound
game.fireEvent(new GameEventCardDestroyed()); game.fireEvent(new GameEventCardDestroyed());
recheck = true; recheck = true;
@@ -1619,7 +1619,7 @@ public class GameAction {
"You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)", null); "You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)", null);
for (Card c: cc) { for (Card c: cc) {
if (c != toKeep) { if (c != toKeep) {
sacrificeDestroy(c, null, table); sacrificeDestroy(c, null, table, null);
} }
} }
game.fireEvent(new GameEventCardDestroyed()); game.fireEvent(new GameEventCardDestroyed());
@@ -1653,28 +1653,24 @@ public class GameAction {
} }
for (Card c : worlds) { for (Card c : worlds) {
sacrificeDestroy(c, null, table); sacrificeDestroy(c, null, table, null);
game.fireEvent(new GameEventCardDestroyed()); game.fireEvent(new GameEventCardDestroyed());
} }
return true; return true;
} }
@Deprecated public final Card sacrifice(final Card c, final SpellAbility source, CardZoneTable table, Map<AbilityKey, Object> params) {
public final Card sacrifice(final Card c, final SpellAbility source) {
return sacrifice(c, source, null);
}
public final Card sacrifice(final Card c, final SpellAbility source, CardZoneTable table) {
if (!c.canBeSacrificedBy(source)) { if (!c.canBeSacrificedBy(source)) {
return null; return null;
} }
c.getController().addSacrificedThisTurn(c, source); c.getController().addSacrificedThisTurn(c, source);
return sacrificeDestroy(c, source, table); return sacrificeDestroy(c, source, table, params);
} }
public final boolean destroy(final Card c, final SpellAbility sa, final boolean regenerate, CardZoneTable table) { public final boolean destroy(final Card c, final SpellAbility sa, final boolean regenerate, CardZoneTable table, Map<AbilityKey, Object> params) {
Player activator = null; Player activator = null;
if (!c.canBeDestroyed()) { if (!c.canBeDestroyed()) {
return false; return false;
@@ -1685,6 +1681,9 @@ public class GameAction {
repRunParams.put(AbilityKey.Source, sa); repRunParams.put(AbilityKey.Source, sa);
repRunParams.put(AbilityKey.Affected, c); repRunParams.put(AbilityKey.Affected, c);
repRunParams.put(AbilityKey.Regeneration, regenerate); repRunParams.put(AbilityKey.Regeneration, regenerate);
if (params != null) {
repRunParams.putAll(params);
}
if (game.getReplacementHandler().run(ReplacementType.Destroy, repRunParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(ReplacementType.Destroy, repRunParams) != ReplacementResult.NotReplaced) {
return false; return false;
@@ -1701,11 +1700,14 @@ public class GameAction {
// Run triggers // Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put(AbilityKey.Causer, activator); runParams.put(AbilityKey.Causer, activator);
if (params != null) {
runParams.putAll(params);
}
game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false);
// in case the destroyed card has such a trigger // in case the destroyed card has such a trigger
game.getTriggerHandler().registerActiveLTBTrigger(c); game.getTriggerHandler().registerActiveLTBTrigger(c);
final Card sacrificed = sacrificeDestroy(c, sa, table); final Card sacrificed = sacrificeDestroy(c, sa, table, params);
return sacrificed != null; return sacrificed != null;
} }
@@ -1713,12 +1715,12 @@ public class GameAction {
* @return the sacrificed Card in its new location, or {@code null} if the * @return the sacrificed Card in its new location, or {@code null} if the
* sacrifice wasn't successful. * sacrifice wasn't successful.
*/ */
protected final Card sacrificeDestroy(final Card c, SpellAbility cause, CardZoneTable table) { protected final Card sacrificeDestroy(final Card c, SpellAbility cause, CardZoneTable table, Map<AbilityKey, Object> params) {
if (!c.isInPlay()) { if (!c.isInPlay()) {
return null; return null;
} }
final Card newCard = moveToGraveyard(c, cause, null); final Card newCard = moveToGraveyard(c, cause, params);
if (table != null && newCard != null && newCard.getZone() != null) { if (table != null && newCard != null && newCard.getZone() != null) {
table.put(ZoneType.Battlefield, newCard.getZone().getZoneType(), newCard); table.put(ZoneType.Battlefield, newCard.getZone().getZoneType(), newCard);
} }

View File

@@ -638,6 +638,9 @@ public final class GameActionUtil {
} }
public static CardCollectionView orderCardsByTheirOwners(Game game, CardCollectionView list, ZoneType dest, SpellAbility sa) { public static CardCollectionView orderCardsByTheirOwners(Game game, CardCollectionView list, ZoneType dest, SpellAbility sa) {
if (list.size() <= 1) {
return list;
}
CardCollection completeList = new CardCollection(); CardCollection completeList = new CardCollection();
for (Player p : game.getPlayers()) { for (Player p : game.getPlayers()) {
CardCollection subList = new CardCollection(); CardCollection subList = new CardCollection();

View File

@@ -73,6 +73,7 @@ public enum AbilityKey {
IsCombatDamage("IsCombatDamage"), IsCombatDamage("IsCombatDamage"),
IndividualCostPaymentInstance("IndividualCostPaymentInstance"), IndividualCostPaymentInstance("IndividualCostPaymentInstance"),
IsMadness("IsMadness"), IsMadness("IsMadness"),
LastStateBattlefield("LastStateBattlefield"),
LifeAmount("LifeAmount"), //TODO confirm that this and LifeGained can be merged LifeAmount("LifeAmount"), //TODO confirm that this and LifeGained can be merged
LifeGained("LifeGained"), LifeGained("LifeGained"),
Mana("Mana"), Mana("Mana"),

View File

@@ -173,15 +173,13 @@ public class AbilityUtils {
} }
} }
else if (defined.equals("Targeted") && sa instanceof SpellAbility) { else if (defined.equals("Targeted") && sa instanceof SpellAbility) {
final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingCard(); for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) {
if (saTargeting != null) { Iterables.addAll(cards, tc.getTargetCards());
Iterables.addAll(cards, saTargeting.getTargets().getTargetCards());
} }
} }
else if (defined.equals("TargetedSource") && sa instanceof SpellAbility) { else if (defined.equals("TargetedSource") && sa instanceof SpellAbility) {
final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingSA(); for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) {
if (saTargeting != null) { for (SpellAbility s : tc.getTargetSpells()) {
for (SpellAbility s : saTargeting.getTargets().getTargetSpells()) {
cards.add(s.getHostCard()); cards.add(s.getHostCard());
} }
} }
@@ -1008,9 +1006,8 @@ public class AbilityUtils {
players.addAll(getDefinedPlayers(card, "TargetedController", sa)); players.addAll(getDefinedPlayers(card, "TargetedController", sa));
} }
else if ((defined.equals("Targeted") || defined.equals("TargetedPlayer")) && sa instanceof SpellAbility) { else if ((defined.equals("Targeted") || defined.equals("TargetedPlayer")) && sa instanceof SpellAbility) {
final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingPlayer(); for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) {
if (saTargeting != null) { players.addAll(tc.getTargetPlayers());
players.addAll(saTargeting.getTargets().getTargetPlayers());
} }
} }
else if (defined.equals("ParentTarget") && sa instanceof SpellAbility) { else if (defined.equals("ParentTarget") && sa instanceof SpellAbility) {
@@ -1298,9 +1295,8 @@ public class AbilityUtils {
s = ((SpellAbility)sa).getRootAbility(); s = ((SpellAbility)sa).getRootAbility();
} }
else if (defined.equals("Targeted") && sa instanceof SpellAbility) { else if (defined.equals("Targeted") && sa instanceof SpellAbility) {
final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingSA(); for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) {
if (saTargeting != null) { for (SpellAbility targetSpell : tc.getTargetSpells()) {
for (SpellAbility targetSpell : saTargeting.getTargets().getTargetSpells()) {
SpellAbilityStackInstance stackInstance = game.getStack().getInstanceFromSpellAbility(targetSpell); SpellAbilityStackInstance stackInstance = game.getStack().getInstanceFromSpellAbility(targetSpell);
if (stackInstance != null) { if (stackInstance != null) {
SpellAbility instanceSA = stackInstance.getSpellAbility(true); SpellAbility instanceSA = stackInstance.getSpellAbility(true);
@@ -1412,7 +1408,6 @@ public class AbilityUtils {
} }
return; return;
} }
AbilityUtils.resolveApiAbility(sa, game); AbilityUtils.resolveApiAbility(sa, game);
} }

View File

@@ -7,6 +7,7 @@ import java.util.Map;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
@@ -47,6 +48,7 @@ public class BalanceEffect extends SpellAbilityEffect {
min = Math.min(min, validCards.get(i).size()); min = Math.min(min, validCards.get(i).size());
} }
Map<AbilityKey, Object> params = AbilityKey.newMap();
CardZoneTable table = new CardZoneTable(); CardZoneTable table = new CardZoneTable();
for (int i = 0; i < players.size(); i++) { for (int i = 0; i < players.size(); i++) {
Player p = players.get(i); Player p = players.get(i);
@@ -59,7 +61,7 @@ public class BalanceEffect extends SpellAbilityEffect {
} else { // Battlefield } else { // Battlefield
for (Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) { for (Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) {
if ( null == card ) continue; if ( null == card ) continue;
game.getAction().sacrifice(card, sa, table); game.getAction().sacrifice(card, sa, table, params);
} }
} }
} }

View File

@@ -12,6 +12,7 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardFactoryUtil; import forge.game.card.CardFactoryUtil;
import forge.game.card.CardZoneTable;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType; import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -113,6 +114,8 @@ public class CounterEffect extends SpellAbilityEffect {
} }
} }
Map<AbilityKey, Object> params = AbilityKey.newMap();
CardZoneTable table = new CardZoneTable();
for (final SpellAbility tgtSA : sas) { for (final SpellAbility tgtSA : sas) {
final Card tgtSACard = tgtSA.getHostCard(); final Card tgtSACard = tgtSA.getHostCard();
// should remember even that spell cannot be countered, e.g. Dovescape // should remember even that spell cannot be countered, e.g. Dovescape
@@ -137,7 +140,7 @@ public class CounterEffect extends SpellAbilityEffect {
// Destroy Permanent may be able to be turned into a SubAbility // Destroy Permanent may be able to be turned into a SubAbility
if (tgtSA.isAbility() && sa.hasParam("DestroyPermanent")) { if (tgtSA.isAbility() && sa.hasParam("DestroyPermanent")) {
game.getAction().destroy(tgtSACard, sa, true, null); game.getAction().destroy(tgtSACard, sa, true, table, params);
} }
if (sa.hasParam("RememberCountered")) { if (sa.hasParam("RememberCountered")) {
@@ -152,6 +155,7 @@ public class CounterEffect extends SpellAbilityEffect {
} }
} }
} }
table.triggerChangesZoneAll(game, sa);
} // end counterResolve } // end counterResolve
/** /**

View File

@@ -6,6 +6,7 @@ import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.GameActionUtil; import forge.game.GameActionUtil;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -90,10 +91,12 @@ public class DestroyAllEffect extends SpellAbilityEffect {
} }
CardZoneTable table = new CardZoneTable(); CardZoneTable table = new CardZoneTable();
Map<AbilityKey, Object> params = AbilityKey.newMap();
params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield());
Map<Integer, Card> cachedMap = Maps.newHashMap(); Map<Integer, Card> cachedMap = Maps.newHashMap();
for (Card c : list) { for (Card c : list) {
if (game.getAction().destroy(c, sa, !noRegen, table) && remDestroyed) { if (game.getAction().destroy(c, sa, !noRegen, table, params) && remDestroyed) {
card.addRemembered(CardUtil.getLKICopy(c, cachedMap)); card.addRemembered(CardUtil.getLKICopy(c, cachedMap));
} }
} }

View File

@@ -8,9 +8,10 @@ import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.GameActionUtil; import forge.game.GameActionUtil;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollectionView;
import forge.game.card.CardUtil; import forge.game.card.CardUtil;
import forge.game.card.CardZoneTable; import forge.game.card.CardZoneTable;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -72,13 +73,16 @@ public class DestroyEffect extends SpellAbilityEffect {
card.clearRemembered(); card.clearRemembered();
} }
CardCollection tgtCards = getTargetCards(sa); CardCollectionView tgtCards = getTargetCards(sa);
CardCollection untargetedCards = CardUtil.getRadiance(sa); CardCollectionView untargetedCards = CardUtil.getRadiance(sa);
if (tgtCards.size() > 1) { if (tgtCards.size() > 1) {
tgtCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard, sa); tgtCards = GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard, sa);
} }
Map<AbilityKey, Object> params = AbilityKey.newMap();
params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield());
CardZoneTable table = new CardZoneTable(); CardZoneTable table = new CardZoneTable();
Map<Integer, Card> cachedMap = Maps.newHashMap(); Map<Integer, Card> cachedMap = Maps.newHashMap();
for (final Card tgtC : tgtCards) { for (final Card tgtC : tgtCards) {
@@ -90,24 +94,24 @@ public class DestroyEffect extends SpellAbilityEffect {
if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) { if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) {
continue; continue;
} }
internalDestroy(gameCard, sa, table, cachedMap); internalDestroy(gameCard, sa, table, cachedMap, params);
} }
} }
if (untargetedCards.size() > 1) { if (untargetedCards.size() > 1) {
untargetedCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, untargetedCards, ZoneType.Graveyard, sa); untargetedCards = GameActionUtil.orderCardsByTheirOwners(game, untargetedCards, ZoneType.Graveyard, sa);
} }
for (final Card unTgtC : untargetedCards) { for (final Card unTgtC : untargetedCards) {
if (unTgtC.isInPlay()) { if (unTgtC.isInPlay()) {
internalDestroy(unTgtC, sa, table, cachedMap); internalDestroy(unTgtC, sa, table, cachedMap, params);
} }
} }
table.triggerChangesZoneAll(game, sa); table.triggerChangesZoneAll(game, sa);
} }
protected void internalDestroy(Card gameCard, SpellAbility sa, CardZoneTable table, Map<Integer, Card> cachedMap) { protected void internalDestroy(Card gameCard, SpellAbility sa, CardZoneTable table, Map<Integer, Card> cachedMap, Map<AbilityKey, Object> params) {
final Card card = sa.getHostCard(); final Card card = sa.getHostCard();
final Game game = card.getGame(); final Game game = card.getGame();
@@ -122,9 +126,9 @@ public class DestroyEffect extends SpellAbilityEffect {
card.addRemembered(gameCard.getAttachedCards()); card.addRemembered(gameCard.getAttachedCards());
} }
if (sac) { if (sac) {
destroyed = game.getAction().sacrifice(gameCard, sa, table) != null; destroyed = game.getAction().sacrifice(gameCard, sa, table, params) != null;
} else { } else {
destroyed = game.getAction().destroy(gameCard, sa, !noRegen, table); destroyed = game.getAction().destroy(gameCard, sa, !noRegen, table, params);
} }
if (destroyed && remDestroyed) { if (destroyed && remDestroyed) {
card.addRemembered(gameCard); card.addRemembered(gameCard);

View File

@@ -6,6 +6,7 @@ import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.GameActionUtil; import forge.game.GameActionUtil;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -86,9 +87,12 @@ public class SacrificeAllEffect extends SpellAbilityEffect {
CardZoneTable table = new CardZoneTable(); CardZoneTable table = new CardZoneTable();
Map<Integer, Card> cachedMap = Maps.newHashMap(); Map<Integer, Card> cachedMap = Maps.newHashMap();
Map<AbilityKey, Object> params = AbilityKey.newMap();
params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield());
for (Card sac : list) { for (Card sac : list) {
final Card lKICopy = CardUtil.getLKICopy(sac, cachedMap); final Card lKICopy = CardUtil.getLKICopy(sac, cachedMap);
if (game.getAction().sacrifice(sac, sa, table) != null) { if (game.getAction().sacrifice(sac, sa, table, params) != null) {
if (remSacrificed) { if (remSacrificed) {
card.addRemembered(lKICopy); card.addRemembered(lKICopy);
} }

View File

@@ -106,10 +106,12 @@ public class SacrificeEffect extends SpellAbilityEffect {
final String remSVar = sa.getParam("RememberSacrificedSVar"); final String remSVar = sa.getParam("RememberSacrificedSVar");
int countSacrificed = 0; int countSacrificed = 0;
CardZoneTable table = new CardZoneTable(); CardZoneTable table = new CardZoneTable();
Map<AbilityKey, Object> params = AbilityKey.newMap();
params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield());
if (valid.equals("Self") && game.getZoneOf(card) != null) { if (valid.equals("Self") && game.getZoneOf(card) != null) {
if (game.getZoneOf(card).is(ZoneType.Battlefield)) { if (game.getZoneOf(card).is(ZoneType.Battlefield)) {
if (game.getAction().sacrifice(card, sa, table) != null) { if (game.getAction().sacrifice(card, sa, table, params) != null) {
countSacrificed++; countSacrificed++;
if (remSacrificed) { if (remSacrificed) {
card.addRemembered(card); card.addRemembered(card);
@@ -152,8 +154,8 @@ public class SacrificeEffect extends SpellAbilityEffect {
Map<Integer, Card> cachedMap = Maps.newHashMap(); Map<Integer, Card> cachedMap = Maps.newHashMap();
for (Card sac : choosenToSacrifice) { for (Card sac : choosenToSacrifice) {
final Card lKICopy = CardUtil.getLKICopy(sac, cachedMap); final Card lKICopy = CardUtil.getLKICopy(sac, cachedMap);
boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa, table) != null; boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa, table, params) != null;
boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa, true, table); boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa, true, table, params);
// Run Devour Trigger // Run Devour Trigger
if (devour) { if (devour) {
card.addDevoured(lKICopy); card.addDevoured(lKICopy);

View File

@@ -519,28 +519,6 @@ public class CardFactoryUtil {
return types.size(); return types.size();
} }
/**
* <p>
* getNeededXDamage.
* </p>
*
* @param ability
* a {@link forge.game.spellability.SpellAbility} object.
* @return a int.
*/
public static int getNeededXDamage(final SpellAbility ability) {
// when targeting a creature, make sure the AI won't overkill on X
// damage
final Card target = ability.getTargetCard();
int neededDamage = -1;
if ((target != null)) {
neededDamage = target.getNetToughness() - target.getDamage();
}
return neededDamage;
}
/** /**
* Adds the ability factory abilities. * Adds the ability factory abilities.
* *

View File

@@ -126,7 +126,7 @@ public class CostSacrifice extends CostPartWithList {
@Override @Override
protected Card doPayment(SpellAbility ability, Card targetCard) { protected Card doPayment(SpellAbility ability, Card targetCard) {
// no table there, it is already handled by CostPartWithList // no table there, it is already handled by CostPartWithList
return targetCard.getGame().getAction().sacrifice(targetCard, ability, null); return targetCard.getGame().getAction().sacrifice(targetCard, ability, null, null);
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableList;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardZoneTable; import forge.game.card.CardZoneTable;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -22,8 +23,17 @@ public class StaticAbilityPanharmonicon {
public static int handlePanharmonicon(final Game game, final Trigger t, final Map<AbilityKey, Object> runParams) { public static int handlePanharmonicon(final Game game, final Trigger t, final Map<AbilityKey, Object> runParams) {
int n = 0; int n = 0;
CardCollectionView cardList = null;
// currently only used for leave the battlefield trigger
if (runParams.containsKey(AbilityKey.LastStateBattlefield)) {
cardList = (CardCollectionView) runParams.get(AbilityKey.LastStateBattlefield);
}
if (cardList == null) {
cardList = t.getMode() == TriggerType.ChangesZone && "Battlefield".equals(t.getParam("Origin")) ? game.getLastStateBattlefield() : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES);
}
// Checks only the battlefield, as those effects only work from there // Checks only the battlefield, as those effects only work from there
for (final Card ca : t.getMode() == TriggerType.ChangesZone ? game.getLastStateBattlefield() : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { for (final Card ca : cardList) {
for (final StaticAbility stAb : ca.getStaticAbilities()) { for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) { if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) {
continue; continue;

View File

@@ -2,9 +2,9 @@ Name:Boom
ManaCost:1 R ManaCost:1 R
AlternateMode: Split AlternateMode: Split
Types:Sorcery Types:Sorcery
A:SP$ Destroy | Cost$ 1 R | TgtPrompt$ Choose target land you control to destroy | ValidTgts$ Land.YouCtrl | SubAbility$ DestroyOpp | SpellDescription$ Destroy target land you control and target land you don't control. A:SP$ Pump | Cost$ 1 R | TgtPrompt$ Choose target land you control to destroy | ValidTgts$ Land.YouCtrl | AILogic$ Destroy | Curse$ True | SubAbility$ DestroyOpp | SpellDescription$ Destroy target land you control and target land you don't control.
SVar:DestroyOpp:DB$ Destroy | TgtPrompt$ Choose target land you don't control to destroy | ValidTgts$ Land.YouDontCtrl SVar:DestroyOpp:DB$ Pump | TgtPrompt$ Choose target land you don't control to destroy | ValidTgts$ Land.YouDontCtrl | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:Picture:http://www.wizards.com/global/images/magic/general/boombust.jpg SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
Oracle:Destroy target land you control and target land you don't control. Oracle:Destroy target land you control and target land you don't control.
ALTERNATE ALTERNATE

View File

@@ -1,9 +1,9 @@
Name:Decimate Name:Decimate
ManaCost:2 R G ManaCost:2 R G
Types:Sorcery Types:Sorcery
A:SP$ Destroy | Cost$ 2 R G | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SubAbility$ DestroyCreature | SpellDescription$ Destroy target artifact, target creature, target enchantment, and target land. A:SP$ Pump | Cost$ 2 R G | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SubAbility$ DestroyCreature | AILogic$ Destroy | Curse$ True | SpellDescription$ Destroy target artifact, target creature, target enchantment, and target land.
SVar:DestroyCreature:DB$ Destroy | ValidTgts$ Creature | SubAbility$ DestroyEnch | TgtPrompt$ Select target creature SVar:DestroyCreature:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Destroy | Curse$ True | SubAbility$ DestroyEnch
SVar:DestroyEnch:DB$ Destroy | ValidTgts$ Enchantment | SubAbility$ DestroyLand | TgtPrompt$ Select target enchantment SVar:DestroyEnch:DB$ Pump | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | AILogic$ Destroy | Curse$ True | SubAbility$ DestroyLand
SVar:DestroyLand:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land SVar:DestroyLand:DB$ Pump | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:Picture:http://www.wizards.com/global/images/magic/general/decimate.jpg SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
Oracle:Destroy target artifact, target creature, target enchantment, and target land. Oracle:Destroy target artifact, target creature, target enchantment, and target land.

View File

@@ -1,7 +1,7 @@
Name:Fumarole Name:Fumarole
ManaCost:3 B R ManaCost:3 B R
Types:Sorcery Types:Sorcery
A:SP$ Destroy | Cost$ 3 B R PayLife<3> | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBDestroy | SpellDescription$ Destroy target creature and target land. A:SP$ Pump | Cost$ 3 B R PayLife<3> | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Destroy | Curse$ True | SubAbility$ DBLand | SpellDescription$ Destroy target creature and target land.
SVar:DBDestroy:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land SVar:DBLand:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:Picture:http://www.wizards.com/global/images/magic/general/fumarole.jpg SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
Oracle:As an additional cost to cast this spell, pay 3 life.\nDestroy target creature and target land. Oracle:As an additional cost to cast this spell, pay 3 life.\nDestroy target creature and target land.

View File

@@ -3,6 +3,7 @@ ManaCost:3 R
Types:Creature Goblin Types:Creature Goblin
PT:2/2 PT:2/2
T:Mode$ AttackerUnblocked | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDestroyCreature | TriggerDescription$ Whenever CARDNAME attacks and isn't blocked, you may sacrifice it. If you do, destroy target creature and target land. T:Mode$ AttackerUnblocked | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDestroyCreature | TriggerDescription$ Whenever CARDNAME attacks and isn't blocked, you may sacrifice it. If you do, destroy target creature and target land.
SVar:TrigDestroyCreature:AB$ Destroy | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBDestroyLand SVar:TrigDestroyCreature:AB$ Pump | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Destroy | Curse$ True | SubAbility$ DBLand
SVar:DBDestroyLand:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land SVar:DBLand:DB$ Pump | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
Oracle:Whenever Goblin Grenadiers attacks and isn't blocked, you may sacrifice it. If you do, destroy target creature and target land. Oracle:Whenever Goblin Grenadiers attacks and isn't blocked, you may sacrifice it. If you do, destroy target creature and target land.

View File

@@ -4,8 +4,8 @@ Types:Sorcery
A:SP$ Charm | Cost$ R G | Choices$ DBDestroy1,DBDestroy2,DBDestroy3 | CharmNum$ 1 A:SP$ Charm | Cost$ R G | Choices$ DBDestroy1,DBDestroy2,DBDestroy3 | CharmNum$ 1
SVar:DBDestroy1:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact. SVar:DBDestroy1:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact.
SVar:DBDestroy2:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | SpellDescription$ Destroy target enchantment. SVar:DBDestroy2:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | SpellDescription$ Destroy target enchantment.
SVar:DBDestroy3:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact and target enchantment. | SubAbility$ DestroyEnch SVar:DBDestroy3:DB$ Pump | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | AILogic$ Destroy | Curse$ True | SubAbility$ DestroyEnch | SpellDescription$ Destroy target artifact and target enchantment.
SVar:DestroyEnch:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment SVar:DestroyEnch:DB$ Pump | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
AI:RemoveDeck:All AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/hull_breach.jpg
Oracle:Choose one —\n• Destroy target artifact.\n• Destroy target enchantment.\n• Destroy target artifact and target enchantment. Oracle:Choose one —\n• Destroy target artifact.\n• Destroy target enchantment.\n• Destroy target artifact and target enchantment.

View File

@@ -1,7 +1,7 @@
Name:Plague Spores Name:Plague Spores
ManaCost:4 B R ManaCost:4 B R
Types:Sorcery Types:Sorcery
A:SP$ Destroy | Cost$ 4 B R | ValidTgts$ Creature.nonBlack | TgtPrompt$ Select nonblack creature | NoRegen$ True | SubAbility$ DestroyLand | SpellDescription$ Destroy target nonblack creature and target land. They can't be regenerated. A:SP$ Pump | Cost$ 4 B R | ValidTgts$ Creature.nonBlack | TgtPrompt$ Select nonblack creature | AILogic$ Destroy | Curse$ True | SubAbility$ DBLand | SpellDescription$ Destroy target nonblack creature and target land. They can't be regenerated.
SVar:DestroyLand:DB$ Destroy | ValidTgts$ Land | NoRegen$ True | TgtPrompt$ Select target land SVar:DBLand:DB$ Pump | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:Picture:http://www.wizards.com/global/images/magic/general/plague_spores.jpg SVar:DBDestroy:DB$ Destroy | Defined$ Targeted | NoRegen$ True
Oracle:Destroy target nonblack creature and target land. They can't be regenerated. Oracle:Destroy target nonblack creature and target land. They can't be regenerated.

View File

@@ -2,10 +2,10 @@ Name:Reign of Chaos
ManaCost:2 R R ManaCost:2 R R
Types:Sorcery Types:Sorcery
A:SP$ Charm | Cost$ 2 R R | Choices$ DBDestroy1,DBDestroy2 | CharmNum$ 1 A:SP$ Charm | Cost$ 2 R R | Choices$ DBDestroy1,DBDestroy2 | CharmNum$ 1
SVar:DBDestroy1:DB$ Destroy | ValidTgts$ Plains | TgtPrompt$ Select target Plains | SubAbility$ DBDestroyWhite | SpellDescription$ Destroy target Plains and target white creature. SVar:DBDestroy1:DB$ Pump | ValidTgts$ Plains | TgtPrompt$ Select target Plains | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroyWhite | SpellDescription$ Destroy target Plains and target white creature.
SVar:DBDestroy2:DB$ Destroy | ValidTgts$ Island | TgtPrompt$ Select target Island | SubAbility$ DBDestroyBlue | SpellDescription$ Destroy target Island and target blue creature. SVar:DBDestroy2:DB$ Pump | ValidTgts$ Island | TgtPrompt$ Select target Island | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroyBlue | SpellDescription$ Destroy target Island and target blue creature.
SVar:DBDestroyWhite:DB$ Destroy | ValidTgts$ Creature.White | TgtPrompt$ Select target white creature SVar:DBDestroyWhite:DB$ Pump | ValidTgts$ Creature.White | TgtPrompt$ Select target white creature | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:DBDestroyBlue:DB$ Destroy | ValidTgts$ Creature.Blue | TgtPrompt$ Select target blue creature SVar:DBDestroyBlue:DB$ Pump | ValidTgts$ Creature.Blue | TgtPrompt$ Select target blue creature | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
AI:RemoveDeck:Random AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/reign_of_chaos.jpg
Oracle:Choose one —\n• Destroy target Plains and target white creature.\n• Destroy target Island and target blue creature. Oracle:Choose one —\n• Destroy target Plains and target white creature.\n• Destroy target Island and target blue creature.

View File

@@ -1,7 +1,7 @@
Name:Spiteful Blow Name:Spiteful Blow
ManaCost:4 B B ManaCost:4 B B
Types:Sorcery Types:Sorcery
A:SP$ Destroy | Cost$ 4 B B | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBDestroy | SpellDescription$ Destroy target creature and target land. A:SP$ Pump | Cost$ 4 B B | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBLand | AILogic$ Destroy | Curse$ True | SpellDescription$ Destroy target creature and target land.
SVar:DBDestroy:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land SVar:DBLand:DB$ Pump | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:Picture:http://www.wizards.com/global/images/magic/general/spiteful_blow.jpg SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
Oracle:Destroy target creature and target land. Oracle:Destroy target creature and target land.

View File

@@ -1,7 +1,7 @@
Name:Stomp and Howl Name:Stomp and Howl
ManaCost:2 G ManaCost:2 G
Types:Sorcery Types:Sorcery
A:SP$ Destroy | Cost$ 2 G | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact and target enchantment. | SubAbility$ DestroyEnch A:SP$ Pump | Cost$ 2 G | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | AILogic$ Destroy | Curse$ True | SubAbility$ DestroyEnch | SpellDescription$ Destroy target artifact and target enchantment.
SVar:DestroyEnch:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment SVar:DestroyEnch:DB$ Pump | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:Picture:http://www.wizards.com/global/images/magic/general/stomp_and_howl.jpg SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
Oracle:Destroy target artifact and target enchantment. Oracle:Destroy target artifact and target enchantment.

View File

@@ -1,9 +1,9 @@
Name:Volcanic Offering Name:Volcanic Offering
ManaCost:4 R ManaCost:4 R
Types:Instant Types:Instant
A:SP$ Destroy | Cost$ 4 R | ValidTgts$ Land.nonBasic+YouDontCtrl | TgtPrompt$ Select target nonbasic land you don't control | SubAbility$ DBDestroyLand | SpellDescription$ Destroy target nonbasic land you don't control and target nonbasic land of an opponent's choice you don't control. A:SP$ Pump | Cost$ 4 R | ValidTgts$ Land.nonBasic+YouDontCtrl | TgtPrompt$ Select target nonbasic land you don't control | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroyLand | SpellDescription$ Destroy target nonbasic land you don't control and target nonbasic land of an opponent's choice you don't control.
SVar:DBDestroyLand:DB$ Destroy | TargetingPlayer$ Player.Opponent | ValidTgts$ Land.nonBasic+YouDontCtrl | TgtPrompt$ Select target nonbasic land the caster of this spell don't control | SubAbility$ DBDamage SVar:DBDestroyLand:DB$ Pump | TargetingPlayer$ Player.Opponent | ValidTgts$ Land.nonBasic+YouDontCtrl | TgtPrompt$ Select target nonbasic land the caster of this spell don't control | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:DBDestroy:DB$ Destroy | Defined$ Targeted | SubAbility$ DBDamage
SVar:DBDamage:DB$ DealDamage | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select target creature you don't control | NumDmg$ 7 | SubAbility$ DBDamage2 | SpellDescription$ CARDNAME deals 7 damage to target creature you don't control and 7 damage to target creature of an opponent's choice you don't control. SVar:DBDamage:DB$ DealDamage | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select target creature you don't control | NumDmg$ 7 | SubAbility$ DBDamage2 | SpellDescription$ CARDNAME deals 7 damage to target creature you don't control and 7 damage to target creature of an opponent's choice you don't control.
SVar:DBDamage2:DB$ DealDamage | TargetingPlayer$ Player.Opponent | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select target creature the caster of this spell don't control | NumDmg$ 7 SVar:DBDamage2:DB$ DealDamage | TargetingPlayer$ Player.Opponent | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select target creature the caster of this spell don't control | NumDmg$ 7
SVar:Picture:http://www.wizards.com/global/images/magic/general/volcanic_offering.jpg
Oracle:Destroy target nonbasic land you don't control and target nonbasic land of an opponent's choice you don't control.\nVolcanic Offering deals 7 damage to target creature you don't control and 7 damage to target creature of an opponent's choice you don't control. Oracle:Destroy target nonbasic land you don't control and target nonbasic land of an opponent's choice you don't control.\nVolcanic Offering deals 7 damage to target creature you don't control and 7 damage to target creature of an opponent's choice you don't control.

View File

@@ -3,8 +3,8 @@ ManaCost:2 B
Types:Creature Snake Wall Types:Creature Snake Wall
PT:2/4 PT:2/4
K:Defender K:Defender
A:AB$ Destroy | Cost$ 3 | Defined$ Self | Activator$ Player | SubAbility$ SnakeBite | SpellDescription$ Destroy CARDNAME and target creature it's blocking. Any player may activate this ability. A:AB$ Pump | Cost$ 3 | Defined$ Self | Activator$ Player | AILogic$ Destroy | Curse$ True | SubAbility$ SnakeBite | SpellDescription$ Destroy CARDNAME and target creature it's blocking. Any player may activate this ability.
SVar:SnakeBite:DB$ Destroy | ValidTgts$ Creature.blockedBySource SVar:SnakeBite:DB$ Pump | ValidTgts$ Creature.blockedBySource | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy
SVar:DBDestroy:DB$ Destroy | Defined$ Targeted
AI:RemoveDeck:All AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/wall_of_vipers.jpg
Oracle:Defender (This creature can't attack.)\n{3}: Destroy Wall of Vipers and target creature it's blocking. Any player may activate this ability. Oracle:Defender (This creature can't attack.)\n{3}: Destroy Wall of Vipers and target creature it's blocking. Any player may activate this ability.

View File

@@ -673,7 +673,7 @@ public class HumanPlay {
final Card offering = ability.getSacrificedAsOffering(); final Card offering = ability.getSacrificedAsOffering();
offering.setUsedToPay(false); offering.setUsedToPay(false);
if (!manaInputCancelled) { if (!manaInputCancelled) {
game.getAction().sacrifice(offering, ability, table); game.getAction().sacrifice(offering, ability, table, null);
} }
ability.resetSacrificedAsOffering(); ability.resetSacrificedAsOffering();
} }
@@ -681,7 +681,7 @@ public class HumanPlay {
final Card emerge = ability.getSacrificedAsEmerge(); final Card emerge = ability.getSacrificedAsEmerge();
emerge.setUsedToPay(false); emerge.setUsedToPay(false);
if (!manaInputCancelled) { if (!manaInputCancelled) {
game.getAction().sacrifice(emerge, ability, table); game.getAction().sacrifice(emerge, ability, table, null);
} }
ability.resetSacrificedAsEmerge(); ability.resetSacrificedAsEmerge();
} }
@@ -785,7 +785,7 @@ public class HumanPlay {
if (ability.getSacrificedAsOffering() != null) { if (ability.getSacrificedAsOffering() != null) {
System.out.println("Finishing up Offering"); System.out.println("Finishing up Offering");
offering.setUsedToPay(false); offering.setUsedToPay(false);
activator.getGame().getAction().sacrifice(offering, ability, null); activator.getGame().getAction().sacrifice(offering, ability, null, null);
ability.resetSacrificedAsOffering(); ability.resetSacrificedAsOffering();
} }
} }
@@ -796,7 +796,7 @@ public class HumanPlay {
if (ability.getSacrificedAsEmerge() != null) { if (ability.getSacrificedAsEmerge() != null) {
System.out.println("Finishing up Emerge"); System.out.println("Finishing up Emerge");
emerge.setUsedToPay(false); emerge.setUsedToPay(false);
activator.getGame().getAction().sacrifice(emerge, ability, null); activator.getGame().getAction().sacrifice(emerge, ability, null, null);
ability.resetSacrificedAsEmerge(); ability.resetSacrificedAsEmerge();
} }
} }