From 0c333a0c9ab7e944f1e0ad3eed46319cbb8ab8fe Mon Sep 17 00:00:00 2001 From: Tim Mocny Date: Sun, 30 Jan 2022 04:40:52 +0000 Subject: [PATCH] NEO: Initial Reconfigure keyword support and cards --- .../src/main/java/forge/game/GameEntity.java | 3 +- .../src/main/java/forge/game/card/Card.java | 3 +- .../java/forge/game/card/CardFactoryUtil.java | 29 +++++++++++++++++-- .../main/java/forge/game/keyword/Keyword.java | 1 + .../cardsfolder/upcoming/bronzeplate_boar.txt | 8 +++++ .../cardsfolder/upcoming/leech_gauntlet.txt | 9 ++++++ .../cardsfolder/upcoming/lizard_blades.txt | 8 +++++ .../res/cardsfolder/upcoming/simian_sling.txt | 9 ++++++ .../cardsfolder/upcoming/the_reality_chip.txt | 8 +++++ 9 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/bronzeplate_boar.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/leech_gauntlet.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/lizard_blades.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/simian_sling.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/the_reality_chip.txt diff --git a/forge-game/src/main/java/forge/game/GameEntity.java b/forge-game/src/main/java/forge/game/GameEntity.java index c173c1c7fc7..6e9d7c48156 100644 --- a/forge-game/src/main/java/forge/game/GameEntity.java +++ b/forge-game/src/main/java/forge/game/GameEntity.java @@ -217,7 +217,8 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { } public boolean canBeAttached(final Card attach, boolean checkSBA) { // master mode - if (!attach.isAttachment() || attach.isCreature() || equals(attach)) { + if (!attach.isAttachment() || (attach.isCreature() && !attach.hasKeyword(Keyword.RECONFIGURE)) + || equals(attach)) { return false; } 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 7531a499594..2de6290b317 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -1948,7 +1948,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars { sbLong.append(TextUtil.fastReplace(keyword, ":", " ")).append("\r\n"); } else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph") || keyword.startsWith("Escape") || keyword.startsWith("Foretell:") - || keyword.startsWith("Disturb") || keyword.startsWith("Madness:")){ + || keyword.startsWith("Disturb") || keyword.startsWith("Madness:") + || keyword.startsWith("Reconfigure")) { 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 c21628ea5b0..6650280df7e 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -2773,8 +2773,8 @@ public class CardFactoryUtil { String equipCost = k[1]; String valid = k.length > 2 && !k[2].isEmpty() ? k[2] : "Creature.YouCtrl"; String vstr = k.length > 3 && !k[3].isEmpty() ? k[3] : "creature"; - String extra = k.length > 4 ? k[4] : ""; - String extraDesc = k.length > 5 ? k[5] : ""; + String extra = k.length > 4 ? k[4] : ""; + String extraDesc = k.length > 5 ? k[5] : ""; // Create attach ability string final StringBuilder abilityStr = new StringBuilder(); abilityStr.append("AB$ Attach | Cost$ "); @@ -3111,6 +3111,27 @@ public class CardFactoryUtil { newSA.setIntrinsic(intrinsic); inst.addSpellAbility(newSA); + } else if (keyword.startsWith("Reconfigure")) { + if (!keyword.contains(":")) { + System.err.println("Malformed Reconfigure entry! - Card: " + card.toString()); + return; + } + String[] k = keyword.split(":"); + String bothStr = "| Cost$ " + k[1] + " | SorcerySpeed$ True | Reconfigure$ True | PrecostDesc$ Reconfigure "; + final StringBuilder attachStr = new StringBuilder(); + attachStr.append("AB$ Attach | ValidTgts$ Creature.YouCtrl+Other | TgtPrompt$ Select target creature you "); + attachStr.append("control | AILogic$ Pump | Secondary$ True | SpellDescription$ Attach ").append(bothStr); + final StringBuilder unattachStr = new StringBuilder(); + unattachStr.append("AB$ Unattach | Defined$ Self | SpellDescription$ Unattach | Secondary$ True "); + unattachStr.append(bothStr); + // instantiate attach ability + SpellAbility attachSA = AbilityFactory.getAbility(attachStr.toString(), card); + attachSA.setIntrinsic(intrinsic); + inst.addSpellAbility(attachSA); + // instantiate unattach ability + SpellAbility unattachSA = AbilityFactory.getAbility(unattachStr.toString(), card); + unattachSA.setIntrinsic(intrinsic); + inst.addSpellAbility(unattachSA); } else if (keyword.startsWith("Reinforce")) { final String[] k = keyword.split(":"); final String n = k[1]; @@ -3585,6 +3606,10 @@ public class CardFactoryUtil { } effect += " | Description$ " + desc; inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic)); + } else if (keyword.startsWith("Reconfigure")) { + String effect = "Mode$ Continuous | Affected$ Card.Self | IsPresent$ Card.Self+AttachedTo Creature | " + + "RemoveType$ Creature | Secondary$ True | Description$ Reconfigure (" + inst.getReminderText() + ")"; + inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic)); } else if (keyword.equals("Shroud")) { String effect = "Mode$ CantTarget | Shroud$ True | ValidCard$ Card.Self | Secondary$ True" + " | Description$ Shroud (" + inst.getReminderText() + ")"; 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 62131dfe0ba..f87e9c6f2ca 100644 --- a/forge-game/src/main/java/forge/game/keyword/Keyword.java +++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java @@ -135,6 +135,7 @@ public enum Keyword { REACH("Reach", SimpleKeyword.class, true, "This creature can block creatures with flying."), REBOUND("Rebound", SimpleKeyword.class, true, "If you cast this spell from your hand, exile it as it resolves. At the beginning of your next upkeep, you may cast this card from exile without paying its mana cost."), RECOVER("Recover", KeywordWithCost.class, false, "When a creature is put into your graveyard from the battlefield, you may pay %s. If you do, return this card from your graveyard to your hand. Otherwise, exile this card."), + RECONFIGURE("Reconfigure", KeywordWithCost.class, false, "%s: Attach to target creature you control; or unattach from a creature. Reconfigure only as a sorcery. While attached, this isn't a creature."), REFLECT("Reflect", KeywordWithCost.class, false, "As this enters the battlefield, each opponent may pay %s. When they do, they create a token copy of this except it lacks this ability."), REINFORCE("Reinforce", KeywordWithCostAndAmount.class, false, "%s, Discard this card: Put {%d:+1/+1 counter} on target creature."), RENOWN("Renown", KeywordWithAmount.class, false, "When this creature deals combat damage to a player, if it isn't renowned, put {%d:+1/+1 counter} on it and it becomes renowned."), diff --git a/forge-gui/res/cardsfolder/upcoming/bronzeplate_boar.txt b/forge-gui/res/cardsfolder/upcoming/bronzeplate_boar.txt new file mode 100644 index 00000000000..42b7df23169 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/bronzeplate_boar.txt @@ -0,0 +1,8 @@ +Name:Bronzeplate Boar +ManaCost:2 R +Types:Artifact Creature Equipment Boar +PT:3/2 +K:Trample +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 3 | AddToughness$ 2 | AddKeyword$ Trample | Description$ Equipped creature gets +3/+2 and has trample. +K:Reconfigure:5 +Oracle:Trample\nEquipped creature gets +3/+2 and has trample.\nReconfigure {5} ({5}: Attach to target creature you control; or unattach from a creature. Reconfigure only as a sorcery. While attached, this isn't a creature.) diff --git a/forge-gui/res/cardsfolder/upcoming/leech_gauntlet.txt b/forge-gui/res/cardsfolder/upcoming/leech_gauntlet.txt new file mode 100644 index 00000000000..b07822a21f1 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/leech_gauntlet.txt @@ -0,0 +1,9 @@ +Name:Leech Gauntlet +ManaCost:1 B +Types:Artifact Creature Equipment Leech +PT:2/2 +K:Lifelink +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Lifelink | Description$ Equipped creature has lifelink. +K:Reconfigure:4 +DeckHas:Ability$LifeGain +Oracle:Lifelink\nEquipped creature has lifelink.\nReconfigure {4} ({4}: Attach to target creature you control; or unattach from a creature. Reconfigure only as a sorcery. While attached, this isn't a creature.) diff --git a/forge-gui/res/cardsfolder/upcoming/lizard_blades.txt b/forge-gui/res/cardsfolder/upcoming/lizard_blades.txt new file mode 100644 index 00000000000..d83c063fd53 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/lizard_blades.txt @@ -0,0 +1,8 @@ +Name:Lizard Blades +ManaCost:1 R +Types:Artifact Creature Equipment Lizard +PT:1/1 +K:Double strike +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Double strike | Description$ Equipped creature has double strike. +K:Reconfigure:2 +Oracle:Trample\nEquipped creature has double strike.\nReconfigure {2} ({2}: Attach to target creature you control; or unattach from a creature. Reconfigure only as a sorcery. While attached, this isn't a creature.) diff --git a/forge-gui/res/cardsfolder/upcoming/simian_sling.txt b/forge-gui/res/cardsfolder/upcoming/simian_sling.txt new file mode 100644 index 00000000000..ee9d38fe149 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/simian_sling.txt @@ -0,0 +1,9 @@ +Name:Simian Sling +ManaCost:R +Types:Artifact Creature Equipment Monkey +PT:1/1 +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 1 | AddToughness$ 1 | Description$ Equipped creature gets +1/+1. +T:Mode$ AttackerBlocked | ValidCard$ Card.Self,Creature.EquippedBy | Execute$ TrigDamage | TriggerDescription$ Whenever CARDNAME or equipped creature becomes blocked, it deals 1 damage to defending player. +SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredDefendingPlayer | NumDmg$ 1 +K:Reconfigure:2 +Oracle:Equipped creature gets +1/+1.\nWhenever Simian Sling or equipped creature becomes blocked, it deals 1 damage to defending player.\nReconfigure {2} ({2}: Attach to target creature you control; or unattach from a creature. Reconfigure only as a sorcery. While attached, this isn't a creature.) diff --git a/forge-gui/res/cardsfolder/upcoming/the_reality_chip.txt b/forge-gui/res/cardsfolder/upcoming/the_reality_chip.txt new file mode 100644 index 00000000000..0982e89a6a9 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/the_reality_chip.txt @@ -0,0 +1,8 @@ +Name:The Reality Chip +ManaCost:1 U +Types:Legendary Artifact Creature Equipment Jellyfish +PT:0/4 +S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ You | Description$ You may look at the top card of your library any time. +S:Mode$ Continuous | IsPresent$ Card.Self+AttachedTo Creature | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayPlay$ True | Description$ As long as CARDNAME is attached to a creature, you may play lands and cast spells from the top of your library. +K:Reconfigure:2 U +Oracle:You may look at the top card of your library any time.\nAs long as The Reality Chip is attached to a creature, you may play lands and cast spells from the top of your library.\nReconfigure {2}{U} ({2}{U}: Attach to target creature you control; or unattach from a creature. Reconfigure only as a sorcery. While attached, this isn't a creature.)