diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 6f4961a9c77..fa885dcccc2 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -851,6 +851,9 @@ public class GameAction { } public final Card moveToStack(final Card c, SpellAbility cause, Map params) { Card result = moveTo(game.getStackZone(), c, cause, params); + if (cause.hasParam("Prototype")) { + result.addCloneState(CardFactory.getCloneStates(c, c, cause), game.getNextTimestamp()); + } if (cause != null && cause.isSpell() && result.equals(cause.getHostCard())) { result.setSplitStateToPlayAbility(cause); 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 b56437f1a58..cd9a0e03cbe 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -2284,7 +2284,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { || keyword.startsWith("Transfigure") || keyword.startsWith("Aura swap") || keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling") || keyword.startsWith("Encore") || keyword.startsWith("Mutate") || keyword.startsWith("Dungeon") - || keyword.startsWith("Class") || keyword.startsWith("Blitz") + || keyword.startsWith("Class") || keyword.startsWith("Blitz") || keyword.startsWith("Prototype") || keyword.startsWith("Specialize") || keyword.equals("Ravenous")) { // keyword parsing takes care of adding a proper description } else if(keyword.startsWith("Read ahead")) { diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index 0dd9ba86c26..e6eec57b756 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -24,6 +24,7 @@ import forge.ImageKeys; import forge.StaticData; import forge.card.*; import forge.card.mana.ManaCost; +import forge.card.mana.ManaCostParser; import forge.game.CardTraitBase; import forge.game.Game; import forge.game.ability.AbilityFactory; @@ -688,6 +689,14 @@ public class CardFactory { colors = ColorSet.fromNames(sa.getParam("SetColor").split(",")); } + if (sa.hasParam("SetColorByManaCost")) { + if (sa.hasParam("SetManaCost")) { + colors = ColorSet.fromManaCost(new ManaCost(new ManaCostParser(sa.getParam("SetManaCost")))); + } else { + colors = ColorSet.fromManaCost(host.getManaCost()); + } + } + // TODO handle Volrath's Shapeshifter if (in.isFaceDown()) { @@ -736,7 +745,7 @@ public class CardFactory { state.addColor(colors.getColor()); } - if (sa.hasParam("SetColor")) { + if (sa.hasParam("SetColor") || sa.hasParam("SetColorByManaCost")) { state.setColor(colors.getColor()); } @@ -777,6 +786,10 @@ public class CardFactory { state.setManaCost(ManaCost.NO_COST); } + if (sa.hasParam("SetManaCost")) { + state.setManaCost(new ManaCost(new ManaCostParser(sa.getParam("SetManaCost")))); + } + // SVars to add to clone if (sa.hasParam("AddSVars") || sa.hasParam("GainTextSVars")) { final String str = sa.getParamOrDefault("GainTextSVars", sa.getParam("AddSVars")); @@ -900,7 +913,8 @@ public class CardFactory { if (sa.hasParam("SetCreatureTypes")) { state.removeIntrinsicKeyword("Changeling"); } - if (sa.hasParam("SetColor") || sa.hasParam("Embalm") || sa.hasParam("Eternalize")) { + if (sa.hasParam("SetColor") || sa.hasParam("Embalm") || sa.hasParam("Eternalize") + || sa.hasParam("SetColorByManaCost")) { state.removeIntrinsicKeyword("Devoid"); } } 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 6f8bf19d7f4..b283ffd7c69 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -3189,6 +3189,33 @@ public class CardFactoryUtil { sa.setIntrinsic(intrinsic); sa.setAlternativeCost(AlternativeCost.Outlast); inst.addSpellAbility(sa); + } else if (keyword.startsWith("Prototype")) { + final String[] k = keyword.split(":"); + if (k.length < 4) { + System.err.println("Malformed Prototype entry! - Card: " + card.toString()); + return; + } + + final Cost protoCost = new Cost(k[1], false); + final SpellAbility newSA = card.getFirstSpellAbility().copyWithDefinedCost(protoCost); + newSA.putParam("SetManaCost", k[1]); + newSA.putParam("SetColorByManaCost", "True"); + newSA.putParam("SetPower", k[2]); + newSA.putParam("SetToughness", k[3]); + newSA.putParam("PrecostDesc", "Prototype"); + newSA.putParam("Prototype", "True"); + newSA.putParam("CostDesc", ManaCostParser.parse(k[1])); + + // makes new SpellDescription + final StringBuilder sb = new StringBuilder(); + sb.append(newSA.getCostDescription()).append("[").append(k[2]).append("/").append(k[3]).append("] "); + sb.append("(").append(inst.getReminderText()).append(")"); + newSA.setDescription(sb.toString()); + + newSA.setAlternativeCost(AlternativeCost.Prototype); + + newSA.setIntrinsic(intrinsic); + inst.addSpellAbility(newSA); } else if (keyword.startsWith("Prowl")) { final String[] k = keyword.split(":"); final Cost prowlCost = new Cost(k[1], 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 570cb5ee228..4ced94b48b0 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 { POISONOUS("Poisonous", KeywordWithAmount.class, false, "Whenever this creature deals combat damage to a player, that player gets {%d:poison counter}."), PRESENCE("Presence", KeywordWithType.class, false, "As an additional cost to cast this spell, you may reveal a %s card from your hand."), PROTECTION("Protection", Protection.class, false, "This creature can't be blocked, targeted, dealt damage, or equipped/enchanted by %s."), + PROTOTYPE("Prototype", KeywordWithCost.class, false, "You may cast this spell with different mana cost, color, and size. It keeps its abilities and types."), PROVOKE("Provoke", SimpleKeyword.class, false, "Whenever this creature attacks, you may have target creature defending player controls untap and block it if able."), PROWESS("Prowess", SimpleKeyword.class, false, "Whenever you cast a noncreature spell, this creature gets +1/+1 until end of turn."), PROWL("Prowl", KeywordWithCost.class, false, "You may pay %s rather than pay this spell's mana cost if a player was dealt combat damage this turn by a source that, at the time it dealt that damage, was under your control and had any of this spell's creature types."), 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 b33858ff990..4e2d2d5f36d 100644 --- a/forge-game/src/main/java/forge/game/spellability/AlternativeCost.java +++ b/forge-game/src/main/java/forge/game/spellability/AlternativeCost.java @@ -17,6 +17,7 @@ public enum AlternativeCost { Mutate, Offering, Outlast, // ActivatedAbility + Prototype, Prowl, Spectacle, Surge;