diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index e3e2130e05f..bb630f23d2a 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -884,7 +884,7 @@ public class AiController { } // move snap-casted spells to front if (source.isInZone(ZoneType.Graveyard)) { - if(sa.getMayPlayHost() != null && source.mayPlay(sa.getMayPlayHost()) != null) { + if(sa.getMayPlay() != null && source.mayPlay(sa.getMayPlay()) != null) { p += 50; } } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 77d14d0f995..6b9e91834f1 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -1516,10 +1516,10 @@ public class ComputerUtil { ComputerUtilCombat.combatantWouldBeDestroyed(ai, source, game.getCombat())) { return true; } - } else if (zone.getZoneType() == ZoneType.Exile && sa.getMayPlayHost() != null) { + } else if (zone.getZoneType() == ZoneType.Exile && sa.getMayPlay() != null) { // play cards in exile that can only be played that turn if (game.getPhaseHandler().getPhase() == PhaseType.MAIN2) { - if (source.mayPlay(sa.getMayPlayHost()) != null) { + if (source.mayPlay(sa.getMayPlay()) != null) { return true; } } diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 54e7088d682..ce052181a2f 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -191,7 +191,7 @@ public final class GameActionUtil { } sar.setZone(null); newSA.setRestrictions(sar); - newSA.setMayPlayHost(host); + newSA.setMayPlay(o.getAbility()); if (o.getPayManaCost() == PayManaCost.NO) { newSA.setBasicSpell(false); newSA.setPayCosts(newSA.getPayCosts().copyWithNoMana()); diff --git a/forge-game/src/main/java/forge/game/StaticEffect.java b/forge-game/src/main/java/forge/game/StaticEffect.java index a8c6adb7910..cd7c7c153a7 100644 --- a/forge-game/src/main/java/forge/game/StaticEffect.java +++ b/forge-game/src/main/java/forge/game/StaticEffect.java @@ -46,6 +46,7 @@ import com.google.common.collect.Maps; public class StaticEffect { private final Card source; + private StaticAbility ability; private int keywordNumber = 0; private CardCollectionView affectedCards = new CardCollection(); private List affectedPlayers = Lists.newArrayList(); @@ -83,8 +84,14 @@ public class StaticEffect { this.source = source; } + StaticEffect(final StaticAbility ability) { + this(ability.getHostCard()); + this.ability = ability; + } + private StaticEffect makeMappedCopy(GameObjectMap map) { StaticEffect copy = new StaticEffect(map.map(this.source)); + copy.ability = this.ability; copy.keywordNumber = this.keywordNumber; copy.affectedCards = map.mapCollection(this.affectedCards); copy.affectedPlayers = map.mapList(this.affectedPlayers); @@ -1046,7 +1053,7 @@ public class StaticEffect { affectedCard.setMayLookAt(controller, false); } if (removeMayPlay) { - affectedCard.removeMayPlay(source); + affectedCard.removeMayPlay(ability); } affectedCard.updateStateForView(); } diff --git a/forge-game/src/main/java/forge/game/StaticEffects.java b/forge-game/src/main/java/forge/game/StaticEffects.java index dbd81d91e15..96064e5f4a6 100644 --- a/forge-game/src/main/java/forge/game/StaticEffects.java +++ b/forge-game/src/main/java/forge/game/StaticEffects.java @@ -72,7 +72,7 @@ public class StaticEffects { return currentEffect; } - final StaticEffect newEffect = new StaticEffect(staticAbility.getHostCard()); + final StaticEffect newEffect = new StaticEffect(staticAbility); this.staticEffects.put(staticAbility, newEffect); return newEffect; } 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 32ad86a355b..08285377ebe 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -110,7 +110,7 @@ public class Card extends GameEntity implements Comparable { private GameEntity enchanting = null; private GameEntity mustAttackEntity = null; - private final Map mayPlay = Maps.newTreeMap(); + private final Map mayPlay = Maps.newTreeMap(); private int mayPlayTurn = 0; // changes by AF animate and continuous static effects - timestamp is the key of maps @@ -2271,11 +2271,11 @@ public class Card extends GameEntity implements Comparable { view.setPlayerMayLook(player, mayLookAt, temp); } - public final CardPlayOption mayPlay(final Card host) { - if (host == null) { + public final CardPlayOption mayPlay(final StaticAbility sta) { + if (sta == null) { return null; } - return mayPlay.get(host); + return mayPlay.get(sta); } public final List mayPlay(final Player player) { List result = Lists.newArrayList(); @@ -2286,11 +2286,11 @@ public class Card extends GameEntity implements Comparable { } return result; } - public final void setMayPlay(final Player player, final boolean withoutManaCost, final boolean ignoreColor, final boolean withFlash, final Card host) { - this.mayPlay.put(host, new CardPlayOption(player, host, withoutManaCost, ignoreColor, withFlash)); + public final void setMayPlay(final Player player, final boolean withoutManaCost, final boolean ignoreColor, final boolean withFlash, final StaticAbility sta) { + this.mayPlay.put(sta, new CardPlayOption(player, sta, withoutManaCost, ignoreColor, withFlash)); } - public final void removeMayPlay(final Card host) { - this.mayPlay.remove(host); + public final void removeMayPlay(final StaticAbility sta) { + this.mayPlay.remove(sta); } public int getMayPlayTurn() { 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 d7e03aaf4a1..597c7c77aaa 100644 --- a/forge-game/src/main/java/forge/game/card/CardPlayOption.java +++ b/forge-game/src/main/java/forge/game/card/CardPlayOption.java @@ -3,6 +3,7 @@ package forge.game.card; import org.apache.commons.lang3.StringUtils; import forge.game.player.Player; +import forge.game.staticability.StaticAbility; public final class CardPlayOption { public enum PayManaCost { @@ -13,17 +14,17 @@ public final class CardPlayOption { } private final Player player; - private final Card host; + private final StaticAbility sta; private final PayManaCost payManaCost; private final boolean ignoreManaCostColor; private final boolean withFlash; - public CardPlayOption(final Player player, final Card host, final boolean withoutManaCost, final boolean ignoreManaCostColor, final boolean withFlash) { - this(player, host, withoutManaCost ? PayManaCost.NO : PayManaCost.YES, ignoreManaCostColor, withFlash); + public CardPlayOption(final Player player, final StaticAbility sta, final boolean withoutManaCost, final boolean ignoreManaCostColor, final boolean withFlash) { + this(player, sta, withoutManaCost ? PayManaCost.NO : PayManaCost.YES, ignoreManaCostColor, withFlash); } - private CardPlayOption(final Player player, final Card host, final PayManaCost payManaCost, final boolean ignoreManaCostColor, final boolean withFlash) { + private CardPlayOption(final Player player, final StaticAbility sta, final PayManaCost payManaCost, final boolean ignoreManaCostColor, final boolean withFlash) { this.player = player; - this.host = host; + this.sta = sta; this.payManaCost = payManaCost; this.ignoreManaCostColor = ignoreManaCostColor; this.withFlash = withFlash; @@ -35,7 +36,11 @@ public final class CardPlayOption { } public Card getHost() { - return host; + return sta.getHostCard(); + } + + public StaticAbility getAbility() { + return sta; } public PayManaCost getPayManaCost() { 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 671c5901046..db9f035477e 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -36,6 +36,7 @@ import forge.game.cost.CostPart; import forge.game.cost.CostPartMana; import forge.game.mana.Mana; import forge.game.player.Player; +import forge.game.staticability.StaticAbility; import forge.game.trigger.TriggerType; import forge.game.trigger.WrappedAbility; import forge.util.Expressions; @@ -141,7 +142,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit private SpellAbilityView view; - private Card mayPlay = null; + private StaticAbility mayPlay = null; protected SpellAbility(final Card iSourceCard, final Cost toPay) { this(iSourceCard, toPay, null); @@ -584,11 +585,11 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit outlast = outlast0; } - public Card getMayPlayHost() { + public StaticAbility getMayPlay() { return mayPlay; } - public void setMayPlayHost(final Card host) { - mayPlay = host; + public void setMayPlay(final StaticAbility sta) { + mayPlay = sta; } public boolean isLeftSplit() { 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 9ed753fc3ab..c8d4f609bf8 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java @@ -28,6 +28,7 @@ import forge.game.card.CardCollectionView; import forge.game.card.CardFactoryUtil; import forge.game.card.CardLists; import forge.game.card.CardPlayOption; +import forge.game.card.CardUtil; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.zone.Zone; @@ -201,26 +202,39 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { * @return a boolean. */ public final boolean checkZoneRestrictions(final Card c, final SpellAbility sa) { - if (this.getZone() == null) { - return true; - } final Player activator = sa.getActivatingPlayer(); final Zone cardZone = activator.getGame().getZoneOf(c); - if (cardZone == null || !cardZone.is(this.getZone())) { + Card cp = c; + + // for Bestow need to check the animated State + if (sa.isSpell() && sa.hasParam("Bestow")) { + cp = CardUtil.getLKICopy(c); + cp.animateBestow(); + } + + if (cardZone == null || this.getZone() == null || !cardZone.is(this.getZone())) { // If Card is not in the default activating zone, do some additional checks // Not a Spell, or on Battlefield, return false if (!sa.isSpell() || (cardZone != null && ZoneType.Battlefield.equals(cardZone.getZoneType())) - || !this.getZone().equals(ZoneType.Hand)) { + || (this.getZone() != null && !this.getZone().equals(ZoneType.Hand))) { return false; } if (cardZone != null && cardZone.is(ZoneType.Stack)) { return false; } if (sa.isSpell()) { - final CardPlayOption o = c.mayPlay(sa.getMayPlayHost()); + final CardPlayOption o = c.mayPlay(sa.getMayPlay()); if (o != null && o.getPlayer() == activator) { - return true; + Map params = sa.getMayPlay().getMapParams(); + + if (params.containsKey("Affected")) { + if (!cp.isValid(params.get("Affected"), activator, o.getHost(), null)) { + return false; + } + } + + return true; } } return false; @@ -301,7 +315,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { } if (sa.isSpell()) { - final CardPlayOption o = c.mayPlay(sa.getMayPlayHost()); + final CardPlayOption o = c.mayPlay(sa.getMayPlay()); if (o != null && o.getPlayer() == activator) { return true; } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index 4e41b471473..02e479ed3ca 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -42,7 +42,7 @@ import com.google.common.collect.Maps; /** * The Class StaticAbility. */ -public class StaticAbility extends CardTraitBase { +public class StaticAbility extends CardTraitBase implements Comparable { private final Set layers; private CardCollectionView ignoreEffectCards = new CardCollection(); @@ -620,4 +620,8 @@ public class StaticAbility extends CardTraitBase { return layers; } + @Override + public int compareTo(StaticAbility arg0) { + return getHostCard().compareTo(arg0.getHostCard()); + } } // end class StaticAbility 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 55296c2d2f4..4eb319a6355 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -617,7 +617,7 @@ public final class StaticAbilityContinuous { } if (controllerMayPlay && (mayPlayLimit == null || hostCard.getMayPlayTurn() < mayPlayLimit)) { Player mayPlayController = params.containsKey("MayPlayCardOwner") ? affectedCard.getOwner() : controller; - affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost, mayPlayIgnoreColor, mayPlayWithFlash, hostCard); + affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost, mayPlayIgnoreColor, mayPlayWithFlash, stAb); } affectedCard.updateStateForView(); 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 5af7054e097..8fb41f70706 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -451,8 +451,8 @@ public class MagicStack /* extends MyObservable */ implements Iterable