diff --git a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java index 6cee9511771..13d36cd4633 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityFactory.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 . */ @@ -28,6 +28,7 @@ import forge.card.CardStateName; import forge.game.CardTraitBase; import forge.game.IHasSVars; import forge.game.ability.effects.CharmEffect; +import forge.game.ability.effects.RollDiceEffect; import forge.game.card.Card; import forge.game.card.CardState; import forge.game.cost.Cost; @@ -45,7 +46,7 @@ import io.sentry.event.BreadcrumbBuilder; *

* AbilityFactory class. *

- * + * * @author Forge * @version $Id$ */ @@ -71,7 +72,7 @@ public final class AbilityFactory { Spell("SP"), StaticAbility("ST"), SubAbility("DB"); - + private final String prefix; AbilityRecordType(String prefix) { this.prefix = prefix; @@ -79,7 +80,7 @@ public final class AbilityFactory { public String getPrefix() { return prefix; } - + public SpellAbility buildSpellAbility(ApiType api, Card hostCard, Cost abCost, TargetRestrictions abTgt, Map mapParams ) { switch(this) { case Ability: return new AbilityApiBased(api, hostCard, abCost, abTgt, mapParams); @@ -89,11 +90,11 @@ public final class AbilityFactory { } return null; // exception here would be fine! } - + public ApiType getApiTypeOf(Map abParams) { return ApiType.smartValueOf(abParams.get(this.getPrefix())); } - + public static AbilityRecordType getRecordType(Map abParams) { if (abParams.containsKey(AbilityRecordType.Ability.getPrefix())) { return AbilityRecordType.Ability; @@ -108,7 +109,7 @@ public final class AbilityFactory { } } } - + public static final SpellAbility getAbility(final String abString, final Card card) { return getAbility(abString, card, card.getCurrentState()); } @@ -119,7 +120,7 @@ public final class AbilityFactory { *

* getAbility. *

- * + * * @param abString * a {@link java.lang.String} object. * @param state @@ -129,7 +130,7 @@ public final class AbilityFactory { public static final SpellAbility getAbility(final String abString, final CardState state) { return getAbility(abString, state, state); } - + private static final SpellAbility getAbility(final String abString, final CardState state, final IHasSVars sVarHolder) { Map mapParams; try { @@ -155,7 +156,7 @@ public final class AbilityFactory { throw new RuntimeException(msg + " of card: " + state.getName(), ex); } } - + public static final SpellAbility getAbility(final Card hostCard, final String svar) { return getAbility(hostCard, svar, hostCard.getCurrentState()); } @@ -163,7 +164,7 @@ public final class AbilityFactory { public static final SpellAbility getAbility(final Card hostCard, final String svar, final IHasSVars sVarHolder) { return getAbility(hostCard.getCurrentState(), svar, sVarHolder); } - + public static final SpellAbility getAbility(final CardState state, final String svar, final IHasSVars sVarHolder) { if (!sVarHolder.hasSVar(svar)) { String source = state.getCard().getName(); @@ -285,15 +286,18 @@ public final class AbilityFactory { @Override public AbilitySub apply(String input) { return getSubAbility(state, input, sVarHolder); - } + } })); } } if (api == ApiType.RollDice) { - for (String param : mapParams.keySet()) { - if (param.startsWith("On") || param.equals("Else")) { - spellAbility.setAdditionalAbility(param, getSubAbility(state, mapParams.get(param), sVarHolder)); + final String key = "ResultSubAbilities"; + if (mapParams.containsKey(key)) { + String [] diceAbilities = mapParams.get(key).split(","); + for (String ab : diceAbilities) { + String [] kv = ab.split(":"); + spellAbility.setAdditionalAbility(kv[0], getSubAbility(state, kv[1], sVarHolder)); } } } @@ -311,7 +315,6 @@ public final class AbilityFactory { } sb.append(mapParams.get("SpellDescription")); - spellAbility.setDescription(sb.toString()); } else if (api == ApiType.Charm) { spellAbility.setDescription(CharmEffect.makeFormatedDescription(spellAbility)); @@ -319,6 +322,12 @@ public final class AbilityFactory { spellAbility.setDescription(""); } + if (api == ApiType.RollDice) { + spellAbility.setDescription(spellAbility.getDescription() + RollDiceEffect.makeFormatedDescription(spellAbility)); + } else if (api == ApiType.Repeat) { + spellAbility.setDescription(spellAbility.getDescription() + spellAbility.getAdditionalAbility("RepeatSubAbility").getDescription()); + } + initializeParams(spellAbility); makeRestrictions(spellAbility); makeConditions(spellAbility); @@ -399,7 +408,7 @@ public final class AbilityFactory { *

* initializeParams. *

- * + * * @param sa * a {@link forge.game.spellability.SpellAbility} object. */ @@ -414,7 +423,7 @@ public final class AbilityFactory { *

* makeRestrictions. *

- * + * * @param sa * a {@link forge.game.spellability.SpellAbility} object. */ @@ -428,7 +437,7 @@ public final class AbilityFactory { *

* makeConditions. *

- * + * * @param sa * a {@link forge.game.spellability.SpellAbility} object. */ @@ -444,7 +453,7 @@ public final class AbilityFactory { * getSubAbility. *

* @param sSub - * + * * @return a {@link forge.game.spellability.AbilitySub} object. */ private static final AbilitySub getSubAbility(CardState state, String sSub, final IHasSVars sVarHolder) { @@ -466,19 +475,19 @@ public final class AbilityFactory { List origin = ZoneType.listValueOf(params.get("Origin")); final TargetRestrictions tgt = sa.getTargetRestrictions(); - + // Don't set the zone if it targets a player if ((tgt != null) && !tgt.canTgtPlayer()) { sa.getTargetRestrictions().setZone(origin); } } - + } public static final SpellAbility buildFusedAbility(final Card card) { - if(!card.isSplitCard()) + if(!card.isSplitCard()) throw new IllegalStateException("Fuse ability may be built only on split cards"); - + CardState leftState = card.getState(CardStateName.LeftSplit); SpellAbility leftAbility = leftState.getFirstAbility(); Map leftMap = Maps.newHashMap(leftAbility.getMapParams()); 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 b0b6aaf65ae..ac3267a8710 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -740,7 +740,18 @@ public class AbilityUtils { final SpellAbility root = sa.getRootAbility(); final String[] l = calcX[1].split("/"); final String m = CardFactoryUtil.extractOperators(calcX[1]); - final Integer count = (Integer) root.getTriggeringObject(AbilityKey.fromString(l[0])); + Integer count = null; + if (calcX[0].endsWith("Max")) { + @SuppressWarnings("unchecked") + Iterable numbers = (Iterable) root.getTriggeringObject(AbilityKey.fromString(l[0])); + for (Integer n : numbers) { + if (count == null || n > count) { + count = n; + } + } + } else { + count = (Integer) root.getTriggeringObject(AbilityKey.fromString(l[0])); + } val = doXMath(ObjectUtils.firstNonNull(count, 0), m, card, ability); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java index ab26ada5ced..4fc0511c5b4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java @@ -19,6 +19,28 @@ import forge.util.MyRandom; public class RollDiceEffect extends SpellAbilityEffect { + public static String makeFormatedDescription(SpellAbility sa) { + StringBuilder sb = new StringBuilder(); + final String key = "ResultSubAbilities"; + if (sa.hasParam(key)) { + String [] diceAbilities = sa.getParam(key).split(","); + for (String ab : diceAbilities) { + String [] kv = ab.split(":"); + String desc = sa.getAdditionalAbility(kv[0]).getDescription(); + if (!desc.isEmpty()) { + sb.append("\n\n").append(desc); + } + } + } + + return sb.toString(); + } + + private static int getRollAdvange(final Player player) { + String str = "If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll."; + return player.getKeywords().getAmount(str); + } + /* (non-Javadoc) * @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility) */ @@ -32,9 +54,9 @@ public class RollDiceEffect extends SpellAbilityEffect { } else { stringBuilder.append(player).append(" rolls "); } - stringBuilder.append(sa.getParamOrDefault("Amt", "a")).append(" "); + stringBuilder.append(sa.getParamOrDefault("Amount", "a")).append(" "); stringBuilder.append(sa.getParamOrDefault("Sides", "6")).append("-sided "); - if (sa.getParamOrDefault("Amt", "1").equals("1")) { + if (sa.getParamOrDefault("Amount", "1").equals("1")) { stringBuilder.append("die."); } else { stringBuilder.append("dice."); @@ -42,6 +64,73 @@ public class RollDiceEffect extends SpellAbilityEffect { return stringBuilder.toString(); } + private void rollDice(SpellAbility sa, Player player, int amount, int sides) { + final Card host = sa.getHostCard(); + final int modifier = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Modifier", "0"), sa); + final int advantage = getRollAdvange(player); + amount += advantage; + int total = 0; + List rolls = new ArrayList<>(); + + for (int i = 0; i < amount; i++) { + int roll = MyRandom.getRandom().nextInt(sides) + 1; + rolls.add(roll); + total += roll; + } + + if (amount > 0) { + String message = Localizer.getInstance().getMessage("lblPlayerRolledResult", player, StringUtils.join(rolls, ", ")); + player.getGame().getAction().notifyOfValue(sa, player, message, null); + } + + // Ignore lowest rolls + if (advantage > 0) { + rolls.sort(null); + for (int i = advantage - 1; i >= 0; --i) { + total -= rolls.get(i); + rolls.remove(i); + } + } + + // Run triggers + for (Integer roll : rolls) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Player, player); + runParams.put(AbilityKey.Result, roll); + player.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDie, runParams, false); + } + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Player, player); + runParams.put(AbilityKey.Result, rolls); + player.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDieOnce, runParams, false); + + total += modifier; + if (sa.hasParam("ResultSVar")) { + host.setSVar(sa.getParam("ResultSVar"), Integer.toString(total)); + } + + Map diceAbilities = sa.getAdditionalAbilities(); + SpellAbility resultAbility = null; + for (Map.Entry e: diceAbilities.entrySet()) { + String diceKey = e.getKey(); + if (diceKey.contains("-")) { + String [] ranges = diceKey.split("-"); + if (Integer.parseInt(ranges[0]) <= total && Integer.parseInt(ranges[1]) >= total) { + resultAbility = e.getValue(); + break; + } + } else if (StringUtils.isNumeric(diceKey) && Integer.parseInt(diceKey) == total) { + resultAbility = e.getValue(); + break; + } + } + if (resultAbility != null) { + AbilityUtils.resolve(resultAbility); + } else if (sa.hasAdditionalAbility("Else")) { + AbilityUtils.resolve(sa.getAdditionalAbility("Else")); + } + } + /* (non-Javadoc) * @see forge.card.ability.SpellAbilityEffect#resolve(forge.card.spellability.SpellAbility) */ @@ -49,42 +138,13 @@ public class RollDiceEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); - int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Amt", "1"), sa); + int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Amount", "1"), sa); int sides = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Sides", "6"), sa); final PlayerCollection playersToRoll = getTargetPlayers(sa); for(Player player : playersToRoll) { - int total = 0; - List rolls = new ArrayList<>(); - for (int i = 0; i < amount; i++) { - int roll = MyRandom.getRandom().nextInt(sides) + 1; - rolls.add(roll); - - final Map runParams = AbilityKey.newMap(); - runParams.put(AbilityKey.Player, player); - runParams.put(AbilityKey.Result, roll); - player.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDie, runParams, false); - - total += roll; - } - - if (amount > 0) { - String message = Localizer.getInstance().getMessage("lblPlayerRolledResult", player, StringUtils.join(rolls, ", ")); - player.getGame().getAction().notifyOfValue(sa, player, message, null); - } - - if (sa.hasParam("ResultSVar")) { - host.setSVar(sa.getParam("ResultSVar"), ""+total); - } - if (sa.hasAdditionalAbility("OnDoubles") && rolls.get(0).equals(rolls.get(1))) { - AbilityUtils.resolve(sa.getAdditionalAbility("OnDoubles")); - } - if (sa.hasAdditionalAbility("On"+total)) { - AbilityUtils.resolve(sa.getAdditionalAbility("On"+total)); - } else if (sa.hasAdditionalAbility("Else")) { - AbilityUtils.resolve(sa.getAdditionalAbility("Else")); - } + rollDice(sa, player, amount, sides); } } -} \ No newline at end of file +} diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 00994aa4a53..cb1ed0c530b 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -807,7 +807,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return description; } public void setDescription(final String s) { - originalDescription = s; + originalDescription = TextUtil.fastReplace(s, "VERT", "|"); description = originalDescription; } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerRolledDie.java b/forge-game/src/main/java/forge/game/trigger/TriggerRolledDie.java index 2e22f76f275..a478b73e932 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerRolledDie.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerRolledDie.java @@ -17,7 +17,8 @@ public class TriggerRolledDie extends Trigger { } /** {@inheritDoc} - * @param runParams*/ + * @param runParams + */ @Override public final boolean performTest(final Map runParams) { if (hasParam("ValidPlayer")) { diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerRolledDieOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerRolledDieOnce.java new file mode 100644 index 00000000000..d7eb65bd34f --- /dev/null +++ b/forge-game/src/main/java/forge/game/trigger/TriggerRolledDieOnce.java @@ -0,0 +1,41 @@ +package forge.game.trigger; + +import java.util.Map; + +import forge.game.ability.AbilityKey; +import forge.game.card.Card; +import forge.game.spellability.SpellAbility; +import forge.util.Localizer; + +public class TriggerRolledDieOnce extends Trigger { + + public TriggerRolledDieOnce(final Map params, final Card host, final boolean intrinsic) { + super(params, host, intrinsic); + } + + /** {@inheritDoc} + * @param runParams + */ + @Override + public final boolean performTest(final Map runParams) { + if (hasParam("ValidPlayer")) { + if (!matchesValid(runParams.get(AbilityKey.Player), getParam("ValidPlayer").split(","), + this.getHostCard())) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + @Override + public final void setTriggeringObjects(final SpellAbility sa, Map runParams) { + sa.setTriggeringObjectsFrom(runParams, AbilityKey.Result, AbilityKey.Player); + } + + @Override + public String getImportantStackObjects(SpellAbility sa) { + return Localizer.getInstance().getMessage("lblPlayer") + ": " + sa.getTriggeringObject(AbilityKey.Player) + ", " + + Localizer.getInstance().getMessage("lblResultIs", sa.getTriggeringObject(AbilityKey.Result)); + } +} diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerType.java b/forge-game/src/main/java/forge/game/trigger/TriggerType.java index ad50db3d606..b332b264256 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerType.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerType.java @@ -89,6 +89,7 @@ public enum TriggerType { Regenerated(TriggerRegenerated.class), Revealed(TriggerRevealed.class), RolledDie(TriggerRolledDie.class), + RolledDieOnce(TriggerRolledDieOnce.class), RoomEntered(TriggerEnteredRoom.class), Sacrificed(TriggerSacrificed.class), Scry(TriggerScry.class), diff --git a/forge-game/src/main/java/forge/util/MessageUtil.java b/forge-game/src/main/java/forge/util/MessageUtil.java index 10db6860e03..431054e395f 100644 --- a/forge-game/src/main/java/forge/util/MessageUtil.java +++ b/forge-game/src/main/java/forge/util/MessageUtil.java @@ -52,6 +52,8 @@ public class MessageUtil { : Localizer.getInstance().getMessage("lblPlayerActionFlip", flipper, Lang.joinVerb(flipper, value)); case Protection: return Localizer.getInstance().getMessage("lblPlayerChooseValue", choser, value); + case RollDice: + return value; case Vote: String chooser = StringUtils.capitalize(mayBeYou(player, target)); return Localizer.getInstance().getMessage("lblPlayerVoteValue", chooser, value); diff --git a/forge-gui/res/cardsfolder/c/chicken_egg.txt b/forge-gui/res/cardsfolder/c/chicken_egg.txt index af495aa4312..65c6367d95b 100644 --- a/forge-gui/res/cardsfolder/c/chicken_egg.txt +++ b/forge-gui/res/cardsfolder/c/chicken_egg.txt @@ -3,7 +3,7 @@ ManaCost:1 R Types:Creature Egg PT:0/1 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRoll | TriggerDescription$ At the beginning of your upkeep, roll a six-sided die. If you roll a 6, sacrifice CARDNAME and create a 4/4 red Giant Bird creature token. -SVar:TrigRoll:DB$ RollDice | On6$ DBSac +SVar:TrigRoll:DB$ RollDice | ResultSubAbilities$ 6:DBSac SVar:DBSac:DB$ Sacrifice | Defined$ Self | SubAbility$ DBToken SVar:DBToken:DB$ Token | TokenScript$ r_4_4_giant_chicken DeckHas:Ability$Token diff --git a/forge-gui/res/cardsfolder/d/dungeon_master.txt b/forge-gui/res/cardsfolder/d/dungeon_master.txt index 6c2c694614b..b56d4c5388c 100644 --- a/forge-gui/res/cardsfolder/d/dungeon_master.txt +++ b/forge-gui/res/cardsfolder/d/dungeon_master.txt @@ -6,9 +6,9 @@ K:ETBReplacement:Other:RollLoyal SVar:RollLoyal:DB$ RollDice | Sides$ 4 | ResultSVar$ Result | SubAbility$ DBLoyalty | SpellDescription$ Add 1d4 loyalty counters to CARDNAME SVar:DBLoyalty:DB$ PutCounter | Defined$ Self | CounterType$ LOYALTY | CounterNum$ Result | ETB$ True A:AB$ Token | Cost$ AddCounter<1/LOYALTY> | ValidTgts$ Opponent | TokenOwner$ Targeted | TokenScript$ b_1_1_skeleton_opp_life | Planeswalker$ True | SpellDescription$ Target opponent creates a 1/1 black Skeleton creature token with "When this creature dies, each opponent gains 2 life." -A:AB$ RollDice | Cost$ AddCounter<1/LOYALTY> | Sides$ 20 | On1$ DBSkipTurn | ResultSVar$ Result | Planeswalker$ True | SubAbility$ DBDraw | SpellDescription$ Roll a d20. If you roll a 1, skip your next turn. If you roll a 12 or higher, draw a card. +A:AB$ RollDice | Cost$ AddCounter<1/LOYALTY> | Sides$ 20 | ResultSubAbilities$ 1:DBSkipTurn,12-20:DBDraw | Planeswalker$ True | SpellDescription$ Roll a d20. If you roll a 1, skip your next turn. If you roll a 12 or higher, draw a card. SVar:DBSkipTurn:DB$ SkipTurn | Defined$ You | NumTurns$ 1 -SVar:DBDraw:DB$ Draw | ConditionCheckSVar$ Result | ConditionSVarCompare$ GE12 +SVar:DBDraw:DB$ Draw A:AB$ Token | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | TokenScript$ r_3_3_fighter_first_strike | SubAbility$ DBCleric | SpellDescription$ You get an adventuring party. (Your party is a 3/3 red Fighter with first strike, a 1/1 white Cleric with lifelink, a 2/2 black Rogue with hexproof, and a 1/1 blue Wizard with flying.) SVar:DBCleric:DB$ Token | TokenScript$ w_1_1_cleric_lifelink | SubAbility$ DBRogue SVar:DBRogue:DB$ Token | TokenScript$ b_2_2_rogue_hexproof | SubAbility$ DBWizard diff --git a/forge-gui/res/cardsfolder/g/goblin_tutor.txt b/forge-gui/res/cardsfolder/g/goblin_tutor.txt index a6b35d65380..3bff47a9588 100644 --- a/forge-gui/res/cardsfolder/g/goblin_tutor.txt +++ b/forge-gui/res/cardsfolder/g/goblin_tutor.txt @@ -1,10 +1,10 @@ Name:Goblin Tutor ManaCost:R Types:Instant -A:SP$ RollDice | Cost$ R | On2$ GetGobTut | On3$ GetEnch | On4$ GetArtif | On5$ GetCreat| On6$ GetSpell | SpellDescription$ Roll a six-sided die. Search your library for the indicated card, reveal it, put it into your hand, then shuffle.\n2 — A card named Goblin Tutor\n3 — An enchantment\n4 — An artifact\n5 — A creature\n6 — An instant or sorcery -SVar:GetGobTut:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Card.namedGoblin Tutor | ChangeNum$ 1 -SVar:GetEnch:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Enchantment | ChangeNum$ 1 -SVar:GetArtif:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Artifact | ChangeNum$ 1 -SVar:GetCreat:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Creature | ChangeNum$ 1 -SVar:GetSpell:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Instant,Sorcery | ChangeNum$ 1 +A:SP$ RollDice | Cost$ R | ResultSubAbilities$ 2:GetGobTut,3:GetEnch,4:GetArtif,5:GetCreat,6:GetSpell | SpellDescription$ Roll a six-sided die. If you roll a 1, CARDNAME has no effect. Otherwise, search your library for the indicated card, reveal it, put it into your hand, then shuffle. +SVar:GetGobTut:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Card.namedGoblin Tutor | ChangeNum$ 1 | SpellDescription$ 2 — A card named Goblin Tutor +SVar:GetEnch:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Enchantment | ChangeNum$ 1 | SpellDescription$ 3 — An enchantment +SVar:GetArtif:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Artifact | ChangeNum$ 1 | SpellDescription$ 4 — An artifact +SVar:GetCreat:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Creature | ChangeNum$ 1 | SpellDescription$ 5 — A creature +SVar:GetSpell:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Instant,Sorcery | ChangeNum$ 1 | SpellDescription$ 6 — An instant or sorcery Oracle:Roll a six-sided die. If you roll a 1, Goblin Tutor has no effect. Otherwise, search your library for the indicated card, reveal it, put it into your hand, then shuffle.\n2 — A card named Goblin Tutor\n3 — An enchantment\n4 — An artifact\n5 — A creature\n6 — An instant or sorcery diff --git a/forge-gui/res/cardsfolder/h/hydradoodle.txt b/forge-gui/res/cardsfolder/h/hydradoodle.txt index 9b0db0b9574..2da6084ff7f 100644 --- a/forge-gui/res/cardsfolder/h/hydradoodle.txt +++ b/forge-gui/res/cardsfolder/h/hydradoodle.txt @@ -4,7 +4,7 @@ Types:Creature Hydra Dog PT:0/0 K:ETBReplacement:Other:RollCounters SVar:X:Count$xPaid -SVar:RollCounters:DB$ RollDice | Amt$ X | ETB$ True | ResultSVar$ Result | SubAbility$ DBCounters | SpellDescription$ As CARDNAME enters the battlefield, roll X six-sided dice. CARDNAME enters the battlefield with a number of +1/+1 counters on it equal to the total of those results. +SVar:RollCounters:DB$ RollDice | Amount$ X | ETB$ True | ResultSVar$ Result | SubAbility$ DBCounters | SpellDescription$ As CARDNAME enters the battlefield, roll X six-sided dice. CARDNAME enters the battlefield with a number of +1/+1 counters on it equal to the total of those results. SVar:DBCounters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ Result | ETB$ True K:Reach K:Trample diff --git a/forge-gui/res/cardsfolder/i/inhumaniac.txt b/forge-gui/res/cardsfolder/i/inhumaniac.txt index 47e60a8e386..be2ff08db0c 100644 --- a/forge-gui/res/cardsfolder/i/inhumaniac.txt +++ b/forge-gui/res/cardsfolder/i/inhumaniac.txt @@ -3,7 +3,7 @@ ManaCost:1 B Types:Creature Brainiac PT:1/1 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRoll | TriggerDescription$ At the beginning of your upkeep, roll a six-sided die. On a 3 or 4, put a +1/+1 counter on Inhumaniac. On a 5 or higher, put two +1/+1 counters on it. On a 1, remove all +1/+1 counters from Inhumaniac. -SVar:TrigRoll:DB$ RollDice | On3$ DBOne | On4$ DBOne | On5$ DBTwo | On6$ DBTwo | On1$ DBRemove +SVar:TrigRoll:DB$ RollDice | ResultSubAbilities$ 3-4:DBOne,5-6:DBTwo,1:DBRemove SVar:DBOne:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 SVar:DBTwo:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 2 SVar:DBRemove:DB$ RemoveCounterAll | ValidCards$ Card.Self | CounterType$ P1P1 | AllCounters$ True diff --git a/forge-gui/res/cardsfolder/j/jack_in_the_mox.txt b/forge-gui/res/cardsfolder/j/jack_in_the_mox.txt index 41a065b0581..8ddbfbfdebb 100644 --- a/forge-gui/res/cardsfolder/j/jack_in_the_mox.txt +++ b/forge-gui/res/cardsfolder/j/jack_in_the_mox.txt @@ -1,14 +1,14 @@ Name:Jack-in-the-Mox ManaCost:0 Types:Artifact -A:AB$ RollDice | Cost$ T | On1$ DBSac | On2$ AddW | On3$ AddU | On4$ AddB | On5$ AddR | On6$ AddG | InstantSpeed$ True | SubAbility$ Add0 | SpellDescription$ Roll a six-sided die. This ability has the indicated effect. 1—Sacrifice Jack-in-the-Mox and you lose 5 life. 2—Add {W}. 3—Add {U}. 4—Add {B}. 5-Add {R}. 6-Add {G}. -SVar:DBSac:DB$ Sacrifice | Defined$ Self | SubAbility$ DBLoseLife +A:AB$ RollDice | Cost$ T | ResultSubAbilities$ 1:DBSac,2:AddW,3:AddU,4:AddB,5:AddR,6:AddG | InstantSpeed$ True | SubAbility$ Add0 | SpellDescription$ Roll a six-sided die. This ability has the indicated effect. +SVar:DBSac:DB$ Sacrifice | Defined$ Self | SubAbility$ DBLoseLife | SpellDescription$ 1 — Sacrifice CARDNAME and you lose 5 life. SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 5 -SVar:AddW:DB$ Mana | Produced$ W -SVar:AddU:DB$ Mana | Produced$ U -SVar:AddB:DB$ Mana | Produced$ B -SVar:AddR:DB$ Mana | Produced$ R -SVar:AddG:DB$ Mana | Produced$ G +SVar:AddW:DB$ Mana | Produced$ W | SpellDescription$ 2 — Add {W}. +SVar:AddU:DB$ Mana | Produced$ U | SpellDescription$ 3 — Add {U}. +SVar:AddB:DB$ Mana | Produced$ B | SpellDescription$ 4 — Add {B}. +SVar:AddR:DB$ Mana | Produced$ R | SpellDescription$ 5 — Add {R}. +SVar:AddG:DB$ Mana | Produced$ G | SpellDescription$ 6 — Add {G}. SVar:Add0:DB$ Mana | Produced$ C | Amount$ 0 SVar:PlayMain1:TRUE Oracle:{T}: Roll a six-sided die. This ability has the indicated effect.\n1 — Sacrifice Jack-in-the-Mox and you lose 5 life.\n2 — Add {W}.\n3 — Add {U}.\n4 — Add {B}.\n5 — Add {R}.\n6 — Add {G}. diff --git a/forge-gui/res/cardsfolder/k/krazy_kow.txt b/forge-gui/res/cardsfolder/k/krazy_kow.txt index f8f83308370..634694504ff 100644 --- a/forge-gui/res/cardsfolder/k/krazy_kow.txt +++ b/forge-gui/res/cardsfolder/k/krazy_kow.txt @@ -3,7 +3,7 @@ ManaCost:3 R Types:Creature Cow PT:3/3 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRoll | TriggerDescription$ At the beginning of your upkeep, roll a six-sided die. If you a roll a 1, sacrifice Krazy Kow and it deals 3 damage to each creature and each player. -SVar:TrigRoll:DB$ RollDice | On1$ DBSac +SVar:TrigRoll:DB$ RollDice | ResultSubAbilities$ 1:DBSac SVar:DBSac:DB$ Sacrifice | Defined$ Self | SubAbility$ DBDamage SVar:DBDamage:DB$ DamageAll | ValidCards$ Creature | ValidPlayers$ Player | NumDmg$ 3 Oracle:At the beginning of your upkeep, roll a six-sided die. If you a roll a 1, sacrifice Krazy Kow and it deals 3 damage to each creature and each player. diff --git a/forge-gui/res/cardsfolder/l/lobe_lobber.txt b/forge-gui/res/cardsfolder/l/lobe_lobber.txt index 8e90cc71c4b..5d5c977b5a7 100644 --- a/forge-gui/res/cardsfolder/l/lobe_lobber.txt +++ b/forge-gui/res/cardsfolder/l/lobe_lobber.txt @@ -4,6 +4,6 @@ Types:Artifact Equipment K:Equip:2 S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddAbility$ WandDamage | AddSVar$ DBWandDmg | Description$ Equipped creature has "{T}: This creature deals 1 damage to target player or planeswalker. Roll a six-sided die. On a 5 or higher, untap it." SVar:WandDamage:AB$ DealDamage | Cost$ T | ValidTgts$ Planeswalker,Player | TgtPrompt$ Select target Planeswalker or player | NumDmg$ 1 | SubAbility$ DBRoll | SpellDescription$ This creature deals 1 damage to target player or planeswalker. Roll a six-sided die. On a 5 or higher, untap it. -SVar:DBRoll:DB$ RollDice | On5$ DBUntap | On6$ DBUntap +SVar:DBRoll:DB$ RollDice | ResultSubAbilities$ 5-6:DBUntap SVar:DBUntap:DB$ Untap Oracle:Equipped creature has "{T}: This creature deals 1 damage to target player or planeswalker. Roll a six-sided die. On a 5 or higher, untap it."\nEquip {2} diff --git a/forge-gui/res/cardsfolder/m/mad_science_fair_project.txt b/forge-gui/res/cardsfolder/m/mad_science_fair_project.txt index b329c61016c..d897784c12b 100644 --- a/forge-gui/res/cardsfolder/m/mad_science_fair_project.txt +++ b/forge-gui/res/cardsfolder/m/mad_science_fair_project.txt @@ -2,7 +2,7 @@ Name:Mad Science Fair Project ManaCost:3 Types:Artifact A:AB$ Pump | Cost$ T | ValidTgts$ Player | SubAbility$ DBRoll -SVar:DBRoll:DB$ RollDice | On1$ AddC | On2$ AddC | On3$ AddC | Else$ AddAny | AILogic$ Main2 | SpellDescription$ {T}: Roll a six-sided die. On a 3 or lower, target player adds {C}. Otherwise, that player adds one mana of any color they choose. +SVar:DBRoll:DB$ RollDice | ResultSubAbilities$ 1-3:AddC,Else:AddAny | AILogic$ Main2 | SpellDescription$ {T}: Roll a six-sided die. On a 3 or lower, target player adds {C}. Otherwise, that player adds one mana of any color they choose. SVar:AddC:DB$ Mana | Produced$ C | Defined$ Targeted SVar:AddAny:DB$ Mana | Produced$ Any | Defined$ Targeted SVar:PlayMain1:TRUE diff --git a/forge-gui/res/cardsfolder/p/poultrygeist.txt b/forge-gui/res/cardsfolder/p/poultrygeist.txt index 714b1f2fda5..69bdad81919 100644 --- a/forge-gui/res/cardsfolder/p/poultrygeist.txt +++ b/forge-gui/res/cardsfolder/p/poultrygeist.txt @@ -4,7 +4,7 @@ Types:Creature Bird Spirit PT:1/1 K:Flying T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigRoll | TriggerDescription$ Whenever a creature dies, you may roll a six-sided die. If you roll a 1, sacrifice CARDNAME. Otherwise, put a +1/+1 counter on CARDNAME. -SVar:TrigRoll:DB$ RollDice | On1$ DBSac | Else$ DBCounter +SVar:TrigRoll:DB$ RollDice | ResultSubAbilities$ 1:DBSac,Else:DBCounter SVar:DBSac:DB$ Sacrifice | Defined$ Self SVar:DBCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 DeckHas:Ability$Counters diff --git a/forge-gui/res/cardsfolder/s/spark_fiend.txt b/forge-gui/res/cardsfolder/s/spark_fiend.txt index 22766f3b029..8e105dacc25 100644 --- a/forge-gui/res/cardsfolder/s/spark_fiend.txt +++ b/forge-gui/res/cardsfolder/s/spark_fiend.txt @@ -3,13 +3,13 @@ ManaCost:4 R Types:Creature Beast PT:5/6 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRollETB | TriggerDescription$ When Spark Fiend enters the battlefield, roll two six-sided dice. If you rolled 2, 3, or 12, sacrifice Spark Fiend. If you rolled 7 or 11, don’t roll dice for Spark Fiend during any of your following upkeeps. If you rolled any other total, note that total. -SVar:TrigRollETB:DB$ RollDice | Amt$ 2 | On2$ DBSac | On3$ DBSac | On12$ DBSac | On7$ DBSafe | Else$ DBNote | ResultSVar$ Result +SVar:TrigRollETB:DB$ RollDice | Amount$ 2 | ResultSubAbilities$ 2-3:DBSac,12:DBSac,7:DBSafe,Else:DBNote | ResultSVar$ Result SVar:DBSac:DB$ Sacrifice | Defined$ Self SVar:Safe:Number$1 SVar:Noted:Number$0 SVar:DBSafe:DB$ StoreSVar | SVar$ Safe | Type$ Number | Expression$ 0 SVar:DBNote:DB$ StoreSVar | SVar$ Noted | Type$ CountSVar | Expression$ Result T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | CheckSVar$ Safe | SVarCompare$ NE0 | TriggerZones$ Battlefield | Execute$ TrigRoll | TriggerDescription$ At the beginning of your upkeep, roll two six-sided dice. If you rolled 7, sacrifice Spark Fiend. If you roll the noted total, don’t roll dice for Spark Fiend during any of your following upkeeps. Otherwise, do nothing. -SVar:TrigRoll:DB$ RollDice | Amt$ 2 | On7$ DBSac | ResultSVar$ Result | SubAbility$ DBCheck +SVar:TrigRoll:DB$ RollDice | Amount$ 2 | ResultSubAbilities$ 7:DBSac | ResultSVar$ Result | SubAbility$ DBCheck SVar:DBCheck:DB$ StoreSVar | SVar$ Safe | Type$ CountSVar | Expression$ Result/Minus.Noted Oracle:When Spark Fiend enters the battlefield, roll two six-sided dice. If you rolled 2, 3, or 12, sacrifice Spark Fiend. If you rolled 7 or 11, don't roll dice for Spark Fiend during any of your following upkeeps. If you rolled any other total, note that total.\nAt the beginning of your upkeep, roll two six-sided dice. If you rolled 7, sacrifice Spark Fiend. If you roll the noted total, don't roll dice for Spark Fiend during any of your following upkeeps. Otherwise, do nothing. diff --git a/forge-gui/res/cardsfolder/s/strategy_schmategy.txt b/forge-gui/res/cardsfolder/s/strategy_schmategy.txt index 5bce9eb6050..4d32dd22cd6 100644 --- a/forge-gui/res/cardsfolder/s/strategy_schmategy.txt +++ b/forge-gui/res/cardsfolder/s/strategy_schmategy.txt @@ -2,13 +2,14 @@ Name:Strategy, Schmategy ManaCost:1 R Types:Sorcery A:SP$ StoreSVar | Cost$ 1 R | SVar$ Left | Type$ Number | Expression$ 1 | SubAbility$ DBRepeat -SVar:DBRepeat:DB$ Repeat | RepeatCheckSVar$ Left | RepeatSVarCompare$ GT0 | RepeatSubAbility$ Roll | StackDescription$ Roll a six-sided die. Strategy, Schmategy has the indicated effect. 1-Do nothing. 2-Destroy all artifacts. 3-Destroy all lands. 4-Strategy, Schmategy deals 3 damage to each creature and each player. 5-Each player discards their hand and draws seven cards. 6-Repeat this process two more times. -SVar:Roll:DB$ RollDice | On2$ DBArtif | On3$ DBLand | On4$ DBDamage | On5$ DBWheel | On6$ DBTwoMore | SubAbility$ DBDecr -SVar:DBArtif:DB$ DestroyAll | ValidCards$ Artifact -SVar:DBLand:DB$ DestroyAll | ValidCards$ Land -SVar:DBDamage:DB$ DamageAll | ValidCards$ Creature | ValidPlayers$ Player | NumDmg$ 3 -SVar:DBWheel:DB$ Discard | Mode$ Hand | Defined$ Player | SubAbility$ DBEachDraw +SVar:DBRepeat:DB$ Repeat | RepeatCheckSVar$ Left | RepeatSVarCompare$ GT0 | RepeatSubAbility$ Roll | StackDescription$ Roll a six-sided die. CARDNAME has the indicated effect. +SVar:Roll:DB$ RollDice | ResultSubAbilities$ 1:DBNothing,2:DBArtif,3:DBLand,4:DBDamage,5:DBWheel,6:DBTwoMore | SubAbility$ DBDecr +SVar:DBNothing:DB$ Pump | SpellDescription$ 1 — Do nothing. +SVar:DBArtif:DB$ DestroyAll | ValidCards$ Artifact | SpellDescription$ 2 — Destroy all artifacts. +SVar:DBLand:DB$ DestroyAll | ValidCards$ Land | SpellDescription$ 3 — Destroy all lands. +SVar:DBDamage:DB$ DamageAll | ValidCards$ Creature | ValidPlayers$ Player | NumDmg$ 3 | SpellDescription$ 4 — CARDNAME deals 3 damage to each creature and each player. +SVar:DBWheel:DB$ Discard | Mode$ Hand | Defined$ Player | SubAbility$ DBEachDraw | SpellDescription$ 5 — Each player discards their hand and draws seven cards. SVar:DBEachDraw:DB$ Draw | Defined$ Player | NumCards$ 7 -SVar:DBTwoMore:DB$ StoreSVar | SVar$ Left | Type$ CountSVar | Expression$ Left/Plus.2 +SVar:DBTwoMore:DB$ StoreSVar | SVar$ Left | Type$ CountSVar | Expression$ Left/Plus.2 | SpellDescription$ 6 — Repeat this process two more times. SVar:DBDecr:DB$ StoreSVar | SVar$ Left | Type$ CountSVar | Expression$ Left/Minus.1 Oracle:Roll a six-sided die. Strategy, Schmategy has the indicated effect.\n1 — Do nothing.\n2 — Destroy all artifacts.\n3 — Destroy all lands.\n4 — Strategy, Schmategy deals 3 damage to each creature and each player.\n5 — Each player discards their hand and draws seven cards.\n6 — Repeat this process two more times. diff --git a/forge-gui/res/cardsfolder/s/sword_of_dungeons_dragons.txt b/forge-gui/res/cardsfolder/s/sword_of_dungeons_dragons.txt index b03103e7670..70f55085813 100644 --- a/forge-gui/res/cardsfolder/s/sword_of_dungeons_dragons.txt +++ b/forge-gui/res/cardsfolder/s/sword_of_dungeons_dragons.txt @@ -6,7 +6,7 @@ S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddToughness$ T:Mode$ DamageDone | ValidSource$ Creature.EquippedBy | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigLoop | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature deals combat damage to a player, create a 4/4 gold Dragon creature token with flying and roll a d20 (a twenty-sided die). If you roll a 20, repeat this process. SVar:TrigLoop:DB$ Repeat | RepeatCheckSVar$ RepeatCheck | RepeatSVarCompare$ GT0 | RepeatSubAbility$ TrigToken | StackDescription$ Create a 4/4 gold Dragon creature token with flying and roll a d20. If you roll a 20, repeat this process. SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_4_4_dragon_flying | TokenOwner$ You | SubAbility$ RollDie -SVar:RollDie:DB$ RollDice | Sides$ 20 | On20$ Win | Else$ Lose +SVar:RollDie:DB$ RollDice | Sides$ 20 | ResultSubAbilities$ 20:Win,Else:Lose SVar:Win:DB$ StoreSVar | SVar$ RepeatCheck | Type$ Number | Expression$ 1 SVar:Lose:DB$ StoreSVar | SVar$ RepeatCheck | Type$ Number | Expression$ 0 SVar:RepeatCheck:Number$ 1 diff --git a/forge-gui/res/cardsfolder/u/urzas_science_fair_project.txt b/forge-gui/res/cardsfolder/u/urzas_science_fair_project.txt index 2484884ab67..dc3f0eef86d 100644 --- a/forge-gui/res/cardsfolder/u/urzas_science_fair_project.txt +++ b/forge-gui/res/cardsfolder/u/urzas_science_fair_project.txt @@ -2,11 +2,11 @@ Name:Urza's Science Fair Project ManaCost:6 Types:Artifact Creature Construct PT:4/4 -A:AB$ RollDice | Cost$ 2 | On1$ M2 | On2$ Fog | On3$ Vig | On4$ FS | On5$ Fly | On6$ P2 | AILogic$ CombatEarly | SpellDescription$ Roll a six-sided die. CARDNAME gets the indicated result: 1-It gets -2/-2 until end of turn. 2-Prevent all combat damage it would deal this turn. 3-It gains vigilance until end of turn. 4-It gains first strike until end of turn. 5-It gains flying until end of turn. 6-It gets +2/+2 until end of turn. -SVar:M2:DB$ Pump | Defined$ Self | NumAtt$ -2 | NumDef$ -2 -SVar:Fog:DB$ Pump | Defined$ Self | KW$ Prevent all combat damage that would be dealt by CARDNAME. -SVar:Vig:DB$ Pump | Defined$ Self | KW$ Vigilance -SVar:FS:DB$ Pump | Defined$ Self | KW$ First Strike -SVar:Fly:DB$ Pump | Defined$ Self | KW$ Flying -SVar:P2:DB$ Pump | Defined$ Self | NumAtt$ 2 | NumDef$ 2 +A:AB$ RollDice | Cost$ 2 | ResultSubAbilities$ 1:M2,2:Fog,3:Vig,4:FS,5:Fly,6:P2 | AILogic$ CombatEarly | SpellDescription$ Roll a six-sided die. CARDNAME gets the indicated result. +SVar:M2:DB$ Pump | Defined$ Self | NumAtt$ -2 | NumDef$ -2 | SpellDescription$ 1 — It gets -2/-2 until end of turn. +SVar:Fog:DB$ Pump | Defined$ Self | KW$ Prevent all combat damage that would be dealt by CARDNAME. | SpellDescription$ 2 — Prevent all combat damage it would deal this turn. +SVar:Vig:DB$ Pump | Defined$ Self | KW$ Vigilance | SpellDescription$ 3 — It gains vigilance until end of turn. +SVar:FS:DB$ Pump | Defined$ Self | KW$ First Strike | SpellDescription$ 4 — It gains first strike until end of turn. +SVar:Fly:DB$ Pump | Defined$ Self | KW$ Flying | SpellDescription$ 5 — It gains flying until end of turn. +SVar:P2:DB$ Pump | Defined$ Self | NumAtt$ 2 | NumDef$ 2 | SpellDescription$ 6 — It gets +2/+2 until end of turn. Oracle:{2}: Roll a six-sided die. Urza's Science Fair Project gets the indicated result.\n1 — It gets -2/-2 until end of turn.\n2 — Prevent all combat damage it would deal this turn.\n3 — It gains vigilance until end of turn.\n4 — It gains first strike until end of turn.\n5 — It gains flying until end of turn.\n6 — It gets +2/+2 until end of turn. diff --git a/forge-gui/res/cardsfolder/upcoming/critical_hit.txt b/forge-gui/res/cardsfolder/upcoming/critical_hit.txt new file mode 100644 index 00000000000..770600b5268 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/critical_hit.txt @@ -0,0 +1,7 @@ +Name:Critical Hit +ManaCost:1 R +Types:Instant +A:SP$ Pump | KW$ Double Strike | ValidTgts$ Creature +T:Mode$ RolledDie | TriggerZones$ Graveyard | ValidResult$ 20 | ValidPlayer$ You | Execute$ TrigReturn | TriggerDescription$ When you roll a natural 20, return CARDNAME from your graveyard to your hand. (A natural 20 is a roll that displays 20 on the die.) +SVar:TrigReturn:DB$ ChangeZone | Defined$ Self | Origin$ Graveyard | Destination$ Hand +Oracle:Target creature gains double strike until end of turn.\nWhen you roll a natural 20, return Critical Hit from your graveyard to your hand. (A natural 20 is a roll that displays 20 on the die.) \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/delina_wild_mage.txt b/forge-gui/res/cardsfolder/upcoming/delina_wild_mage.txt new file mode 100644 index 00000000000..f4c665d2972 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/delina_wild_mage.txt @@ -0,0 +1,15 @@ +Name:Delina, Wild Mage +ManaCost:3 R +Types:Legendary Creature Elf Shaman +PT:3/2 +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBLoop | TriggerDescription$ Whenever CARDNAME attacks, choose target creature you control, then ABILITY +SVar:DBLoop:DB$ Repeat | ValidTgts$ Creature.YouCtrl | RepeatCheckSVar$ RepeatCheck | RepeatSVarCompare$ GT0 | RepeatSubAbility$ DBRollDice | RepeatOptional$ True +SVar:DBRollDice:DB$ RollDice | Sides$ 20 | ResultSubAbilities$ 1-14:DBCopy,15-20:DBCopyRepeat | SpellDescription$ roll a d20. +SVar:DBCopy:DB$ CopyPermanent | Defined$ Targeted | TokenTapped$ True | TokenAttacking$ True | NonLegendary$ True | AtEOT$ ExileCombat | SubAbility$ DBNotRepeat | SpellDescription$ 1-14 VERT Create a tapped and attacking token that's a copy of that creature, except it's not legendary and it has "Exile this creature at end of combat. +SVar:DBNotRepeat:DB$ StoreSVar | SVar$ RepeatCheck | Type$ Number | Expression$ 0 +SVar:DBCopyRepeat:DB$ CopyPermanent | Defined$ Targeted | TokenTapped$ True | TokenAttacking$ True | NonLegendary$ True | AtEOT$ ExileCombat | SubAbility$ DBRepeat | SpellDescription$ 15-20 VERT Create one of those tokens. You may roll again. +SVar:DBRepeat:DB$ StoreSVar | SVar$ RepeatCheck | Type$ Number | Expression$ 1 +SVar:RepeatCheck:Number$1 +SVar:HasAttackEffect:TRUE +DeckHas:Ability$Token +Oracle:Whenever Delina, Wild Mage attacks, choose target creature you control, then roll a d20.\n1-14 | Create a tapped and attacking token that's a copy of that creature, except it's not legendary and it has "Exile this creature at end of combat."\n15-20 | Create one of those tokens. You may roll again. diff --git a/forge-gui/res/cardsfolder/upcoming/farideh_devils_chosen.txt b/forge-gui/res/cardsfolder/upcoming/farideh_devils_chosen.txt new file mode 100644 index 00000000000..b8e01dd2376 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/farideh_devils_chosen.txt @@ -0,0 +1,9 @@ +Name:Farideh, Devil's Chosen +ManaCost:2 U R +Types:Legendary Creature Tiefling Warlock +PT:3/3 +T:Mode$ RolledDieOnce | TriggerZones$ Battlefield | ValidPlayer$ You | Execute$ TrigPump | TriggerDescription$ Dark One's Own Luck — Whenever you roll one or more dice, Farideh, Devil's Chosen gains flying and menace until end of turn. If any of those results was 10 or higher, draw a card. +SVar:TrigPump:DB$ Pump | Defined$ Self | KW$ Flying & Menace | SubAbility$ DBDraw +SVar:DBDraw:DB$ Draw | NumCards$ 1 | ConditionCheckSVar$ DiceResult | ConditionSVarCompare$ GE10 +SVar:DiceResult:TriggerCountMax$Result +Oracle:Dark One's Own Luck — Whenever you roll one or more dice, Farideh, Devil's Chosen gains flying and menace until end of turn. If any of those results was 10 or higher, draw a card. diff --git a/forge-gui/res/cardsfolder/upcoming/feywild_trickster.txt b/forge-gui/res/cardsfolder/upcoming/feywild_trickster.txt new file mode 100644 index 00000000000..5e07f1e067c --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/feywild_trickster.txt @@ -0,0 +1,7 @@ +Name:Feywild Trickster +ManaCost:2 U +Types:Creature Gnome Warlock +PT:2/2 +T:Mode$ RolledDieOnce | TriggerZones$ Battlefield | ValidPlayer$ You | Execute$ TrigToken | TriggerDescription$ Whenever you roll one or more dice, create a 1/1 blue Faerie Dragon creature token with flying. +SVar:TrigToken:DB$ Token | TokenScript$ u_1_1_faerie_dragon_flying | TokenAmount$ 1 | TokenOwner$ You +Oracle:Whenever you roll one or more dice, create a 1/1 blue Faerie Dragon creature token with flying. diff --git a/forge-gui/res/cardsfolder/upcoming/pixie_guide.txt b/forge-gui/res/cardsfolder/upcoming/pixie_guide.txt new file mode 100644 index 00000000000..54799ca966b --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/pixie_guide.txt @@ -0,0 +1,7 @@ +Name:Pixie Guide +ManaCost:1 U +Types:Creature Faerie +PT:1/3 +K:Flying +S:Mode$ Continuous | Affected$ You | AddKeyword$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. | Description$ Grant an Advantage — if you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. +Oracle:Flying\nGrant an Advantage — if you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. diff --git a/forge-gui/res/cardsfolder/upcoming/the_deck_of_many_things.txt b/forge-gui/res/cardsfolder/upcoming/the_deck_of_many_things.txt new file mode 100644 index 00000000000..bed0629901e --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/the_deck_of_many_things.txt @@ -0,0 +1,16 @@ +Name:The Deck of Many Things +ManaCost:5 +Types:Legendary Artifact +A:AB$ RollDice | Cost$ 2 T | Sides$ 20 | Modifier$ CardsInHand | ResultSubAbilities$ Else:DBDiscard,1-9:DBReturn,10-19:DBDrawTwo,20:DBReanimate | SpellDescription$ Roll a d20 and subtract the number of cards in your hand. If the result is 0 or less, discard your hand. +SVar:CardsInHand:Count$InYourHand/Negative +SVar:DBDiscard:DB$ Discard | Mode$ Hand +SVar:DBReturn:DB$ ChangeZone | ChangeType$ Card.YouCtrl | ChangeNum$ 1 | Hidden$ True | Origin$ Graveyard | AtRandom$ True | Destination$ Hand | SpellDescription$ 1-9 VERT Return a card at random from your graveyard to your hand. +SVar:DBDrawTwo:DB$ Draw | NumCards$ 2 | SpellDescription$ 10-19 VERT Draw two cards. +SVar:DBReanimate:DB$ ChooseCard | Choices$ Creature | ChoiceZone$ Graveyard | Amount$ 1 | SubAbility$ DBChangeZone | SpellDescription$ 20 VERT Put a creature card from any graveyard onto the battlefield under your control. When that creature dies, its owner loses the game. +SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Defined$ ChosenCard | GainControl$ True | RememberChanged$ True | SubAbility$ DBLoseEffect +SVar:DBLoseEffect:DB$ Effect | Triggers$ TrigDie | RememberObjects$ ChosenCard | Duration$ Permanent | ExileOnMoved$ Battlefield | SubAbility$ DBCleanup +SVar:TrigDie:Mode$ ChangesZone | ValidCard$ Creature.IsRemembered | Origin$ Battlefield | Destination$ Graveyard | Execute$ DBLose | TriggerDescription$ When that creature dies, its owner loses the game. +SVar:DBLose:DB$ LosesGame | Defined$ RememberedOwner +SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True +DeckHas:Ability$Discard & Ability$Graveyard +Oracle:{2}, {T}: Roll a d20 and subtract the number of cards in your hand. If the result is 0 or less, discard your hand.\n1-9 | Return a card at random from your graveyard to your hand.\n10-19 | Draw two cards.\n20 | Put a creature card from any graveyard onto the battlefield under your control. When that creature dies, its owner loses the game. diff --git a/forge-gui/res/cardsfolder/upcoming/wizards_spellbook.txt b/forge-gui/res/cardsfolder/upcoming/wizards_spellbook.txt new file mode 100644 index 00000000000..4163dc1f6e2 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/wizards_spellbook.txt @@ -0,0 +1,11 @@ +Name:Wizard's Spellbook +ManaCost:5 U U +Types:Artifact +A:AB$ ChangeZone | Cost$ T | SorcerySpeed$ True | Origin$ Graveyard | Destination$ Exile | Mandatory$ True | ValidTgts$ Instant,Sorcery | TgtPrompt$ Select target instant or sorcery card in a graveyard | RememberChanged$ True | Imprint$ True | SubAbility$ DBRollDice | SpellDescription$ Exile target instant or sorcery card from a graveyard. Roll a d20. Activate only as a sorcery. +SVar:DBRollDice:DB$ RollDice | Sides$ 20 | ResultSubAbilities$ 1-9:PlayCopy,10-19:PlayCost1,20:PlayAny +SVar:PlayCopy:DB$ Play | Valid$ Card.IsRemembered+ExiledWithSource | ValidZone$ Exile | Amount$ All | CopyOnce$ True | CopyCard$ True | Optional$ True | SubAbility$ DBCleanup | SpellDescription$ 1-9 VERT Copy that card. You may cast the copy. +SVar:PlayCost1:DB$ Play | Valid$ Card.IsRemembered+ExiledWithSource | ValidZone$ Exile | Amount$ All | CopyOnce$ True | CopyCard$ True | Optional$ True | PlayCost$ 1 | SubAbility$ DBCleanup | SpellDescription$ 10-19 VERT Copy that card. You may cast the copy by paying {1} rather than paying its mana cost. +SVar:PlayAny:DB$ Play | Valid$ Card.IsImprinted+ExiledWithSource | ValidZone$ Exile | Amount$ All | CopyOnce$ True | CopyCard$ True | Optional$ True | WithoutManaCost$ True | SubAbility$ DBCleanup | SpellDescription$ 20 VERT Copy each card exiled with Wizard's Spellbook. You may cast any number of the copies without paying their mana costs. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +DeckHas:Ability$Graveyard +Oracle:{T}: Exile target instant or sorcery card from a graveyard. Roll a d20. Activate only as a sorcery.\n1-9 | Copy that card. You may cast the copy.\n10-19 | Copy that card. You may cast the copy by paying {1} rather than paying its mana cost.\n20 | Copy each card exiled with Wizard's Spellbook. You may cast any number of the copies without paying their mana costs. diff --git a/forge-gui/res/lists/TypeLists.txt b/forge-gui/res/lists/TypeLists.txt index 7129eee7b5c..feb85ee3f8a 100644 --- a/forge-gui/res/lists/TypeLists.txt +++ b/forge-gui/res/lists/TypeLists.txt @@ -257,6 +257,7 @@ Tetravite:Tetravites Thalakos:Thalakoses Thopter:Thopters Thrull:Thrulls +Tiefling:Tieflings Treefolk:Treefolks Trilobite:Trilobites Triskelavite:Triskelavites diff --git a/forge-gui/res/tokenscripts/u_1_1_faerie_dragon_flying.txt b/forge-gui/res/tokenscripts/u_1_1_faerie_dragon_flying.txt new file mode 100644 index 00000000000..23f14a9f4ea --- /dev/null +++ b/forge-gui/res/tokenscripts/u_1_1_faerie_dragon_flying.txt @@ -0,0 +1,7 @@ +Name:Faerie Dragon +ManaCost:no cost +Types:Creature Faerie Dragon +Colors:blue +PT:1/1 +K:Flying +Oracle:Flying