diff --git a/forge-game/src/main/java/forge/game/ability/effects/DetachedCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DetachedCardEffect.java index 0b8ea7cb666..6b2bdae251d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DetachedCardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DetachedCardEffect.java @@ -15,6 +15,8 @@ public class DetachedCardEffect extends Card { addType("Effect"); setOwner(card0.getOwner()); setImmutable(true); + + setEffectSource(card0); } @Override 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 f50d9446a0e..71075391bf6 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -4024,6 +4024,15 @@ public class Card extends GameEntity implements Comparable { if (!getExiledWith().equals(host)) { return false; } + } else if (property.equals("EffectSource")) { + if (!source.isEmblem() && !source.getType().hasSubtype("Effect")) { + return false; + } + + final Card c = source.getEffectSource(); + if (!equals(c)) { + return false; + } } else if (property.equals("CanBeSacrificedBy")) { if (!canBeSacrificedBy(spellAbility)) { return false; 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 8d09a2c5e67..6e1833da284 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -901,10 +901,13 @@ public class CardFactoryUtil { } if (l[0].startsWith("CommanderCastFromCommandZone")) { - // TODO fix it for multiple commanders // Read SVar CommanderCostRaise from Commander Effect - Card commeff = CardLists.filter(cc.getCardsIn(ZoneType.Command), - CardPredicates.nameEquals("Commander Effect")).get(0); + Card commeff = CardLists.filter(cc.getCardsIn(ZoneType.Command), new Predicate() { + @Override + public boolean apply(Card input) { + return c.equals(input.getEffectSource()) && input.getName().endsWith("Commander Effect"); + } + }).get(0); return doXMath(xCount(commeff, commeff.getSVar("CommanderCostRaise")), "DivideEvenlyDown.2", c); } diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index 620fb66293d..25dbfb0d64d 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -568,7 +568,7 @@ public class CardView extends GameEntityView { } if (isCommander()) { sb.append(getOwner()).append("'s Commander\r\n"); - sb.append(getOwner().getCommanderInfo()).append("\r\n"); + sb.append(getOwner().getCommanderInfo(this)).append("\r\n"); } if (isSplitCard()) { diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 9e7f65724ae..b8d2d982c0d 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -27,7 +27,6 @@ import com.google.common.collect.Maps; import forge.LobbyPlayer; import forge.card.MagicColor; -import forge.card.mana.ManaCost; import forge.game.*; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityUtils; @@ -44,7 +43,6 @@ import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.replacement.ReplacementHandler; import forge.game.replacement.ReplacementResult; -import forge.game.spellability.Ability; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; import forge.game.trigger.Trigger; @@ -1349,11 +1347,6 @@ public class Player extends GameEntity implements Comparable { } view.updateNumDrawnThisTurn(this); - // Miracle draws - if (numDrawnThisTurn == 1 && game.getAge() != GameStage.Mulligan) { - drawMiracle(c); - } - // Run triggers final HashMap runParams = new HashMap(); runParams.put("Card", c); @@ -2773,26 +2766,6 @@ public class Player extends GameEntity implements Comparable { } } - public final void drawMiracle(final Card card) { - // Whenever a card with miracle is the first card drawn in a turn, - // you may cast it for it's miracle cost - if (card.getMiracleCost() == null) { - return; - } - - final SpellAbility playForMiracleCost = card.getFirstSpellAbility().copy(); - playForMiracleCost.setPayCosts(card.getMiracleCost()); - playForMiracleCost.setStackDescription(card.getName() + " - Cast via Miracle"); - - // TODO Convert this to a Trigger - final Ability miracleTrigger = new MiracleTrigger(card, ManaCost.ZERO, playForMiracleCost); - miracleTrigger.setStackDescription(card.getName() + " - Miracle."); - miracleTrigger.setActivatingPlayer(card.getOwner()); - miracleTrigger.setTrigger(true); - - game.getStack().add(miracleTrigger); - } - public boolean isSkippingDraw() { if (hasKeyword("Skip your next draw step.")) { removeKeyword("Skip your next draw step."); @@ -2812,22 +2785,6 @@ public class Player extends GameEntity implements Comparable { inboundTokens.remove(c); } - private final class MiracleTrigger extends Ability { - private final SpellAbility miracle; - - private MiracleTrigger(Card sourceCard0, ManaCost manaCost0, SpellAbility miracle0) { - super(sourceCard0, manaCost0); - miracle = miracle0; - } - - @Override - public void resolve() { - miracle.setActivatingPlayer(getHostCard().getOwner()); - // pay miracle cost here. - getHostCard().getOwner().getController().playMiracle(miracle, getHostCard()); - } - } - public void onMulliganned() { game.fireEvent(new GameEventMulligan(this)); // quest listener may interfere here final int newHand = getCardsIn(ZoneType.Hand).size(); @@ -2936,27 +2893,30 @@ public class Player extends GameEntity implements Comparable { } public static DetachedCardEffect createCommanderEffect(Game game, Card commander) { - DetachedCardEffect eff = new DetachedCardEffect(commander, "Commander Effect"); + final String name = Lang.getPossesive(commander.getName()) + " Commander Effect"; + DetachedCardEffect eff = new DetachedCardEffect(commander, name); eff.setSVar("CommanderMoveReplacement", "DB$ ChangeZone | Origin$ Battlefield,Graveyard,Exile,Library,Hand | Destination$ Command | Defined$ ReplacedCard"); eff.setSVar("DBCommanderIncCast","DB$ StoreSVar | References$ CommanderCostRaise | SVar$ CommanderCostRaise | Type$ CountSVar | Expression$ CommanderCostRaise/Plus.2"); eff.setSVar("CommanderCostRaise","Number$0"); - Trigger t = TriggerHandler.parseTrigger("Mode$ SpellCast | Static$ True | ValidCard$ Card.YouOwn+IsCommander+wasCastFromCommand | References$ CommanderCostRaise | Execute$ DBCommanderIncCast", eff, true); + Trigger t = TriggerHandler.parseTrigger("Mode$ SpellCast | Static$ True | ValidCard$ Card.YouOwn+EffectSource+wasCastFromCommand | References$ CommanderCostRaise | Execute$ DBCommanderIncCast", eff, true); eff.addTrigger(t); - String moved = "Event$ Moved | ValidCard$ Card.IsCommander+YouOwn | Secondary$ True | Optional$ True | OptionalDecider$ You | ReplaceWith$ CommanderMoveReplacement "; + + String moved = "Event$ Moved | ValidCard$ Card.EffectSource+YouOwn | Secondary$ True | Optional$ True | OptionalDecider$ You | ReplaceWith$ CommanderMoveReplacement "; if (game.getRules().hasAppliedVariant(GameType.TinyLeaders)) { moved += " | Destination$ Graveyard,Exile | Description$ If a commander would be put into its owner's graveyard or exile from anywhere, that player may put it into the command zone instead."; } else { moved += " | Destination$ Graveyard,Exile,Hand,Library | Description$ If a commander would be exiled or put into hand, graveyard, or library from anywhere, that player may put it into the command zone instead."; } eff.addReplacementEffect(ReplacementHandler.parseReplacement(moved, eff, true)); - String mayBePlayedAbility = "Mode$ Continuous | EffectZone$ Command | MayPlay$ True | Affected$ Card.YouOwn+IsCommander | AffectedZone$ Command"; + + String mayBePlayedAbility = "Mode$ Continuous | EffectZone$ Command | MayPlay$ True | Affected$ Card.YouOwn+EffectSource | AffectedZone$ Command"; if (game.getRules().hasAppliedVariant(GameType.Planeswalker)) { //support paying for Planeswalker with any color mana mayBePlayedAbility += " | MayPlayIgnoreColor$ True"; } eff.addStaticAbility(mayBePlayedAbility); - eff.addStaticAbility("Mode$ RaiseCost | EffectZone$ Command | References$ CommanderCostRaise | Amount$ CommanderCostRaise | Type$ Spell | ValidCard$ Card.YouOwn+IsCommander+wasCastFromCommand | AffectedZone$ Command,Stack"); + eff.addStaticAbility("Mode$ RaiseCost | EffectZone$ Command | References$ CommanderCostRaise | Amount$ CommanderCostRaise | Type$ Spell | ValidCard$ Card.YouOwn+EffectSource+wasCastFromCommand | AffectedZone$ Command,Stack"); return eff; } diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java index 8818f906a0f..327a5a84302 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -152,7 +152,6 @@ public abstract class PlayerController { /** p = target player, validCards - possible discards, min cards to discard */ public abstract CardCollectionView chooseCardsToDiscardFrom(Player playerDiscard, SpellAbility sa, CardCollection validCards, int min, int max); - public abstract void playMiracle(SpellAbility miracle, Card card); public abstract CardCollectionView chooseCardsToDelve(int genericAmount, CardCollection grave); public abstract CardCollectionView chooseCardsToRevealFromHand(int min, int max, CardCollectionView valid); public abstract CardCollectionView chooseCardsToDiscardUnlessType(int min, CardCollectionView hand, String param, SpellAbility sa); diff --git a/forge-game/src/main/java/forge/game/player/PlayerView.java b/forge-game/src/main/java/forge/game/player/PlayerView.java index 2db4f603deb..71ae2bc12a8 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerView.java +++ b/forge-game/src/main/java/forge/game/player/PlayerView.java @@ -96,9 +96,8 @@ public class PlayerView extends GameEntityView { return opponents != null && opponents.contains(other); } - public final String getCommanderInfo() { - final List commanders = getCommanders(); - if (commanders == null || commanders.isEmpty()) { + public final String getCommanderInfo(CardView v) { + if (v == null) { return StringUtils.EMPTY; } @@ -108,12 +107,10 @@ public class PlayerView extends GameEntityView { opponents = Collections.emptyList(); } for (final PlayerView p : Iterables.concat(Collections.singleton(this), opponents)) { - for (final CardView v : this.getCommanders()) { - final int damage = p.getCommanderDamage(v); - if (damage > 0) { - final String text = String.format("Commander damage to %s from %s:", p, v.getName()); - sb.append(String.format(text + " %d\r\n", damage)); - } + final int damage = p.getCommanderDamage(v); + if (damage > 0) { + final String text = String.format("Commander damage to %s from %s:", p, v.getName()); + sb.append(String.format(text + " %d\r\n", damage)); } } return sb.toString();