From a61adee5707d2f563795617c8aeb3afa26da42eb Mon Sep 17 00:00:00 2001 From: Sol Date: Wed, 13 Mar 2013 04:14:42 +0000 Subject: [PATCH 1/8] - Fix smart quote in Saparazzan Outrigger --- res/cardsfolder/s/saprazzan_outrigger.txt | 2 +- res/mtg-data.txt | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/res/cardsfolder/s/saprazzan_outrigger.txt b/res/cardsfolder/s/saprazzan_outrigger.txt index 3e4157d0a25..0552dcc187e 100644 --- a/res/cardsfolder/s/saprazzan_outrigger.txt +++ b/res/cardsfolder/s/saprazzan_outrigger.txt @@ -4,7 +4,7 @@ Types:Creature Merfolk PT:5/5 T:Mode$ Attacks | ValidCard$ Card.Self | DelayedTrigger$ DelTrig | TriggerDescription$ Whenever CARDNAME attacks or blocks, put it on top of its owner’s library at end of combat. T:Mode$ Blocks | ValidCard$ Card.Self | DelayedTrigger$ DelTrig | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks or blocks, put it on top of its owner’s library at end of combat. -SVar:DelTrig:Mode$ Phase | Phase$ EndCombat | Execute$ TrigChange | TriggerDescription$ Put CARDNAME on top of its owner’s library. +SVar:DelTrig:Mode$ Phase | Phase$ EndCombat | Execute$ TrigChange | TriggerDescription$ Put CARDNAME on top of its owner's library. SVar:TrigChange:AB$ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Library | LibraryPosition$ 0 | Defined$ Self SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/saprazzan_outrigger.jpg diff --git a/res/mtg-data.txt b/res/mtg-data.txt index f5bb8fd8ed0..57fc8ca6e21 100644 --- a/res/mtg-data.txt +++ b/res/mtg-data.txt @@ -4029,7 +4029,7 @@ Battery {3}{G} Sorcery Put a 3/3 green Elephant creature token onto the battlefield. -IN U (x2), TSB S, HOP U +IN U, TSB S, HOP U Assault Griffin {3}{W} @@ -57039,7 +57039,7 @@ Suffering {3}{R} Sorcery Destroy target land. -IN U (x2), DDH U +IN U, DDH U Pain Kami {2}{R} @@ -76314,7 +76314,7 @@ Malice {3}{B} Instant Destroy target nonblack creature. It can't be regenerated. -IN U (x2), DDH U +IN U, DDH U Spitebellows {5}{R} @@ -77073,7 +77073,7 @@ Deliver {2}{U} Instant Return target permanent to its owner's hand. -IN U (x2) +IN U Stand Firm {W} @@ -90406,7 +90406,7 @@ Wane {W} Instant Destroy target enchantment. -IN U (x2), ARC U +IN U, ARC U Waxmane Baku {2}{W} From 1d3147a5ae1a1963e0b8e1c5a805bab689e4e18c Mon Sep 17 00:00:00 2001 From: moomarc Date: Wed, 13 Mar 2013 07:37:00 +0000 Subject: [PATCH 2/8] - Added Trickbind (Thanks AlexV) --- .gitattributes | 1 + res/cardsfolder/t/trickbind.txt | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 res/cardsfolder/t/trickbind.txt diff --git a/.gitattributes b/.gitattributes index e5c9dba5ab0..e8ca8fedd5d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11215,6 +11215,7 @@ res/cardsfolder/t/tribal_golem.txt svneol=native#text/plain res/cardsfolder/t/tribal_unity.txt -text res/cardsfolder/t/tribute_to_hunger.txt -text res/cardsfolder/t/tribute_to_the_wild.txt svneol=native#text/plain +res/cardsfolder/t/trickbind.txt -text res/cardsfolder/t/trickery_charm.txt -text svneol=unset#text/plain res/cardsfolder/t/tricks_of_the_trade.txt -text res/cardsfolder/t/trickster_mage.txt svneol=native#text/plain diff --git a/res/cardsfolder/t/trickbind.txt b/res/cardsfolder/t/trickbind.txt new file mode 100644 index 00000000000..bde9d2c6b57 --- /dev/null +++ b/res/cardsfolder/t/trickbind.txt @@ -0,0 +1,11 @@ +Name:Trickbind +ManaCost:1 U +Types:Instant +K:Split second +A:SP$ Counter | Cost$ 1 U | TargetType$ Activated,Triggered | TgtPrompt$ Select target Activated or Triggered Ability | RememberTargets$ True | ValidTgts$ Card | SubAbility$ DBEffect | SpellDescription$ Counter target activated or triggered ability. If a permanent's ability is countered this way, activated abilities of that permanent can't be activated this turn. (Mana abilities can't be targeted.) +SVar:DBEffect:DB$ Effect | Name$ Trickbind Effect | StaticAbilities$ STCantBeActivated | RememberObjects$ Remembered | SubAbility$ DBCleanup | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ1 +SVar:STCantBeActivated:Mode$ CantBeActivated | EffectZone$ Command | ValidCard$ Permanent.IsRemembered +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:Picture:http://www.wizards.com/global/images/magic/general/trickbind.jpg +Oracle:Split second (As long as this spell is on the stack, players can't cast spells or activate abilities that aren't mana abilities.)\nCounter target activated or triggered ability. If a permanent's ability is countered this way, activated abilities of that permanent can't be activated this turn. (Mana abilities can't be targeted.) +SetInfo:TSP Rare \ No newline at end of file From cbbf22f34ab09e124793d1362912ccfe26ce98ac Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Wed, 13 Mar 2013 08:31:49 +0000 Subject: [PATCH 3/8] added reveal method to PlayerController (should probably add one to game? to reveal to all players) AI mulligan decision code moved to ComputerUtil --- .../forge/card/ability/effects/DigEffect.java | 6 ++-- .../forge/control/input/InputMulligan.java | 28 +++++-------------- src/main/java/forge/game/ai/ComputerUtil.java | 11 ++++++++ .../forge/game/player/PlayerController.java | 4 +++ .../forge/game/player/PlayerControllerAi.java | 9 ++++++ .../game/player/PlayerControllerHuman.java | 14 ++++++++++ 6 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/main/java/forge/card/ability/effects/DigEffect.java b/src/main/java/forge/card/ability/effects/DigEffect.java index 6d143710bab..e681d344949 100644 --- a/src/main/java/forge/card/ability/effects/DigEffect.java +++ b/src/main/java/forge/card/ability/effects/DigEffect.java @@ -143,9 +143,9 @@ public class DigEffect extends SpellAbilityEffect { } // Singletons.getModel().getGameAction().revealToCopmuter(top.toArray()); // - for when it exists - } else if (choser.isHuman() && !sa.hasParam("NoLooking")) { + } else if (!sa.hasParam("NoLooking")) { // show the user the revealed cards - GuiChoose.one("Looking at cards from library", top); + choser.getController().reveal("Looking at cards from library", top, library.getZoneType(), library.getPlayer()); } if ((sa.hasParam("RememberRevealed")) && !sa.hasParam("RevealValid")) { @@ -251,7 +251,7 @@ public class DigEffect extends SpellAbilityEffect { } for (j = 0; j < changeNum; j++) { Card chosen = ComputerUtilCard.getBestAI(valid); - if (sa.getActivatingPlayer().isHuman() && p.isHuman()) { + if (sa.getActivatingPlayer().isOpponentOf(choser) && p.isOpponentOf(choser)) { chosen = ComputerUtilCard.getWorstAI(valid); } if (chosen == null) { diff --git a/src/main/java/forge/control/input/InputMulligan.java b/src/main/java/forge/control/input/InputMulligan.java index 6524268240d..c1d10ecb0aa 100644 --- a/src/main/java/forge/control/input/InputMulligan.java +++ b/src/main/java/forge/control/input/InputMulligan.java @@ -23,7 +23,6 @@ import java.util.List; import com.google.common.collect.Iterables; import forge.Card; -import forge.CardLists; import forge.CardPredicates; import forge.Singletons; import forge.card.ability.AbilityFactory; @@ -54,8 +53,6 @@ public class InputMulligan extends Input { /** Constant serialVersionUID=-8112954303001155622L. */ private static final long serialVersionUID = -8112954303001155622L; - private static final int AI_MULLIGAN_THRESHOLD = 5; - /** {@inheritDoc} */ @Override public final void showMessage() { @@ -100,24 +97,13 @@ public class InputMulligan extends Input { GameState game = Singletons.getModel().getGame(); // Computer mulligan - for (Player ai : game.getPlayers()) { - if (ai.isHuman()) { + for (Player p : game.getPlayers()) { + if (!(p instanceof AIPlayer)) { continue; } - - boolean aiTakesMulligan = true; - - // Computer mulligans if there are no cards with converted mana cost of - // 0 in its hand - while (aiTakesMulligan) { - - final List handList = ai.getCardsIn(ZoneType.Hand); - final boolean hasLittleCmc0Cards = CardLists.getValidCards(handList, "Card.cmcEQ0", ai, null).size() < 2; - aiTakesMulligan = (handList.size() > InputMulligan.AI_MULLIGAN_THRESHOLD) && hasLittleCmc0Cards; - - if (aiTakesMulligan) { - ai.doMulligan(); - } + AIPlayer ai = (AIPlayer) p; + while (ComputerUtil.wantMulligan(ai)) { + ai.doMulligan(); } } @@ -135,7 +121,7 @@ public class InputMulligan extends Input { final String effName = kw.split(":")[1]; final SpellAbility effect = AbilityFactory.getAbility(c.getSVar(effName), c); - if (GuiDialog.confirm(c, "Use this card's ability?")) { + if (GuiDialog.confirm(c, "Use " + c +"'s ability?")) { // If we ever let the AI memorize cards in the players // hand, this would be a place to do so. game.getActionPlay().playSpellAbilityNoStack(p, effect, false); @@ -143,7 +129,7 @@ public class InputMulligan extends Input { } } if (c.getName().startsWith("Leyline of")) { - if (GuiDialog.confirm(c, "Use this card's ability?")) { + if (GuiDialog.confirm(c, "Use " + c + "'s ability?")) { ga.moveToPlay(c); } } diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java index 4820a5e2c87..5d3cf8d97f9 100644 --- a/src/main/java/forge/game/ai/ComputerUtil.java +++ b/src/main/java/forge/game/ai/ComputerUtil.java @@ -1212,4 +1212,15 @@ public class ComputerUtil { threatened.addAll(ComputerUtil.predictThreatenedObjects(aiPlayer, saviour, topStack.getSubAbility())); return threatened; } + + // Computer mulligans if there are no cards with converted mana cost of + // 0 in its hand + public static boolean wantMulligan(AIPlayer ai) { + final int AI_MULLIGAN_THRESHOLD = 5; + + final List handList = ai.getCardsIn(ZoneType.Hand); + final boolean hasLittleCmc0Cards = CardLists.getValidCards(handList, "Card.cmcEQ0", ai, null).size() < 2; + return (handList.size() > AI_MULLIGAN_THRESHOLD) && hasLittleCmc0Cards; + + } } diff --git a/src/main/java/forge/game/player/PlayerController.java b/src/main/java/forge/game/player/PlayerController.java index 91092f71e57..bc3fc07cb41 100644 --- a/src/main/java/forge/game/player/PlayerController.java +++ b/src/main/java/forge/game/player/PlayerController.java @@ -12,6 +12,7 @@ import forge.game.GameState; import forge.game.GameType; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; +import forge.game.zone.ZoneType; /** @@ -100,4 +101,7 @@ public abstract class PlayerController { public abstract List orderBlockers(Card attacker, List blockers); public abstract List orderAttackers(Card blocker, List attackers); + + /** Shows the card to this player*/ + public abstract void reveal(String string, List cards, ZoneType zone, Player owner); } diff --git a/src/main/java/forge/game/player/PlayerControllerAi.java b/src/main/java/forge/game/player/PlayerControllerAi.java index de9e1477167..696043136cc 100644 --- a/src/main/java/forge/game/player/PlayerControllerAi.java +++ b/src/main/java/forge/game/player/PlayerControllerAi.java @@ -17,6 +17,7 @@ import forge.game.ai.AiInputCommon; import forge.game.ai.ComputerUtil; import forge.game.ai.ComputerUtilBlock; import forge.game.ai.ComputerUtilCombat; +import forge.game.zone.ZoneType; import forge.gui.GuiChoose; @@ -219,4 +220,12 @@ public class PlayerControllerAi extends PlayerController { return ComputerUtilBlock.orderAttackers(blocker, attackers); } + /* (non-Javadoc) + * @see forge.game.player.PlayerController#reveal(java.lang.String, java.util.List) + */ + @Override + public void reveal(String string, List cards, ZoneType zone, Player owner) { + // We don't know how to reveal cards to AI + } + } diff --git a/src/main/java/forge/game/player/PlayerControllerHuman.java b/src/main/java/forge/game/player/PlayerControllerHuman.java index 0282bde6975..1bd07544911 100644 --- a/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/src/main/java/forge/game/player/PlayerControllerHuman.java @@ -7,6 +7,8 @@ import java.util.Map; import javax.swing.JOptionPane; +import org.apache.commons.lang3.StringUtils; + import forge.Card; import forge.GameEntity; import forge.card.spellability.SpellAbility; @@ -20,6 +22,7 @@ import forge.deck.DeckSection; import forge.game.GameState; import forge.game.GameType; import forge.game.phase.PhaseType; +import forge.game.zone.ZoneType; import forge.gui.GuiChoose; import forge.gui.GuiDialog; import forge.gui.GuiUtils; @@ -274,4 +277,15 @@ public class PlayerControllerHuman extends PlayerController { GuiUtils.setPanelSelection(blocker); return GuiChoose.order("Choose Blocking Order", "Damaged First", 0, attackers, null, blocker); } + + /* (non-Javadoc) + * @see forge.game.player.PlayerController#reveal(java.lang.String, java.util.List, forge.game.zone.ZoneType, forge.game.player.Player) + */ + @Override + public void reveal(String string, List cards, ZoneType zone, Player owner) { + String message = string; + if ( StringUtils.isBlank(message) ) + message = String.format("Looking at %s's %s", owner, zone); + GuiChoose.oneOrNone(message, cards); + } } From 59125c91f0530014cdf35ab06395b76cc179ed03 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 13 Mar 2013 10:56:28 +0000 Subject: [PATCH 4/8] - Added new card names to changes.txt. --- CHANGES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 155027b6919..2492c6208e6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -66,6 +66,8 @@ Ooze Flux Simic Manipulator Ashling the Pilgrim Inner-Flame Igniter +Novijen Sages +Trickbind New Phenomenons: From 0d707646e4082dfd4720067780855e61c53518e4 Mon Sep 17 00:00:00 2001 From: Sloth Date: Wed, 13 Mar 2013 16:40:43 +0000 Subject: [PATCH 5/8] - Fixed AI crashing on Squandered Resources (but it still can't use it). --- src/main/java/forge/card/ability/AbilityUtils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/forge/card/ability/AbilityUtils.java b/src/main/java/forge/card/ability/AbilityUtils.java index 09c3269fd9a..380734a7365 100644 --- a/src/main/java/forge/card/ability/AbilityUtils.java +++ b/src/main/java/forge/card/ability/AbilityUtils.java @@ -246,7 +246,9 @@ public class AbilityUtils { return cards; } - cards.addAll(list); + if (list != null) { + cards.addAll(list); + } } if (c != null) { From d6b249e897af06e91f4d3f7ea6cb00ec2a924a10 Mon Sep 17 00:00:00 2001 From: Sloth Date: Wed, 13 Mar 2013 19:35:58 +0000 Subject: [PATCH 6/8] - Fixed splicing spells with subAbilities. --- src/main/java/forge/game/GameActionUtil.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/forge/game/GameActionUtil.java b/src/main/java/forge/game/GameActionUtil.java index 081ef2666ad..a2c551e77c7 100644 --- a/src/main/java/forge/game/GameActionUtil.java +++ b/src/main/java/forge/game/GameActionUtil.java @@ -1334,25 +1334,36 @@ public final class GameActionUtil { } String newSubSAString = c.getCharacteristics().getIntrinsicAbility().get(0); newSubSAString = newSubSAString.replace("SP", "DB"); - final AbilitySub newSubSA = (AbilitySub) AbilityFactory.getAbility(newSubSAString, source); + final AbilitySub newSubSA = (AbilitySub) AbilityFactory.getAbility(newSubSAString, c); ArrayList addSAs = new ArrayList(); // Add the subability to all existing variants for (SpellAbility s : allSAs) { + //create a new spell copy final SpellAbility newSA = s.copy(); newSA.setBasicSpell(false); newSA.setPayCosts(combineCosts(newSA, keyword.substring(19))); newSA.setManaCost(ManaCost.NO_COST); newSA.setDescription(s.getDescription() + " (Splicing " + c + " onto it)"); newSA.addSplicedCards(c); + + // copy all subAbilities SpellAbility child = newSA; while (child.getSubAbility() != null) { AbilitySub newChild = child.getSubAbility().getCopy(); child.setSubAbility(newChild); - newChild.setParent(child); child = newChild; } + + //add the spliced ability to the end of the chain child.setSubAbility(newSubSA); - newSubSA.setParent(child); + + //set correct source and activating player to all the spliced abilities + child = newSubSA; + while (child != null) { + child.setSourceCard(source); + child.setActivatingPlayer(s.getActivatingPlayer()); + child = child.getSubAbility(); + } newSAs.add(0, newSA); addSAs.add(newSA); } From 945d5a5f56862eaf49a3877a49313cdfac81796b Mon Sep 17 00:00:00 2001 From: Sloth Date: Wed, 13 Mar 2013 22:58:45 +0000 Subject: [PATCH 7/8] - Improved the script pf Quietus Spike. --- res/cardsfolder/q/quietus_spike.txt | 2 +- src/main/java/forge/card/cardfactory/CardFactoryUtil.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/res/cardsfolder/q/quietus_spike.txt b/res/cardsfolder/q/quietus_spike.txt index df2bc315d8c..35c4d63459f 100644 --- a/res/cardsfolder/q/quietus_spike.txt +++ b/res/cardsfolder/q/quietus_spike.txt @@ -5,7 +5,7 @@ K:Equip 3 S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Deathtouch | Description$ Equipped creature has deathtouch. Whenever equipped creature deals combat damage to a player, that player loses half his or her life, rounded up. T:Mode$ DamageDone | ValidSource$ Creature.EquippedBy | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigLoseLifeOpp | TriggerDescription$ Whenever equipped creature deals combat damage to a player, that player loses half his or her life, rounded up. SVar:TrigLoseLifeOpp:AB$ LoseLife | Cost$ 0 | Defined$ TriggeredTarget | LifeAmount$ QuietusX | References$ QuietusX -SVar:QuietusX:Count$DefenderLifeTotal/HalfUp +SVar:QuietusX:TriggeredTarget$LifeTotal/HalfUp SVar:Picture:http://www.wizards.com/global/images/magic/general/quietus_spike.jpg Oracle:Equipped creature has deathtouch.\nWhenever equipped creature deals combat damage to a player, that player loses half his or her life, rounded up.\nEquip {3} SetInfo:PC2 Rare diff --git a/src/main/java/forge/card/cardfactory/CardFactoryUtil.java b/src/main/java/forge/card/cardfactory/CardFactoryUtil.java index ac1e8a4becb..457dc1e448c 100644 --- a/src/main/java/forge/card/cardfactory/CardFactoryUtil.java +++ b/src/main/java/forge/card/cardfactory/CardFactoryUtil.java @@ -1568,12 +1568,6 @@ public class CardFactoryUtil { return CardFactoryUtil.doXMath(oppController.getLife(), m, c); } - // Count$DefenderLifeTotal - if (sq[0].contains("DefenderLifeTotal")) { - Player defender = Singletons.getModel().getGame().getCombat().getDefendingPlayerRelatedTo(c); - return CardFactoryUtil.doXMath(defender.getLife(), m, c); - } - // Count$TargetedLifeTotal (targeted player's life total) if (sq[0].contains("TargetedLifeTotal")) { for (final SpellAbility sa : c.getCharacteristics().getSpellAbility()) { From f705d358235c299a17b3be1658b68e0c97c32129 Mon Sep 17 00:00:00 2001 From: Sloth Date: Wed, 13 Mar 2013 23:25:06 +0000 Subject: [PATCH 8/8] - Changed getDefendingPlayerRelatedTo to return a list instead of a single player (which brings it closer to the rules). - Added Yare. --- .gitattributes | 1 + res/cardsfolder/y/yare.txt | 8 +++++++ src/main/java/forge/Card.java | 4 +--- .../java/forge/card/ability/AbilityUtils.java | 5 +---- src/main/java/forge/game/phase/Combat.java | 21 +++++++++++++------ .../java/forge/game/phase/CombatUtil.java | 7 +++++-- 6 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 res/cardsfolder/y/yare.txt diff --git a/.gitattributes b/.gitattributes index e8ca8fedd5d..cdcaa9bc2f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12298,6 +12298,7 @@ res/cardsfolder/x/xira_arien.txt svneol=native#text/plain res/cardsfolder/x/xun_yu_wei_advisor.txt svneol=native#text/plain res/cardsfolder/y/yamabushis_flame.txt svneol=native#text/plain res/cardsfolder/y/yamabushis_storm.txt -text +res/cardsfolder/y/yare.txt -text res/cardsfolder/y/yavimaya_ancients.txt svneol=native#text/plain res/cardsfolder/y/yavimaya_ants.txt svneol=native#text/plain res/cardsfolder/y/yavimaya_barbarian.txt svneol=native#text/plain diff --git a/res/cardsfolder/y/yare.txt b/res/cardsfolder/y/yare.txt new file mode 100644 index 00000000000..448e1cde04c --- /dev/null +++ b/res/cardsfolder/y/yare.txt @@ -0,0 +1,8 @@ +Name:Yare +ManaCost:2 W +Types:Instant +A:SP$ Pump | Cost$ 2 W | ValidTgts$ Creature.DefenderCtrl | TgtPrompt$ Select target creature defending player controls | NumAtt$ 3 | KW$ HIDDEN CARDNAME can block an additional creature. & HIDDEN CARDNAME can block an additional creature. | SpellDescription$ Target creature defending player controls gets +3/+0 until end of turn. That creature can block up to two additional creatures this turn. +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/yare.jpg +Oracle:Target creature defending player controls gets +3/+0 until end of turn. That creature can block up to two additional creatures this turn. +SetInfo:MIR Rare \ No newline at end of file diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index 23c9a1429b5..68193b5a34d 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -6358,12 +6358,10 @@ public class Card extends GameEntity implements Comparable { return false; } } else if (property.startsWith("DefenderCtrl")) { - Combat combat = Singletons.getModel().getGame().getCombat(); if (!Singletons.getModel().getGame().getPhaseHandler().inCombat()) { return false; } - Player defender = combat.getDefendingPlayerRelatedTo(source); - if (!this.getController().equals(defender)) { + if (!Singletons.getModel().getGame().getCombat().getDefendingPlayerRelatedTo(source).contains(this.getController())) { return false; } } else if (property.startsWith("EnchantedPlayerCtrl")) { diff --git a/src/main/java/forge/card/ability/AbilityUtils.java b/src/main/java/forge/card/ability/AbilityUtils.java index 380734a7365..61507715edb 100644 --- a/src/main/java/forge/card/ability/AbilityUtils.java +++ b/src/main/java/forge/card/ability/AbilityUtils.java @@ -855,10 +855,7 @@ public class AbilityUtils { players.add(p); } } else if (defined.equals("DefendingPlayer")) { - final Player p = Singletons.getModel().getGame().getCombat().getDefendingPlayerRelatedTo(card); - if (!players.contains(p)) { - players.add(p); - } + players.addAll(Singletons.getModel().getGame().getCombat().getDefendingPlayerRelatedTo(card)); } else if (defined.equals("ChosenPlayer")) { final Player p = card.getChosenPlayer(); if (!players.contains(p)) { diff --git a/src/main/java/forge/game/phase/Combat.java b/src/main/java/forge/game/phase/Combat.java index e593c54be6b..0feb0369a91 100644 --- a/src/main/java/forge/game/phase/Combat.java +++ b/src/main/java/forge/game/phase/Combat.java @@ -546,7 +546,8 @@ public class Combat { * a {@link forge.Card} object. * @return a {@link forge.Player} object. */ - public Player getDefendingPlayerRelatedTo(final Card source) { + public List getDefendingPlayerRelatedTo(final Card source) { + List players = new ArrayList(); Card attacker = source; if (source.isAura()) { attacker = source.getEnchantingCard(); @@ -554,13 +555,21 @@ public class Combat { attacker = source.getEquippingCard(); } + // return the corresponding defender Player defender = getDefenderPlayerByAttacker(attacker); - if (null == defender) { // too bad, have to choose now - // don't have ui, cannot choose - have to getOpponent - // that's inaccurate. That opponent may be not even a defender - defender = source.getController().getOpponent(); + if (null != defender) { + players.add(defender); + return players; } - return defender; + + // return all defenders + List defenders = this.getDefenders(); + for (GameEntity ge : defenders) { + if (ge instanceof Player) { + players.add((Player) ge); + } + } + return players; } /** diff --git a/src/main/java/forge/game/phase/CombatUtil.java b/src/main/java/forge/game/phase/CombatUtil.java index 0ada189912e..151e7cfd6ed 100644 --- a/src/main/java/forge/game/phase/CombatUtil.java +++ b/src/main/java/forge/game/phase/CombatUtil.java @@ -278,7 +278,10 @@ public class CombatUtil { } String valid = StringUtils.join(walkTypes, ","); - final Player defendingPlayer = Singletons.getModel().getGame().getCombat().getDefendingPlayerRelatedTo(attacker); + Player defendingPlayer = attacker.getController().getOpponent(); + if (attacker.isAttacking()) { + defendingPlayer = Singletons.getModel().getGame().getCombat().getDefendingPlayerRelatedTo(attacker).get(0); + } List defendingLands = defendingPlayer.getCardsIn(ZoneType.Battlefield); for (Card c : defendingLands) { if (c.isValid(valid.split(","), defendingPlayer, attacker)) { @@ -1225,7 +1228,7 @@ public class CombatUtil { @Override public void resolve() { this.api = ApiType.Sacrifice; - final Player opponent = Singletons.getModel().getGame().getCombat().getDefendingPlayerRelatedTo(c); + final Player opponent = Singletons.getModel().getGame().getCombat().getDefendingPlayerRelatedTo(c).get(0); //List list = AbilityUtils.filterListByType(opponent.getCardsIn(ZoneType.Battlefield), "Permanent", this); final List list = opponent.getCardsIn(ZoneType.Battlefield); List toSac = opponent.getController().choosePermanentsToSacrifice(list, a, this, false, false);