From 2c097cd62c3d176dce79423a3191b765a42fc741 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Wed, 3 Aug 2016 15:42:28 +0000 Subject: [PATCH] Big MayPlay rewrite, now use StaticAbility as Key in the mayPlay Map SpellAbilityRestriction now does check if the spell is still valid when playing. Add Special Logic for Bestow spells there. MayPlay that only allows creature spells, can't be used for Bestow. --- .../src/main/java/forge/ai/AiController.java | 2 +- .../src/main/java/forge/ai/ComputerUtil.java | 4 +-- .../main/java/forge/game/GameActionUtil.java | 2 +- .../main/java/forge/game/StaticEffect.java | 9 +++++- .../main/java/forge/game/StaticEffects.java | 2 +- .../src/main/java/forge/game/card/Card.java | 16 +++++----- .../java/forge/game/card/CardPlayOption.java | 17 +++++++---- .../forge/game/spellability/SpellAbility.java | 9 +++--- .../spellability/SpellAbilityRestriction.java | 30 ++++++++++++++----- .../game/staticability/StaticAbility.java | 6 +++- .../StaticAbilityContinuous.java | 2 +- .../main/java/forge/game/zone/MagicStack.java | 4 +-- .../main/java/forge/game/zone/PlayerZone.java | 11 +++++-- 13 files changed, 75 insertions(+), 39 deletions(-) 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