diff --git a/forge-game/src/main/java/forge/game/ForgeScript.java b/forge-game/src/main/java/forge/game/ForgeScript.java index e27dcd4dc53..59870a830de 100644 --- a/forge-game/src/main/java/forge/game/ForgeScript.java +++ b/forge-game/src/main/java/forge/game/ForgeScript.java @@ -168,6 +168,10 @@ public class ForgeScript { if (!sa.isFlashBackAbility()) { return false; } + } else if (property.equals("Jumpstart")) { + if (!sa.isJumpstart()) { + return false; + } } else if (property.equals("Kicked")) { if (!sa.isKicked()) { 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 32d61833834..6fc7ffde41c 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -1960,7 +1960,7 @@ public class Card extends GameEntity implements Comparable { sbBefore.append(keyword + " (" + inst.getReminderText() + ")"); sbBefore.append("\r\n"); } else if(keyword.equals("Conspire") || keyword.equals("Epic") - || keyword.equals("Suspend")) { + || keyword.equals("Suspend") || keyword.equals("Jump-start")) { sbAfter.append(keyword + " (" + inst.getReminderText() + ")"); sbAfter.append("\r\n"); } else if (keyword.startsWith("Ripple")) { 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 cbae0b7ff75..2219ab5ddc6 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -3370,6 +3370,29 @@ public class CardFactoryUtil { final ReplacementEffect re = makeEtbCounter(sb.toString(), card, intrinsic); + inst.addReplacement(re); + } else if (keyword.equals("Jump-start")) { + StringBuilder sb = new StringBuilder(); + sb.append("Event$ Moved | ValidCard$ Card.Self | Origin$ Stack | ExcludeDestination$ Exile "); + sb.append("| Secondary$ True | ValidStackSa$ Spell.Jumpstart | Description$ Jump-start ("); + sb.append(inst.getReminderText()); + sb.append(")"); + + String repeffstr = sb.toString(); + + String abExile = "DB$ ChangeZone | Defined$ Self | Origin$ Stack | Destination$ Exile"; + + SpellAbility saExile = AbilityFactory.getAbility(abExile, card); + + if (!intrinsic) { + saExile.setIntrinsic(false); + } + + ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, card, intrinsic); + re.setLayer(ReplacementLayer.Other); + + re.setOverridingAbility(saExile); + inst.addReplacement(re); } else if (keyword.startsWith("Madness")) { // Set Madness Replacement effects @@ -3872,6 +3895,25 @@ public class CardFactoryUtil { sa.setIntrinsic(intrinsic); inst.addSpellAbility(sa); } + } else if (keyword.equals("Jump-start")) { + SpellAbility sa = card.getFirstSpellAbility(); + + final SpellAbility newSA = sa.copyWithDefinedCost( + sa.getPayCosts().copy().add(new Cost("Discard<1/Card>", false)));; + + newSA.getMapParams().put("Secondary", "True"); + newSA.setBasicSpell(false); + newSA.setJumpstart(true); + + newSA.getRestrictions().setZone(ZoneType.Graveyard); + + String desc = "Jump-start (" + inst.getReminderText() + ")"; + newSA.setDescription(desc); + + newSA.setIntrinsic(intrinsic); + + newSA.setTemporary(!intrinsic); + inst.addSpellAbility(newSA); } else if (keyword.startsWith("Level up")) { final String[] k = keyword.split(":"); final String manacost = k[1]; @@ -4114,9 +4156,8 @@ public class CardFactoryUtil { } else if (keyword.startsWith("Surge")) { final String[] k = keyword.split(":"); final Cost surgeCost = new Cost(k[1], false); - final SpellAbility newSA = card.getFirstSpellAbility().copy(); + final SpellAbility newSA = card.getFirstSpellAbility().copyWithDefinedCost(surgeCost); - newSA.setPayCosts(surgeCost); newSA.setBasicSpell(false); newSA.setSurged(true); 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 0796271ac78..72c45bc8589 100644 --- a/forge-game/src/main/java/forge/game/keyword/Keyword.java +++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java @@ -2,6 +2,8 @@ package forge.game.keyword; import java.util.*; +import org.apache.commons.lang3.StringUtils; + import forge.StaticData; import forge.game.card.Card; import forge.item.PaperCard; @@ -84,6 +86,7 @@ public enum Keyword { INGEST(SimpleKeyword.class, false, "Whenever this creature deals combat damage to a player, that player exiles the top card of their library."), INTIMIDATE(SimpleKeyword.class, true, "This creature can't be blocked except by artifact creatures and/or creatures that share a color with it."), KICKER(Kicker.class, false, "You may pay an additional %s as you cast this spell."), + JUMP_START(SimpleKeyword.class, false, "You may cast this card from your graveyard by discarding a card in addition to paying its other costs. Then exile this card."), LANDWALK(KeywordWithType.class, false, "This creature is unblockable as long as defending player controls a %s."), LEVEL_UP(KeywordWithCost.class, false, "%s: Put a level counter on this. Level up only as a sorcery."), LIFELINK(SimpleKeyword.class, true, "Damage dealt by this creature also causes its controller to gain that much life."), @@ -279,8 +282,7 @@ public enum Keyword { } public static Keyword smartValueOf(String value) { - - final String valToCompate = value.replace(" ", "_").toUpperCase(); + final String valToCompate = StringUtils.replaceChars(value, " -", "__").toUpperCase(); for (final Keyword v : Keyword.values()) { if (valToCompate.equals(v.name())) { return v; 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 767abebede9..43bef36fb59 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -93,6 +93,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit private List triggerRemembered = Lists.newArrayList(); private boolean flashBackAbility = false; + private boolean jumpstart = false; private boolean aftermath = false; private boolean cycling = false; private boolean dash = false; @@ -787,6 +788,13 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit outlast = outlast0; } + public boolean isJumpstart() { + return jumpstart; + } + public void setJumpstart(boolean jumpstart0) { + jumpstart = jumpstart0; + } + public boolean isBlessing() { return blessing; } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java index 3ff247bc3ed..111659b7e03 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java @@ -20,8 +20,6 @@ package forge.game.spellability; import java.util.List; import java.util.Map; -import com.google.common.collect.Lists; - import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.card.Card; diff --git a/forge-gui/res/cardsfolder/upcoming/quasiduplicate.txt b/forge-gui/res/cardsfolder/upcoming/quasiduplicate.txt new file mode 100644 index 00000000000..ddc7552bb2e --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/quasiduplicate.txt @@ -0,0 +1,6 @@ +Name:Quasiduplicate +ManaCost:1 U U +Types:Sorcery +K:Jump-start +A:SP$ CopyPermanent | Cost$ 1 U U | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | SpellDescription$ Create a creature token that's a copy of target creature you control. +Oracle:Create a creature token that's a copy of target creature you control.\nJump-start (You may cast this card from your graveyard by discarding a card in addition to paying its other costs. Then exile this card.)