diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index cc40e8af4cb..dd770ff3edf 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -1077,7 +1077,7 @@ public class ComputerUtil { playNow = false; break; } - if (!playNow && c.isCreature() && ComputerUtilCombat.canAttackNextTurn(c) && c.canBeAttached(card)) { + if (!playNow && c.isCreature() && ComputerUtilCombat.canAttackNextTurn(c) && c.canBeAttached(card, null)) { playNow = true; } } diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java index 29557f0ddb5..4b0a7f0274a 100644 --- a/forge-ai/src/main/java/forge/ai/GameState.java +++ b/forge-ai/src/main/java/forge/ai/GameState.java @@ -1135,7 +1135,7 @@ public abstract class GameState { Card attachedTo = idToCard.get(entry.getValue()); Card attacher = entry.getKey(); if (attacher.isAttachment()) { - attacher.attachToEntity(attachedTo); + attacher.attachToEntity(attachedTo, null, true); } } @@ -1146,7 +1146,7 @@ public abstract class GameState { Game game = attacher.getGame(); Player attachedTo = entry.getValue() == TARGET_AI ? game.getPlayers().get(1) : game.getPlayers().get(0); - attacher.attachToEntity(attachedTo); + attacher.attachToEntity(attachedTo, null); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java index dd2868cb976..d1947a73875 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java @@ -618,7 +618,7 @@ public class AttachAi extends SpellAbilityAi { CardCollection preList = new CardCollection(lki); preList.add(attachSourceLki); c.getGame().getAction().checkStaticAbilities(false, Sets.newHashSet(preList), preList); - boolean result = lki.canBeAttached(attachSourceLki); + boolean result = lki.canBeAttached(attachSourceLki, null); //reset static abilities c.getGame().getAction().checkStaticAbilities(false); @@ -1354,7 +1354,7 @@ public class AttachAi extends SpellAbilityAi { if (tgt == null) { list = AbilityUtils.getDefinedCards(attachSource, sa.getParam("Defined"), sa); } else { - list = CardLists.filter(CardUtil.getValidCardsToTarget(tgt, sa), CardPredicates.canBeAttached(attachSource)); + list = CardLists.filter(CardUtil.getValidCardsToTarget(tgt, sa), CardPredicates.canBeAttached(attachSource, sa)); } if (list.isEmpty()) { @@ -1627,7 +1627,6 @@ public class AttachAi extends SpellAbilityAi { * @return true, if is useful keyword */ private static boolean isUsefulCurseKeyword(final String keyword, final Card card, final SpellAbility sa) { - final Player ai = sa.getActivatingPlayer(); if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/ZoneExchangeAi.java b/forge-ai/src/main/java/forge/ai/ability/ZoneExchangeAi.java index fe9fff071d5..ff061ff580a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ZoneExchangeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ZoneExchangeAi.java @@ -39,7 +39,7 @@ public class ZoneExchangeAi extends SpellAbilityAi { } if (type.equals("Aura")) { Card c = object1.getEnchantingCard(); - if (!c.canBeAttached(object2)) { + if (!c.canBeAttached(object2, sa)) { return false; } } diff --git a/forge-game/src/main/java/forge/game/ForgeScript.java b/forge-game/src/main/java/forge/game/ForgeScript.java index cab22a401f8..78b978e0ec4 100644 --- a/forge-game/src/main/java/forge/game/ForgeScript.java +++ b/forge-game/src/main/java/forge/game/ForgeScript.java @@ -178,7 +178,7 @@ public class ForgeScript { } else if (property.equals("Modular")) { return sa.hasParam("Modular"); } else if (property.equals("Equip")) { - return sa.hasParam("Equip"); + return sa.isEquip(); } else if (property.equals("Boast")) { return sa.isBoast(); } else if (property.equals("Mutate")) { diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index d20e1db967e..8e2d3918f45 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -162,13 +162,13 @@ public class GameAction { // need to check before it enters if (c.isAura() && !c.isAttachedToEntity() && toBattlefield && (zoneFrom == null || !zoneFrom.is(ZoneType.Stack))) { boolean found = false; - if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(c))) { + if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(c, null))) { found = true; } - else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(c))) { + else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(c, null))) { found = true; } - else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(c))) { + else if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(c, null))) { found = true; } if (!found) { @@ -398,13 +398,13 @@ public class GameAction { if (copied.isAura() && !copied.isAttachedToEntity() && toBattlefield) { if (zoneFrom != null && zoneFrom.is(ZoneType.Stack) && game.getStack().isResolving(c)) { boolean found = false; - if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(copied))) { + if (Iterables.any(game.getPlayers(), PlayerPredicates.canBeAttached(copied, null))) { found = true; } - if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(copied))) { + if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateBattlefield), CardPredicates.canBeAttached(copied, null))) { found = true; } - if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(copied))) { + if (Iterables.any((CardCollectionView) params.get(AbilityKey.LastStateGraveyard), CardPredicates.canBeAttached(copied, null))) { found = true; } if (!found) { @@ -1515,7 +1515,7 @@ public class GameAction { if (c.isAttachedToEntity()) { final GameEntity ge = c.getEntityAttachedTo(); - if (!ge.canBeAttached(c, true)) { + if (!ge.canBeAttached(c, null, true)) { unAttachList.add(c); checkAgain = true; } @@ -2381,7 +2381,7 @@ public class GameAction { final Player pa = p.getController().chooseSingleEntityForEffect(players, aura, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", CardTranslation.getTranslatedName(source.getName())), null); if (pa != null) { - source.attachToEntity(pa); + source.attachToEntity(pa, null); return true; } } else { @@ -2408,7 +2408,7 @@ public class GameAction { final Card o = p.getController().chooseSingleEntityForEffect(list, aura, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(source.getName())), null); if (o != null) { - source.attachToEntity(game.getCardState(o), true); + source.attachToEntity(game.getCardState(o), null, true); 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 7bdb0ff4497..3f563ff302a 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -341,7 +341,7 @@ public final class GameActionUtil { alternatives.add(newSA); } } - if (sa.hasParam("Equip") && activator.hasKeyword("You may pay 0 rather than pay equip costs.")) { + if (sa.isEquip() && activator.hasKeyword("You may pay 0 rather than pay equip costs.")) { for (final KeywordInterface inst : source.getKeywords()) { // need to find the correct Keyword from which this Ability is from if (!inst.getAbilities().contains(sa)) { diff --git a/forge-game/src/main/java/forge/game/GameEntity.java b/forge-game/src/main/java/forge/game/GameEntity.java index 6e9d7c48156..531bc6e6ecf 100644 --- a/forge-game/src/main/java/forge/game/GameEntity.java +++ b/forge-game/src/main/java/forge/game/GameEntity.java @@ -212,10 +212,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { } } - public boolean canBeAttached(final Card attach) { - return canBeAttached(attach, false); + public boolean canBeAttached(final Card attach, SpellAbility sa) { + return canBeAttached(attach, sa, false); } - public boolean canBeAttached(final Card attach, boolean checkSBA) { + public boolean canBeAttached(final Card attach, SpellAbility sa, boolean checkSBA) { // master mode if (!attach.isAttachment() || (attach.isCreature() && !attach.hasKeyword(Keyword.RECONFIGURE)) || equals(attach)) { @@ -226,7 +226,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { if (attach.isAura() && !canBeEnchantedBy(attach)) { return false; } - if (attach.isEquipment() && !canBeEquippedBy(attach)) { + if (attach.isEquipment() && !canBeEquippedBy(attach, sa)) { return false; } if (attach.isFortification() && !canBeFortifiedBy(attach)) { @@ -242,7 +242,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { return true; } - protected boolean canBeEquippedBy(final Card aura) { + protected boolean canBeEquippedBy(final Card aura, SpellAbility sa) { /** * Equip only to Creatures which are cards */ diff --git a/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java index 096476127dc..566ad27c37a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java @@ -84,7 +84,7 @@ public class AttachEffect extends SpellAbilityEffect { choices = AbilityUtils.getDefinedEntities(source, sa.getParam("PlayerChoices"), sa); for (final Card attachment : attachments) { for (GameEntity g : choices) { - if (!g.canBeAttached(attachment)) { + if (!g.canBeAttached(attachment, sa)) { choices.remove(g); } } @@ -100,7 +100,7 @@ public class AttachEffect extends SpellAbilityEffect { if (e != null) cardChoices.remove(e); } - cardChoices = CardLists.filter(cardChoices, CardPredicates.canBeAttached(attachment)); + cardChoices = CardLists.filter(cardChoices, CardPredicates.canBeAttached(attachment, sa)); } choices.addAll(cardChoices); } @@ -138,7 +138,7 @@ public class AttachEffect extends SpellAbilityEffect { // TODO add params for message continue; - attachment.attachToEntity(attachTo); + attachment.attachToEntity(attachTo, sa); if (sa.hasParam("RememberAttached") && attachment.isAttachedToEntity(attachTo)) { source.addRemembered(attachment); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 0f4c82e7f47..0319d92273c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -615,7 +615,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { // only valid choices are when they could be attached // TODO for multiple Auras entering attached this way, need to use LKI info if (!list.isEmpty()) { - list = CardLists.filter(list, CardPredicates.canBeAttached(gameCard)); + list = CardLists.filter(list, CardPredicates.canBeAttached(gameCard, sa)); } if (!list.isEmpty()) { Map params = Maps.newHashMap(); @@ -624,7 +624,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { // TODO can't attach later or moveToPlay would attach indirectly // bypass canBeAttached to skip Protection checks when trying to attach multiple auras that would grant protection - gameCard.attachToEntity(game.getCardState(attachedTo), true); + gameCard.attachToEntity(game.getCardState(attachedTo), sa, true); } else { // When it should enter the battlefield attached to an illegal permanent it fails continue; } @@ -636,7 +636,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { Map params = Maps.newHashMap(); params.put("Attach", gameCard); Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", gameCard.toString()), params); - gameCard.attachToEntity(attachedTo); + gameCard.attachToEntity(attachedTo, sa); } else { // When it should enter the battlefield attached to an illegal player it fails continue; @@ -708,7 +708,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { Map params = Maps.newHashMap(); params.put("Attach", gameCard); Card attachedTo = chooser.getController().chooseSingleEntityForEffect(list, sa, title, params); - movedCard.attachToEntity(attachedTo); + movedCard.attachToEntity(attachedTo, sa); } } } else { @@ -1287,7 +1287,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { // only valid choices are when they could be attached // TODO for multiple Auras entering attached this way, need to use LKI info if (!list.isEmpty()) { - list = CardLists.filter(list, CardPredicates.canBeAttached(c)); + list = CardLists.filter(list, CardPredicates.canBeAttached(c, sa)); } if (!list.isEmpty()) { String title = Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(c.getName())); @@ -1297,7 +1297,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { // TODO can't attach later or moveToPlay would attach indirectly // bypass canBeAttached to skip Protection checks when trying to attach multiple auras that would grant protection - c.attachToEntity(game.getCardState(attachedTo), true); + c.attachToEntity(game.getCardState(attachedTo), sa, true); } else { // When it should enter the battlefield attached to an illegal permanent it fails continue; @@ -1311,7 +1311,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { Map params = Maps.newHashMap(); params.put("Attach", c); Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, title, params); - c.attachToEntity(attachedTo); + c.attachToEntity(attachedTo, sa); } else { // When it should enter the battlefield attached to an illegal permanent it fails continue; @@ -1341,7 +1341,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { Map params = Maps.newHashMap(); params.put("Attach", movedCard); Card attachedTo = decider.getController().chooseSingleEntityForEffect(list, sa, title, params); - movedCard.attachToEntity(attachedTo); + movedCard.attachToEntity(attachedTo, sa); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java index 760d8a56325..402511c8ecf 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java @@ -238,7 +238,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect { boolean canAttach = lki.isAttachment(); - if (canAttach && !ge.canBeAttached(lki)) { + if (canAttach && !ge.canBeAttached(lki, sa)) { canAttach = false; } @@ -254,7 +254,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect { return false; } - tok.attachToEntity(ge); + tok.attachToEntity(ge, sa); return true; } // not a GameEntity, cant be attach diff --git a/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java index 280d5360963..06dd7d9d4bc 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java @@ -81,14 +81,14 @@ public class ZoneExchangeEffect extends SpellAbilityEffect { Card c = null; if (type != null && type.equals("Aura") && object1.getEnchantingCard() != null) { c = object1.getEnchantingCard(); - if (!c.canBeAttached(object2)) { + if (!c.canBeAttached(object2, sa)) { return; } } // Enchant first if (c != null) { object1.unattachFromEntity(c); - object2.attachToEntity(c); + object2.attachToEntity(c, sa); } Map moveParams = AbilityKey.newMap(); moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); 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 31162c4d59e..65fd16043ff 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -3440,22 +3440,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return this.isAttachedToEntity(); } - public final void equipCard(final Card c) { - if (!isEquipment()) { - return; - } - - this.attachToEntity(c); - } - - public final void fortifyCard(final Card c) { - if (!isFortification()) { - return; - } - - this.attachToEntity(c); - } - public final void unEquipCard(final Card c) { // equipment.unEquipCard(equippedCard); this.unattachFromEntity(c); } @@ -3511,11 +3495,11 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return getEnchantingCard() != null; } - public final void attachToEntity(final GameEntity entity) { - attachToEntity(entity, false); + public final void attachToEntity(final GameEntity entity, SpellAbility sa) { + attachToEntity(entity, sa, false); } - public final void attachToEntity(final GameEntity entity, boolean overwrite) { - if (!overwrite && !entity.canBeAttached(this)) { + public final void attachToEntity(final GameEntity entity, SpellAbility sa, boolean overwrite) { + if (!overwrite && !entity.canBeAttached(this, sa)) { return; } @@ -6082,17 +6066,14 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } @Override - protected final boolean canBeEquippedBy(final Card equip) { - if (isCreature() && isInPlay()) { - return true; - } else if (isPlaneswalker() && isInPlay()) { - for (KeywordInterface inst : equip.getKeywords(Keyword.EQUIP)) { - if (inst.getOriginal().contains("planeswalker")) { - return true; - } - } + protected final boolean canBeEquippedBy(final Card equip, SpellAbility sa) { + if (!isInPlay()) { + return false; } - return false; + if (sa != null && sa.isEquip()) { + return isValid(sa.getTargetRestrictions().getValidTgts(), sa.getActivatingPlayer(), equip, sa); + } + return isCreature(); } @Override @@ -6104,13 +6085,13 @@ public class Card extends GameEntity implements Comparable, IHasSVars { * @see forge.game.GameEntity#canBeAttached(forge.game.card.Card, boolean) */ @Override - public boolean canBeAttached(Card attach, boolean checkSBA) { + public boolean canBeAttached(Card attach, SpellAbility sa, boolean checkSBA) { // phase check there if (isPhasedOut() && !attach.isPhasedOut()) { return false; } - return super.canBeAttached(attach, checkSBA); + return super.canBeAttached(attach, sa, checkSBA); } public FCollectionView getReplacementEffects() { diff --git a/forge-game/src/main/java/forge/game/card/CardPredicates.java b/forge-game/src/main/java/forge/game/card/CardPredicates.java index 7391da1959d..50074df3c52 100644 --- a/forge-game/src/main/java/forge/game/card/CardPredicates.java +++ b/forge-game/src/main/java/forge/game/card/CardPredicates.java @@ -251,11 +251,11 @@ public final class CardPredicates { }; } - public static final Predicate canBeAttached(final Card aura) { + public static final Predicate canBeAttached(final Card aura, final SpellAbility sa) { return new Predicate() { @Override public boolean apply(final Card c) { - return c.canBeAttached(aura); + return c.canBeAttached(aura, sa); } }; } diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index bb35a4e0e97..92dc1717758 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -477,20 +477,20 @@ public class CardProperty { } else if (property.startsWith("CanEnchant")) { final String restriction = property.substring(10); if (restriction.equals("EquippedBy")) { - if (!source.getEquipping().canBeAttached(card)) return false; + if (!source.getEquipping().canBeAttached(card, null)) return false; } if (restriction.equals("Remembered")) { for (final Object rem : source.getRemembered()) { - if (!(rem instanceof Card) || !((Card) rem).canBeAttached(card)) + if (!(rem instanceof Card) || !((Card) rem).canBeAttached(card, null)) return false; } } else if (restriction.equals("Source")) { - if (!source.canBeAttached(card)) return false; + if (!source.canBeAttached(card, null)) return false; } } else if (property.startsWith("CanBeEnchantedBy")) { if (property.substring(16).equals("Targeted")) { for (final Card c : AbilityUtils.getDefinedCards(source, "Targeted", spellAbility)) { - if (!card.canBeAttached(c)) { + if (!card.canBeAttached(c, null)) { return false; } } @@ -498,13 +498,13 @@ public class CardProperty { for (final Object rem : source.getRemembered()) { if (rem instanceof Card) { final Card c = (Card) rem; - if (!card.canBeAttached(c)) { + if (!card.canBeAttached(c, null)) { return false; } } } } else { - if (!card.canBeAttached(source)) { + if (!card.canBeAttached(source, null)) { return false; } } @@ -530,7 +530,7 @@ public class CardProperty { return false; } } else if (property.startsWith("CanBeAttachedBy")) { - if (!card.canBeAttached(source)) { + if (!card.canBeAttached(source, null)) { return false; } } else if (property.startsWith("Fortified")) { diff --git a/forge-game/src/main/java/forge/game/player/PlayerPredicates.java b/forge-game/src/main/java/forge/game/player/PlayerPredicates.java index 049550ddf55..8c438f7bf13 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerPredicates.java +++ b/forge-game/src/main/java/forge/game/player/PlayerPredicates.java @@ -121,11 +121,11 @@ public final class PlayerPredicates { }; } - public static final Predicate canBeAttached(final Card aura) { + public static final Predicate canBeAttached(final Card aura, SpellAbility sa) { return new Predicate() { @Override public boolean apply(final Player p) { - return p.canBeAttached(aura); + return p.canBeAttached(aura, sa); } }; } 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 a255568c5ed..109ba9657a4 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -1035,6 +1035,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return isAlternativeCost(AlternativeCost.Outlast); } + public boolean isEquip() { + return hasParam("Equip"); + } + public boolean isBlessing() { return blessing; } 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 0522bac6114..ed849630e9a 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -328,7 +328,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable players ) { + + public GameWrapper(GameStateSpecification initialGameStateSpecification, PlayerActions playerActions, + List players) { this.initialGameStateSpecification = initialGameStateSpecification; this.playerActions = playerActions; this.players = players; - + gameLog = new GameLog(); } - + /** - * This start method attempts to start from the specified game state. - * That requires a bit of ugly hackery, possibly breaking after harmless refactorings or improvements to real code, - * and always casting doubt upon the veracity of test results. - * To somewhat minimize those concerns, starting with stuff on the stack and/or combat in progress is pretty much out of the question. - * Note that if you use this option, regular startup is ignored (using player deck, shuffling, drawing hand, mulligan, ...) + * This start method attempts to start from the specified game state. That + * requires a bit of ugly hackery, possibly breaking after harmless refactorings + * or improvements to real code, and always casting doubt upon the veracity of + * test results. To somewhat minimize those concerns, starting with stuff on the + * stack and/or combat in progress is pretty much out of the question. Note that + * if you use this option, regular startup is ignored (using player deck, + * shuffling, drawing hand, mulligan, ...) */ public void runGame() { List registeredPlayers = new ArrayList<>(); - for( PlayerSpecification player : players ) { + for (PlayerSpecification player : players) { RegisteredPlayer registeredPlayer = new RegisteredPlayer(new Deck(player.getName())); - LobbyPlayerForTests lobbyPlayer = new LobbyPlayerForTests( player.getName(), playerActions ); - registeredPlayer.setPlayer( lobbyPlayer ); - registeredPlayers.add( registeredPlayer ); + LobbyPlayerForTests lobbyPlayer = new LobbyPlayerForTests(player.getName(), playerActions); + registeredPlayer.setPlayer(lobbyPlayer); + registeredPlayers.add(registeredPlayer); } - + GameRules rules = new GameRules(GameType.Constructed); rules.setPlayForAnte(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE)); - rules.setMatchAnteRarity(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE_MATCH_RARITY)); + rules.setMatchAnteRarity(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE_MATCH_RARITY)); rules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN)); rules.setUseGrayText(FModel.getPreferences().getPrefBoolean(FPref.UI_GRAY_INACTIVE_TEXT)); Match match = new Match(rules, registeredPlayers, "Test"); game = match.createGame(); - - //GameNew.newGame( game, false, false ) does a bit of internal setup, then prepares libraries etc - Trigger.resetIDs(); - TriggerHandler trigHandler = game.getTriggerHandler(); - trigHandler.clearDelayedTrigger(); - - //instead of preparing libraries the normal way, we'll distribute cards across the specified zones - if( initialGameStateSpecification != null && !initialGameStateSpecification.getCards().isEmpty() ) { - for( CardSpecification card : initialGameStateSpecification.getCards() ) { - PaperCard paperCard = CardDatabaseHelper.getCard( card.getName() ); - - PlayerSpecification owner = card.getOwner(); - PlayerSpecification controller = card.getController(); - if( owner == null ) { - owner = controller; - } - if( controller == null ) { - controller = owner; - } - - if( owner == null ) { - throw new IllegalStateException( "Cards must specify owner for game state specification" ); - } - Player actualOwner = PlayerSpecificationHandler.INSTANCE.find( game, owner ); - if( controller == null ) { - throw new IllegalStateException( "Cards must specify controller for game state specification" ); - } - Player actualController = PlayerSpecificationHandler.INSTANCE.find( game, controller ); - - ZoneType zoneType = card.getZoneType(); - if( zoneType == null ) { - throw new IllegalStateException( "Cards must specify zone for game state specification" ); - } - - Card actualCard = Card.fromPaperCard( paperCard, actualOwner ); - actualController.getZone( zoneType ).add( actualCard ); - - if( card.getTarget() != null ) { - Card target = CardSpecificationHandler.INSTANCE.find( game, card.getTarget() ); - if (actualCard.isAttachment()) { - if (target.canBeAttached(actualCard)) { - actualCard.attachToEntity(target); - } else { - throw new IllegalStateException( actualCard + " can't attach to " + target ); - } - } else { - throw new IllegalStateException( "Don't know how to make " + actualCard + " target anything" ); - } - } - - - } - } - - //may need to tweak players a bit too - if( initialGameStateSpecification != null && !initialGameStateSpecification.getPlayerFacts().isEmpty() ) { - for( final PlayerSpecification playerFact : initialGameStateSpecification.getPlayerFacts() ) { - final PlayerSpecification basePlayerSpec = new PlayerSpecificationBuilder( playerFact.getName() ).build(); - Player player = PlayerSpecificationHandler.INSTANCE.find( game, basePlayerSpec ); - - if( playerFact.getLife() != null ) { - player.setLife( playerFact.getLife(), null ); - } - - if( playerFact.getPoison() != null ) { - player.setPoisonCounters( playerFact.getPoison(), null ); - } - } - } - - //game.getAction().startGame( null ) determines starting player, draws starting hands, handles mulligans, and initiates the first turn - //skip drawing initial hand and mulliganing - game.setAge( GameStage.Play ); - game.getTriggerHandler().runTrigger(TriggerType.NewGame, AbilityKey.newMap(), false); - //first player in the list starts, no coin toss etc - game.getPhaseHandler().startFirstTurn( game.getPlayers().get( 0 ) ); - game.fireEvent( new GameEventGameFinished() ); + // GameNew.newGame( game, false, false ) does a bit of internal setup, then + // prepares libraries etc + Trigger.resetIDs(); + TriggerHandler trigHandler = game.getTriggerHandler(); + trigHandler.clearDelayedTrigger(); + + // instead of preparing libraries the normal way, we'll distribute cards across + // the specified zones + if (initialGameStateSpecification != null && !initialGameStateSpecification.getCards().isEmpty()) { + for (CardSpecification card : initialGameStateSpecification.getCards()) { + PaperCard paperCard = CardDatabaseHelper.getCard(card.getName()); + + PlayerSpecification owner = card.getOwner(); + PlayerSpecification controller = card.getController(); + if (owner == null) { + owner = controller; + } + if (controller == null) { + controller = owner; + } + + if (owner == null) { + throw new IllegalStateException("Cards must specify owner for game state specification"); + } + Player actualOwner = PlayerSpecificationHandler.INSTANCE.find(game, owner); + if (controller == null) { + throw new IllegalStateException("Cards must specify controller for game state specification"); + } + Player actualController = PlayerSpecificationHandler.INSTANCE.find(game, controller); + + ZoneType zoneType = card.getZoneType(); + if (zoneType == null) { + throw new IllegalStateException("Cards must specify zone for game state specification"); + } + + Card actualCard = Card.fromPaperCard(paperCard, actualOwner); + actualController.getZone(zoneType).add(actualCard); + + if (card.getTarget() != null) { + Card target = CardSpecificationHandler.INSTANCE.find(game, card.getTarget()); + if (actualCard.isAttachment()) { + if (target.canBeAttached(actualCard, null)) { + actualCard.attachToEntity(target, null); + } else { + throw new IllegalStateException(actualCard + " can't attach to " + target); + } + } else { + throw new IllegalStateException("Don't know how to make " + actualCard + " target anything"); + } + } + } + } + + // may need to tweak players a bit too + if (initialGameStateSpecification != null && !initialGameStateSpecification.getPlayerFacts().isEmpty()) { + for (final PlayerSpecification playerFact : initialGameStateSpecification.getPlayerFacts()) { + final PlayerSpecification basePlayerSpec = new PlayerSpecificationBuilder(playerFact.getName()).build(); + Player player = PlayerSpecificationHandler.INSTANCE.find(game, basePlayerSpec); + + if (playerFact.getLife() != null) { + player.setLife(playerFact.getLife(), null); + } + + if (playerFact.getPoison() != null) { + player.setPoisonCounters(playerFact.getPoison(), null); + } + } + } + + // game.getAction().startGame( null ) determines starting player, draws starting + // hands, handles mulligans, and initiates the first turn + // skip drawing initial hand and mulliganing + game.setAge(GameStage.Play); + game.getTriggerHandler().runTrigger(TriggerType.NewGame, AbilityKey.newMap(), false); + + // first player in the list starts, no coin toss etc + game.getPhaseHandler().startFirstTurn(game.getPlayers().get(0)); + game.fireEvent(new GameEventGameFinished()); } - + public PlayerActions getPlayerActions() { return playerActions; } - + public Game getGame() { return game; } - + @Override public String toString() { StringBuilder sb = new StringBuilder(); - - sb.append( "Game log : \r\n" ); - List gameLogEntries = gameLog.getLogEntries( GameLogEntryType.PHASE ); - Collections.reverse( gameLogEntries ); - for( GameLogEntry gameLogEntry : gameLogEntries ) { - sb.append( gameLogEntry.toString() ).append( "\r\n" ); + + sb.append("Game log : \r\n"); + List gameLogEntries = gameLog.getLogEntries(GameLogEntryType.PHASE); + Collections.reverse(gameLogEntries); + for (GameLogEntry gameLogEntry : gameLogEntries) { + sb.append(gameLogEntry.toString()).append("\r\n"); } - + return sb.toString(); } }