From 423e866cb0eaee026f45c0f372fbf50550bb004f Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Tue, 9 Jul 2024 07:33:23 +0200 Subject: [PATCH] Keyword: Impending (#5544) * Keyword: Impending * Update overlord_of_the_hauntwoods.txt --------- Co-authored-by: tool4ever --- .../src/main/java/forge/game/card/Card.java | 2 +- .../java/forge/game/card/CardFactoryUtil.java | 48 +++++++++++++++++++ .../java/forge/game/card/CardProperty.java | 8 ++++ .../main/java/forge/game/keyword/Keyword.java | 1 + .../game/spellability/AlternativeCost.java | 1 + .../forge/game/spellability/SpellAbility.java | 4 ++ .../upcoming/overlord_of_the_hauntwoods.txt | 9 ++++ forge-gui/res/tokenscripts/everywhere.txt | 4 ++ 8 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/overlord_of_the_hauntwoods.txt create mode 100644 forge-gui/res/tokenscripts/everywhere.txt 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 bfb67429153..2fe7bf5c8af 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -2494,7 +2494,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { || keyword.startsWith("Bestow") || keyword.startsWith("Surge") || keyword.startsWith("Transmute") || keyword.startsWith("Suspend") || keyword.startsWith("Dash") || keyword.startsWith("Disturb") - || keyword.equals("Undaunted") || keyword.startsWith("Monstrosity") + || keyword.equals("Undaunted") || keyword.startsWith("Monstrosity") || keyword.startsWith("Impending") || keyword.startsWith("Embalm") || keyword.equals("Prowess") || keyword.startsWith("Eternalize") || keyword.startsWith("Reinforce") || keyword.startsWith("Champion") || keyword.startsWith("Freerunning") || keyword.startsWith("Prowl") || keyword.startsWith("Adapt") 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 0532f57d10f..8c4280fbf1e 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1427,6 +1427,16 @@ public class CardFactoryUtil { trigger.setOverridingAbility(AbilityFactory.getAbility(abStr, card)); inst.addTrigger(trigger); + } else if (keyword.startsWith("Impending")) { + // Remove Time counter trigger + final String endTrig = "Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | IsPresent$ Card.Self+counters_GE1_TIME" + + " | Secondary$ True | TriggerDescription$ At the beginning of your end step, remove a time counter from it."; + + final String remove = "DB$ RemoveCounter | Defined$ Self | CounterType$ TIME | CounterNum$ 1"; + final Trigger parsedEndTrig = TriggerHandler.parseTrigger(endTrig, card, intrinsic); + parsedEndTrig.setOverridingAbility(AbilityFactory.getAbility(remove, card)); + + inst.addTrigger(parsedEndTrig); } else if (keyword.equals("Living Weapon")) { final StringBuilder sbTrig = new StringBuilder(); sbTrig.append("Mode$ ChangesZone | Destination$ Battlefield | "); @@ -2329,6 +2339,21 @@ public class CardFactoryUtil { final ReplacementEffect re = makeEtbCounter(sb.toString(), card, intrinsic); + inst.addReplacement(re); + } else if (keyword.startsWith("Impending")) { + final String[] k = keyword.split(":"); + final String m = k[1]; + final Cost cost = new Cost(k[2], false); + + StringBuilder desc = new StringBuilder(); + desc.append("Impending "); + desc.append(m).append("—").append(cost.toSimpleString()); + + final String effect = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ TIME | CounterNum$ " + m + + " | ETB$ True | SpellDescription$ " + desc; + + final ReplacementEffect re = createETBReplacement(card, ReplacementLayer.Other, effect, false, true, intrinsic, "Card.Self+impended", ""); + inst.addReplacement(re); } else if (keyword.equals("Jump-start")) { StringBuilder sb = new StringBuilder(); @@ -3165,6 +3190,26 @@ public class CardFactoryUtil { sa.setIntrinsic(intrinsic); inst.addSpellAbility(sa); } + } else if (keyword.startsWith("Impending")) { + final String[] k = keyword.split(":"); + final Cost cost = new Cost(k[2], false); + final SpellAbility newSA = card.getFirstSpellAbility().copyWithDefinedCost(cost); + + newSA.putParam("PrecostDesc", "Impending"); + StringBuilder costDesc = new StringBuilder(); + costDesc.append(k[1]).append("—").append(cost.toSimpleString()); + newSA.putParam("CostDesc", costDesc.toString()); + + // makes new SpellDescription + final StringBuilder sb = new StringBuilder(); + sb.append(newSA.getCostDescription()); + sb.append("(").append(inst.getReminderText()).append(")"); + newSA.setDescription(sb.toString()); + + newSA.setAlternativeCost(AlternativeCost.Impending); + + newSA.setIntrinsic(intrinsic); + inst.addSpellAbility(newSA); } else if (keyword.startsWith("Level up")) { final String[] k = keyword.split(":"); final String manacost = k[1]; @@ -3953,6 +3998,9 @@ public class CardFactoryUtil { String effect = "Mode$ CantBlockBy | ValidAttacker$ Creature.Self | ValidBlocker$ Creature.withoutHorsemanship | Secondary$ True " + " | Description$ Horsemanship (" + inst.getReminderText() + ")"; inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic)); + } else if (keyword.startsWith("Impending")) { + String effect = "Mode$ Continuous | Affected$ Card.Self+counters_GE1_TIME | RemoveType$ Creature | Secondary$ True"; + inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic)); } else if (keyword.equals("Intimidate")) { String effect = "Mode$ CantBlockBy | ValidAttacker$ Creature.Self | ValidBlocker$ Creature.nonArtifact+notSharesColorWith | Secondary$ True " + " | Description$ Intimidate (" + inst.getReminderText() + ")"; diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index f901355ee19..383bad0b260 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -1882,6 +1882,14 @@ public class CardProperty { return false; } return card.getCastSA().isEvoke(); + } else if (property.equals("impended")) { + if (card.getCastSA() == null) { + return false; + } + if (AbilityUtils.isUnlinkedFromCastSA(spellAbility, card)) { + return false; + } + return card.getCastSA().isImpending(); } else if (property.equals("prowled")) { if (card.getCastSA() == null) { return false; 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 efbffabba9c..65a7a66e8fa 100644 --- a/forge-game/src/main/java/forge/game/keyword/Keyword.java +++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java @@ -106,6 +106,7 @@ public enum Keyword { HEXPROOF("Hexproof", Hexproof.class, true, "This can't be the target of %s spells or abilities your opponents control."), HIDEAWAY("Hideaway", KeywordWithAmount.class, false, "When this permanent enters the battlefield, look at the top {%d:card} of your library, exile one face down, then put the rest on the bottom of your library."), HORSEMANSHIP("Horsemanship", SimpleKeyword.class, true, "This creature can't be blocked except by creatures with horsemanship."), + IMPENDING("Impending", KeywordWithCostAndAmount.class, false, "If you cast this spell for its impending cost, it enters with {%2$d:time counter} and isn’t a creature until the last is removed. At the beginning of your end step, remove a time counter from it."), IMPROVISE("Improvise", SimpleKeyword.class, true, "Your artifacts can help cast this spell. Each artifact you tap after you're done activating mana abilities pays for {1}."), INDESTRUCTIBLE("Indestructible", SimpleKeyword.class, true, "Effects that say \"destroy\" don't destroy this."), INFECT("Infect", SimpleKeyword.class, true, "This creature deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters."), diff --git a/forge-game/src/main/java/forge/game/spellability/AlternativeCost.java b/forge-game/src/main/java/forge/game/spellability/AlternativeCost.java index 71aeccd3f95..b3ec170fb52 100644 --- a/forge-game/src/main/java/forge/game/spellability/AlternativeCost.java +++ b/forge-game/src/main/java/forge/game/spellability/AlternativeCost.java @@ -12,6 +12,7 @@ public enum AlternativeCost { Flashback, Foretold, Freerunning, + Impending, Madness, MTMtE, // More Than Meets the Eye (Transformers Universes Beyond) Mutate, 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 744adafe626..e45fb691419 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -1553,6 +1553,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return isAlternativeCost(AlternativeCost.Freerunning); } + public final boolean isImpending() { + return isAlternativeCost(AlternativeCost.Impending); + } + public final boolean isMadness() { return isAlternativeCost(AlternativeCost.Madness); } diff --git a/forge-gui/res/cardsfolder/upcoming/overlord_of_the_hauntwoods.txt b/forge-gui/res/cardsfolder/upcoming/overlord_of_the_hauntwoods.txt new file mode 100644 index 00000000000..bc5f3915e4a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/overlord_of_the_hauntwoods.txt @@ -0,0 +1,9 @@ +Name:Overlord of the Hauntwoods +ManaCost:3 G G +Types:Enchantment Creature Avatar Horror +PT:6/5 +K:Impending:4:1 G G +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type. +T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type. +SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ everywhere | LockTokenScript$ True | TokenTapped$ True +Oracle:Impending 4—{1}{G}{G} (If you cast this spell for its impending cost, it enters with four time counters and isn’t a creature until the last is removed. At the beginning of your end step, remove a time counter from it.)\nWhenever Overlord of the Hauntwoods enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type. diff --git a/forge-gui/res/tokenscripts/everywhere.txt b/forge-gui/res/tokenscripts/everywhere.txt new file mode 100644 index 00000000000..d8c77977f58 --- /dev/null +++ b/forge-gui/res/tokenscripts/everywhere.txt @@ -0,0 +1,4 @@ +Name:Everywhere +ManaCost:no cost +Types:Land Plains Island Swamp Mountain Forest +Oracle: