diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 13c905a9f19..0fecc6c1fe8 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -319,7 +319,11 @@ public final class GameActionUtil { newSA.getMapParams().put("ValidAfterStack", o.getAbility().getParam("ValidAfterStack")); } if (o.getAbility().hasParam("RaiseCost")) { - newSA.getMapParams().put("RaiseCost", Integer.toString(AbilityUtils.calculateAmount(host, o.getAbility().getParam("RaiseCost"), o.getAbility()))); + String raise = o.getAbility().getParam("RaiseCost"); + if (o.getAbility().hasSVar(raise)) { + raise = Integer.toString(AbilityUtils.calculateAmount(host, raise, o.getAbility())); + } + newSA.getMapParams().put("RaiseCost", raise); } final SpellAbilityRestriction sar = newSA.getRestrictions(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index d961ffe3b04..0d81d8a9a3b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -449,13 +449,13 @@ public class PlayEffect extends SpellAbilityEffect { if (sa.hasParam("ReplaceGraveyard")) { if (!sa.hasParam("ReplaceGraveyardValid") || tgtSA.isValid(sa.getParam("ReplaceGraveyardValid").split(","), controller, source, sa)) { - addReplaceGraveyardEffect(tgtCard, sa, tgtSA, sa.getParam("ReplaceGraveyard"), moveParams); + addReplaceGraveyardEffect(tgtCard, source, sa, tgtSA, sa.getParam("ReplaceGraveyard")); } } // For Illusionary Mask effect if (sa.hasParam("ReplaceIlluMask")) { - addIllusionaryMaskReplace(tgtCard, sa, moveParams); + addIllusionaryMaskReplace(tgtCard, sa); } // Add controlled by player to target SA so when the spell is resolving, the controller would be changed again @@ -500,8 +500,7 @@ public class PlayEffect extends SpellAbilityEffect { } } - protected void addReplaceGraveyardEffect(Card c, SpellAbility sa, SpellAbility tgtSA, String zone, Map moveParams) { - final Card hostCard = sa.getHostCard(); + public static void addReplaceGraveyardEffect(Card c, Card hostCard, SpellAbility sa, SpellAbility tgtSA, String zone) { final Game game = hostCard.getGame(); final Player controller = sa.getActivatingPlayer(); final String name = hostCard.getName() + "'s Effect"; @@ -535,7 +534,7 @@ public class PlayEffect extends SpellAbilityEffect { game.getAction().moveToCommand(eff, sa); } - protected void addIllusionaryMaskReplace(Card c, SpellAbility sa, Map moveParams) { + protected void addIllusionaryMaskReplace(Card c, SpellAbility sa) { final Card hostCard = sa.getHostCard(); final Game game = hostCard.getGame(); final Player controller = sa.getActivatingPlayer(); 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 1489dec177c..c8d85bdbec8 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -3777,8 +3777,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } return result; } - public final void setMayPlay(final Player player, final boolean withoutManaCost, final Cost altManaCost, final boolean altIsAdditional, final boolean withFlash, final boolean grantZonePermissions, final StaticAbility sta) { - this.mayPlay.put(sta, new CardPlayOption(player, sta, withoutManaCost, altManaCost, altIsAdditional, withFlash, grantZonePermissions)); + public final void setMayPlay(final Player player, final boolean withoutManaCost, final Cost altManaCost, final boolean withFlash, final boolean grantZonePermissions, final StaticAbility sta) { + this.mayPlay.put(sta, new CardPlayOption(player, sta, withoutManaCost, altManaCost, withFlash, grantZonePermissions)); this.updateMayPlay(); } public final void removeMayPlay(final StaticAbility sta) { 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 2e2a551d07d..411a7c31118 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -3954,7 +3954,7 @@ public class CardFactoryUtil { String effect = "Mode$ AttackVigilance | ValidCard$ Card.Self | Secondary$ True | Description$ Vigilance (" + inst.getReminderText() + ")"; inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic)); } else if (keyword.equals("MayFlashSac")) { - String effect = "Mode$ Continuous | EffectZone$ All | Affected$ Card.Self | Secondary$ True | MayPlay$ True" + String effect = "Mode$ Continuous | EffectZone$ All | Affected$ Card.Self | Secondary$ True | MayPlay$ True | MayPlayDontGrantZonePermissions$ True" + " | MayPlayNotSorcerySpeed$ True | MayPlayWithFlash$ True | MayPlayText$ Sacrifice at the next cleanup step" + " | AffectedZone$ Exile,Graveyard,Hand,Library,Stack | Description$ " + inst.getReminderText(); inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic)); diff --git a/forge-game/src/main/java/forge/game/card/CardPlayOption.java b/forge-game/src/main/java/forge/game/card/CardPlayOption.java index 4ed9c5011a6..ce7c527469d 100644 --- a/forge-game/src/main/java/forge/game/card/CardPlayOption.java +++ b/forge-game/src/main/java/forge/game/card/CardPlayOption.java @@ -23,12 +23,11 @@ public final class CardPlayOption { private final boolean withFlash; private final boolean grantsZonePermissions; private final Cost altManaCost; - private final boolean altIsAdditional; - public CardPlayOption(final Player player, final StaticAbility sta, final boolean withoutManaCost, final Cost altManaCost, final boolean altIsAdditional, final boolean withFlash, final boolean grantZonePermissions) { - this(player, sta, withoutManaCost ? PayManaCost.NO : PayManaCost.YES, altManaCost, altIsAdditional, withFlash, grantZonePermissions); + public CardPlayOption(final Player player, final StaticAbility sta, final boolean withoutManaCost, final Cost altManaCost, final boolean withFlash, final boolean grantZonePermissions) { + this(player, sta, withoutManaCost ? PayManaCost.NO : PayManaCost.YES, altManaCost, withFlash, grantZonePermissions); } - private CardPlayOption(final Player player, final StaticAbility sta, final PayManaCost payManaCost, final Cost altManaCost, final boolean altIsAdditional, final boolean withFlash, + private CardPlayOption(final Player player, final StaticAbility sta, final PayManaCost payManaCost, final Cost altManaCost, final boolean withFlash, final boolean grantZonePermissions) { this.player = player; this.sta = sta; @@ -36,7 +35,6 @@ public final class CardPlayOption { this.withFlash = withFlash; this.grantsZonePermissions = grantZonePermissions; this.altManaCost = altManaCost; - this.altIsAdditional = altIsAdditional; } @@ -102,14 +100,9 @@ public final class CardPlayOption { switch (getPayManaCost()) { case YES: if (altManaCost != null) { - if (altIsAdditional) { - String desc = sta.getParam("Description"); - sb.append(" (").append(desc, desc.indexOf("by "), desc.indexOf(".")); - } else { - String insteadCost = getFormattedAltManaCost(); - insteadCost = insteadCost.replace("Pay ",""); - sb.append(" (by paying ").append(insteadCost).append(" instead of paying its mana cost"); - } + String insteadCost = getFormattedAltManaCost(); + insteadCost = insteadCost.replace("Pay ",""); + sb.append(" (by paying ").append(insteadCost).append(" instead of paying its mana cost"); if (isWithFlash()) { sb.append(" and as though it has flash"); } @@ -120,6 +113,10 @@ public final class CardPlayOption { } else if (isIgnoreManaCostColor()) { sb.append(" (may spend mana as though it were mana of any color to cast it)"); } + if (sta.hasParam("RaiseCost")) { + String desc = sta.getParam("Description"); + sb.append(" (").append(desc, desc.indexOf("by ") + desc.indexOf("pay "), desc.indexOf(".")).append(")"); + } break; case NO: sb.append(" (without paying its mana cost"); diff --git a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java index cf14e3aae89..0925f84ae97 100644 --- a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java +++ b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java @@ -84,15 +84,16 @@ public class CostAdjustment { } } } + if (sa.hasParam("RaiseCost")) { String raise = sa.getParam("RaiseCost"); - ManaCost mc; + Cost inc; if (sa.hasSVar(raise)) { - mc = ManaCost.get(AbilityUtils.calculateAmount(host, raise, sa)); + inc = new Cost(ManaCost.get(AbilityUtils.calculateAmount(host, raise, sa)), false); } else { - mc = new ManaCost(new ManaCostParser(raise)); + inc = new Cost(raise, false); } - result.add(new Cost(mc, false)); + result.add(inc); } // Raise cost diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index 00897a8d025..e857717e6b3 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -938,15 +938,11 @@ public final class StaticAbilityContinuous { if (controllerMayPlay && (mayPlayLimit == null || stAb.getMayPlayTurn() < mayPlayLimit)) { String mayPlayAltCost = mayPlayAltManaCost; - boolean additional = mayPlayAltCost != null && mayPlayAltCost.contains("RegularCost"); if (mayPlayAltCost != null) { if (mayPlayAltCost.contains("ConvertedManaCost")) { final String costcmc = Integer.toString(affectedCard.getCMC()); mayPlayAltCost = mayPlayAltCost.replace("ConvertedManaCost", costcmc); - } else if (additional) { - final String regCost = affectedCard.getManaCost().getShortString(); - mayPlayAltCost = mayPlayAltManaCost.replace("RegularCost", regCost); } } @@ -954,7 +950,7 @@ public final class StaticAbilityContinuous { AbilityUtils.getDefinedPlayers(affectedCard, params.get("MayPlayPlayer"), stAb).get(0) : controller; affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost, - mayPlayAltCost != null ? new Cost(mayPlayAltCost, false, affectedCard.equals(hostCard)) : null, additional, mayPlayWithFlash, + mayPlayAltCost != null ? new Cost(mayPlayAltCost, false, affectedCard.equals(hostCard)) : null, mayPlayWithFlash, mayPlayGrantZonePermissions, stAb); // If the MayPlay effect only affected itself, check if it is in graveyard and give other player who cast Shaman's Trance MayPlay @@ -962,7 +958,7 @@ public final class StaticAbilityContinuous { for (final Player p : game.getPlayers()) { if (p.hasKeyword("Shaman's Trance") && mayPlayController != p) { affectedCard.setMayPlay(p, mayPlayWithoutManaCost, - mayPlayAltCost != null ? new Cost(mayPlayAltCost, false) : null, additional, + mayPlayAltCost != null ? new Cost(mayPlayAltCost, false) : null, mayPlayWithFlash, mayPlayGrantZonePermissions, stAb); } } diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index ae27f7d1e90..29611e18258 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -40,6 +40,7 @@ import forge.game.*; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; +import forge.game.ability.effects.PlayEffect; import forge.game.card.Card; import forge.game.card.CardCopyService; import forge.game.event.EventValueChangeType; @@ -85,7 +86,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable thisTurnCast = Lists.newArrayList(); private List lastTurnCast = Lists.newArrayList(); - private final List abilitiesActivatedThisTurn = Lists.newArrayList(); + private final List thisTurnActivated = Lists.newArrayList(); private Card curResolvingCard = null; private final Map> commandList = Maps.newHashMap(); @@ -493,6 +494,9 @@ public class MagicStack /* extends MyObservable */ implements Iterable sources = new TreeSet<>(); for (SpellAbilityStackInstance s : stack) { if (s.isSpell()) { - distinctSources += 1; + distinctSources++; } else { sources.add(s.getSourceCard().getId()); } @@ -895,11 +899,14 @@ public class MagicStack /* extends MyObservable */ implements Iterable getSpellsCastThisTurn() { return thisTurnCast; } + public final List getSpellsCastLastTurn() { + return lastTurnCast; + } public final void onNextTurn() { final Player active = game.getPhaseHandler().getPlayerTurn(); game.getStackZone().resetCardsAddedThisTurn(); - this.abilitiesActivatedThisTurn.clear(); + this.thisTurnActivated.clear(); if (thisTurnCast.isEmpty()) { lastTurnCast = Lists.newArrayList(); active.resetSpellCastSinceBegOfYourLastTurn(); @@ -914,17 +921,13 @@ public class MagicStack /* extends MyObservable */ implements Iterable getSpellsCastLastTurn() { - return lastTurnCast; - } - public void addAbilityActivatedThisTurn(SpellAbility sa, final Card source) { source.addAbilityActivated(sa); - abilitiesActivatedThisTurn.add(sa.copy(CardCopyService.getLKICopy(source), true)); + thisTurnActivated.add(sa.copy(CardCopyService.getLKICopy(source), true)); } public List getAbilityActivatedThisTurn() { - return abilitiesActivatedThisTurn; + return thisTurnActivated; } public final void addCastCommand(final String valid, final GameCommand c) { diff --git a/forge-gui/res/cardsfolder/f/falco_spara_pactweaver.txt b/forge-gui/res/cardsfolder/f/falco_spara_pactweaver.txt index 66aaeefec92..f2ed573f3e3 100644 --- a/forge-gui/res/cardsfolder/f/falco_spara_pactweaver.txt +++ b/forge-gui/res/cardsfolder/f/falco_spara_pactweaver.txt @@ -6,7 +6,7 @@ K:Flying K:Trample K:etbCounter:SHIELD:1 S:Mode$ Continuous | Affected$ Card.TopLibrary+YouOwn | AffectedZone$ Library | MayLookAt$ You | Description$ You may look at the top card of your library any time. -S:Mode$ Continuous | Affected$ Card.TopLibrary+YouOwn+nonLand | AffectedZone$ Library | MayPlay$ True | MayPlayAltManaCost$ RegularCost RemoveAnyCounter<1/Any/Creature.YouCtrl/a creature you control> | Description$ You may cast spells from the top of your library by removing a counter from a creature you control in addition to paying their other costs. +S:Mode$ Continuous | Affected$ Card.TopLibrary+YouOwn+nonLand | AffectedZone$ Library | MayPlay$ True | RaiseCost$ RemoveAnyCounter<1/Any/Creature.YouCtrl/a creature you control> | Description$ You may cast spells from the top of your library by removing a counter from a creature you control in addition to paying their other costs. DeckHas:Ability$Counters DeckHints:Ability$Counters|Proliferate Oracle:Flying, trample\nFalco Spara, Pactweaver enters the battlefield with a shield counter on it.\nYou may look at the top card of your library any time.\nYou may cast spells from the top of your library by removing a counter from a creature you control in addition to paying their other costs. diff --git a/forge-gui/res/cardsfolder/k/kess_dissident_mage.txt b/forge-gui/res/cardsfolder/k/kess_dissident_mage.txt index fc913e7222d..11c092801fc 100644 --- a/forge-gui/res/cardsfolder/k/kess_dissident_mage.txt +++ b/forge-gui/res/cardsfolder/k/kess_dissident_mage.txt @@ -3,7 +3,5 @@ ManaCost:1 U B R Types:Legendary Creature Human Wizard PT:3/4 K:Flying -S:Mode$ Continuous | Affected$ Instant.YouCtrl,Sorcery.YouCtrl | Condition$ PlayerTurn | MayPlay$ True | MayPlayLimit$ 1 | EffectZone$ Battlefield | AffectedZone$ Graveyard | Description$ During each of your turns, you may cast an instant or sorcery spell from your graveyard. If a spell cast this way would be put into your graveyard, exile it instead. -R:Event$ Moved | ValidLKI$ Card.CastSa Spell.MayPlaySource | Origin$ Stack | Destination$ Graveyard | ReplaceWith$ MoveExile -SVar:MoveExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Stack | Destination$ Exile +S:Mode$ Continuous | Affected$ Instant.YouCtrl,Sorcery.YouCtrl | Condition$ PlayerTurn | ReplaceGraveyard$ Exile | MayPlay$ True | MayPlayLimit$ 1 | EffectZone$ Battlefield | AffectedZone$ Graveyard | Description$ During each of your turns, you may cast an instant or sorcery spell from your graveyard. If a spell cast this way would be put into your graveyard, exile it instead. Oracle:Flying\nDuring each of your turns, you may cast an instant or sorcery spell from your graveyard. If a spell cast this way would be put into your graveyard, exile it instead. diff --git a/forge-gui/res/cardsfolder/m/maestros_ascendancy.txt b/forge-gui/res/cardsfolder/m/maestros_ascendancy.txt index 76b886fb25e..226947c58e6 100644 --- a/forge-gui/res/cardsfolder/m/maestros_ascendancy.txt +++ b/forge-gui/res/cardsfolder/m/maestros_ascendancy.txt @@ -1,7 +1,5 @@ Name:Maestros Ascendancy ManaCost:U B R Types:Enchantment -S:Mode$ Continuous | Affected$ Instant.YouCtrl,Sorcery.YouCtrl | Condition$ PlayerTurn | MayPlay$ True | MayPlayAltManaCost$ RegularCost Sac<1/Creature> | MayPlayLimit$ 1 | EffectZone$ Battlefield | AffectedZone$ Graveyard | Description$ Once during each of your turns, you may cast an instant or sorcery spell from your graveyard by sacrificing a creature in addition to paying its other costs. If a spell cast this way would be put into your graveyard, exile it instead. -R:Event$ Moved | ValidLKI$ Card.CastSa Spell.MayPlaySource | Origin$ Stack | Destination$ Graveyard | ReplaceWith$ MoveExile -SVar:MoveExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Stack | Destination$ Exile +S:Mode$ Continuous | Affected$ Instant.YouCtrl,Sorcery.YouCtrl | Condition$ PlayerTurn | ReplaceGraveyard$ Exile | MayPlay$ True | RaiseCost$ Sac<1/Creature> | MayPlayLimit$ 1 | EffectZone$ Battlefield | AffectedZone$ Graveyard | Description$ Once during each of your turns, you may cast an instant or sorcery spell from your graveyard by sacrificing a creature in addition to paying its other costs. If a spell cast this way would be put into your graveyard, exile it instead. Oracle:Once during each of your turns, you may cast an instant or sorcery spell from your graveyard by sacrificing a creature in addition to paying its other costs. If a spell cast this way would be put into your graveyard, exile it instead. diff --git a/forge-gui/res/cardsfolder/s/shadowborn_apostle.txt b/forge-gui/res/cardsfolder/s/shadowborn_apostle.txt index adef62f4269..1690f32af5d 100644 --- a/forge-gui/res/cardsfolder/s/shadowborn_apostle.txt +++ b/forge-gui/res/cardsfolder/s/shadowborn_apostle.txt @@ -4,7 +4,6 @@ Types:Creature Human Cleric PT:1/1 K:A deck can have any number of cards named CARDNAME. A:AB$ ChangeZone | Cost$ B Sac<6/Creature.namedShadowborn Apostle/creatures named Shadowborn Apostle> | Origin$ Library | Destination$ Battlefield | ChangeType$ Creature.Demon | ChangeNum$ 1 | SpellDescription$ Search your library for a Demon creature card, put it onto the battlefield, then shuffle. -DeckNeeds:Name$Shadowborn Apostle -DeckNeeds:Type$Demon +DeckNeeds:Name$Shadowborn Apostle & Type$Demon DeckHints:Name$Shadowborn Demon Oracle:A deck can have any number of cards named Shadowborn Apostle.\n{B}, Sacrifice six creatures named Shadowborn Apostle: Search your library for a Demon creature card, put it onto the battlefield, then shuffle.