From beeaf3cc50eb5d809e71ef2926e163a952b43608 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Mon, 22 Apr 2013 19:59:18 +0000 Subject: [PATCH] removed the 'currentdefender' field from Combat, each user has to track himself the defenders canAttack and addAttacker methods now require a defender. --- .../forge/card/ability/ai/ChangeZoneAi.java | 59 ++++++++------- .../ability/effects/ChangeZoneEffect.java | 74 ++++++++++--------- .../card/ability/effects/TokenEffect.java | 21 +++--- .../java/forge/control/input/InputAttack.java | 12 ++- .../forge/game/ai/AiAttackController.java | 45 +++++------ src/main/java/forge/game/ai/ComputerUtil.java | 2 +- src/main/java/forge/game/phase/Combat.java | 48 ------------ .../java/forge/game/phase/CombatUtil.java | 5 +- .../forge/gui/match/controllers/CDock.java | 14 +++- 9 files changed, 125 insertions(+), 155 deletions(-) diff --git a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java index af6ac1db69a..3924405d09a 100644 --- a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java +++ b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java @@ -16,7 +16,6 @@ import forge.CardPredicates; import forge.CardPredicates.Presets; import forge.Constant; import forge.GameEntity; -import forge.Singletons; import forge.card.ability.AbilityUtils; import forge.card.ability.ApiType; import forge.card.ability.SpellAbilityAi; @@ -28,6 +27,7 @@ import forge.card.spellability.AbilitySub; import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; import forge.card.trigger.TriggerType; +import forge.game.GameState; import forge.game.GlobalRuleChange; import forge.game.ai.ComputerUtil; import forge.game.ai.ComputerUtilBlock; @@ -191,17 +191,17 @@ public class ChangeZoneAi extends SpellAbilityAi { //Ninjutsu if (sa.hasParam("Ninjutsu")) { if (source.isType("Legendary") - && !Singletons.getModel().getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) { + && !ai.getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) { final List list = ai.getCardsIn(ZoneType.Battlefield); if (Iterables.any(list, CardPredicates.nameEquals(source.getName()))) { return false; } } - if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE)) { + if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE)) { return false; } List attackers = new ArrayList(); - attackers.addAll(Singletons.getModel().getGame().getCombat().getUnblockedAttackers()); + attackers.addAll(ai.getGame().getCombat().getUnblockedAttackers()); boolean lowerCMC = false; for (Card attacker : attackers) { if (attacker.getCMC() < source.getCMC()) { @@ -284,7 +284,7 @@ public class ChangeZoneAi extends SpellAbilityAi { } // don't use fetching to top of library/graveyard before main2 - if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) + if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) && !sa.hasParam("ActivationPhases")) { if (!destination.equals("Battlefield") && !destination.equals("Hand")) { return false; @@ -495,7 +495,7 @@ public class ChangeZoneAi extends SpellAbilityAi { combat.initiatePossibleDefenders(ai); List attackers = ai.getOpponent().getCreaturesInPlay(); for (Card att : attackers) { - combat.addAttacker(att); + combat.addAttacker(att, ai); } combat = ComputerUtilBlock.getBlockers(ai, combat, ai.getCreaturesInPlay()); @@ -589,7 +589,7 @@ public class ChangeZoneAi extends SpellAbilityAi { // in general this should only be used to protect from Imminent Harm // (dying or losing control of) if (origin.equals(ZoneType.Battlefield)) { - if (Singletons.getModel().getGame().getStack().size() == 0) { + if (ai.getGame().getStack().size() == 0) { return false; } @@ -620,14 +620,14 @@ public class ChangeZoneAi extends SpellAbilityAi { // don't return something to your hand if your hand is full of good stuff if (destination.equals(ZoneType.Hand) && origin.equals(ZoneType.Graveyard)) { final int handSize = ai.getCardsIn(ZoneType.Hand).size(); - if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN1)) { + if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN1)) { return false; } - if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) + if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) && handSize > 1) { return false; } - if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(ai) + if (ai.getGame().getPhaseHandler().isPlayerTurn(ai) && handSize >= ai.getMaxHandSize()) { return false; } @@ -688,7 +688,7 @@ public class ChangeZoneAi extends SpellAbilityAi { } tgt.resetTargets(); - List list = CardLists.getValidCards(Singletons.getModel().getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source); + List list = CardLists.getValidCards(ai.getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source); if (sa.hasParam("AITgts")) { list = CardLists.getValidCards(list, sa.getParam("AITgts"), sa.getActivatingPlayer(), source); } @@ -721,7 +721,7 @@ public class ChangeZoneAi extends SpellAbilityAi { // check stack for something on the stack that will kill // anything i control - if (Singletons.getModel().getGame().getStack().size() > 0) { + if (ai.getGame().getStack().size() > 0) { final ArrayList objects = ComputerUtil.predictThreatenedObjects(ai, sa); final List threatenedTargets = new ArrayList(); @@ -739,7 +739,7 @@ public class ChangeZoneAi extends SpellAbilityAi { } } // Save combatants - else if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { + else if (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { final List combatants = CardLists.filter(aiPermanents, CardPredicates.Presets.CREATURES); CardLists.sortByEvaluateCreature(combatants); @@ -795,7 +795,7 @@ public class ChangeZoneAi extends SpellAbilityAi { if (origin.equals(ZoneType.Battlefield) && destination.equals(ZoneType.Exile) && (subApi == ApiType.DelayedTrigger || (subApi == ApiType.ChangeZone && subAffected.equals("Remembered"))) - && !(Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || sa + && !(ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || sa .isAbility())) { return false; } @@ -805,8 +805,8 @@ public class ChangeZoneAi extends SpellAbilityAi { // don't rush bouncing stuff when not going to attack if (!sa.isTrigger() && sa.getPayCosts() != null - && Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) - && Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(ai) + && ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) + && ai.getGame().getPhaseHandler().isPlayerTurn(ai) && ai.getCreaturesInPlay().isEmpty()) { return false; } @@ -825,7 +825,7 @@ public class ChangeZoneAi extends SpellAbilityAi { } // Only care about combatants during combat - if (Singletons.getModel().getGame().getPhaseHandler().inCombat()) { + if (ai.getGame().getPhaseHandler().inCombat()) { CardLists.getValidCards(list, "Card.attacking,Card.blocking", null, null); } @@ -931,7 +931,7 @@ public class ChangeZoneAi extends SpellAbilityAi { final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination")); final Target tgt = sa.getTarget(); - List list = CardLists.getValidCards(Singletons.getModel().getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source); + List list = CardLists.getValidCards(ai.getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source); // Narrow down the list: if (origin.equals(ZoneType.Battlefield)) { @@ -1070,6 +1070,7 @@ public class ChangeZoneAi extends SpellAbilityAi { final Card card = sa.getSourceCard(); final boolean defined = sa.hasParam("Defined"); final Player activator = sa.getActivatingPlayer(); + final GameState game = ai.getGame(); if (tgt != null) { if (!tgt.getTargetPlayers().isEmpty()) { @@ -1101,7 +1102,7 @@ public class ChangeZoneAi extends SpellAbilityAi { } } else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand) && !sa.hasParam("DefinedPlayer")) { - fetchList = Singletons.getModel().getGame().getCardsIn(origin); + fetchList = game.getCardsIn(origin); fetchList = AbilityUtils.filterListByType(fetchList, type, sa); } else { fetchList = player.getCardsIn(origin); @@ -1253,7 +1254,7 @@ public class ChangeZoneAi extends SpellAbilityAi { Card movedCard = null; if (ZoneType.Library.equals(destination)) { final int libraryPos = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : 0; - movedCard = Singletons.getModel().getGame().getAction().moveToLibrary(c, libraryPos); + movedCard = game.getAction().moveToLibrary(c, libraryPos); } else if (ZoneType.Battlefield.equals(destination)) { if (sa.hasParam("Tapped")) { c.setTapped(true); @@ -1261,9 +1262,9 @@ public class ChangeZoneAi extends SpellAbilityAi { if (sa.hasParam("GainControl")) { if (sa.hasParam("NewController")) { final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("DefinedPlayer"), sa).get(0); - c.setController(p, Singletons.getModel().getGame().getNextTimestamp()); + c.setController(p, game.getNextTimestamp()); } else { - c.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp()); + c.setController(sa.getActivatingPlayer(), game.getNextTimestamp()); } } @@ -1271,7 +1272,7 @@ public class ChangeZoneAi extends SpellAbilityAi { List list = AbilityUtils.getDefinedCards(sa.getSourceCard(), sa.getParam("AttachedTo"), sa); if (list.isEmpty()) { - list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield); + list = game.getCardsIn(ZoneType.Battlefield); list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), c.getController(), c); } if (!list.isEmpty()) { @@ -1289,7 +1290,9 @@ public class ChangeZoneAi extends SpellAbilityAi { } if (sa.hasParam("Attacking")) { - Singletons.getModel().getGame().getCombat().addAttacker(c); + List defenders = game.getCombat().getDefenders(); + if ( !defenders.isEmpty() ) + game.getCombat().addAttacker(c, defenders.get(0)); } // Auras without Candidates stay in their current location if (c.isAura()) { @@ -1299,24 +1302,24 @@ public class ChangeZoneAi extends SpellAbilityAi { } } - movedCard = Singletons.getModel().getGame().getAction().moveTo(c.getController().getZone(destination), c); + movedCard = game.getAction().moveTo(c.getController().getZone(destination), c); if (sa.hasParam("Tapped")) { movedCard.setTapped(true); } } else if (destination.equals(ZoneType.Exile)) { - movedCard = Singletons.getModel().getGame().getAction().exile(c); + movedCard = game.getAction().exile(c); if (sa.hasParam("ExileFaceDown")) { movedCard.setState(CardCharacteristicName.FaceDown); } } else { - movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c); + movedCard = game.getAction().moveTo(destination, c); } if (champion) { final HashMap runParams = new HashMap(); runParams.put("Card", card); runParams.put("Championed", c); - Singletons.getModel().getGame().getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false); + game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false); } if (remember != null) { diff --git a/src/main/java/forge/card/ability/effects/ChangeZoneEffect.java b/src/main/java/forge/card/ability/effects/ChangeZoneEffect.java index 9c05ac43e4d..84ec7b6dcbf 100644 --- a/src/main/java/forge/card/ability/effects/ChangeZoneEffect.java +++ b/src/main/java/forge/card/ability/effects/ChangeZoneEffect.java @@ -11,7 +11,6 @@ import forge.CardCharacteristicName; import forge.CardLists; import forge.CardPredicates; import forge.GameEntity; -import forge.Singletons; import forge.card.ability.AbilityUtils; import forge.card.ability.SpellAbilityEffect; import forge.card.ability.ai.ChangeZoneAi; @@ -20,6 +19,7 @@ import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbilityStackInstance; import forge.card.spellability.Target; import forge.card.trigger.TriggerType; +import forge.game.GameState; import forge.game.ai.ComputerUtilCard; import forge.game.player.AIPlayer; import forge.game.player.HumanPlayer; @@ -375,6 +375,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { final Target tgt = sa.getTarget(); final Player player = sa.getActivatingPlayer(); final Card hostCard = sa.getSourceCard(); + final GameState game = player.getGame(); final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination")); final List origin = ZoneType.listValueOf(sa.getParam("Origin")); @@ -400,12 +401,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect { continue; } - final SpellAbilityStackInstance si = Singletons.getModel().getGame().getStack().getInstanceFromSpellAbility(tgtSA); + final SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(tgtSA); if (si == null) { continue; } - removeFromStack(tgtSA, sa, si); + removeFromStack(tgtSA, sa, si, game); } // End of change from stack final String remember = sa.getParam("RememberChanged"); @@ -431,7 +432,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (player.isHuman() && optional && !GuiDialog.confirm(hostCard, prompt)) { continue; } - final Zone originZone = Singletons.getModel().getGame().getZoneOf(tgtC); + final Zone originZone = game.getZoneOf(tgtC); // if Target isn't in the expected Zone, continue @@ -445,7 +446,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { // library position is zero indexed final int libraryPosition = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : 0; - movedCard = Singletons.getModel().getGame().getAction().moveToLibrary(tgtC, libraryPosition); + movedCard = game.getAction().moveToLibrary(tgtC, libraryPosition); // for things like Gaea's Blessing if (sa.hasParam("Shuffle")) { @@ -459,16 +460,16 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (sa.hasParam("GainControl")) { if (sa.hasParam("NewController")) { final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("NewController"), sa).get(0); - tgtC.setController(p, Singletons.getModel().getGame().getNextTimestamp()); + tgtC.setController(p, game.getNextTimestamp()); } else { - tgtC.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp()); + tgtC.setController(sa.getActivatingPlayer(), game.getNextTimestamp()); } } if (sa.hasParam("AttachedTo")) { List list = AbilityUtils.getDefinedCards(hostCard, sa.getParam("AttachedTo"), sa); if (list.isEmpty()) { - list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield); + list = game.getCardsIn(ZoneType.Battlefield); list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), tgtC.getController(), tgtC); } if (!list.isEmpty()) { @@ -511,25 +512,28 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } } - movedCard = Singletons.getModel().getGame().getAction() - .moveTo(tgtC.getController().getZone(destination), tgtC); + movedCard = game.getAction().moveTo(tgtC.getController().getZone(destination), tgtC); if (sa.hasParam("Ninjutsu") || sa.hasParam("Attacking")) { - Singletons.getModel().getGame().getCombat().addAttacker(tgtC); - Singletons.getModel().getGame().getCombat().addUnblockedAttacker(tgtC); + // What should they attack? + List defenders = game.getCombat().getDefenders(); + if (!defenders.isEmpty()) { + game.getCombat().addAttacker(tgtC, defenders.get(0)); + game.getCombat().addUnblockedAttacker(tgtC); + } } if (sa.hasParam("Tapped") || sa.hasParam("Ninjutsu")) { tgtC.setTapped(true); } } else { - movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, tgtC); + movedCard = game.getAction().moveTo(destination, tgtC); // If a card is Exiled from the stack, remove its spells from the stack if (sa.hasParam("Fizzle")) { ArrayList spells = tgtC.getSpellAbilities(); for (SpellAbility spell : spells) { if (tgtC.isInZone(ZoneType.Exile)) { - final SpellAbilityStackInstance si = Singletons.getModel().getGame().getStack().getInstanceFromSpellAbility(spell); - Singletons.getModel().getGame().getStack().remove(si); + final SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(spell); + game.getStack().remove(si); } } } @@ -615,6 +619,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { final List movedCards = new ArrayList(); final boolean defined = sa.hasParam("Defined"); final boolean optional = sa.hasParam("Optional"); + final GameState game = player.getGame(); final Target tgt = sa.getTarget(); if (tgt != null) { @@ -675,7 +680,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } } else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand) && !sa.hasParam("DefinedPlayer")) { - fetchList = Singletons.getModel().getGame().getCardsIn(origin); + fetchList = game.getCardsIn(origin); } else { fetchList = player.getCardsIn(origin); } @@ -744,7 +749,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (origin.contains(ZoneType.Library) && (i < 1) && !"False".equals(sa.getParam("Shuffle"))) { player.shuffle(); } - movedCard = Singletons.getModel().getGame().getAction().moveToLibrary(c, libraryPos); + movedCard = game.getAction().moveToLibrary(c, libraryPos); } else if (destination.equals(ZoneType.Battlefield)) { if (sa.hasParam("Tapped")) { c.setTapped(true); @@ -752,9 +757,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (sa.hasParam("GainControl")) { if (sa.hasParam("NewController")) { final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("NewController"), sa).get(0); - c.setController(p, Singletons.getModel().getGame().getNextTimestamp()); + c.setController(p, game.getNextTimestamp()); } else { - c.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp()); + c.setController(sa.getActivatingPlayer(), game.getNextTimestamp()); } } @@ -762,7 +767,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { List list = AbilityUtils.getDefinedCards(sa.getSourceCard(), sa.getParam("AttachedTo"), sa); if (list.isEmpty()) { - list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield); + list = game.getCardsIn(ZoneType.Battlefield); list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), c.getController(), c); } if (!list.isEmpty()) { @@ -826,20 +831,20 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (sa.hasParam("Attacking")) { final List e = c.getController().getGame().getCombat().getDefenders(); final GameEntity defender = e.size() == 1 ? e.get(0) : GuiChoose.one("Declare " + c, e); - Singletons.getModel().getGame().getCombat().addAttacker(c, defender); + game.getCombat().addAttacker(c, defender); } - movedCard = Singletons.getModel().getGame().getAction().moveTo(c.getController().getZone(destination), c); + movedCard = game.getAction().moveTo(c.getController().getZone(destination), c); if (sa.hasParam("Tapped")) { movedCard.setTapped(true); } } else if (destination.equals(ZoneType.Exile)) { - movedCard = Singletons.getModel().getGame().getAction().exile(c); + movedCard = game.getAction().exile(c); if (sa.hasParam("ExileFaceDown")) { movedCard.setState(CardCharacteristicName.FaceDown); } } else { - movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c); + movedCard = game.getAction().moveTo(destination, c); } movedCards.add(movedCard); @@ -847,7 +852,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { final HashMap runParams = new HashMap(); runParams.put("Card", card); runParams.put("Championed", c); - Singletons.getModel().getGame().getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false); + game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false); } if (remember != null) { @@ -895,28 +900,29 @@ public class ChangeZoneEffect extends SpellAbilityEffect { * @param si * a {@link forge.card.spellability.SpellAbilityStackInstance} * object. + * @param game */ - private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si) { - Singletons.getModel().getGame().getStack().remove(si); + private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si, final GameState game) { + game.getStack().remove(si); if (srcSA.hasParam("Destination")) { final boolean remember = srcSA.hasParam("RememberChanged"); if (tgtSA.isAbility()) { // Shouldn't be able to target Abilities but leaving this in for now } else if (tgtSA.isFlashBackAbility()) { - Singletons.getModel().getGame().getAction().exile(tgtSA.getSourceCard()); + game.getAction().exile(tgtSA.getSourceCard()); } else if (srcSA.getParam("Destination").equals("Graveyard")) { - Singletons.getModel().getGame().getAction().moveToGraveyard(tgtSA.getSourceCard()); + game.getAction().moveToGraveyard(tgtSA.getSourceCard()); } else if (srcSA.getParam("Destination").equals("Exile")) { - Singletons.getModel().getGame().getAction().exile(tgtSA.getSourceCard()); + game.getAction().exile(tgtSA.getSourceCard()); } else if (srcSA.getParam("Destination").equals("TopOfLibrary")) { - Singletons.getModel().getGame().getAction().moveToLibrary(tgtSA.getSourceCard()); + game.getAction().moveToLibrary(tgtSA.getSourceCard()); } else if (srcSA.getParam("Destination").equals("Hand")) { - Singletons.getModel().getGame().getAction().moveToHand(tgtSA.getSourceCard()); + game.getAction().moveToHand(tgtSA.getSourceCard()); } else if (srcSA.getParam("Destination").equals("BottomOfLibrary")) { - Singletons.getModel().getGame().getAction().moveToBottomOfLibrary(tgtSA.getSourceCard()); + game.getAction().moveToBottomOfLibrary(tgtSA.getSourceCard()); } else if (srcSA.getParam("Destination").equals("ShuffleIntoLibrary")) { - Singletons.getModel().getGame().getAction().moveToBottomOfLibrary(tgtSA.getSourceCard()); + game.getAction().moveToBottomOfLibrary(tgtSA.getSourceCard()); tgtSA.getSourceCard().getController().shuffle(); } else { throw new IllegalArgumentException("AbilityFactory_ChangeZone: Invalid Destination argument for card " diff --git a/src/main/java/forge/card/ability/effects/TokenEffect.java b/src/main/java/forge/card/ability/effects/TokenEffect.java index 0e1c03b75fa..e7b228863a1 100644 --- a/src/main/java/forge/card/ability/effects/TokenEffect.java +++ b/src/main/java/forge/card/ability/effects/TokenEffect.java @@ -22,7 +22,7 @@ import java.util.List; import forge.Card; import forge.GameEntity; -import forge.Singletons; + import forge.card.ability.AbilityFactory; import forge.card.ability.AbilityUtils; import forge.card.ability.SpellAbilityEffect; @@ -30,6 +30,7 @@ import forge.card.cardfactory.CardFactory; import forge.card.spellability.SpellAbility; import forge.card.trigger.Trigger; import forge.card.trigger.TriggerHandler; +import forge.game.GameState; import forge.game.event.TokenCreatedEvent; import forge.game.player.Player; import forge.gui.GuiChoose; @@ -206,9 +207,9 @@ public class TokenEffect extends SpellAbilityEffect { final List tokens = CardFactory.makeToken(substitutedName, imageName, controller, cost, substitutedTypes, finalPower, finalToughness, this.tokenKeywords); for(Card tok : tokens) { - Singletons.getModel().getGame().getAction().moveToPlay(tok); + controller.getGame().getAction().moveToPlay(tok); } - Singletons.getModel().getGame().getEvents().post(new TokenCreatedEvent()); + controller.getGame().getEvents().post(new TokenCreatedEvent()); // Grant rule changes if (this.tokenHiddenKeywords != null) { @@ -274,25 +275,25 @@ public class TokenEffect extends SpellAbilityEffect { } } + final GameState game = controller.getGame(); for (final Card c : tokens) { if (this.tokenTapped) { c.setTapped(true); } if (this.tokenAttacking) { + final List defs = c.getController().getGame().getCombat().getDefenders(); if (c.getController().isHuman()) { - final List e = c.getController().getGame().getCombat().getDefenders(); - final GameEntity defender = e.size() == 1 - ? e.get(0) : GuiChoose.one("Declare " + c, e); - Singletons.getModel().getGame().getCombat().addAttacker(c, defender); + final GameEntity defender = defs.size() == 1 ? defs.get(0) : GuiChoose.one("Declare " + c, defs); + game.getCombat().addAttacker(c, defender); } else { - Singletons.getModel().getGame().getCombat().addAttacker(c); + game.getCombat().addAttacker(c, defs.get(0)); } } if (remember != null) { - Singletons.getModel().getGame().getCardState(sa.getSourceCard()).addRemembered(c); + game.getCardState(sa.getSourceCard()).addRemembered(c); } if (sa.getParam("RememberSource") != null) { - Singletons.getModel().getGame().getCardState(c).addRemembered(host); + game.getCardState(c).addRemembered(host); } } } diff --git a/src/main/java/forge/control/input/InputAttack.java b/src/main/java/forge/control/input/InputAttack.java index fe4063d934a..6739943aef9 100644 --- a/src/main/java/forge/control/input/InputAttack.java +++ b/src/main/java/forge/control/input/InputAttack.java @@ -76,8 +76,14 @@ public class InputAttack extends InputBase { List possibleAttackers = player.getCardsIn(ZoneType.Battlefield); for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) { - if (c.hasKeyword("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c, game.getCombat()) ) { - game.getCombat().addAttacker(c, currentDefender); + if (!c.hasKeyword("CARDNAME attacks each turn if able.")) + continue; // do not force + + for(GameEntity def : defenders ) { + if( CombatUtil.canAttack(c, def, game.getCombat()) ) { + game.getCombat().addAttacker(c, currentDefender); + break; + } } } } @@ -125,7 +131,7 @@ public class InputAttack extends InputBase { } Zone zone = game.getZoneOf(card); - if (zone.is(ZoneType.Battlefield, player) && CombatUtil.canAttack(card, game.getCombat())) { + if (zone.is(ZoneType.Battlefield, player) && CombatUtil.canAttack(card, currentDefender, game.getCombat())) { // TODO add the propaganda code here and remove it in // Phase.nextPhase() diff --git a/src/main/java/forge/game/ai/AiAttackController.java b/src/main/java/forge/game/ai/AiAttackController.java index a3fdf7afc39..60f8028f349 100644 --- a/src/main/java/forge/game/ai/AiAttackController.java +++ b/src/main/java/forge/game/ai/AiAttackController.java @@ -445,7 +445,7 @@ public class AiAttackController { * @param bAssault * a boolean. */ - public final void chooseDefender(final Combat c, final boolean bAssault) { + public final GameEntity chooseDefender(final Combat c, final Combat gameCombat, final boolean bAssault) { final List defs = c.getDefenders(); // Start with last planeswalker @@ -453,23 +453,17 @@ public class AiAttackController { final GameEntity entity = ai.getMustAttackEntity(); if (null != entity) { - final List defenders = Singletons.getModel().getGame().getCombat().getDefenders(); + final List defenders = gameCombat.getDefenders(); n = defenders.indexOf(entity); if (-1 == n) { System.out.println("getMustAttackEntity() returned something not in defenders."); - c.setCurrentDefenderNumber(0); + return defs.get(0); } else { - c.setCurrentDefenderNumber(n); + return entity; } } else { - if (bAssault) { - c.setCurrentDefenderNumber(0); - } else { - c.setCurrentDefenderNumber(n); - } + return defs.get(bAssault ? 0 : n); } - - return; } /** @@ -501,11 +495,11 @@ public class AiAttackController { final boolean bAssault = this.doAssault(ai); // Determine who will be attacked - this.chooseDefender(combat, bAssault); + GameEntity defender = this.chooseDefender(combat, game.getCombat(), bAssault); List attackersLeft = new ArrayList(this.attackers); // Attackers that don't really have a choice for (final Card attacker : this.attackers) { - if (!CombatUtil.canAttack(attacker, combat)) { + if (!CombatUtil.canAttack(attacker, defender, combat)) { continue; } boolean mustAttack = false; @@ -521,7 +515,7 @@ public class AiAttackController { if (mustAttack || attacker.getSacrificeAtEOT() || attacker.getController().getMustAttackEntity() != null || attacker.getSVar("MustAttack").equals("True")) { - combat.addAttacker(attacker); + combat.addAttacker(attacker, defender); attackersLeft.remove(attacker); } } @@ -532,8 +526,8 @@ public class AiAttackController { System.out.println("Assault"); CardLists.sortByPowerDesc(attackersLeft); for (Card attacker : attackersLeft) { - if (CombatUtil.canAttack(attacker, combat) && this.isEffectiveAttacker(ai, attacker, combat)) { - combat.addAttacker(attacker); + if (CombatUtil.canAttack(attacker, defender, combat) && this.isEffectiveAttacker(ai, attacker, combat)) { + combat.addAttacker(attacker, defender); } } return combat; @@ -566,8 +560,8 @@ public class AiAttackController { System.out.println("Exalted"); this.aiAggression = 6; for (Card attacker : this.attackers) { - if (CombatUtil.canAttack(attacker, combat) && this.shouldAttack(ai, attacker, this.blockers, combat)) { - combat.addAttacker(attacker); + if (CombatUtil.canAttack(attacker, defender, combat) && this.shouldAttack(ai, attacker, this.blockers, combat)) { + combat.addAttacker(attacker, defender); return combat; } } @@ -780,6 +774,7 @@ public class AiAttackController { attackersLeft = this.sortAttackers(attackersLeft); + int iDefender = combat.getDefenders().indexOf(defender); for (int i = 0; i < attackersLeft.size(); i++) { final Card attacker = attackersLeft.get(i); if (this.aiAggression < 5 && !attacker.hasFirstStrike() && !attacker.hasDoubleStrike() @@ -788,16 +783,15 @@ public class AiAttackController { continue; } - if (this.shouldAttack(ai, attacker, this.blockers, combat) - && CombatUtil.canAttack(attacker, combat)) { - combat.addAttacker(attacker); + if (this.shouldAttack(ai, attacker, this.blockers, combat) && CombatUtil.canAttack(attacker, defender, combat)) { + combat.addAttacker(attacker, defender); // check if attackers are enough to finish the attacked planeswalker - if (combat.getCurrentDefenderNumber() > 0) { - Card pw = (Card) combat.getDefender(); + if (iDefender > 0) { + Card pw = (Card) defender; final int blockNum = this.blockers.size(); int attackNum = 0; int damage = 0; - List attacking = combat.getAttackersByDefenderSlot(combat.getCurrentDefenderNumber()); + List attacking = combat.getAttackersByDefenderSlot(iDefender); CardLists.sortByPowerAsc(attacking); for (Card atta : attacking) { if (attackNum >= blockNum || !CombatUtil.canBeBlocked(attacker, this.blockers)) { @@ -808,7 +802,8 @@ public class AiAttackController { } // if enough damage: switch to next planeswalker or player if (damage >= pw.getCounters(CounterType.LOYALTY)) { - combat.setCurrentDefenderNumber(combat.getCurrentDefenderNumber() - 1); + iDefender--; + defender = combat.getDefenders().get(iDefender); } } } diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java index 486a499a7f6..5099a282d64 100644 --- a/src/main/java/forge/game/ai/ComputerUtil.java +++ b/src/main/java/forge/game/ai/ComputerUtil.java @@ -917,7 +917,7 @@ public class ComputerUtil { List attackers = ai.getOpponent().getCreaturesInPlay(); for (Card att : attackers) { if (CombatUtil.canAttackNextTurn(att)) { - combat.addAttacker(att); + combat.addAttacker(att, att.getController().getOpponent()); } } combat = ComputerUtilBlock.getBlockers(ai, combat, ai.getCreaturesInPlay()); diff --git a/src/main/java/forge/game/phase/Combat.java b/src/main/java/forge/game/phase/Combat.java index 14ca1c0f001..547838b89a5 100644 --- a/src/main/java/forge/game/phase/Combat.java +++ b/src/main/java/forge/game/phase/Combat.java @@ -57,7 +57,6 @@ public class Combat { // Defenders are the Defending Player + Each controlled Planeswalker private List defenders = new ArrayList(); private Map> defenderMap = new HashMap>(); - private int currentDefender = 0; // This Hash keeps track of @@ -87,7 +86,6 @@ public class Combat { this.defendingDamageMap.clear(); this.attackingPlayer = null; - this.currentDefender = 0; this.initiatePossibleDefenders(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().getOpponents()); } @@ -125,40 +123,6 @@ public class Combat { } } - /** - *

- * getDefender. - *

- * - * @return a {@link java.lang.Object} object. - */ - public final GameEntity getDefender() { - return this.defenders.get(this.currentDefender); - } - - /** - *

- * Setter for the field currentDefender. - *

- * - * @param def - * a int. - */ - public final void setCurrentDefenderNumber(final int def) { - this.currentDefender = def; - } - - /** - *

- * Setter for the field currentDefender. - *

- * - * @return a int. - */ - public final int getCurrentDefenderNumber() { - return this.currentDefender; - } - /** *

* Getter for the field defenders. @@ -304,18 +268,6 @@ public class Combat { return this.attackerMap.containsKey(c); } - /** - *

- * addAttacker. - *

- * - * @param c - * a {@link forge.Card} object. - */ - public final void addAttacker(final Card c) { - this.addAttacker(c, defenders.get(this.currentDefender)); - } - /** *

* addAttacker. diff --git a/src/main/java/forge/game/phase/CombatUtil.java b/src/main/java/forge/game/phase/CombatUtil.java index 07e2d497f02..d486586af8d 100644 --- a/src/main/java/forge/game/phase/CombatUtil.java +++ b/src/main/java/forge/game/phase/CombatUtil.java @@ -765,10 +765,9 @@ public class CombatUtil { * a {@link forge.game.phase.Combat} object. * @return a boolean. */ - public static boolean canAttack(final Card c, final Combat combat) { - + public static boolean canAttack(final Card c, final GameEntity def, final Combat combat) { int cntAttackers = combat.getAttackers().size(); - final GameEntity def = combat.getDefender(); + for (final Card card : Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield)) { for (final String keyword : card.getKeyword()) { if (keyword.equals("No more than two creatures can attack each combat.") && cntAttackers > 1) { diff --git a/src/main/java/forge/gui/match/controllers/CDock.java b/src/main/java/forge/gui/match/controllers/CDock.java index 5f111610a99..0ada575baf5 100644 --- a/src/main/java/forge/gui/match/controllers/CDock.java +++ b/src/main/java/forge/gui/match/controllers/CDock.java @@ -22,6 +22,7 @@ import java.awt.datatransfer.StringSelection; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; +import java.util.List; import java.util.Map.Entry; import java.util.TreeMap; @@ -191,10 +192,17 @@ public enum CDock implements ICDoc { final PhaseHandler ph = game.getPhaseHandler(); if (ph.is(PhaseType.COMBAT_DECLARE_ATTACKERS, player)) { + List defenders = player.getOpponents(); + for (Card c : CardLists.filter(player.getCardsIn(ZoneType.Battlefield), Presets.CREATURES)) { - if (!c.isAttacking() && CombatUtil.canAttack(c, game.getCombat())) { - game.getCombat().addAttacker(c); - } + if (c.isAttacking()) + continue; + + for(Player defender : defenders) + if( CombatUtil.canAttack(c, defender, game.getCombat())) { + game.getCombat().addAttacker(c, defender); + break; + } } //human.updateObservers();