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.
This commit is contained in:
Hanmac
2016-08-03 15:42:28 +00:00
parent 90debcf4ad
commit 2c097cd62c
13 changed files with 75 additions and 39 deletions

View File

@@ -884,7 +884,7 @@ public class AiController {
} }
// move snap-casted spells to front // move snap-casted spells to front
if (source.isInZone(ZoneType.Graveyard)) { 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; p += 50;
} }
} }

View File

@@ -1516,10 +1516,10 @@ public class ComputerUtil {
ComputerUtilCombat.combatantWouldBeDestroyed(ai, source, game.getCombat())) { ComputerUtilCombat.combatantWouldBeDestroyed(ai, source, game.getCombat())) {
return true; 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 // play cards in exile that can only be played that turn
if (game.getPhaseHandler().getPhase() == PhaseType.MAIN2) { if (game.getPhaseHandler().getPhase() == PhaseType.MAIN2) {
if (source.mayPlay(sa.getMayPlayHost()) != null) { if (source.mayPlay(sa.getMayPlay()) != null) {
return true; return true;
} }
} }

View File

@@ -191,7 +191,7 @@ public final class GameActionUtil {
} }
sar.setZone(null); sar.setZone(null);
newSA.setRestrictions(sar); newSA.setRestrictions(sar);
newSA.setMayPlayHost(host); newSA.setMayPlay(o.getAbility());
if (o.getPayManaCost() == PayManaCost.NO) { if (o.getPayManaCost() == PayManaCost.NO) {
newSA.setBasicSpell(false); newSA.setBasicSpell(false);
newSA.setPayCosts(newSA.getPayCosts().copyWithNoMana()); newSA.setPayCosts(newSA.getPayCosts().copyWithNoMana());

View File

@@ -46,6 +46,7 @@ import com.google.common.collect.Maps;
public class StaticEffect { public class StaticEffect {
private final Card source; private final Card source;
private StaticAbility ability;
private int keywordNumber = 0; private int keywordNumber = 0;
private CardCollectionView affectedCards = new CardCollection(); private CardCollectionView affectedCards = new CardCollection();
private List<Player> affectedPlayers = Lists.newArrayList(); private List<Player> affectedPlayers = Lists.newArrayList();
@@ -83,8 +84,14 @@ public class StaticEffect {
this.source = source; this.source = source;
} }
StaticEffect(final StaticAbility ability) {
this(ability.getHostCard());
this.ability = ability;
}
private StaticEffect makeMappedCopy(GameObjectMap map) { private StaticEffect makeMappedCopy(GameObjectMap map) {
StaticEffect copy = new StaticEffect(map.map(this.source)); StaticEffect copy = new StaticEffect(map.map(this.source));
copy.ability = this.ability;
copy.keywordNumber = this.keywordNumber; copy.keywordNumber = this.keywordNumber;
copy.affectedCards = map.mapCollection(this.affectedCards); copy.affectedCards = map.mapCollection(this.affectedCards);
copy.affectedPlayers = map.mapList(this.affectedPlayers); copy.affectedPlayers = map.mapList(this.affectedPlayers);
@@ -1046,7 +1053,7 @@ public class StaticEffect {
affectedCard.setMayLookAt(controller, false); affectedCard.setMayLookAt(controller, false);
} }
if (removeMayPlay) { if (removeMayPlay) {
affectedCard.removeMayPlay(source); affectedCard.removeMayPlay(ability);
} }
affectedCard.updateStateForView(); affectedCard.updateStateForView();
} }

View File

@@ -72,7 +72,7 @@ public class StaticEffects {
return currentEffect; return currentEffect;
} }
final StaticEffect newEffect = new StaticEffect(staticAbility.getHostCard()); final StaticEffect newEffect = new StaticEffect(staticAbility);
this.staticEffects.put(staticAbility, newEffect); this.staticEffects.put(staticAbility, newEffect);
return newEffect; return newEffect;
} }

View File

