diff --git a/forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java b/forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java index 3bf67c08cb7..87bb8b48e0a 100644 --- a/forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java +++ b/forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java @@ -88,7 +88,7 @@ public abstract class DeckGeneratorBase { protected void addCreaturesAndSpells(int size, List> cmcLevels, boolean forAi) { trace.append("Building deck of ").append(size).append("cards\n"); - + final Iterable cards = selectCardsOfMatchingColorForPlayer(forAi); // build subsets based on type @@ -102,7 +102,7 @@ public abstract class DeckGeneratorBase { final int spellCnt = (int) Math.ceil(getSpellPercentage() * size); trace.append("Spells to add:").append(spellCnt).append("\n"); addCmcAdjusted(spells, spellCnt, cmcLevels); - + trace.append(String.format("Current deck size: %d... should be %f%n", tDeck.countAll(), size * (getCreaturePercentage() + getSpellPercentage()))); } @@ -258,7 +258,7 @@ public abstract class DeckGeneratorBase { for (ImmutablePair pair : cmcLevels) { totalWeight += pair.getRight(); } - + float variability = 0.6f; // if set to 1, you'll get minimum cards to choose from float desiredWeight = (float)cnt / ( maxDuplicates * variability ); float desiredOverTotal = desiredWeight / totalWeight; diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index 59506328d64..8cb6acad942 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -184,7 +184,7 @@ public class Game { public Player getHasInitiative() { return initiative; } - public void setHasInitiative(final Player p ) { + public void setHasInitiative(final Player p) { initiative = p; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 7bf9039878c..2c8ca87cf51 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -606,7 +606,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (sa.hasParam("GainControl")) { final String g = sa.getParam("GainControl"); Player newController = g.equals("True") ? player : - AbilityUtils.getDefinedPlayers(sa.getHostCard(), g, sa).get(0); + AbilityUtils.getDefinedPlayers(hostCard, g, sa).get(0); if (newController != null) { if (newController != gameCard.getController()) { gameCard.runChangeControllerCommands(); @@ -1318,7 +1318,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (sa.hasParam("GainControl")) { final String g = sa.getParam("GainControl"); Player newController = g.equals("True") ? sa.getActivatingPlayer() : - AbilityUtils.getDefinedPlayers(sa.getHostCard(), g, sa).get(0); + AbilityUtils.getDefinedPlayers(source, g, sa).get(0); if (newController != c.getController()) { c.runChangeControllerCommands(); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java index f74cc649e8d..af7592e4830 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DamageDealEffect.java @@ -39,12 +39,7 @@ public class DamageDealEffect extends DamageBaseEffect { // when damageStackDescription is called, just build exactly what is happening final StringBuilder stringBuilder = new StringBuilder(); final String damage = spellAbility.getParam("NumDmg"); - int dmg; - try { // try-catch to fix Volcano Hellion Crash - dmg = AbilityUtils.calculateAmount(spellAbility.getHostCard(), damage, spellAbility); - } catch (NullPointerException e) { - dmg = 0; - } + int dmg = AbilityUtils.calculateAmount(spellAbility.getHostCard(), damage, spellAbility); List targets = SpellAbilityEffect.getTargets(spellAbility); final List definedSources = AbilityUtils.getDefinedCards(spellAbility.getHostCard(), spellAbility.getParam("DamageSource"), spellAbility); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DraftEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DraftEffect.java index 45778fbfbff..9ae1331ed61 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DraftEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DraftEffect.java @@ -63,7 +63,6 @@ import java.util.*; } Card chosenCard = player.getController().chooseSingleCardForZoneChange(ZoneType.None, new ArrayList(), sa, new CardCollection(draftOptions), null, Localizer.getInstance().getMessage("lblChooseCardDraft"), false, player); - chosenCard.setTokenCard(true); game.getAction().moveTo(ZoneType.None, chosenCard, sa, moveParams); drafted.add(chosenCard); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java index 0b4d242663e..444a5810d9b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/MakeCardEffect.java @@ -87,17 +87,16 @@ public class MakeCardEffect extends SpellAbilityEffect { int toMake = amount; if (!name.equals("")) { while (toMake > 0) { - Card card = Card.fromPaperCard(StaticData.instance().getCommonCards().getUniqueByName(name), - player); + Card card = Card.fromPaperCard(StaticData.instance().getCommonCards().getUniqueByName(name), player); if (sa.hasParam("TokenCard")) { card.setTokenCard(true); } game.getAction().moveTo(ZoneType.None, card, sa, moveParams); cards.add(card); toMake--; - if (sa.hasParam("Tapped")) { - card.setTapped(true); - } + if (sa.hasParam("Tapped")) { + card.setTapped(true); + } } } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDamagePrevented.java b/forge-game/src/main/java/forge/game/trigger/TriggerDamagePrevented.java index f58dab78055..d3c0f00a10f 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDamagePrevented.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDamagePrevented.java @@ -80,11 +80,6 @@ public class TriggerDamagePrevented extends Trigger { if (!Expressions.compare(actualAmount, operator, operand)) { return false; } - - System.out.print("DamageDone Amount Operator: "); - System.out.println(operator); - System.out.print("DamageDone Amount Operand: "); - System.out.println(operand); } return true; diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDamagePreventedOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerDamagePreventedOnce.java index d64c2ca41f6..6ade0a05ec8 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDamagePreventedOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDamagePreventedOnce.java @@ -75,11 +75,6 @@ public class TriggerDamagePreventedOnce extends Trigger { if (!Expressions.compare(actualAmount, operator, operand)) { return false; } - - System.out.print("DamageDone Amount Operator: "); - System.out.println(operator); - System.out.print("DamageDone Amount Operand: "); - System.out.println(operand); } return true; diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java index b91a39db1e4..7f33bc8604a 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java @@ -19,11 +19,13 @@ package forge.game.trigger; import java.util.*; +import com.google.common.base.Predicates; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimaps; +import com.google.common.collect.Table.Cell; import forge.game.CardTraitBase; import forge.game.CardTraitPredicates; @@ -445,29 +447,71 @@ public class TriggerHandler { // Torpor Orb check if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noCreatureETBTriggers) - && !regtrig.isStatic() && mode.equals(TriggerType.ChangesZone)) { - if (runParams.get(AbilityKey.Destination) instanceof String) { - final String dest = (String) runParams.get(AbilityKey.Destination); - if (dest.equals("Battlefield") && runParams.get(AbilityKey.Card) instanceof Card) { - final Card card = (Card) runParams.get(AbilityKey.Card); - if (card.isCreature()) { - return false; + && !regtrig.isStatic()) { + if (mode.equals(TriggerType.ChangesZone)) { + if (runParams.get(AbilityKey.Destination) instanceof String) { + final String dest = (String) runParams.get(AbilityKey.Destination); + if (dest.equals("Battlefield") && runParams.get(AbilityKey.Card) instanceof Card) { + final Card card = (Card) runParams.get(AbilityKey.Card); + if (card.isCreature()) { + return false; + } } } + } else if (mode.equals(TriggerType.ChangesZoneAll)) { + CardZoneTable table = (CardZoneTable) runParams.get(AbilityKey.Cards); + // find out if any other cards would still trigger it + boolean found = false; + for (Cell cell : table.cellSet()) { + // this currently assumes the table will not contain multiple destinations + // however with some effects (e.g. Goblin Welder) that should indeed be the case + // once Forge handles that correctly this section needs to account for that + // (by doing a closer check of the triggered ability first) + if (cell.getColumnKey() != ZoneType.Battlefield) { + found = true; + } else if (Iterables.any(cell.getValue(), Predicates.not(CardPredicates.isType("Creature")))) { + found = true; + } + if (found) break; + } + if (!found) { + return false; + } } } // Torpor Orb check if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noCreatureDyingTriggers) - && !regtrig.isStatic() && mode.equals(TriggerType.ChangesZone)) { - if (runParams.get(AbilityKey.Destination) instanceof String && runParams.get(AbilityKey.Origin) instanceof String) { - final String dest = (String) runParams.get(AbilityKey.Destination); - final String origin = (String) runParams.get(AbilityKey.Origin); - if (dest.equals("Graveyard") && origin.equals("Battlefield") && runParams.get(AbilityKey.Card) instanceof Card) { - final Card card = (Card) runParams.get(AbilityKey.Card); - if (card.isCreature()) { - return false; + && !regtrig.isStatic()) { + if (mode.equals(TriggerType.ChangesZone)) { + if (runParams.get(AbilityKey.Destination) instanceof String && runParams.get(AbilityKey.Origin) instanceof String) { + final String dest = (String) runParams.get(AbilityKey.Destination); + final String origin = (String) runParams.get(AbilityKey.Origin); + if (dest.equals("Graveyard") && origin.equals("Battlefield") && runParams.get(AbilityKey.Card) instanceof Card) { + // It will trigger if the ability is of a dying creature that triggers only when that creature is put into a graveyard from anywhere + if (!"Card.Self".equals(regtrig.getParam("ValidCard")) || (regtrig.hasParam("Origin") && !"Any".equals(regtrig.getParam("Origin")))) { + final Card card = (Card) runParams.get(AbilityKey.Card); + if (card.isCreature()) { + return false; + } + } } } + } else if (mode.equals(TriggerType.ChangesZoneAll)) { + CardZoneTable table = (CardZoneTable) runParams.get(AbilityKey.Cards); + boolean found = false; + for (Cell cell : table.cellSet()) { + if (cell.getRowKey() != ZoneType.Battlefield) { + found = true; + } else if (cell.getColumnKey() != ZoneType.Graveyard) { + found = true; + } else if (Iterables.any(cell.getValue(), Predicates.not(CardPredicates.isType("Creature")))) { + found = true; + } + if (found) break; + } + if (!found) { + return false; + } } } return true; diff --git a/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java b/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java index 18fe2cad984..8aa56bc5053 100644 --- a/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java +++ b/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java @@ -440,7 +440,8 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest { AssertJUnit.assertEquals(blocker, sa.getTargetCard()); } - @Test + // Run the test 100 times to ensure there's no flakiness. + @Test(invocationCount = 100) public void testChoicesResultingFromRandomEffects() { // Sometimes, the effect of a spell can be random, and as a result of that, new choices // could be selected during simulation. This test verifies that this doesn't cause problems. @@ -449,40 +450,37 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest { // seed during choice evaluation, although in the future, it may make sense to handle it // some other way. - // Run the test 100 times to ensure there's no flakiness. - for (int i = 0; i < 100; i++) { - Game game = initAndCreateGame(); - Player p = game.getPlayers().get(1); - Player opponent = game.getPlayers().get(0); + Game game = initAndCreateGame(); + Player p = game.getPlayers().get(1); + Player opponent = game.getPlayers().get(0); - addCardToZone("Chaos Warp", p, ZoneType.Hand); - addCard("Mountain", p); - addCard("Mountain", p); - addCard("Mountain", p); + addCardToZone("Chaos Warp", p, ZoneType.Hand); + addCard("Mountain", p); + addCard("Mountain", p); + addCard("Mountain", p); - addCard("Plains", opponent); - addCard("Mountain", opponent); - addCard("Forest", opponent); - // Use a card that is worthwhile to target even if the shuffle ends up choosing it - // again. In this case, life loss on ETB and leaving. - Card expectedTarget = addCard("Raving Oni-Slave", opponent); + addCard("Plains", opponent); + addCard("Mountain", opponent); + addCard("Forest", opponent); + // Use a card that is worthwhile to target even if the shuffle ends up choosing it + // again. In this case, life loss on ETB and leaving. + Card expectedTarget = addCard("Raving Oni-Slave", opponent); - addCardToZone("Chaos Warp", opponent, ZoneType.Library); - addCardToZone("Island", opponent, ZoneType.Library); - addCardToZone("Swamp", opponent, ZoneType.Library); - // The presence of Pilgrim's Eye in the library is important for this test, as this - // will result in sub-choices (which land to pick) if this card ends up being the top - // of the library during simulation. - addCardToZone("Pilgrim's Eye", opponent, ZoneType.Library); + addCardToZone("Chaos Warp", opponent, ZoneType.Library); + addCardToZone("Island", opponent, ZoneType.Library); + addCardToZone("Swamp", opponent, ZoneType.Library); + // The presence of Pilgrim's Eye in the library is important for this test, as this + // will result in sub-choices (which land to pick) if this card ends up being the top + // of the library during simulation. + addCardToZone("Pilgrim's Eye", opponent, ZoneType.Library); - game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); - game.getAction().checkStateEffects(true); + game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); + game.getAction().checkStateEffects(true); - SpellAbilityPicker picker = new SpellAbilityPicker(game, p); - SpellAbility sa = picker.chooseSpellAbilityToPlay(null); - AssertJUnit.assertNotNull(sa); - AssertJUnit.assertEquals("Chaos Warp", sa.getHostCard().getName()); - AssertJUnit.assertEquals(expectedTarget, sa.getTargetCard()); - } + SpellAbilityPicker picker = new SpellAbilityPicker(game, p); + SpellAbility sa = picker.chooseSpellAbilityToPlay(null); + AssertJUnit.assertNotNull(sa); + AssertJUnit.assertEquals("Chaos Warp", sa.getHostCard().getName()); + AssertJUnit.assertEquals(expectedTarget, sa.getTargetCard()); } } diff --git a/forge-gui/res/cardsfolder/a/ashcoat_of_the_shadow_swarm.txt b/forge-gui/res/cardsfolder/a/ashcoat_of_the_shadow_swarm.txt index 1d808fc1103..af54e6306ac 100644 --- a/forge-gui/res/cardsfolder/a/ashcoat_of_the_shadow_swarm.txt +++ b/forge-gui/res/cardsfolder/a/ashcoat_of_the_shadow_swarm.txt @@ -7,7 +7,7 @@ T:Mode$ Blocks | ValidCard$ Card.Self | Execute$ TrigPump | Secondary$ True | Tr SVar:TrigPump:DB$ PumpAll | ValidCards$ Rat.Other+YouCtrl | NumAtt$ +X | NumDef$ +X SVar:X:Count$Valid Rat.YouCtrl T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigChange | TriggerDescription$ At the beginning of your end step, you may mill four cards. If you do, return up to two Rat creature cards from your graveyard to your hand. (To mill a card, put the top card of your library into your graveyard.) -SVar:TrigChange:AB$ ChangeZone | Cost$ Mill<4> | Origin$ Graveyard | Destination$ Hand | ChangeType$ Rat.Creature+YouOwn | ChangeNum$ 2 | SelectPrompt$ Select up to two Rat creature cards +SVar:TrigChange:AB$ ChangeZone | Cost$ Mill<4> | Origin$ Graveyard | Destination$ Hand | ChangeType$ Rat.Creature+YouOwn | ChangeNum$ 2 | Hidden$ True | SelectPrompt$ Select up to two Rat creature cards SVar:HasAttackEffect:TRUE SVar:HasBlockEffect:TRUE DeckNeeds:Type$Rat diff --git a/forge-gui/res/cardsfolder/d/district_guide.txt b/forge-gui/res/cardsfolder/d/district_guide.txt index f227c42871b..85720f104c3 100644 --- a/forge-gui/res/cardsfolder/d/district_guide.txt +++ b/forge-gui/res/cardsfolder/d/district_guide.txt @@ -2,6 +2,6 @@ Name:District Guide ManaCost:2 G Types:Creature Elf Scout PT:2/2 -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ TrigChange | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library for a basic land card or Gate card, reveal it, put it into your hand, then shuffle. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChange | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library for a basic land card or Gate card, reveal it, put it into your hand, then shuffle. SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Basic,Card.Gate | ChangeNum$ 1 | ShuffleNonMandatory$ True Oracle:When District Guide enters the battlefield, you may search your library for a basic land card or Gate card, reveal it, put it into your hand, then shuffle. diff --git a/forge-gui/res/cardsfolder/d/djeru_with_eyes_open.txt b/forge-gui/res/cardsfolder/d/djeru_with_eyes_open.txt index 4f2f2363548..32d1d25f730 100644 --- a/forge-gui/res/cardsfolder/d/djeru_with_eyes_open.txt +++ b/forge-gui/res/cardsfolder/d/djeru_with_eyes_open.txt @@ -3,7 +3,7 @@ ManaCost:3 W W Types:Legendary Creature Human Warrior PT:4/3 K:Vigilance -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ TrigChange | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library for a planeswalker card, reveal it, put it into your hand, then shuffle. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChange | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library for a planeswalker card, reveal it, put it into your hand, then shuffle. SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Planeswalker | ChangeNum$ 1 | ShuffleNonMandatory$ True R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Planeswalker.YouCtrl | ReplaceWith$ DBReplace | PreventionEffect$ True | Description$ If a source would deal damage to a planeswalker you control, prevent 1 of that damage. SVar:DBReplace:DB$ ReplaceDamage | Amount$ 1 diff --git a/forge-gui/res/cardsfolder/d/dread.txt b/forge-gui/res/cardsfolder/d/dread.txt index 51d664eadce..39b56b691b3 100644 --- a/forge-gui/res/cardsfolder/d/dread.txt +++ b/forge-gui/res/cardsfolder/d/dread.txt @@ -4,7 +4,7 @@ Types:Creature Elemental Incarnation PT:6/6 K:Fear T:Mode$ DamageDone | ValidSource$ Creature.inZoneBattlefield | ValidTarget$ You | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever a creature deals damage to you, destroy it. -T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. SVar:TrigShuffle:DB$ ChangeZone | Origin$ Graveyard | Destination$ Library | Shuffle$ True | Defined$ TriggeredCardLKICopy SVar:TrigDestroy:DB$ Destroy | Defined$ TriggeredSourceLKICopy Oracle:Fear (This creature can't be blocked except by artifact creatures and/or black creatures.)\nWhenever a creature deals damage to you, destroy it.\nWhen Dread is put into a graveyard from anywhere, shuffle it into its owner's library. diff --git a/forge-gui/res/cardsfolder/e/emrakul_the_aeons_torn.txt b/forge-gui/res/cardsfolder/e/emrakul_the_aeons_torn.txt index ba1d21bbe8e..883771f9f04 100644 --- a/forge-gui/res/cardsfolder/e/emrakul_the_aeons_torn.txt +++ b/forge-gui/res/cardsfolder/e/emrakul_the_aeons_torn.txt @@ -6,7 +6,7 @@ K:This spell can't be countered. K:Flying K:Protection:Spell.nonColorless:Protection from colored spells K:Annihilator:6 -T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, its owner shuffles their graveyard into their library. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, its owner shuffles their graveyard into their library. SVar:TrigShuffle:DB$ ChangeZoneAll | Defined$ TriggeredCardOwner | ChangeType$ Card | Origin$ Graveyard | Destination$ Library | Shuffle$ True T:Mode$ SpellCast | ValidCard$ Card.Self | Execute$ TrigAddTurn | TriggerDescription$ When you cast CARDNAME, take an extra turn after this one. SVar:TrigAddTurn:DB$ AddTurn | Defined$ You | NumTurns$ 1 diff --git a/forge-gui/res/cardsfolder/h/hostility.txt b/forge-gui/res/cardsfolder/h/hostility.txt index 2df2f1d4fd2..e2077ab6d37 100644 --- a/forge-gui/res/cardsfolder/h/hostility.txt +++ b/forge-gui/res/cardsfolder/h/hostility.txt @@ -6,6 +6,6 @@ K:Haste R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Spell.YouCtrl | ValidTarget$ Opponent | PreventionEffect$ True | ReplaceWith$ HostilityTokens | Description$ If a spell you control would deal damage to an opponent, prevent that damage. Create a 3/1 red Elemental Shaman creature token with haste for each 1 damage prevented this way. SVar:HostilityTokens:DB$ Token | TokenAmount$ X | TokenScript$ r_3_1_elemental_shaman_haste | TokenOwner$ You SVar:X:ReplaceCount$DamageAmount -T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. SVar:TrigShuffle:DB$ ChangeZone | Origin$ Graveyard | Destination$ Library | Shuffle$ True | Defined$ TriggeredCardLKICopy Oracle:Haste\nIf a spell you control would deal damage to an opponent, prevent that damage. Create a 3/1 red Elemental Shaman creature token with haste for each 1 damage prevented this way.\nWhen Hostility is put into a graveyard from anywhere, shuffle it into its owner's library. diff --git a/forge-gui/res/cardsfolder/h/hunters_insight.txt b/forge-gui/res/cardsfolder/h/hunters_insight.txt index 1a4865e5cd7..b8b1a609362 100644 --- a/forge-gui/res/cardsfolder/h/hunters_insight.txt +++ b/forge-gui/res/cardsfolder/h/hunters_insight.txt @@ -1,7 +1,7 @@ Name:Hunter's Insight ManaCost:2 G Types:Instant -A:SP$ Effect | ValidTgts$ Creature | TgtPrompt$ Select target creature | Triggers$ TrigDamage | RememberObjects$ Targeted | SpellDescription$ Choose target creature you control. Whenever that creature deals combat damage to a player or planeswalker this turn, draw that many cards. +A:SP$ Effect | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature | Triggers$ TrigDamage | RememberObjects$ Targeted | SpellDescription$ Choose target creature you control. Whenever that creature deals combat damage to a player or planeswalker this turn, draw that many cards. SVar:TrigDamage:Mode$ DamageDone | ValidSource$ Creature.IsRemembered | ValidTarget$ Player,Planeswalker | Execute$ TrigDraw | CombatDamage$ True | TriggerDescription$ Whenever that creature deals combat damage to a player or planeswalker this turn, draw that many cards. SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ X SVar:X:TriggerCount$DamageAmount diff --git a/forge-gui/res/cardsfolder/l/lord_of_tresserhorn.txt b/forge-gui/res/cardsfolder/l/lord_of_tresserhorn.txt index ebec32e0139..e188b8272dd 100644 --- a/forge-gui/res/cardsfolder/l/lord_of_tresserhorn.txt +++ b/forge-gui/res/cardsfolder/l/lord_of_tresserhorn.txt @@ -2,7 +2,7 @@ Name:Lord of Tresserhorn ManaCost:1 U B R Types:Legendary Creature Zombie PT:10/4 -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ TrigLose | AILogic$ BadETB | TriggerDescription$ When CARDNAME enters the battlefield, you lose 2 life, you sacrifice two creatures, and target opponent draws two cards. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigLose | AILogic$ BadETB | TriggerDescription$ When CARDNAME enters the battlefield, you lose 2 life, you sacrifice two creatures, and target opponent draws two cards. A:AB$ Regenerate | Cost$ B | SpellDescription$ Regenerate CARDNAME. SVar:TrigLose:DB$ LoseLife | LifeAmount$ 2 | SubAbility$ DBSac SVar:DBSac:DB$ Sacrifice | Amount$ 2 | SacValid$ Creature | SubAbility$ DBDraw diff --git a/forge-gui/res/cardsfolder/m/mandate_of_abaddon.txt b/forge-gui/res/cardsfolder/m/mandate_of_abaddon.txt index 9036d835c98..7ac1feed5b2 100644 --- a/forge-gui/res/cardsfolder/m/mandate_of_abaddon.txt +++ b/forge-gui/res/cardsfolder/m/mandate_of_abaddon.txt @@ -1,7 +1,7 @@ Name:Mandate of Abaddon ManaCost:3 B Types:Sorcery -A:SP$ ChooseCard | Choices$ Creature.YouCtrl | TgtPrompt$ Choose target creature you control | SubAbility$ DBDestroyAll | SpellDescription$ Choose target creature you control. Destroy all creatures with power less than that creature's power. +A:SP$ ChooseCard | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Choose target creature you control | SubAbility$ DBDestroyAll | SpellDescription$ Choose target creature you control. Destroy all creatures with power less than that creature's power. SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Creature.powerLTX SVar:X:Targeted$CardPower Oracle:Choose target creature you control. Destroy all creatures with power less than that creature's power. diff --git a/forge-gui/res/cardsfolder/n/nicol_bolas_dragon_god.txt b/forge-gui/res/cardsfolder/n/nicol_bolas_dragon_god.txt index 1da2899ce24..d947b80f1f8 100644 --- a/forge-gui/res/cardsfolder/n/nicol_bolas_dragon_god.txt +++ b/forge-gui/res/cardsfolder/n/nicol_bolas_dragon_god.txt @@ -5,7 +5,7 @@ Loyalty:4 S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Battlefield | GainsAbilitiesOf$ Planeswalker.Other | GainsValidAbilities$ Activated.Loyalty | Description$ CARDNAME has all loyalty abilities of all other planeswalkers on the battlefield. A:AB$ Draw | Cost$ AddCounter<1/LOYALTY> | NumCards$ 1 | SubAbility$ DBChangeZone | Planeswalker$ True | SpellDescription$ You draw a card. Each opponent exiles a card from their hand or a permanent they control. SVar:DBChangeZone:DB$ ChangeZone | Origin$ Battlefield,Hand | Destination$ Exile | DefinedPlayer$ Player.Opponent | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True -AI:RemoveDeck:Random A:AB$ Destroy | Cost$ SubCounter<3/LOYALTY> | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker | Planeswalker$ True | SpellDescription$ Destroy target creature or planeswalker. A:AB$ LosesGame | Cost$ SubCounter<8/LOYALTY> | Defined$ Player.Opponent+controlsLegendary.Creature_EQ0+controlsPlaneswalker_LE0 | Planeswalker$ True | Ultimate$ True | SpellDescription$ Each opponent who doesn't control a legendary creature or planeswalker loses the game. +AI:RemoveDeck:Random Oracle:Nicol Bolas, Dragon-God has all loyalty abilities of all other planeswalkers on the battlefield.\n[+1]: You draw a card. Each opponent exiles a card from their hand or a permanent they control.\n[-3]: Destroy target creature or planeswalker.\n[-8]: Each opponent who doesn't control a legendary creature or planeswalker loses the game. diff --git a/forge-gui/res/cardsfolder/s/serra_avatar.txt b/forge-gui/res/cardsfolder/s/serra_avatar.txt index adc5e5bc115..1cc4b9c1673 100644 --- a/forge-gui/res/cardsfolder/s/serra_avatar.txt +++ b/forge-gui/res/cardsfolder/s/serra_avatar.txt @@ -4,6 +4,6 @@ Types:Creature Avatar PT:*/* S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAME's power and toughness are each equal to your life total. SVar:X:Count$YourLifeTotal -T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. SVar:TrigShuffle:DB$ ChangeZone | Origin$ Graveyard | Destination$ Library | Shuffle$ True | Defined$ TriggeredCardLKICopy Oracle:Serra Avatar's power and toughness are each equal to your life total.\nWhen Serra Avatar is put into a graveyard from anywhere, shuffle it into its owner's library. diff --git a/forge-gui/res/cardsfolder/s/skyline_savior.txt b/forge-gui/res/cardsfolder/s/skyline_savior.txt index 734dc67e916..16a848f3387 100644 --- a/forge-gui/res/cardsfolder/s/skyline_savior.txt +++ b/forge-gui/res/cardsfolder/s/skyline_savior.txt @@ -3,7 +3,7 @@ ManaCost:1 W W Types:Creature Angel PT:3/4 K:Flying -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ TrigChange | TriggerDescription$ When CARDNAME enters the battlefield, return a permanent you control to its owner's hand. If it's a non-Angel creature card, it perpetually gets +1/+1, gains flying, and becomes an Angel in addition to its other types. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChange | TriggerDescription$ When CARDNAME enters the battlefield, return a permanent you control to its owner's hand. If it's a non-Angel creature card, it perpetually gets +1/+1, gains flying, and becomes an Angel in addition to its other types. SVar:TrigChange:DB$ ChangeZone | Origin$ Battlefield | Destination$ Hand | Hidden$ True | Mandatory$ True | ChangeType$ Permanent.YouCtrl | RememberChanged$ True | SubAbility$ DBEffect SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ PerpetualAbility | Duration$ Permanent | Triggers$ Update | Name$ Skyline Savior's Perpetual Effect | ConditionDefined$ Remembered | ConditionPresent$ Creature+nonAngel | SubAbility$ DBCleanup SVar:PerpetualAbility:Mode$ Continuous | Affected$ Card.IsRemembered | AddPower$ 1 | AddToughness$ 1 | AddType$ Angel | AddKeyword$ Flying | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ This creature perpetually gets +1/+1, gains flying, and becomes an Angel in addition to its other types. diff --git a/forge-gui/res/cardsfolder/s/soul_of_emancipation.txt b/forge-gui/res/cardsfolder/s/soul_of_emancipation.txt index a434c8fa7c5..99a84b94924 100644 --- a/forge-gui/res/cardsfolder/s/soul_of_emancipation.txt +++ b/forge-gui/res/cardsfolder/s/soul_of_emancipation.txt @@ -4,7 +4,8 @@ Types:Creature Avatar PT:5/7 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ When CARDNAME enters the battlefield, destroy up to three other target nonland permanents. For each of those permanents, its controller creates a 3/3 white Angel creature token with flying. SVar:TrigDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ 3 | ValidTgts$ Permanent.nonLand | TgtPrompt$ Choose up to three nonland permanents | RememberTargets$ True | SubAbility$ MakeTokens -SVar:MakeTokens:DB$ RepeatEach | RepeatSubAbility$ DBToken | DefinedCards$ Remembered | UseImprinted$ True | ChangeZoneTable$ True +SVar:MakeTokens:DB$ RepeatEach | RepeatSubAbility$ DBToken | DefinedCards$ Remembered | UseImprinted$ True | ChangeZoneTable$ True | SubAbility$ DBCleanup SVar:DBToken:DB$ Token | TokenScript$ w_3_3_angel_flying | TokenOwner$ ImprintedController +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True DeckHas:Ability$Token & Type$Angel Oracle:When Soul of Emancipation enters the battlefield, destroy up to three other target nonland permanents. For each of those permanents, its controller creates a 3/3 white Angel creature token with flying. diff --git a/forge-gui/res/cardsfolder/s/squadron_hawk.txt b/forge-gui/res/cardsfolder/s/squadron_hawk.txt index 98486985942..a2749a1ad9d 100644 --- a/forge-gui/res/cardsfolder/s/squadron_hawk.txt +++ b/forge-gui/res/cardsfolder/s/squadron_hawk.txt @@ -3,7 +3,7 @@ ManaCost:1 W Types:Creature Bird PT:1/1 K:Flying -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ TrigChange | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library for up to three cards named Squadron Hawk, reveal them, put them into your hand, then shuffle. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChange | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library for up to three cards named Squadron Hawk, reveal them, put them into your hand, then shuffle. SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Card.namedSquadron Hawk | ChangeNum$ 3 | ShuffleNonMandatory$ True DeckHints:Name$Squadron Hawk Oracle:Flying\nWhen Squadron Hawk enters the battlefield, you may search your library for up to three cards named Squadron Hawk, reveal them, put them into your hand, then shuffle. diff --git a/forge-gui/res/cardsfolder/s/stalking_yeti.txt b/forge-gui/res/cardsfolder/s/stalking_yeti.txt index 9a818134cb7..d9db5d3a2b3 100644 --- a/forge-gui/res/cardsfolder/s/stalking_yeti.txt +++ b/forge-gui/res/cardsfolder/s/stalking_yeti.txt @@ -2,7 +2,7 @@ Name:Stalking Yeti ManaCost:2 R R Types:Snow Creature Yeti PT:3/3 -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ TrigDamage | TriggerDescription$ When CARDNAME enters the battlefield, if it's on the battlefield, it deals damage equal to its power to target creature an opponent controls and that creature deals damage equal to its power to CARDNAME. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerDescription$ When CARDNAME enters the battlefield, if it's on the battlefield, it deals damage equal to its power to target creature an opponent controls and that creature deals damage equal to its power to CARDNAME. SVar:TrigDamage:DB$ DealDamage | IsPresent$ Card.Self | PresentZone$ Battlefield | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | NumDmg$ X | SubAbility$ DBDamage SVar:DBDamage:DB$ DealDamage | Defined$ Self | DamageSource$ Targeted | NumDmg$ Y A:AB$ ChangeZone | Cost$ 2 S | Origin$ Battlefield | Destination$ Hand | SorcerySpeed$ True | SpellDescription$ Return CARDNAME to its owner's hand. Activate only any time you could cast a sorcery. diff --git a/forge-gui/res/cardsfolder/v/vigor.txt b/forge-gui/res/cardsfolder/v/vigor.txt index 524e3c01fca..1a8b81ab7f5 100644 --- a/forge-gui/res/cardsfolder/v/vigor.txt +++ b/forge-gui/res/cardsfolder/v/vigor.txt @@ -6,6 +6,6 @@ K:Trample R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Creature.YouCtrl+Other | ReplaceWith$ Counters | PreventionEffect$ True | ExecuteMode$ PerTarget | Description$ If damage would be dealt to another creature you control, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way. SVar:Counters:DB$ PutCounter | Defined$ ReplacedTarget | CounterType$ P1P1 | CounterNum$ X SVar:X:ReplaceCount$DamageAmount -T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. SVar:TrigShuffle:DB$ ChangeZone | Origin$ Graveyard | Destination$ Library | Shuffle$ True | Defined$ TriggeredCardLKICopy Oracle:Trample\nIf damage would be dealt to another creature you control, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way.\nWhen Vigor is put into a graveyard from anywhere, shuffle it into its owner's library. diff --git a/forge-gui/res/cardsfolder/w/worldspine_wurm.txt b/forge-gui/res/cardsfolder/w/worldspine_wurm.txt index 83620907ced..c4090c1f5c5 100644 --- a/forge-gui/res/cardsfolder/w/worldspine_wurm.txt +++ b/forge-gui/res/cardsfolder/w/worldspine_wurm.txt @@ -4,7 +4,7 @@ Types:Creature Wurm PT:15/15 K:Trample T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME dies, create three 5/5 green Wurm creature tokens with trample. -T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. SVar:TrigShuffle:DB$ ChangeZone | Origin$ Graveyard | Destination$ Library | Shuffle$ True | Defined$ TriggeredCardLKICopy SVar:TrigToken:DB$ Token | TokenAmount$ 3 | TokenScript$ g_5_5_wurm_trample | TokenOwner$ TriggeredCardController DeckHas:Ability$Token