From 9bdd4b93518af58c267ab61ac61f2ba360c7a5cf Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 12 Jun 2021 12:57:51 +0000 Subject: [PATCH] StaticAbilityPanharmonicon: add LastStateBattlefield to Trigger RunParams for stuff that destroys in sequence --- .../main/java/forge/ai/ComputerUtilMana.java | 4 +-- .../main/java/forge/ai/ability/DestroyAi.java | 2 +- .../main/java/forge/ai/ability/PumpAi.java | 25 +++++++++++++ forge-game/src/main/java/forge/game/Game.java | 9 +++++ .../src/main/java/forge/game/GameAction.java | 36 ++++++++++--------- .../main/java/forge/game/GameActionUtil.java | 3 ++ .../java/forge/game/ability/AbilityKey.java | 1 + .../java/forge/game/ability/AbilityUtils.java | 21 +++++------ .../game/ability/effects/BalanceEffect.java | 6 ++-- .../game/ability/effects/CounterEffect.java | 6 +++- .../ability/effects/DestroyAllEffect.java | 5 ++- .../game/ability/effects/DestroyEffect.java | 24 +++++++------ .../ability/effects/SacrificeAllEffect.java | 6 +++- .../game/ability/effects/SacrificeEffect.java | 8 +++-- .../java/forge/game/card/CardFactoryUtil.java | 22 ------------ .../java/forge/game/cost/CostSacrifice.java | 2 +- .../StaticAbilityPanharmonicon.java | 12 ++++++- .../src/main/java/forge/sound/AudioClip.java | 12 +++---- forge-gui/res/cardsfolder/b/boom_bust.txt | 6 ++-- forge-gui/res/cardsfolder/d/decimate.txt | 10 +++--- forge-gui/res/cardsfolder/f/fumarole.txt | 6 ++-- .../res/cardsfolder/g/goblin_grenadiers.txt | 5 +-- forge-gui/res/cardsfolder/h/hull_breach.txt | 6 ++-- forge-gui/res/cardsfolder/p/plague_spores.txt | 6 ++-- .../res/cardsfolder/r/reign_of_chaos.txt | 10 +++--- forge-gui/res/cardsfolder/s/spiteful_blow.txt | 6 ++-- .../res/cardsfolder/s/stomp_and_howl.txt | 6 ++-- .../res/cardsfolder/v/volcanic_offering.txt | 6 ++-- .../res/cardsfolder/w/wall_of_vipers.txt | 6 ++-- .../src/main/java/forge/player/HumanPlay.java | 8 ++--- 30 files changed, 164 insertions(+), 121 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index b2dcbc7f6a0..3ffa79ca748 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -1880,7 +1880,7 @@ public class ComputerUtilMana { final Card offering = sa.getSacrificedAsOffering(); offering.setUsedToPay(false); if (costIsPaid && !test) { - sa.getHostCard().getGame().getAction().sacrifice(offering, sa, null); + sa.getHostCard().getGame().getAction().sacrifice(offering, sa, null, null); } sa.resetSacrificedAsOffering(); } @@ -1888,7 +1888,7 @@ public class ComputerUtilMana { final Card emerge = sa.getSacrificedAsEmerge(); emerge.setUsedToPay(false); if (costIsPaid && !test) { - sa.getHostCard().getGame().getAction().sacrifice(emerge, sa, null); + sa.getHostCard().getGame().getAction().sacrifice(emerge, sa, null, null); } sa.resetSacrificedAsEmerge(); } diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java index 4bfc4edf461..14e97275514 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java @@ -24,7 +24,7 @@ import forge.game.zone.ZoneType; public class DestroyAi extends SpellAbilityAi { @Override public boolean chkAIDrawback(SpellAbility sa, Player ai) { - return canPlayAI(ai, sa); + return checkApiLogic(ai, sa); } @Override diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java index 02e582b8e69..478d0d70f28 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java @@ -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 // the best for opponents return SacrificeAi.doSacOneEachLogic(ai, sa); + } else if (sa.getParam("AILogic").equals("Destroy")) { + List tgts = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa); + if (tgts.isEmpty()) { + return false; + } + + List alliedTgts = CardLists.filter(tgts, Predicates.or(CardPredicates.isControlledByAnyOf(ai.getAllies()), CardPredicates.isController(ai))); + List 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) { return FightAi.canFightAi(ai, sa, attack, defense); } diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index f322fd5ad39..c96fcad85b5 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -197,6 +197,15 @@ public class Game { } } + public CardCollectionView copyLastStateBattlefield() { + CardCollection result = new CardCollection(); + Map cachedMap = Maps.newHashMap(); + for (final Player p : getPlayers()) { + result.addAll(p.getZone(ZoneType.Battlefield).getLKICopy(cachedMap)); + } + return result; + } + public void updateLastStateForCard(Card c) { if (c == null || c.getZone() == null) { return; diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index a062044769d..6cd1d3aef23 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -1278,7 +1278,7 @@ public class GameAction { orderedNoRegCreats = true; } for (Card c : noRegCreats) { - sacrificeDestroy(c, null, table); + sacrificeDestroy(c, null, table, null); } } if (desCreats != null) { @@ -1290,7 +1290,7 @@ public class GameAction { orderedDesCreats = true; } for (Card c : desCreats) { - destroy(c, null, true, table); + destroy(c, null, true, table, null); } } setHoldCheckingStaticAbilities(false); @@ -1376,7 +1376,7 @@ public class GameAction { return false; } if (!game.getStack().hasSourceOnStack(c, SpellAbilityPredicates.isChapter())) { - sacrifice(c, null, table); + sacrifice(c, null, table, null); checkAgain = true; } return checkAgain; @@ -1404,7 +1404,7 @@ public class GameAction { // cleanup aura if (c.isAura() && c.isInPlay() && !c.isEnchanting()) { - sacrificeDestroy(c, null, table); + sacrificeDestroy(c, null, table, null); checkAgain = true; } return checkAgain; @@ -1556,7 +1556,7 @@ public class GameAction { for (Card c : list) { if (c.getCounters(CounterEnumType.LOYALTY) <= 0) { - sacrificeDestroy(c, null, table); + sacrificeDestroy(c, null, table, null); // Play the Destroy sound game.fireEvent(new GameEventCardDestroyed()); 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); for (Card c: cc) { if (c != toKeep) { - sacrificeDestroy(c, null, table); + sacrificeDestroy(c, null, table, null); } } game.fireEvent(new GameEventCardDestroyed()); @@ -1653,28 +1653,24 @@ public class GameAction { } for (Card c : worlds) { - sacrificeDestroy(c, null, table); + sacrificeDestroy(c, null, table, null); game.fireEvent(new GameEventCardDestroyed()); } return true; } - @Deprecated - 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) { + public final Card sacrifice(final Card c, final SpellAbility source, CardZoneTable table, Map params) { if (!c.canBeSacrificedBy(source)) { return null; } 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 params) { Player activator = null; if (!c.canBeDestroyed()) { return false; @@ -1685,6 +1681,9 @@ public class GameAction { repRunParams.put(AbilityKey.Source, sa); repRunParams.put(AbilityKey.Affected, c); repRunParams.put(AbilityKey.Regeneration, regenerate); + if (params != null) { + repRunParams.putAll(params); + } if (game.getReplacementHandler().run(ReplacementType.Destroy, repRunParams) != ReplacementResult.NotReplaced) { return false; @@ -1701,11 +1700,14 @@ public class GameAction { // Run triggers final Map runParams = AbilityKey.mapFromCard(c); runParams.put(AbilityKey.Causer, activator); + if (params != null) { + runParams.putAll(params); + } game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false); // in case the destroyed card has such a trigger game.getTriggerHandler().registerActiveLTBTrigger(c); - final Card sacrificed = sacrificeDestroy(c, sa, table); + final Card sacrificed = sacrificeDestroy(c, sa, table, params); return sacrificed != null; } @@ -1713,12 +1715,12 @@ public class GameAction { * @return the sacrificed Card in its new location, or {@code null} if the * 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 params) { if (!c.isInPlay()) { return null; } - final Card newCard = moveToGraveyard(c, cause, null); + final Card newCard = moveToGraveyard(c, cause, params); if (table != null && newCard != null && newCard.getZone() != null) { table.put(ZoneType.Battlefield, newCard.getZone().getZoneType(), newCard); } diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 60b17d1a7ab..9a09d1abbe6 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -638,6 +638,9 @@ public final class GameActionUtil { } public static CardCollectionView orderCardsByTheirOwners(Game game, CardCollectionView list, ZoneType dest, SpellAbility sa) { + if (list.size() <= 1) { + return list; + } CardCollection completeList = new CardCollection(); for (Player p : game.getPlayers()) { CardCollection subList = new CardCollection(); diff --git a/forge-game/src/main/java/forge/game/ability/AbilityKey.java b/forge-game/src/main/java/forge/game/ability/AbilityKey.java index 526173cdd87..2c5d4f86b48 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityKey.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityKey.java @@ -73,6 +73,7 @@ public enum AbilityKey { IsCombatDamage("IsCombatDamage"), IndividualCostPaymentInstance("IndividualCostPaymentInstance"), IsMadness("IsMadness"), + LastStateBattlefield("LastStateBattlefield"), LifeAmount("LifeAmount"), //TODO confirm that this and LifeGained can be merged LifeGained("LifeGained"), Mana("Mana"), diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index f28c50b925a..82f1ed8fc78 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -173,15 +173,13 @@ public class AbilityUtils { } } else if (defined.equals("Targeted") && sa instanceof SpellAbility) { - final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingCard(); - if (saTargeting != null) { - Iterables.addAll(cards, saTargeting.getTargets().getTargetCards()); + for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) { + Iterables.addAll(cards, tc.getTargetCards()); } } else if (defined.equals("TargetedSource") && sa instanceof SpellAbility) { - final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingSA(); - if (saTargeting != null) { - for (SpellAbility s : saTargeting.getTargets().getTargetSpells()) { + for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) { + for (SpellAbility s : tc.getTargetSpells()) { cards.add(s.getHostCard()); } } @@ -1008,9 +1006,8 @@ public class AbilityUtils { players.addAll(getDefinedPlayers(card, "TargetedController", sa)); } else if ((defined.equals("Targeted") || defined.equals("TargetedPlayer")) && sa instanceof SpellAbility) { - final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingPlayer(); - if (saTargeting != null) { - players.addAll(saTargeting.getTargets().getTargetPlayers()); + for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) { + players.addAll(tc.getTargetPlayers()); } } else if (defined.equals("ParentTarget") && sa instanceof SpellAbility) { @@ -1298,9 +1295,8 @@ public class AbilityUtils { s = ((SpellAbility)sa).getRootAbility(); } else if (defined.equals("Targeted") && sa instanceof SpellAbility) { - final SpellAbility saTargeting = ((SpellAbility)sa).getSATargetingSA(); - if (saTargeting != null) { - for (SpellAbility targetSpell : saTargeting.getTargets().getTargetSpells()) { + for (TargetChoices tc : ((SpellAbility)sa).getAllTargetChoices()) { + for (SpellAbility targetSpell : tc.getTargetSpells()) { SpellAbilityStackInstance stackInstance = game.getStack().getInstanceFromSpellAbility(targetSpell); if (stackInstance != null) { SpellAbility instanceSA = stackInstance.getSpellAbility(true); @@ -1412,7 +1408,6 @@ public class AbilityUtils { } return; } - AbilityUtils.resolveApiAbility(sa, game); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java index cf998098665..bc03ee03349 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BalanceEffect.java @@ -7,6 +7,7 @@ import java.util.Map; import com.google.common.collect.Maps; import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardCollection; @@ -46,7 +47,8 @@ public class BalanceEffect extends SpellAbilityEffect { validCards.add(CardLists.getValidCards(players.get(i).getCardsIn(zone), valid, activator, source, sa)); min = Math.min(min, validCards.get(i).size()); } - + + Map params = AbilityKey.newMap(); CardZoneTable table = new CardZoneTable(); for (int i = 0; i < players.size(); i++) { Player p = players.get(i); @@ -59,7 +61,7 @@ public class BalanceEffect extends SpellAbilityEffect { } else { // Battlefield for (Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) { if ( null == card ) continue; - game.getAction().sacrifice(card, sa, table); + game.getAction().sacrifice(card, sa, table, params); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java index 3999c0a81be..de281569434 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java @@ -12,6 +12,7 @@ import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardFactoryUtil; +import forge.game.card.CardZoneTable; import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementType; import forge.game.spellability.SpellAbility; @@ -113,6 +114,8 @@ public class CounterEffect extends SpellAbilityEffect { } } + Map params = AbilityKey.newMap(); + CardZoneTable table = new CardZoneTable(); for (final SpellAbility tgtSA : sas) { final Card tgtSACard = tgtSA.getHostCard(); // 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 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")) { @@ -152,6 +155,7 @@ public class CounterEffect extends SpellAbilityEffect { } } } + table.triggerChangesZoneAll(game, sa); } // end counterResolve /** diff --git a/forge-game/src/main/java/forge/game/ability/effects/DestroyAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DestroyAllEffect.java index 5fed2c7a4ef..1160541e5fa 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DestroyAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DestroyAllEffect.java @@ -6,6 +6,7 @@ import com.google.common.collect.Maps; import forge.game.Game; import forge.game.GameActionUtil; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -90,10 +91,12 @@ public class DestroyAllEffect extends SpellAbilityEffect { } CardZoneTable table = new CardZoneTable(); + Map params = AbilityKey.newMap(); + params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); Map cachedMap = Maps.newHashMap(); 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)); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java index 240a87bb202..f7eaba7e38d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DestroyEffect.java @@ -8,9 +8,10 @@ import com.google.common.collect.Maps; import forge.game.Game; import forge.game.GameActionUtil; +import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; -import forge.game.card.CardCollection; +import forge.game.card.CardCollectionView; import forge.game.card.CardUtil; import forge.game.card.CardZoneTable; import forge.game.spellability.SpellAbility; @@ -72,13 +73,16 @@ public class DestroyEffect extends SpellAbilityEffect { card.clearRemembered(); } - CardCollection tgtCards = getTargetCards(sa); - CardCollection untargetedCards = CardUtil.getRadiance(sa); + CardCollectionView tgtCards = getTargetCards(sa); + CardCollectionView untargetedCards = CardUtil.getRadiance(sa); if (tgtCards.size() > 1) { - tgtCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard, sa); + tgtCards = GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard, sa); } + Map params = AbilityKey.newMap(); + params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); + CardZoneTable table = new CardZoneTable(); Map cachedMap = Maps.newHashMap(); for (final Card tgtC : tgtCards) { @@ -90,24 +94,24 @@ public class DestroyEffect extends SpellAbilityEffect { if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) { continue; } - internalDestroy(gameCard, sa, table, cachedMap); + internalDestroy(gameCard, sa, table, cachedMap, params); } } 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) { if (unTgtC.isInPlay()) { - internalDestroy(unTgtC, sa, table, cachedMap); + internalDestroy(unTgtC, sa, table, cachedMap, params); } } table.triggerChangesZoneAll(game, sa); } - protected void internalDestroy(Card gameCard, SpellAbility sa, CardZoneTable table, Map cachedMap) { + protected void internalDestroy(Card gameCard, SpellAbility sa, CardZoneTable table, Map cachedMap, Map params) { final Card card = sa.getHostCard(); final Game game = card.getGame(); @@ -122,9 +126,9 @@ public class DestroyEffect extends SpellAbilityEffect { card.addRemembered(gameCard.getAttachedCards()); } if (sac) { - destroyed = game.getAction().sacrifice(gameCard, sa, table) != null; + destroyed = game.getAction().sacrifice(gameCard, sa, table, params) != null; } else { - destroyed = game.getAction().destroy(gameCard, sa, !noRegen, table); + destroyed = game.getAction().destroy(gameCard, sa, !noRegen, table, params); } if (destroyed && remDestroyed) { card.addRemembered(gameCard); diff --git a/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java index 70128e6bc29..c8028fa4a4b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SacrificeAllEffect.java @@ -6,6 +6,7 @@ import com.google.common.collect.Maps; import forge.game.Game; import forge.game.GameActionUtil; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -86,9 +87,12 @@ public class SacrificeAllEffect extends SpellAbilityEffect { CardZoneTable table = new CardZoneTable(); Map cachedMap = Maps.newHashMap(); + Map params = AbilityKey.newMap(); + params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); + for (Card sac : list) { 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) { card.addRemembered(lKICopy); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java index 8418c8db7d8..6ed1eff907a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java @@ -106,10 +106,12 @@ public class SacrificeEffect extends SpellAbilityEffect { final String remSVar = sa.getParam("RememberSacrificedSVar"); int countSacrificed = 0; CardZoneTable table = new CardZoneTable(); + Map params = AbilityKey.newMap(); + params.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield()); if (valid.equals("Self") && game.getZoneOf(card) != null) { 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++; if (remSacrificed) { card.addRemembered(card); @@ -152,8 +154,8 @@ public class SacrificeEffect extends SpellAbilityEffect { Map cachedMap = Maps.newHashMap(); for (Card sac : choosenToSacrifice) { final Card lKICopy = CardUtil.getLKICopy(sac, cachedMap); - boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa, table) != null; - boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa, true, table); + boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa, table, params) != null; + boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa, true, table, params); // Run Devour Trigger if (devour) { card.addDevoured(lKICopy); diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 29dd3fb5da7..416fd57c25b 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -519,28 +519,6 @@ public class CardFactoryUtil { return types.size(); } - /** - *

- * getNeededXDamage. - *

- * - * @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. * diff --git a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java index 65a536890d8..f9166c185c1 100644 --- a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java +++ b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java @@ -126,7 +126,7 @@ public class CostSacrifice extends CostPartWithList { @Override protected Card doPayment(SpellAbility ability, Card targetCard) { // 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) diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityPanharmonicon.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityPanharmonicon.java index 3db32174d63..4164631b830 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityPanharmonicon.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityPanharmonicon.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableList; import forge.game.Game; import forge.game.ability.AbilityKey; import forge.game.card.Card; +import forge.game.card.CardCollectionView; import forge.game.card.CardZoneTable; import forge.game.spellability.SpellAbility; @@ -22,8 +23,17 @@ public class StaticAbilityPanharmonicon { public static int handlePanharmonicon(final Game game, final Trigger t, final Map runParams) { 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 - 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()) { if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) { continue; diff --git a/forge-gui-desktop/src/main/java/forge/sound/AudioClip.java b/forge-gui-desktop/src/main/java/forge/sound/AudioClip.java index 66dd91540c1..ac2e0be5db5 100644 --- a/forge-gui-desktop/src/main/java/forge/sound/AudioClip.java +++ b/forge-gui-desktop/src/main/java/forge/sound/AudioClip.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -46,7 +46,7 @@ import forge.localinstance.properties.ForgeConstants; /** * SoundSystem - a simple sound playback system for Forge. * Do not use directly. Instead, use the {@link forge.sound.SoundEffectType} enumeration. - * + * * @author Agetian */ public class AudioClip implements IAudioClip { @@ -104,9 +104,9 @@ public class AudioClip implements IAudioClip { private ClipWrapper getIdleClip() { return clips.stream() - .filter(clip -> !clip.isRunning()) - .findFirst() - .orElseGet(this::addClip); + .filter(clip -> !clip.isRunning()) + .findFirst() + .orElseGet(this::addClip); } private ClipWrapper addClip() { diff --git a/forge-gui/res/cardsfolder/b/boom_bust.txt b/forge-gui/res/cardsfolder/b/boom_bust.txt index d8518e6c969..ae372264c65 100644 --- a/forge-gui/res/cardsfolder/b/boom_bust.txt +++ b/forge-gui/res/cardsfolder/b/boom_bust.txt @@ -2,9 +2,9 @@ Name:Boom ManaCost:1 R AlternateMode: Split 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. -SVar:DestroyOpp:DB$ Destroy | TgtPrompt$ Choose target land you don't control to destroy | ValidTgts$ Land.YouDontCtrl -SVar:Picture:http://www.wizards.com/global/images/magic/general/boombust.jpg +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$ Pump | TgtPrompt$ Choose target land you don't control to destroy | ValidTgts$ Land.YouDontCtrl | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +SVar:DBDestroy:DB$ Destroy | Defined$ Targeted Oracle:Destroy target land you control and target land you don't control. ALTERNATE diff --git a/forge-gui/res/cardsfolder/d/decimate.txt b/forge-gui/res/cardsfolder/d/decimate.txt index 06cc7960559..f1f28a7557b 100644 --- a/forge-gui/res/cardsfolder/d/decimate.txt +++ b/forge-gui/res/cardsfolder/d/decimate.txt @@ -1,9 +1,9 @@ Name:Decimate ManaCost:2 R G 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. -SVar:DestroyCreature:DB$ Destroy | ValidTgts$ Creature | SubAbility$ DestroyEnch | TgtPrompt$ Select target creature -SVar:DestroyEnch:DB$ Destroy | ValidTgts$ Enchantment | SubAbility$ DestroyLand | TgtPrompt$ Select target enchantment -SVar:DestroyLand:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land -SVar:Picture:http://www.wizards.com/global/images/magic/general/decimate.jpg +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$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Destroy | Curse$ True | SubAbility$ DestroyEnch +SVar:DestroyEnch:DB$ Pump | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | AILogic$ Destroy | Curse$ True | SubAbility$ DestroyLand +SVar:DestroyLand:DB$ Pump | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +SVar:DBDestroy:DB$ Destroy | Defined$ Targeted Oracle:Destroy target artifact, target creature, target enchantment, and target land. diff --git a/forge-gui/res/cardsfolder/f/fumarole.txt b/forge-gui/res/cardsfolder/f/fumarole.txt index f2adabdad92..c3f6d63722d 100644 --- a/forge-gui/res/cardsfolder/f/fumarole.txt +++ b/forge-gui/res/cardsfolder/f/fumarole.txt @@ -1,7 +1,7 @@ Name:Fumarole ManaCost:3 B R 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. -SVar:DBDestroy:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land -SVar:Picture:http://www.wizards.com/global/images/magic/general/fumarole.jpg +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:DBLand:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +SVar:DBDestroy:DB$ Destroy | Defined$ Targeted Oracle:As an additional cost to cast this spell, pay 3 life.\nDestroy target creature and target land. diff --git a/forge-gui/res/cardsfolder/g/goblin_grenadiers.txt b/forge-gui/res/cardsfolder/g/goblin_grenadiers.txt index 1b1cfa946b6..dd0c88542e1 100644 --- a/forge-gui/res/cardsfolder/g/goblin_grenadiers.txt +++ b/forge-gui/res/cardsfolder/g/goblin_grenadiers.txt @@ -3,6 +3,7 @@ ManaCost:3 R Types:Creature Goblin 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. -SVar:TrigDestroyCreature:AB$ Destroy | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBDestroyLand -SVar:DBDestroyLand:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land +SVar:TrigDestroyCreature:AB$ Pump | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Destroy | Curse$ True | SubAbility$ DBLand +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. diff --git a/forge-gui/res/cardsfolder/h/hull_breach.txt b/forge-gui/res/cardsfolder/h/hull_breach.txt index d970ed2c62d..a948f8474a2 100644 --- a/forge-gui/res/cardsfolder/h/hull_breach.txt +++ b/forge-gui/res/cardsfolder/h/hull_breach.txt @@ -4,8 +4,8 @@ Types:Sorcery 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: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:DestroyEnch:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment +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$ Pump | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +SVar:DBDestroy:DB$ Destroy | Defined$ Targeted 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. diff --git a/forge-gui/res/cardsfolder/p/plague_spores.txt b/forge-gui/res/cardsfolder/p/plague_spores.txt index eafb302bb74..5f0eb8c5f90 100644 --- a/forge-gui/res/cardsfolder/p/plague_spores.txt +++ b/forge-gui/res/cardsfolder/p/plague_spores.txt @@ -1,7 +1,7 @@ Name:Plague Spores ManaCost:4 B R 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. -SVar:DestroyLand:DB$ Destroy | ValidTgts$ Land | NoRegen$ True | TgtPrompt$ Select target land -SVar:Picture:http://www.wizards.com/global/images/magic/general/plague_spores.jpg +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:DBLand:DB$ Pump | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +SVar:DBDestroy:DB$ Destroy | Defined$ Targeted | NoRegen$ True Oracle:Destroy target nonblack creature and target land. They can't be regenerated. diff --git a/forge-gui/res/cardsfolder/r/reign_of_chaos.txt b/forge-gui/res/cardsfolder/r/reign_of_chaos.txt index 0db5267bb8e..e61c088d322 100644 --- a/forge-gui/res/cardsfolder/r/reign_of_chaos.txt +++ b/forge-gui/res/cardsfolder/r/reign_of_chaos.txt @@ -2,10 +2,10 @@ Name:Reign of Chaos ManaCost:2 R R Types:Sorcery 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:DBDestroy2:DB$ Destroy | ValidTgts$ Island | TgtPrompt$ Select target Island | SubAbility$ DBDestroyBlue | SpellDescription$ Destroy target Island and target blue creature. -SVar:DBDestroyWhite:DB$ Destroy | ValidTgts$ Creature.White | TgtPrompt$ Select target white creature -SVar:DBDestroyBlue:DB$ Destroy | ValidTgts$ Creature.Blue | TgtPrompt$ Select target blue 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$ Pump | ValidTgts$ Island | TgtPrompt$ Select target Island | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroyBlue | SpellDescription$ Destroy target Island and target blue creature. +SVar:DBDestroyWhite:DB$ Pump | ValidTgts$ Creature.White | TgtPrompt$ Select target white creature | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +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 -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. diff --git a/forge-gui/res/cardsfolder/s/spiteful_blow.txt b/forge-gui/res/cardsfolder/s/spiteful_blow.txt index 3c0b1b02c7c..e9599895fd6 100644 --- a/forge-gui/res/cardsfolder/s/spiteful_blow.txt +++ b/forge-gui/res/cardsfolder/s/spiteful_blow.txt @@ -1,7 +1,7 @@ Name:Spiteful Blow ManaCost:4 B B Types:Sorcery -A:SP$ Destroy | Cost$ 4 B B | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBDestroy | SpellDescription$ Destroy target creature and target land. -SVar:DBDestroy:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land -SVar:Picture:http://www.wizards.com/global/images/magic/general/spiteful_blow.jpg +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:DBLand:DB$ Pump | ValidTgts$ Land | TgtPrompt$ Select target land | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +SVar:DBDestroy:DB$ Destroy | Defined$ Targeted Oracle:Destroy target creature and target land. diff --git a/forge-gui/res/cardsfolder/s/stomp_and_howl.txt b/forge-gui/res/cardsfolder/s/stomp_and_howl.txt index 4aa06a4c2ee..bb5867f0022 100644 --- a/forge-gui/res/cardsfolder/s/stomp_and_howl.txt +++ b/forge-gui/res/cardsfolder/s/stomp_and_howl.txt @@ -1,7 +1,7 @@ Name:Stomp and Howl ManaCost:2 G Types:Sorcery -A:SP$ Destroy | Cost$ 2 G | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact and target enchantment. | SubAbility$ DestroyEnch -SVar:DestroyEnch:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment -SVar:Picture:http://www.wizards.com/global/images/magic/general/stomp_and_howl.jpg +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$ Pump | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +SVar:DBDestroy:DB$ Destroy | Defined$ Targeted Oracle:Destroy target artifact and target enchantment. diff --git a/forge-gui/res/cardsfolder/v/volcanic_offering.txt b/forge-gui/res/cardsfolder/v/volcanic_offering.txt index 50096c60514..140b7690f1f 100644 --- a/forge-gui/res/cardsfolder/v/volcanic_offering.txt +++ b/forge-gui/res/cardsfolder/v/volcanic_offering.txt @@ -1,9 +1,9 @@ Name:Volcanic Offering ManaCost:4 R 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. -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 +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$ 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: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. diff --git a/forge-gui/res/cardsfolder/w/wall_of_vipers.txt b/forge-gui/res/cardsfolder/w/wall_of_vipers.txt index 9f213ea3319..9ecca56871c 100644 --- a/forge-gui/res/cardsfolder/w/wall_of_vipers.txt +++ b/forge-gui/res/cardsfolder/w/wall_of_vipers.txt @@ -3,8 +3,8 @@ ManaCost:2 B Types:Creature Snake Wall PT:2/4 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. -SVar:SnakeBite:DB$ Destroy | ValidTgts$ Creature.blockedBySource +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$ Pump | ValidTgts$ Creature.blockedBySource | AILogic$ Destroy | Curse$ True | SubAbility$ DBDestroy +SVar:DBDestroy:DB$ Destroy | Defined$ Targeted 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. diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index a177fbb42f5..150f56c50ea 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -673,7 +673,7 @@ public class HumanPlay { final Card offering = ability.getSacrificedAsOffering(); offering.setUsedToPay(false); if (!manaInputCancelled) { - game.getAction().sacrifice(offering, ability, table); + game.getAction().sacrifice(offering, ability, table, null); } ability.resetSacrificedAsOffering(); } @@ -681,7 +681,7 @@ public class HumanPlay { final Card emerge = ability.getSacrificedAsEmerge(); emerge.setUsedToPay(false); if (!manaInputCancelled) { - game.getAction().sacrifice(emerge, ability, table); + game.getAction().sacrifice(emerge, ability, table, null); } ability.resetSacrificedAsEmerge(); } @@ -785,7 +785,7 @@ public class HumanPlay { if (ability.getSacrificedAsOffering() != null) { System.out.println("Finishing up Offering"); offering.setUsedToPay(false); - activator.getGame().getAction().sacrifice(offering, ability, null); + activator.getGame().getAction().sacrifice(offering, ability, null, null); ability.resetSacrificedAsOffering(); } } @@ -796,7 +796,7 @@ public class HumanPlay { if (ability.getSacrificedAsEmerge() != null) { System.out.println("Finishing up Emerge"); emerge.setUsedToPay(false); - activator.getGame().getAction().sacrifice(emerge, ability, null); + activator.getGame().getAction().sacrifice(emerge, ability, null, null); ability.resetSacrificedAsEmerge(); } }