@@ -110,7 +110,7 @@ public class Card extends GameEntity implements Comparable<Card> {
private GameEntity enchanting = null; private GameEntity enchanting = null;
private GameEntity mustAttackEntity = null; private GameEntity mustAttackEntity = null;
private final Map<Card, CardPlayOption> mayPlay = Maps.newTreeMap(); private final Map<StaticAbility, CardPlayOption> mayPlay = Maps.newTreeMap();
private int mayPlayTurn = 0; private int mayPlayTurn = 0;
// changes by AF animate and continuous static effects - timestamp is the key of maps // 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<Card> {
view.setPlayerMayLook(player, mayLookAt, temp); view.setPlayerMayLook(player, mayLookAt, temp);
} }
public final CardPlayOption mayPlay(final Card host) { public final CardPlayOption mayPlay(final StaticAbility sta) {
if (host == null) { if (sta == null) {
return null; return null;
} }
return mayPlay.get(host); return mayPlay.get(sta);
} }
public final List<CardPlayOption> mayPlay(final Player player) { public final List<CardPlayOption> mayPlay(final Player player) {
List<CardPlayOption> result = Lists.newArrayList(); List<CardPlayOption> result = Lists.newArrayList();
@@ -2286,11 +2286,11 @@ public class Card extends GameEntity implements Comparable<Card> {
} }
return result; return result;
} }
public final void setMayPlay(final Player player, final boolean withoutManaCost, final boolean ignoreColor, final boolean withFlash, final Card host) { public final void setMayPlay(final Player player, final boolean withoutManaCost, final boolean ignoreColor, final boolean withFlash, final StaticAbility sta) {
this.mayPlay.put(host, new CardPlayOption(player, host, withoutManaCost, ignoreColor, withFlash)); this.mayPlay.put(sta, new CardPlayOption(player, sta, withoutManaCost, ignoreColor, withFlash));
} }
public final void removeMayPlay(final Card host) { public final void removeMayPlay(final StaticAbility sta) {
this.mayPlay.remove(host); this.mayPlay.remove(sta);
} }
public int getMayPlayTurn() { public int getMayPlayTurn() {

View File

@@ -3,6 +3,7 @@ package forge.game.card;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.staticability.StaticAbility;
public final class CardPlayOption { public final class CardPlayOption {
public enum PayManaCost { public enum PayManaCost {
@@ -13,17 +14,17 @@ public final class CardPlayOption {
} }
private final Player player; private final Player player;
private final Card host; private final StaticAbility sta;
private final PayManaCost payManaCost; private final PayManaCost payManaCost;
private final boolean ignoreManaCostColor; private final boolean ignoreManaCostColor;
private final boolean withFlash; private final boolean withFlash;
public CardPlayOption(final Player player, final Card host, final boolean withoutManaCost, final boolean ignoreManaCostColor, final boolean withFlash) { public CardPlayOption(final Player player, final StaticAbility sta, final boolean withoutManaCost, final boolean ignoreManaCostColor, final boolean withFlash) {
this(player, host, withoutManaCost ? PayManaCost.NO : PayManaCost.YES, ignoreManaCostColor, 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.player = player;
this.host = host; this.sta = sta;
this.payManaCost = payManaCost; this.payManaCost = payManaCost;
this.ignoreManaCostColor = ignoreManaCostColor; this.ignoreManaCostColor = ignoreManaCostColor;
this.withFlash = withFlash; this.withFlash = withFlash;
@@ -35,7 +36,11 @@ public final class CardPlayOption {
} }
public Card getHost() { public Card getHost() {
return host; return sta.getHostCard();
}
public StaticAbility getAbility() {
return sta;
} }
public PayManaCost getPayManaCost() { public PayManaCost getPayManaCost() {

View File

@@ -36,6 +36,7 @@ import forge.game.cost.CostPart;
import forge.game.cost.CostPartMana; import forge.game.cost.CostPartMana;
import forge.game.mana.Mana; import forge.game.mana.Mana;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.game.trigger.WrappedAbility; import forge.game.trigger.WrappedAbility;
import forge.util.Expressions; import forge.util.Expressions;
@@ -141,7 +142,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private SpellAbilityView view; private SpellAbilityView view;
private Card mayPlay = null; private StaticAbility mayPlay = null;
protected SpellAbility(final Card iSourceCard, final Cost toPay) { protected SpellAbility(final Card iSourceCard, final Cost toPay) {
this(iSourceCard, toPay, null); this(iSourceCard, toPay, null);
@@ -584,11 +585,11 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
outlast = outlast0; outlast = outlast0;
} }
public Card getMayPlayHost() { public StaticAbility getMayPlay() {
return mayPlay; return mayPlay;
} }
public void setMayPlayHost(final Card host) { public void setMayPlay(final StaticAbility sta) {
mayPlay = host; mayPlay = sta;
} }
public boolean isLeftSplit() { public boolean isLeftSplit() {

View File

@@ -28,6 +28,7 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil; import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPlayOption; import forge.game.card.CardPlayOption;
import forge.game.card.CardUtil;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.Zone; import forge.game.zone.Zone;
@@ -201,26 +202,39 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
* @return a boolean. * @return a boolean.
*/ */
public final boolean checkZoneRestrictions(final Card c, final SpellAbility sa) { public final boolean checkZoneRestrictions(final Card c, final SpellAbility sa) {
if (this.getZone() == null) {
return true;
}
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final Zone cardZone = activator.getGame().getZoneOf(c); 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 // If Card is not in the default activating zone, do some additional checks
// Not a Spell, or on Battlefield, return false // Not a Spell, or on Battlefield, return false
if (!sa.isSpell() || (cardZone != null && ZoneType.Battlefield.equals(cardZone.getZoneType())) 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; return false;
} }
if (cardZone != null && cardZone.is(ZoneType.Stack)) { if (cardZone != null && cardZone.is(ZoneType.Stack)) {
return false; return false;
} }
if (sa.isSpell()) { if (sa.isSpell()) {
final CardPlayOption o = c.mayPlay(sa.getMayPlayHost()); final CardPlayOption o = c.mayPlay(sa.getMayPlay());
if (o != null && o.getPlayer() == activator) { if (o != null && o.getPlayer() == activator) {
return true; Map<String,String> params = sa.getMayPlay().getMapParams();
if (params.containsKey("Affected")) {
if (!cp.isValid(params.get("Affected"), activator, o.getHost(), null)) {
return false;
}
}
return true;
} }
} }
return false; return false;
@@ -301,7 +315,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
} }
if (sa.isSpell()) { if (sa.isSpell()) {
final CardPlayOption o = c.mayPlay(sa.getMayPlayHost()); final CardPlayOption o = c.mayPlay(sa.getMayPlay());
if (o != null && o.getPlayer() == activator) { if (o != null && o.getPlayer() == activator) {
return true; return true;
} }

View File

@@ -42,7 +42,7 @@ import com.google.common.collect.Maps;
/** /**
* The Class StaticAbility. * The Class StaticAbility.
*/ */
public class StaticAbility extends CardTraitBase { public class StaticAbility extends CardTraitBase implements Comparable<StaticAbility> {
private final Set<StaticAbilityLayer> layers; private final Set<StaticAbilityLayer> layers;
private CardCollectionView ignoreEffectCards = new CardCollection(); private CardCollectionView ignoreEffectCards = new CardCollection();
@@ -620,4 +620,8 @@ public class StaticAbility extends CardTraitBase {
return layers; return layers;
} }
@Override
public int compareTo(StaticAbility arg0) {
return getHostCard().compareTo(arg0.getHostCard());
}
} // end class StaticAbility } // end class StaticAbility

View File

@@ -617,7 +617,7 @@ public final class StaticAbilityContinuous {
} }
if (controllerMayPlay && (mayPlayLimit == null || hostCard.getMayPlayTurn() < mayPlayLimit)) { if (controllerMayPlay && (mayPlayLimit == null || hostCard.getMayPlayTurn() < mayPlayLimit)) {
Player mayPlayController = params.containsKey("MayPlayCardOwner") ? affectedCard.getOwner() : controller; Player mayPlayController = params.containsKey("MayPlayCardOwner") ? affectedCard.getOwner() : controller;
affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost, mayPlayIgnoreColor, mayPlayWithFlash, hostCard); affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost, mayPlayIgnoreColor, mayPlayWithFlash, stAb);
} }
affectedCard.updateStateForView(); affectedCard.updateStateForView();

View File

@@ -451,8 +451,8 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
System.out.println(sp.getHostCard().getName() + " - activatingPlayer not set before adding to stack."); System.out.println(sp.getHostCard().getName() + " - activatingPlayer not set before adding to stack.");
} }
if (sp.isSpell() && sp.getMayPlayHost() != null) { if (sp.isSpell() && sp.getMayPlay() != null) {
sp.getMayPlayHost().incMayPlayTurn(); sp.getMayPlay().getHostCard().incMayPlayTurn();
} }
final SpellAbilityStackInstance si = new SpellAbilityStackInstance(sp); final SpellAbilityStackInstance si = new SpellAbilityStackInstance(sp);

View File

@@ -63,13 +63,18 @@ public class PlayerZone extends Zone {
for (final SpellAbility sa : c.getSpellAbilities()) { for (final SpellAbility sa : c.getSpellAbilities()) {
final ZoneType restrictZone = sa.getRestrictions().getZone(); final ZoneType restrictZone = sa.getRestrictions().getZone();
// for mayPlay the restrictZone is null for reasons
if (sa.isSpell() && c.mayPlay(sa.getMayPlay()) != null) {
return true;
}
if (PlayerZone.this.is(restrictZone)) { if (PlayerZone.this.is(restrictZone)) {
return true; return true;
} }
if (sa.isSpell() if (sa.isSpell()
&& (c.mayPlay(sa.getMayPlayHost()) != null && (c.hasStartOfKeyword("Flashback") && PlayerZone.this.is(ZoneType.Graveyard))
|| (c.hasStartOfKeyword("Flashback") && PlayerZone.this.is(ZoneType.Graveyard)))
&& restrictZone.equals(ZoneType.Hand)) { && restrictZone.equals(ZoneType.Hand)) {
return true; return true;
} }