From d7a51ece0eaaf726cca6dfd173d3c5d1fcf43021 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Thu, 15 Sep 2022 20:15:56 -0400 Subject: [PATCH 1/4] Squad keyword and vanguard_suppressor.txt --- .../main/java/forge/game/GameActionUtil.java | 21 +++++++++++++++++++ .../src/main/java/forge/game/card/Card.java | 2 +- .../java/forge/game/card/CardFactoryUtil.java | 13 ++++++++++++ .../main/java/forge/game/card/CardUtil.java | 2 +- .../main/java/forge/game/keyword/Keyword.java | 1 + .../upcoming/vanguard_suppressor.txt | 10 +++++++++ 6 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/vanguard_suppressor.txt diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 8f8d00cbdb2..b77a94a791f 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -635,6 +635,27 @@ public final class GameActionUtil { tr.setSVar("ReplicateAmount", String.valueOf(v)); tr.getOverridingAbility().setSVar("ReplicateAmount", String.valueOf(v)); + for (int i = 0; i < v; i++) { + if (result == null) { + result = sa.copy(); + } + result.getPayCosts().add(cost); + reset = true; + } + } + } else if (o.startsWith("Squad")) { + Trigger tr = Iterables.getFirst(ki.getTriggers(), null); + if (tr != null) { + String costStr = o.split(":")[1]; + final Cost cost = new Cost(costStr, false); + + String str = "Choose amount for Squad: " + cost.toSimpleString(); + + int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE); + + tr.setSVar("SquadAmount", String.valueOf(v)); + tr.getOverridingAbility().setSVar("SquadAmount", String.valueOf(v)); + for (int i = 0; i < v; i++) { if (result == null) { result = sa.copy(); 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 602ddd0728c..c4403f66944 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -2036,7 +2036,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph") || keyword.startsWith("Escape") || keyword.startsWith("Foretell:") || keyword.startsWith("Disturb") || keyword.startsWith("Madness:") - || keyword.startsWith("Reconfigure")) { + || keyword.startsWith("Reconfigure") || keyword.startsWith("Squad")) { String[] k = keyword.split(":"); sbLong.append(k[0]); if (k.length > 1) { 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 0e8ea263cf9..95cfaf14de8 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1791,6 +1791,19 @@ public class CardFactoryUtil { parsedTrigger.setOverridingAbility(sp); inst.addTrigger(parsedTrigger); + } else if (keyword.startsWith("Squad")) { + final String trigScript = "Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | " + + "ValidCard$ Card.Self+wasCast | CheckSVar$ SquadAmount | Secondary$ True | " + + "TriggerDescription$ When this creature enters the battlefield, create that many tokens that " + + "are copies of it."; + final String abString = "DB$ CopyPermanent | Defined$ TriggeredCard | NumCopies$ SquadAmount"; + + final Trigger squadTrigger = TriggerHandler.parseTrigger(trigScript, card, intrinsic); + final SpellAbility squadAbility = AbilityFactory.getAbility(abString, card); + squadAbility.setSVar("SquadAmount", "0"); + squadTrigger.setOverridingAbility(squadAbility); + squadTrigger.setSVar("SquadAmount", "0"); + inst.addTrigger(squadTrigger); } else if (keyword.equals("Storm")) { final String actualTrigger = "Mode$ SpellCast | ValidCard$ Card.Self | TriggerZones$ Stack | Secondary$ True" + "| TriggerDescription$ Storm (" + inst.getReminderText() + ")"; 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 662bcc30c0a..77abf9b1f43 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -62,7 +62,7 @@ public final class CardUtil { "Enchant", "Protection", "Cumulative upkeep", "Equip", "Buyback", "Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph", "Affinity", "Entwine", "Splice", "Ninjutsu", "Presence", - "Transmute", "Replicate", "Recover", "Suspend", "Aura swap", + "Transmute", "Replicate", "Recover", "Squad", "Suspend", "Aura swap", "Fortify", "Transfigure", "Champion", "Evoke", "Prowl", "IfReach", "Reinforce", "Unearth", "Level up", "Miracle", "Overload", "Cleave", "Scavenge", "Encore", "Bestow", "Outlast", "Dash", "Surge", "Emerge", "Hexproof:", 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 fad129c42f7..4de05739e70 100644 --- a/forge-game/src/main/java/forge/game/keyword/Keyword.java +++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java @@ -158,6 +158,7 @@ public enum Keyword { SPECTACLE("Spectacle", KeywordWithCost.class, false, "You may cast this spell for its spectacle cost rather than its mana cost if an opponent lost life this turn."), SPLICE("Splice", KeywordWithCostAndType.class, false, "As you cast an %2$s spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell."), SPLIT_SECOND("Split second", SimpleKeyword.class, true, "As long as this spell is on the stack, players can't cast other spells or activate abilities that aren't mana abilities."), + SQUAD("Squad", KeywordWithCost.class, false, "As an additional cost to cast this spell, you may pay %s any number of times. When this creature enters the battlefield, create that many tokens that are copies of it."), STARTING_INTENSITY("Starting intensity", KeywordWithAmount.class, true, null), STORM("Storm", SimpleKeyword.class, false, "When you cast this spell, copy it for each other spell that was cast before it this turn. You may choose new targets for the copies."), STRIVE("Strive", KeywordWithCost.class, false, "CARDNAME costs %s more to cast for each target beyond the first."), diff --git a/forge-gui/res/cardsfolder/upcoming/vanguard_suppressor.txt b/forge-gui/res/cardsfolder/upcoming/vanguard_suppressor.txt new file mode 100644 index 00000000000..8b89de588d7 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/vanguard_suppressor.txt @@ -0,0 +1,10 @@ +Name:Vanguard Suppressor +ManaCost:3 U +Types:Creature Astartes Warrior +PT:3/2 +K:Squad:2 +K:Flying +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDraw | TriggerDescription$ Suppressing Fire — Whenever CARDNAME deals combat damage to a player, draw a card. +SVar:TrigDraw:DB$ Draw +DeckHas:Ability$Token +Oracle:Squad {2} (As an additional cost to cast this spell, you may pay {2} any number of times. When this creature enters the battlefield, create that many tokens that are copies of it.)\nFlying\nSuppressing Fire — Whenever Vanguard Suppressor deals combat damage to a player, draw a card. From fa7b589b70b073865cb3217b93e93ce40e804f21 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Sat, 17 Sep 2022 18:31:11 -0500 Subject: [PATCH 2/4] remaining Squad cards --- forge-gui/res/cardsfolder/upcoming/arco_flagellant.txt | 9 +++++++++ .../res/cardsfolder/upcoming/sicarian_infiltrator.txt | 10 ++++++++++ .../cardsfolder/upcoming/space_marine_devastator.txt | 9 +++++++++ .../cardsfolder/upcoming/ultramarines_honor_guard.txt | 8 ++++++++ forge-gui/res/cardsfolder/upcoming/zephyrim.txt | 10 ++++++++++ 5 files changed, 46 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/arco_flagellant.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/sicarian_infiltrator.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/space_marine_devastator.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/ultramarines_honor_guard.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/zephyrim.txt diff --git a/forge-gui/res/cardsfolder/upcoming/arco_flagellant.txt b/forge-gui/res/cardsfolder/upcoming/arco_flagellant.txt new file mode 100644 index 00000000000..d29ddf7083a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/arco_flagellant.txt @@ -0,0 +1,9 @@ +Name:Arco-Flagellant +ManaCost:2 B +Types:Creature Human +PT:3/1 +K:Squad:2 +K:CARDNAME can't block. +A:AB$ Pump | PrecostDesc$ Endurant — | Cost$ PayLife<3> | KW$ Indestructible | SpellDescription$ CARDNAME gains indestructible until end of turn. +DeckHas:Ability$Token +Oracle:Squad {2} (As an additional cost to cast this spell, you may pay {2} any number of times. When this creature enters the battlefield, create that many tokens that are copies of it.)\nArco-Flagellant can't block.\nEndurant — Pay 3 life: Arco-Flagellant gains indestructible until end of turn. diff --git a/forge-gui/res/cardsfolder/upcoming/sicarian_infiltrator.txt b/forge-gui/res/cardsfolder/upcoming/sicarian_infiltrator.txt new file mode 100644 index 00000000000..a77e09723f3 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/sicarian_infiltrator.txt @@ -0,0 +1,10 @@ +Name:Sicarian Infiltrator +ManaCost:2 U +Types:Artifact Creature Human Soldier +PT:1/2 +K:Flash +K:Squad:2 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ Benediction of the Omnissiah — When CARDNAME enters the battlefield, draw a card. +SVar:TrigDraw:DB$ Draw | NumCards$ 1 +DeckHas:Ability$Token +Oracle:Flash\nSquad {2} (As an additional cost to cast this spell, you may pay {2} any number of times. When this creature enters the battlefield, create that many tokens that are copies of it.)\nBenediction of the Omnissiah — When Sicarian Infiltrator enters the battlefield, draw a card. diff --git a/forge-gui/res/cardsfolder/upcoming/space_marine_devastator.txt b/forge-gui/res/cardsfolder/upcoming/space_marine_devastator.txt new file mode 100644 index 00000000000..23b97945db9 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/space_marine_devastator.txt @@ -0,0 +1,9 @@ +Name:Space Marine Devastator +ManaCost:3 W +Types:Creature Astartes Warrior +PT:3/3 +K:Squad:2 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ Grav-cannon — When CARDNAME enters the battlefield, destroy up to one target artifact or enchantment. +SVar:TrigDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Artifact,Enchantment | TgtPrompt$ Select up to one target artifact or enchantment +DeckHas:Ability$Token +Oracle:Squad {2} (As an additional cost to cast this spell, you may pay {2} any number of times. When this creature enters the battlefield, create that many tokens that are copies of it.)\nGrav-cannon — When Space Marine Devastator enters the battlefield, destroy up to one target artifact or enchantment. diff --git a/forge-gui/res/cardsfolder/upcoming/ultramarines_honor_guard.txt b/forge-gui/res/cardsfolder/upcoming/ultramarines_honor_guard.txt new file mode 100644 index 00000000000..4c8a19548eb --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/ultramarines_honor_guard.txt @@ -0,0 +1,8 @@ +Name:Ultramarines Honour Guard +ManaCost:3 W +Types:Creature Astartes Warrior +PT:2/2 +K:Squad:2 +S:Mode$ Continuous | Affected$ Creature.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other creatures you control get +1/+1. +DeckHas:Ability$Token +Oracle:Squad {2} (As an additional cost to cast this spell, you may pay {2} any number of times. When this creature enters the battlefield, create that many tokens that are copies of it.)\nOther creatures you control get +1/+1. diff --git a/forge-gui/res/cardsfolder/upcoming/zephyrim.txt b/forge-gui/res/cardsfolder/upcoming/zephyrim.txt new file mode 100644 index 00000000000..c65d5673764 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/zephyrim.txt @@ -0,0 +1,10 @@ +Name:Zephyrim +ManaCost:3 W +Types:Creature Human Warrior +PT:3/3 +K:Squad:2 +K:Flying +K:Vigilance +K:Miracle:1 W +DeckHas:Ability$Token +Oracle:Squad {2} (As an additional cost to cast this spell, you may pay {2} any number of times. When this creature enters the battlefield, create that many tokens that are copies of it.)\nFlying, vigilance\nMiracle {1}{W} (You may cast this card for its miracle cost when you draw it if it's the first card you drew this turn.) From 9d3e9cd4a27887f62cf1ba407997b672c7430609 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Sat, 17 Sep 2022 18:39:18 -0500 Subject: [PATCH 3/4] ultramarines_honour_guard.txt fix spelling --- ...ultramarines_honor_guard.txt => ultramarines_honour_guard.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename forge-gui/res/cardsfolder/upcoming/{ultramarines_honor_guard.txt => ultramarines_honour_guard.txt} (100%) diff --git a/forge-gui/res/cardsfolder/upcoming/ultramarines_honor_guard.txt b/forge-gui/res/cardsfolder/upcoming/ultramarines_honour_guard.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ultramarines_honor_guard.txt rename to forge-gui/res/cardsfolder/upcoming/ultramarines_honour_guard.txt From f726d1957f5817e4fef40bb441308c214a66de52 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Sat, 17 Sep 2022 18:44:53 -0500 Subject: [PATCH 4/4] add Miracle keyword parsing for non instant/sorcery --- forge-game/src/main/java/forge/game/card/Card.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 c4403f66944..1715aa0e2be 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -2036,7 +2036,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph") || keyword.startsWith("Escape") || keyword.startsWith("Foretell:") || keyword.startsWith("Disturb") || keyword.startsWith("Madness:") - || keyword.startsWith("Reconfigure") || keyword.startsWith("Squad")) { + || keyword.startsWith("Reconfigure") || keyword.startsWith("Squad") + || keyword.startsWith("Miracle")) { String[] k = keyword.split(":"); sbLong.append(k[0]); if (k.length > 1) {