removed the 'currentdefender' field from Combat, each user has to track himself the defenders

canAttack and addAttacker methods now require a defender.
This commit is contained in:
Maxmtg
2013-04-22 19:59:18 +00:00
parent 7984cd3578
commit beeaf3cc50
9 changed files with 125 additions and 155 deletions

View File

@@ -16,7 +16,6 @@ import forge.CardPredicates;
import forge.CardPredicates.Presets; import forge.CardPredicates.Presets;
import forge.Constant; import forge.Constant;
import forge.GameEntity; import forge.GameEntity;
import forge.Singletons;
import forge.card.ability.AbilityUtils; import forge.card.ability.AbilityUtils;
import forge.card.ability.ApiType; import forge.card.ability.ApiType;
import forge.card.ability.SpellAbilityAi; import forge.card.ability.SpellAbilityAi;
@@ -28,6 +27,7 @@ import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target; import forge.card.spellability.Target;
import forge.card.trigger.TriggerType; import forge.card.trigger.TriggerType;
import forge.game.GameState;
import forge.game.GlobalRuleChange; import forge.game.GlobalRuleChange;
import forge.game.ai.ComputerUtil; import forge.game.ai.ComputerUtil;
import forge.game.ai.ComputerUtilBlock; import forge.game.ai.ComputerUtilBlock;
@@ -191,17 +191,17 @@ public class ChangeZoneAi extends SpellAbilityAi {
//Ninjutsu //Ninjutsu
if (sa.hasParam("Ninjutsu")) { if (sa.hasParam("Ninjutsu")) {
if (source.isType("Legendary") if (source.isType("Legendary")
&& !Singletons.getModel().getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) { && !ai.getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) {
final List<Card> list = ai.getCardsIn(ZoneType.Battlefield); final List<Card> list = ai.getCardsIn(ZoneType.Battlefield);
if (Iterables.any(list, CardPredicates.nameEquals(source.getName()))) { if (Iterables.any(list, CardPredicates.nameEquals(source.getName()))) {
return false; return false;
} }
} }
if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE)) { if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE)) {
return false; return false;
} }
List<Card> attackers = new ArrayList<Card>(); List<Card> attackers = new ArrayList<Card>();
attackers.addAll(Singletons.getModel().getGame().getCombat().getUnblockedAttackers()); attackers.addAll(ai.getGame().getCombat().getUnblockedAttackers());
boolean lowerCMC = false; boolean lowerCMC = false;
for (Card attacker : attackers) { for (Card attacker : attackers) {
if (attacker.getCMC() < source.getCMC()) { 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 // 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")) { && !sa.hasParam("ActivationPhases")) {
if (!destination.equals("Battlefield") && !destination.equals("Hand")) { if (!destination.equals("Battlefield") && !destination.equals("Hand")) {
return false; return false;
@@ -495,7 +495,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
combat.initiatePossibleDefenders(ai); combat.initiatePossibleDefenders(ai);
List<Card> attackers = ai.getOpponent().getCreaturesInPlay(); List<Card> attackers = ai.getOpponent().getCreaturesInPlay();
for (Card att : attackers) { for (Card att : attackers) {
combat.addAttacker(att); combat.addAttacker(att, ai);
} }
combat = ComputerUtilBlock.getBlockers(ai, combat, ai.getCreaturesInPlay()); 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 // in general this should only be used to protect from Imminent Harm
// (dying or losing control of) // (dying or losing control of)
if (origin.equals(ZoneType.Battlefield)) { if (origin.equals(ZoneType.Battlefield)) {
if (Singletons.getModel().getGame().getStack().size() == 0) { if (ai.getGame().getStack().size() == 0) {
return false; 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 // don't return something to your hand if your hand is full of good stuff
if (destination.equals(ZoneType.Hand) && origin.equals(ZoneType.Graveyard)) { if (destination.equals(ZoneType.Hand) && origin.equals(ZoneType.Graveyard)) {
final int handSize = ai.getCardsIn(ZoneType.Hand).size(); 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; return false;
} }
if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
&& handSize > 1) { && handSize > 1) {
return false; return false;
} }
if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(ai) if (ai.getGame().getPhaseHandler().isPlayerTurn(ai)
&& handSize >= ai.getMaxHandSize()) { && handSize >= ai.getMaxHandSize()) {
return false; return false;
} }
@@ -688,7 +688,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
tgt.resetTargets(); tgt.resetTargets();
List<Card> list = CardLists.getValidCards(Singletons.getModel().getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source); List<Card> list = CardLists.getValidCards(ai.getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source);
if (sa.hasParam("AITgts")) { if (sa.hasParam("AITgts")) {
list = CardLists.getValidCards(list, sa.getParam("AITgts"), sa.getActivatingPlayer(), source); 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 // check stack for something on the stack that will kill
// anything i control // anything i control
if (Singletons.getModel().getGame().getStack().size() > 0) { if (ai.getGame().getStack().size() > 0) {
final ArrayList<Object> objects = ComputerUtil.predictThreatenedObjects(ai, sa); final ArrayList<Object> objects = ComputerUtil.predictThreatenedObjects(ai, sa);
final List<Card> threatenedTargets = new ArrayList<Card>(); final List<Card> threatenedTargets = new ArrayList<Card>();
@@ -739,7 +739,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
} }
// Save combatants // 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<Card> combatants = CardLists.filter(aiPermanents, CardPredicates.Presets.CREATURES); final List<Card> combatants = CardLists.filter(aiPermanents, CardPredicates.Presets.CREATURES);
CardLists.sortByEvaluateCreature(combatants); CardLists.sortByEvaluateCreature(combatants);
@@ -795,7 +795,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (origin.equals(ZoneType.Battlefield) if (origin.equals(ZoneType.Battlefield)
&& destination.equals(ZoneType.Exile) && destination.equals(ZoneType.Exile)
&& (subApi == ApiType.DelayedTrigger || (subApi == ApiType.ChangeZone && subAffected.equals("Remembered"))) && (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())) { .isAbility())) {
return false; return false;
} }
@@ -805,8 +805,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
// don't rush bouncing stuff when not going to attack // don't rush bouncing stuff when not going to attack
if (!sa.isTrigger() && sa.getPayCosts() != null if (!sa.isTrigger() && sa.getPayCosts() != null
&& Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) && ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
&& Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(ai) && ai.getGame().getPhaseHandler().isPlayerTurn(ai)
&& ai.getCreaturesInPlay().isEmpty()) { && ai.getCreaturesInPlay().isEmpty()) {
return false; return false;
} }
@@ -825,7 +825,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
// Only care about combatants during combat // 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); 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 ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
final Target tgt = sa.getTarget(); final Target tgt = sa.getTarget();
List<Card> list = CardLists.getValidCards(Singletons.getModel().getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source); List<Card> list = CardLists.getValidCards(ai.getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source);
// Narrow down the list: // Narrow down the list:
if (origin.equals(ZoneType.Battlefield)) { if (origin.equals(ZoneType.Battlefield)) {
@@ -1070,6 +1070,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
final Card card = sa.getSourceCard(); final Card card = sa.getSourceCard();
final boolean defined = sa.hasParam("Defined"); final boolean defined = sa.hasParam("Defined");
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final GameState game = ai.getGame();
if (tgt != null) { if (tgt != null) {
if (!tgt.getTargetPlayers().isEmpty()) { if (!tgt.getTargetPlayers().isEmpty()) {
@@ -1101,7 +1102,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
} else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand) } else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand)
&& !sa.hasParam("DefinedPlayer")) { && !sa.hasParam("DefinedPlayer")) {
fetchList = Singletons.getModel().getGame().getCardsIn(origin); fetchList = game.getCardsIn(origin);
fetchList = AbilityUtils.filterListByType(fetchList, type, sa); fetchList = AbilityUtils.filterListByType(fetchList, type, sa);
} else { } else {
fetchList = player.getCardsIn(origin); fetchList = player.getCardsIn(origin);
@@ -1253,7 +1254,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
Card movedCard = null; Card movedCard = null;
if (ZoneType.Library.equals(destination)) { if (ZoneType.Library.equals(destination)) {
final int libraryPos = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : 0; 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)) { } else if (ZoneType.Battlefield.equals(destination)) {
if (sa.hasParam("Tapped")) { if (sa.hasParam("Tapped")) {
c.setTapped(true); c.setTapped(true);
@@ -1261,9 +1262,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (sa.hasParam("GainControl")) { if (sa.hasParam("GainControl")) {
if (sa.hasParam("NewController")) { if (sa.hasParam("NewController")) {
final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("DefinedPlayer"), sa).get(0); 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 { } 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<Card> list = AbilityUtils.getDefinedCards(sa.getSourceCard(), List<Card> list = AbilityUtils.getDefinedCards(sa.getSourceCard(),
sa.getParam("AttachedTo"), sa); sa.getParam("AttachedTo"), sa);
if (list.isEmpty()) { 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); list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), c.getController(), c);
} }
if (!list.isEmpty()) { if (!list.isEmpty()) {
@@ -1289,7 +1290,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
if (sa.hasParam("Attacking")) { if (sa.hasParam("Attacking")) {
Singletons.getModel().getGame().getCombat().addAttacker(c); List<GameEntity> defenders = game.getCombat().getDefenders();
if ( !defenders.isEmpty() )
game.getCombat().addAttacker(c, defenders.get(0));
} }
// Auras without Candidates stay in their current location // Auras without Candidates stay in their current location
if (c.isAura()) { 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")) { if (sa.hasParam("Tapped")) {
movedCard.setTapped(true); movedCard.setTapped(true);
} }
} else if (destination.equals(ZoneType.Exile)) { } else if (destination.equals(ZoneType.Exile)) {
movedCard = Singletons.getModel().getGame().getAction().exile(c); movedCard = game.getAction().exile(c);
if (sa.hasParam("ExileFaceDown")) { if (sa.hasParam("ExileFaceDown")) {
movedCard.setState(CardCharacteristicName.FaceDown); movedCard.setState(CardCharacteristicName.FaceDown);
} }
} else { } else {
movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c); movedCard = game.getAction().moveTo(destination, c);
} }
if (champion) { if (champion) {
final HashMap<String, Object> runParams = new HashMap<String, Object>(); final HashMap<String, Object> runParams = new HashMap<String, Object>();
runParams.put("Card", card); runParams.put("Card", card);
runParams.put("Championed", c); runParams.put("Championed", c);
Singletons.getModel().getGame().getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
} }
if (remember != null) { if (remember != null) {

View File

@@ -11,7 +11,6 @@ import forge.CardCharacteristicName;
import forge.CardLists; import forge.CardLists;
import forge.CardPredicates; import forge.CardPredicates;
import forge.GameEntity; import forge.GameEntity;
import forge.Singletons;
import forge.card.ability.AbilityUtils; import forge.card.ability.AbilityUtils;
import forge.card.ability.SpellAbilityEffect; import forge.card.ability.SpellAbilityEffect;
import forge.card.ability.ai.ChangeZoneAi; import forge.card.ability.ai.ChangeZoneAi;
@@ -20,6 +19,7 @@ import forge.card.spellability.SpellAbility;
import forge.card.spellability.SpellAbilityStackInstance; import forge.card.spellability.SpellAbilityStackInstance;
import forge.card.spellability.Target; import forge.card.spellability.Target;
import forge.card.trigger.TriggerType; import forge.card.trigger.TriggerType;
import forge.game.GameState;
import forge.game.ai.ComputerUtilCard; import forge.game.ai.ComputerUtilCard;
import forge.game.player.AIPlayer; import forge.game.player.AIPlayer;
import forge.game.player.HumanPlayer; import forge.game.player.HumanPlayer;
@@ -375,6 +375,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final Target tgt = sa.getTarget(); final Target tgt = sa.getTarget();
final Player player = sa.getActivatingPlayer(); final Player player = sa.getActivatingPlayer();
final Card hostCard = sa.getSourceCard(); final Card hostCard = sa.getSourceCard();
final GameState game = player.getGame();
final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination")); final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
final List<ZoneType> origin = ZoneType.listValueOf(sa.getParam("Origin")); final List<ZoneType> origin = ZoneType.listValueOf(sa.getParam("Origin"));
@@ -400,12 +401,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
continue; continue;
} }
final SpellAbilityStackInstance si = Singletons.getModel().getGame().getStack().getInstanceFromSpellAbility(tgtSA); final SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(tgtSA);
if (si == null) { if (si == null) {
continue; continue;
} }
removeFromStack(tgtSA, sa, si); removeFromStack(tgtSA, sa, si, game);
} // End of change from stack } // End of change from stack
final String remember = sa.getParam("RememberChanged"); final String remember = sa.getParam("RememberChanged");
@@ -431,7 +432,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (player.isHuman() && optional && !GuiDialog.confirm(hostCard, prompt)) { if (player.isHuman() && optional && !GuiDialog.confirm(hostCard, prompt)) {
continue; continue;
} }
final Zone originZone = Singletons.getModel().getGame().getZoneOf(tgtC); final Zone originZone = game.getZoneOf(tgtC);
// if Target isn't in the expected Zone, continue // if Target isn't in the expected Zone, continue
@@ -445,7 +446,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
// library position is zero indexed // library position is zero indexed
final int libraryPosition = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : 0; 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 // for things like Gaea's Blessing
if (sa.hasParam("Shuffle")) { if (sa.hasParam("Shuffle")) {
@@ -459,16 +460,16 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("GainControl")) { if (sa.hasParam("GainControl")) {
if (sa.hasParam("NewController")) { if (sa.hasParam("NewController")) {
final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("NewController"), sa).get(0); 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 { } else {
tgtC.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp()); tgtC.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
} }
} }
if (sa.hasParam("AttachedTo")) { if (sa.hasParam("AttachedTo")) {
List<Card> list = AbilityUtils.getDefinedCards(hostCard, List<Card> list = AbilityUtils.getDefinedCards(hostCard,
sa.getParam("AttachedTo"), sa); sa.getParam("AttachedTo"), sa);
if (list.isEmpty()) { 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); list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), tgtC.getController(), tgtC);
} }
if (!list.isEmpty()) { if (!list.isEmpty()) {
@@ -511,25 +512,28 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
} }
movedCard = Singletons.getModel().getGame().getAction() movedCard = game.getAction().moveTo(tgtC.getController().getZone(destination), tgtC);
.moveTo(tgtC.getController().getZone(destination), tgtC);
if (sa.hasParam("Ninjutsu") || sa.hasParam("Attacking")) { if (sa.hasParam("Ninjutsu") || sa.hasParam("Attacking")) {
Singletons.getModel().getGame().getCombat().addAttacker(tgtC); // What should they attack?
Singletons.getModel().getGame().getCombat().addUnblockedAttacker(tgtC); List<GameEntity> 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")) { if (sa.hasParam("Tapped") || sa.hasParam("Ninjutsu")) {
tgtC.setTapped(true); tgtC.setTapped(true);
} }
} else { } 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 a card is Exiled from the stack, remove its spells from the stack
if (sa.hasParam("Fizzle")) { if (sa.hasParam("Fizzle")) {
ArrayList<SpellAbility> spells = tgtC.getSpellAbilities(); ArrayList<SpellAbility> spells = tgtC.getSpellAbilities();
for (SpellAbility spell : spells) { for (SpellAbility spell : spells) {
if (tgtC.isInZone(ZoneType.Exile)) { if (tgtC.isInZone(ZoneType.Exile)) {
final SpellAbilityStackInstance si = Singletons.getModel().getGame().getStack().getInstanceFromSpellAbility(spell); final SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(spell);
Singletons.getModel().getGame().getStack().remove(si); game.getStack().remove(si);
} }
} }
} }
@@ -615,6 +619,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final List<Card> movedCards = new ArrayList<Card>(); final List<Card> movedCards = new ArrayList<Card>();
final boolean defined = sa.hasParam("Defined"); final boolean defined = sa.hasParam("Defined");
final boolean optional = sa.hasParam("Optional"); final boolean optional = sa.hasParam("Optional");
final GameState game = player.getGame();
final Target tgt = sa.getTarget(); final Target tgt = sa.getTarget();
if (tgt != null) { if (tgt != null) {
@@ -675,7 +680,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
} else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand) } else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand)
&& !sa.hasParam("DefinedPlayer")) { && !sa.hasParam("DefinedPlayer")) {
fetchList = Singletons.getModel().getGame().getCardsIn(origin); fetchList = game.getCardsIn(origin);
} else { } else {
fetchList = player.getCardsIn(origin); 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"))) { if (origin.contains(ZoneType.Library) && (i < 1) && !"False".equals(sa.getParam("Shuffle"))) {
player.shuffle(); player.shuffle();
} }
movedCard = Singletons.getModel().getGame().getAction().moveToLibrary(c, libraryPos); movedCard = game.getAction().moveToLibrary(c, libraryPos);
} else if (destination.equals(ZoneType.Battlefield)) { } else if (destination.equals(ZoneType.Battlefield)) {
if (sa.hasParam("Tapped")) { if (sa.hasParam("Tapped")) {
c.setTapped(true); c.setTapped(true);
@@ -752,9 +757,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("GainControl")) { if (sa.hasParam("GainControl")) {
if (sa.hasParam("NewController")) { if (sa.hasParam("NewController")) {
final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("NewController"), sa).get(0); 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 { } 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<Card> list = AbilityUtils.getDefinedCards(sa.getSourceCard(), List<Card> list = AbilityUtils.getDefinedCards(sa.getSourceCard(),
sa.getParam("AttachedTo"), sa); sa.getParam("AttachedTo"), sa);
if (list.isEmpty()) { 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); list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), c.getController(), c);
} }
if (!list.isEmpty()) { if (!list.isEmpty()) {
@@ -826,20 +831,20 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("Attacking")) { if (sa.hasParam("Attacking")) {
final List<GameEntity> e = c.getController().getGame().getCombat().getDefenders(); final List<GameEntity> e = c.getController().getGame().getCombat().getDefenders();
final GameEntity defender = e.size() == 1 ? e.get(0) : GuiChoose.one("Declare " + c, e); 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")) { if (sa.hasParam("Tapped")) {
movedCard.setTapped(true); movedCard.setTapped(true);
} }
} else if (destination.equals(ZoneType.Exile)) { } else if (destination.equals(ZoneType.Exile)) {
movedCard = Singletons.getModel().getGame().getAction().exile(c); movedCard = game.getAction().exile(c);
if (sa.hasParam("ExileFaceDown")) { if (sa.hasParam("ExileFaceDown")) {
movedCard.setState(CardCharacteristicName.FaceDown); movedCard.setState(CardCharacteristicName.FaceDown);
} }
} else { } else {
movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c); movedCard = game.getAction().moveTo(destination, c);
} }
movedCards.add(movedCard); movedCards.add(movedCard);
@@ -847,7 +852,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final HashMap<String, Object> runParams = new HashMap<String, Object>(); final HashMap<String, Object> runParams = new HashMap<String, Object>();
runParams.put("Card", card); runParams.put("Card", card);
runParams.put("Championed", c); runParams.put("Championed", c);
Singletons.getModel().getGame().getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
} }
if (remember != null) { if (remember != null) {
@@ -895,28 +900,29 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
* @param si * @param si
* a {@link forge.card.spellability.SpellAbilityStackInstance} * a {@link forge.card.spellability.SpellAbilityStackInstance}
* object. * object.
* @param game
*/ */
private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si) { private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si, final GameState game) {
Singletons.getModel().getGame().getStack().remove(si); game.getStack().remove(si);
if (srcSA.hasParam("Destination")) { if (srcSA.hasParam("Destination")) {
final boolean remember = srcSA.hasParam("RememberChanged"); final boolean remember = srcSA.hasParam("RememberChanged");
if (tgtSA.isAbility()) { if (tgtSA.isAbility()) {
// Shouldn't be able to target Abilities but leaving this in for now // Shouldn't be able to target Abilities but leaving this in for now
} else if (tgtSA.isFlashBackAbility()) { } else if (tgtSA.isFlashBackAbility()) {
Singletons.getModel().getGame().getAction().exile(tgtSA.getSourceCard()); game.getAction().exile(tgtSA.getSourceCard());
} else if (srcSA.getParam("Destination").equals("Graveyard")) { } 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")) { } 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")) { } 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")) { } 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")) { } 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")) { } else if (srcSA.getParam("Destination").equals("ShuffleIntoLibrary")) {
Singletons.getModel().getGame().getAction().moveToBottomOfLibrary(tgtSA.getSourceCard()); game.getAction().moveToBottomOfLibrary(tgtSA.getSourceCard());
tgtSA.getSourceCard().getController().shuffle(); tgtSA.getSourceCard().getController().shuffle();
} else { } else {
throw new IllegalArgumentException("AbilityFactory_ChangeZone: Invalid Destination argument for card " throw new IllegalArgumentException("AbilityFactory_ChangeZone: Invalid Destination argument for card "

View File

@@ -22,7 +22,7 @@ import java.util.List;
import forge.Card; import forge.Card;
import forge.GameEntity; import forge.GameEntity;
import forge.Singletons;
import forge.card.ability.AbilityFactory; import forge.card.ability.AbilityFactory;
import forge.card.ability.AbilityUtils; import forge.card.ability.AbilityUtils;
import forge.card.ability.SpellAbilityEffect; import forge.card.ability.SpellAbilityEffect;
@@ -30,6 +30,7 @@ import forge.card.cardfactory.CardFactory;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.trigger.Trigger; import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerHandler; import forge.card.trigger.TriggerHandler;
import forge.game.GameState;
import forge.game.event.TokenCreatedEvent; import forge.game.event.TokenCreatedEvent;
import forge.game.player.Player; import forge.game.player.Player;
import forge.gui.GuiChoose; import forge.gui.GuiChoose;
@@ -206,9 +207,9 @@ public class TokenEffect extends SpellAbilityEffect {
final List<Card> tokens = CardFactory.makeToken(substitutedName, imageName, controller, cost, final List<Card> tokens = CardFactory.makeToken(substitutedName, imageName, controller, cost,
substitutedTypes, finalPower, finalToughness, this.tokenKeywords); substitutedTypes, finalPower, finalToughness, this.tokenKeywords);
for(Card tok : tokens) { 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 // Grant rule changes
if (this.tokenHiddenKeywords != null) { if (this.tokenHiddenKeywords != null) {
@@ -274,25 +275,25 @@ public class TokenEffect extends SpellAbilityEffect {
} }
} }
final GameState game = controller.getGame();
for (final Card c : tokens) { for (final Card c : tokens) {
if (this.tokenTapped) { if (this.tokenTapped) {
c.setTapped(true); c.setTapped(true);
} }
if (this.tokenAttacking) { if (this.tokenAttacking) {
final List<GameEntity> defs = c.getController().getGame().getCombat().getDefenders();
if (c.getController().isHuman()) { if (c.getController().isHuman()) {
final List<GameEntity> e = c.getController().getGame().getCombat().getDefenders(); final GameEntity defender = defs.size() == 1 ? defs.get(0) : GuiChoose.one("Declare " + c, defs);
final GameEntity defender = e.size() == 1 game.getCombat().addAttacker(c, defender);
? e.get(0) : GuiChoose.one("Declare " + c, e);
Singletons.getModel().getGame().getCombat().addAttacker(c, defender);
} else { } else {
Singletons.getModel().getGame().getCombat().addAttacker(c); game.getCombat().addAttacker(c, defs.get(0));
} }
} }
if (remember != null) { if (remember != null) {
Singletons.getModel().getGame().getCardState(sa.getSourceCard()).addRemembered(c); game.getCardState(sa.getSourceCard()).addRemembered(c);
} }
if (sa.getParam("RememberSource") != null) { if (sa.getParam("RememberSource") != null) {
Singletons.getModel().getGame().getCardState(c).addRemembered(host); game.getCardState(c).addRemembered(host);
} }
} }
} }

View File

@@ -76,8 +76,14 @@ public class InputAttack extends InputBase {
List<Card> possibleAttackers = player.getCardsIn(ZoneType.Battlefield); List<Card> possibleAttackers = player.getCardsIn(ZoneType.Battlefield);
for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) { for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) {
if (c.hasKeyword("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c, game.getCombat()) ) { if (!c.hasKeyword("CARDNAME attacks each turn if able."))
game.getCombat().addAttacker(c, currentDefender); 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); 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 // TODO add the propaganda code here and remove it in
// Phase.nextPhase() // Phase.nextPhase()

View File

@@ -445,7 +445,7 @@ public class AiAttackController {
* @param bAssault * @param bAssault
* a boolean. * 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<GameEntity> defs = c.getDefenders(); final List<GameEntity> defs = c.getDefenders();
// Start with last planeswalker // Start with last planeswalker
@@ -453,23 +453,17 @@ public class AiAttackController {
final GameEntity entity = ai.getMustAttackEntity(); final GameEntity entity = ai.getMustAttackEntity();
if (null != entity) { if (null != entity) {
final List<GameEntity> defenders = Singletons.getModel().getGame().getCombat().getDefenders(); final List<GameEntity> defenders = gameCombat.getDefenders();
n = defenders.indexOf(entity); n = defenders.indexOf(entity);
if (-1 == n) { if (-1 == n) {
System.out.println("getMustAttackEntity() returned something not in defenders."); System.out.println("getMustAttackEntity() returned something not in defenders.");
c.setCurrentDefenderNumber(0); return defs.get(0);
} else { } else {
c.setCurrentDefenderNumber(n); return entity;
} }
} else { } else {
if (bAssault) { return defs.get(bAssault ? 0 : n);
c.setCurrentDefenderNumber(0);
} else {
c.setCurrentDefenderNumber(n);
}
} }
return;
} }
/** /**
@@ -501,11 +495,11 @@ public class AiAttackController {
final boolean bAssault = this.doAssault(ai); final boolean bAssault = this.doAssault(ai);
// Determine who will be attacked // Determine who will be attacked
this.chooseDefender(combat, bAssault); GameEntity defender = this.chooseDefender(combat, game.getCombat(), bAssault);
List<Card> attackersLeft = new ArrayList<Card>(this.attackers); List<Card> attackersLeft = new ArrayList<Card>(this.attackers);
// Attackers that don't really have a choice // Attackers that don't really have a choice
for (final Card attacker : this.attackers) { for (final Card attacker : this.attackers) {
if (!CombatUtil.canAttack(attacker, combat)) { if (!CombatUtil.canAttack(attacker, defender, combat)) {
continue; continue;
} }
boolean mustAttack = false; boolean mustAttack = false;
@@ -521,7 +515,7 @@ public class AiAttackController {
if (mustAttack || attacker.getSacrificeAtEOT() if (mustAttack || attacker.getSacrificeAtEOT()
|| attacker.getController().getMustAttackEntity() != null || attacker.getController().getMustAttackEntity() != null
|| attacker.getSVar("MustAttack").equals("True")) { || attacker.getSVar("MustAttack").equals("True")) {
combat.addAttacker(attacker); combat.addAttacker(attacker, defender);
attackersLeft.remove(attacker); attackersLeft.remove(attacker);
} }
} }
@@ -532,8 +526,8 @@ public class AiAttackController {
System.out.println("Assault"); System.out.println("Assault");
CardLists.sortByPowerDesc(attackersLeft); CardLists.sortByPowerDesc(attackersLeft);
for (Card attacker : attackersLeft) { for (Card attacker : attackersLeft) {
if (CombatUtil.canAttack(attacker, combat) && this.isEffectiveAttacker(ai, attacker, combat)) { if (CombatUtil.canAttack(attacker, defender, combat) && this.isEffectiveAttacker(ai, attacker, combat)) {
combat.addAttacker(attacker); combat.addAttacker(attacker, defender);
} }
} }
return combat; return combat;
@@ -566,8 +560,8 @@ public class AiAttackController {
System.out.println("Exalted"); System.out.println("Exalted");
this.aiAggression = 6; this.aiAggression = 6;
for (Card attacker : this.attackers) { for (Card attacker : this.attackers) {
if (CombatUtil.canAttack(attacker, combat) && this.shouldAttack(ai, attacker, this.blockers, combat)) { if (CombatUtil.canAttack(attacker, defender, combat) && this.shouldAttack(ai, attacker, this.blockers, combat)) {
combat.addAttacker(attacker); combat.addAttacker(attacker, defender);
return combat; return combat;
} }
} }
@@ -780,6 +774,7 @@ public class AiAttackController {
attackersLeft = this.sortAttackers(attackersLeft); attackersLeft = this.sortAttackers(attackersLeft);
int iDefender = combat.getDefenders().indexOf(defender);
for (int i = 0; i < attackersLeft.size(); i++) { for (int i = 0; i < attackersLeft.size(); i++) {
final Card attacker = attackersLeft.get(i); final Card attacker = attackersLeft.get(i);
if (this.aiAggression < 5 && !attacker.hasFirstStrike() && !attacker.hasDoubleStrike() if (this.aiAggression < 5 && !attacker.hasFirstStrike() && !attacker.hasDoubleStrike()
@@ -788,16 +783,15 @@ public class AiAttackController {
continue; continue;
} }
if (this.shouldAttack(ai, attacker, this.blockers, combat) if (this.shouldAttack(ai, attacker, this.blockers, combat) && CombatUtil.canAttack(attacker, defender, combat)) {
&& CombatUtil.canAttack(attacker, combat)) { combat.addAttacker(attacker, defender);
combat.addAttacker(attacker);
// check if attackers are enough to finish the attacked planeswalker // check if attackers are enough to finish the attacked planeswalker
if (combat.getCurrentDefenderNumber() > 0) { if (iDefender > 0) {
Card pw = (Card) combat.getDefender(); Card pw = (Card) defender;
final int blockNum = this.blockers.size(); final int blockNum = this.blockers.size();
int attackNum = 0; int attackNum = 0;
int damage = 0; int damage = 0;
List<Card> attacking = combat.getAttackersByDefenderSlot(combat.getCurrentDefenderNumber()); List<Card> attacking = combat.getAttackersByDefenderSlot(iDefender);
CardLists.sortByPowerAsc(attacking); CardLists.sortByPowerAsc(attacking);
for (Card atta : attacking) { for (Card atta : attacking) {
if (attackNum >= blockNum || !CombatUtil.canBeBlocked(attacker, this.blockers)) { 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 enough damage: switch to next planeswalker or player
if (damage >= pw.getCounters(CounterType.LOYALTY)) { if (damage >= pw.getCounters(CounterType.LOYALTY)) {
combat.setCurrentDefenderNumber(combat.getCurrentDefenderNumber() - 1); iDefender--;
defender = combat.getDefenders().get(iDefender);
} }
} }
} }

View File

@@ -917,7 +917,7 @@ public class ComputerUtil {
List<Card> attackers = ai.getOpponent().getCreaturesInPlay(); List<Card> attackers = ai.getOpponent().getCreaturesInPlay();
for (Card att : attackers) { for (Card att : attackers) {
if (CombatUtil.canAttackNextTurn(att)) { if (CombatUtil.canAttackNextTurn(att)) {
combat.addAttacker(att); combat.addAttacker(att, att.getController().getOpponent());
} }
} }
combat = ComputerUtilBlock.getBlockers(ai, combat, ai.getCreaturesInPlay()); combat = ComputerUtilBlock.getBlockers(ai, combat, ai.getCreaturesInPlay());

View File

@@ -57,7 +57,6 @@ public class Combat {
// Defenders are the Defending Player + Each controlled Planeswalker // Defenders are the Defending Player + Each controlled Planeswalker
private List<GameEntity> defenders = new ArrayList<GameEntity>(); private List<GameEntity> defenders = new ArrayList<GameEntity>();
private Map<GameEntity, List<Card>> defenderMap = new HashMap<GameEntity, List<Card>>(); private Map<GameEntity, List<Card>> defenderMap = new HashMap<GameEntity, List<Card>>();
private int currentDefender = 0;
// This Hash keeps track of // This Hash keeps track of
@@ -87,7 +86,6 @@ public class Combat {
this.defendingDamageMap.clear(); this.defendingDamageMap.clear();
this.attackingPlayer = null; this.attackingPlayer = null;
this.currentDefender = 0;
this.initiatePossibleDefenders(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().getOpponents()); this.initiatePossibleDefenders(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().getOpponents());
} }
@@ -125,40 +123,6 @@ public class Combat {
} }
} }
/**
* <p>
* getDefender.
* </p>
*
* @return a {@link java.lang.Object} object.
*/
public final GameEntity getDefender() {
return this.defenders.get(this.currentDefender);
}
/**
* <p>
* Setter for the field <code>currentDefender</code>.
* </p>
*
* @param def
* a int.
*/
public final void setCurrentDefenderNumber(final int def) {
this.currentDefender = def;
}
/**
* <p>
* Setter for the field <code>currentDefender</code>.
* </p>
*
* @return a int.
*/
public final int getCurrentDefenderNumber() {
return this.currentDefender;
}
/** /**
* <p> * <p>
* Getter for the field <code>defenders</code>. * Getter for the field <code>defenders</code>.
@@ -304,18 +268,6 @@ public class Combat {
return this.attackerMap.containsKey(c); return this.attackerMap.containsKey(c);
} }
/**
* <p>
* addAttacker.
* </p>
*
* @param c
* a {@link forge.Card} object.
*/
public final void addAttacker(final Card c) {
this.addAttacker(c, defenders.get(this.currentDefender));
}
/** /**
* <p> * <p>
* addAttacker. * addAttacker.

View File

@@ -765,10 +765,9 @@ public class CombatUtil {
* a {@link forge.game.phase.Combat} object. * a {@link forge.game.phase.Combat} object.
* @return a boolean. * @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(); int cntAttackers = combat.getAttackers().size();
final GameEntity def = combat.getDefender();
for (final Card card : Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield)) { for (final Card card : Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield)) {
for (final String keyword : card.getKeyword()) { for (final String keyword : card.getKeyword()) {
if (keyword.equals("No more than two creatures can attack each combat.") && cntAttackers > 1) { if (keyword.equals("No more than two creatures can attack each combat.") && cntAttackers > 1) {

View File

@@ -22,6 +22,7 @@ import java.awt.datatransfer.StringSelection;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.io.File; import java.io.File;
import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.TreeMap; import java.util.TreeMap;
@@ -191,10 +192,17 @@ public enum CDock implements ICDoc {
final PhaseHandler ph = game.getPhaseHandler(); final PhaseHandler ph = game.getPhaseHandler();
if (ph.is(PhaseType.COMBAT_DECLARE_ATTACKERS, player)) { if (ph.is(PhaseType.COMBAT_DECLARE_ATTACKERS, player)) {
List<Player> defenders = player.getOpponents();
for (Card c : CardLists.filter(player.getCardsIn(ZoneType.Battlefield), Presets.CREATURES)) { for (Card c : CardLists.filter(player.getCardsIn(ZoneType.Battlefield), Presets.CREATURES)) {
if (!c.isAttacking() && CombatUtil.canAttack(c, game.getCombat())) { if (c.isAttacking())
game.getCombat().addAttacker(c); continue;
}
for(Player defender : defenders)
if( CombatUtil.canAttack(c, defender, game.getCombat())) {
game.getCombat().addAttacker(c, defender);
break;
}
} }
//human.updateObservers(); //human.updateObservers();