diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 9d4320867b1..c9e670ae77e 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -2061,6 +2061,19 @@ public class Card extends GameEntity implements Comparable, IHasSVars { sb.append(" (").append(inst.getReminderText()).append(")"); printedKW.add(keyword); } + } else if (keyword.startsWith("Ward")) { + final String[] k = keyword.split(":"); + final Cost cost = new Cost(k[1], false); + + StringBuilder sbCost = new StringBuilder(k[0]); + if (!cost.isOnlyManaCost()) { + sbCost.append("—"); + } else { + sbCost.append(" "); + } + sbCost.append(cost.toSimpleString()); + sbLong.append(sbCost).append(" (").append(inst.getReminderText()).append(")"); + sbLong.append("\r\n"); } else if (keyword.endsWith(" offering")) { String offeringType = keyword.split(" ")[0]; if (sb.length() != 0) { 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 4a40fbd06ae..3465e014479 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -3331,7 +3331,7 @@ public class CardFactoryUtil { // sacrifice trigger final StringBuilder sacTrig = new StringBuilder("Mode$ CounterRemoved | TriggerZones$ Battlefield" + - " | ValidCard$ Card.Self | NewCounterAmount$ 0 | CounterType$ TIME"); + " | ValidCard$ Card.Self | NewCounterAmount$ 0 | CounterType$ TIME"); if (keyword.contains(":")) { sacTrig.append("| Secondary$ True"); } @@ -3343,6 +3343,21 @@ public class CardFactoryUtil { inst.addTrigger(parsedUpkeepTrig); inst.addTrigger(parsedSacTrigger); + } else if (keyword.startsWith("Ward")) { + final String[] k = keyword.split(":"); + final Cost cost = new Cost(k[1], false); + String costDesc = cost.toSimpleString(); + + String strTrig = "Mode$ BecomesTarget | ValidSource$ Card.OppCtrl | ValidTarget$ Card.Self " + + " | Secondary$ True | TriggerDescription$ Ward " + costDesc + " (" + + inst.getReminderText() + ")"; + String effect = "DB$ Counter | Defined$ TriggeredSourceSA | UnlessCost$ " + k[1] + + " | UnlessPayer$ TriggeredSourceSAController"; + + final Trigger trigger = TriggerHandler.parseTrigger(strTrig, card, intrinsic); + trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card)); + + inst.addTrigger(trigger); } else if (keyword.equals("MayFlashSac")) { String strTrig = "Mode$ SpellCast | ValidCard$ Card.Self | ValidSA$ Spell.MayPlaySource | Static$ True | Secondary$ True " + " | TriggerDescription$ If you cast it any time a sorcery couldn't have been cast, " diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index 9c3027fc6ba..aa5c7ca0195 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -65,7 +65,7 @@ public final class CardUtil { "Fortify", "Transfigure", "Champion", "Evoke", "Prowl", "IfReach", "Reinforce", "Unearth", "Level up", "Miracle", "Overload", "Scavenge", "Encore", "Bestow", "Outlast", "Dash", "Surge", "Emerge", "Hexproof:", - "etbCounter", "Reflect").build(); + "etbCounter", "Reflect", "Ward").build(); /** List of keyword endings of keywords that could be modified by text changes. */ public static final ImmutableList modifiableKeywordEndings = ImmutableList.builder().add( "walk", "cycling", "offering").build(); diff --git a/forge-game/src/main/java/forge/game/keyword/Keyword.java b/forge-game/src/main/java/forge/game/keyword/Keyword.java index f27e0dfc56b..fea88ec24ff 100644 --- a/forge-game/src/main/java/forge/game/keyword/Keyword.java +++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java @@ -161,6 +161,7 @@ public enum Keyword { UNLEASH("Unleash", SimpleKeyword.class, false, "You may have this creature enter the battlefield with a +1/+1 counter on it. It can't block as long as it has a +1/+1 counter on it."), VANISHING("Vanishing", KeywordWithAmount.class, false, "This permanent enters the battlefield with {%d:time counter} on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it."), VIGILANCE("Vigilance", SimpleKeyword.class, true, "Attacking doesn't cause this creature to tap."), + WARD("Ward", KeywordWithCost.class, false, "Whenever this permanent becomes the target of a spell or ability an opponent controls, counter it unless that player pays %s."), WITHER("Wither", SimpleKeyword.class, true, "This deals damage to creatures in the form of -1/-1 counters."), // mayflash additional cast diff --git a/forge-gui/res/cardsfolder/upcoming/torrent_sculptor_flamethrower_sonata.txt b/forge-gui/res/cardsfolder/upcoming/torrent_sculptor_flamethrower_sonata.txt new file mode 100644 index 00000000000..8b395a7f328 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/torrent_sculptor_flamethrower_sonata.txt @@ -0,0 +1,25 @@ +Name:Torrent Sculptor +ManaCost:2 U U +Types:Creature Merfolk Wizard +PT:2/2 +K:Ward:2 +T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$ TrigChangeZone | TriggerDescription$ When CARDNAME enters the battlefield, exile an instant or sorcery card from your graveyard. Put a number of +1/+1 counters on Torrent Sculptor equal to half that card's mana value, rounded up. +SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | ChangeType$ Instant.YouCtrl,Sorcery.YouCtrl | ChangeNum$ 1 | RememberChanged$ True | Hidden$ True | Mandatory$ True | SubAbility$ DBPutCounter +SVar:DBPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ X | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Remembered$CardManaCost/HalfUp +AlternateMode:Modal +Oracle:Ward {2} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {2}.)\nWhen Torrent Sculptor enters the battlefield, exile an instant or sorcery card from your graveyard. Put a number of +1/+1 counters on Torrent Sculptor equal to half that card's mana value, rounded up. + +ALTERNATE + +Name:Flamethrower Sonata +ManaCost:1 R +Types:Sorcery +A:SP$ Discard | Cost$ 1 R | Mode$ TgtChoose | SubAbility$ DBDraw | RememberDiscarded$ True | SpellDescription$ Discard a card, then draw a card. When you discard an instant or sorcery card this way, CARDNAME deals damage equal to that card's mana value to target creature or planeswalker you don't control. +SVar:DBDraw:DB$ Draw | SubAbility$ DBImmediateTrigger +SVar:DBImmediateTrigger:DB$ ImmediateTrigger | ConditionDefined$ Remembered | ConditionPresent$ Instant,Sorcery | Execute$ TrigDealDamage | RememberObjects$ RememberedCard | SubAbility$ DBCleanup | TriggerDescription$ When you discard an instant or sorcery card this way, CARDNAME deals damage equal to that card's mana value to target creature or planeswalker you don't control. +SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Creature.YouDontCtrl,Planeswalker.YouDontCtrl | TgtPrompt$ Select target creature or planeswalker you don't control | NumDmg$ X +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Remembered$CardManaCost +Oracle:Discard a card, then draw a card. When you discard an instant or sorcery card this way, Flamethrower Sonata deals damage equal to that card's mana value to target creature or planeswalker you don't control. diff --git a/forge-gui/res/cardsfolder/upcoming/waterfall_aerialist.txt b/forge-gui/res/cardsfolder/upcoming/waterfall_aerialist.txt new file mode 100644 index 00000000000..dec50e0fc46 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/waterfall_aerialist.txt @@ -0,0 +1,7 @@ +Name:Waterfall Aerialist +ManaCost:3 U +Types:Creature Djinn Wizard +PT:3/1 +K:Flying +K:Ward:2 +Oracle:Flying\nWard {2} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {2}.)