removed CombatUtil.canAttack method without specifying attack target

This commit is contained in:
Maxmtg
2012-10-23 19:36:47 +00:00
parent 32caaf3ac3
commit 9c7d1fe8b6
13 changed files with 91 additions and 123 deletions

View File

@@ -120,13 +120,6 @@ public final class CardPredicates {
}; };
} }
public static final Predicate<Card> possibleAttackers = new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return (c.isCreature() && CombatUtil.canAttack(c));
}
};
public final static Predicate<Card> isProtectedFrom(final Card source) { public final static Predicate<Card> isProtectedFrom(final Card source) {
return new Predicate<Card>() { return new Predicate<Card>() {
@Override @Override
@@ -184,13 +177,6 @@ public final class CardPredicates {
}; };
public static final Predicate<Card> CREATURES_CAN_ATTACK = new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.isCreature() && CombatUtil.canAttack(c);
}
};
/** /**
* a Predicate<Card> to get all enchantments. * a Predicate<Card> to get all enchantments.
*/ */

View File

@@ -392,11 +392,11 @@ public class AbilityFactoryAttach {
* the logic * the logic
* @return the card * @return the card
*/ */
public static Card attachGeneralAI(final Player aiPlayer, final SpellAbility sa, final List<Card> list, final boolean mandatory, public static Card attachGeneralAI(final Player ai, final SpellAbility sa, final List<Card> list, final boolean mandatory,
final Card attachSource, final String logic) { final Card attachSource, final String logic) {
Player prefPlayer = aiPlayer.getOpponent(); Player prefPlayer = ai.getOpponent();
if ("Pump".equals(logic) || "Animate".equals(logic) ) { if ("Pump".equals(logic) || "Animate".equals(logic) ) {
prefPlayer = aiPlayer; prefPlayer = ai;
} }
// Some ChangeType cards are beneficial, and PrefPlayer should be // Some ChangeType cards are beneficial, and PrefPlayer should be
// changed to represent that // changed to represent that
@@ -415,7 +415,7 @@ public class AbilityFactoryAttach {
} else if ("Curse".equals(logic)) { } else if ("Curse".equals(logic)) {
c = AbilityFactoryAttach.attachAICursePreference(sa, prefList, mandatory, attachSource); c = AbilityFactoryAttach.attachAICursePreference(sa, prefList, mandatory, attachSource);
} else if ("Pump".equals(logic)) { } else if ("Pump".equals(logic)) {
c = AbilityFactoryAttach.attachAIPumpPreference(sa, prefList, mandatory, attachSource); c = AbilityFactoryAttach.attachAIPumpPreference(ai, sa, prefList, mandatory, attachSource);
} else if ("ChangeType".equals(logic)) { } else if ("ChangeType".equals(logic)) {
c = AbilityFactoryAttach.attachAIChangeTypePreference(sa, prefList, mandatory, attachSource); c = AbilityFactoryAttach.attachAIChangeTypePreference(sa, prefList, mandatory, attachSource);
} else if ("KeepTapped".equals(logic)) { } else if ("KeepTapped".equals(logic)) {
@@ -688,7 +688,7 @@ public class AbilityFactoryAttach {
* the attach source * the attach source
* @return the card * @return the card
*/ */
public static Card attachAIPumpPreference(final SpellAbility sa, final List<Card> list, final boolean mandatory, public static Card attachAIPumpPreference(final Player ai, final SpellAbility sa, final List<Card> list, final boolean mandatory,
final Card attachSource) { final Card attachSource) {
// AI For choosing a Card to Pump // AI For choosing a Card to Pump
Card c = null; Card c = null;
@@ -724,7 +724,7 @@ public class AbilityFactoryAttach {
magnetList = CardLists.filter(magnetList, new Predicate<Card>() { magnetList = CardLists.filter(magnetList, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
return CombatUtil.canAttack(c); return CombatUtil.canAttack(c, ai.getOpponent());
} }
}); });

View File

@@ -800,7 +800,8 @@ public final class AbilityFactoryDebuff {
// final Card source = sa.getSourceCard(); // final Card source = sa.getSourceCard();
final Card hostCard = af.getHostCard(); final Card hostCard = af.getHostCard();
final HashMap<String, String> params = af.getMapParams(); final HashMap<String, String> params = af.getMapParams();
final Player opp = ai.getOpponent();
final boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); // to final boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); // to
// prevent // prevent
// runaway // runaway
@@ -812,16 +813,17 @@ public final class AbilityFactoryDebuff {
List<Card> comp = ai.getCardsIn(ZoneType.Battlefield); List<Card> comp = ai.getCardsIn(ZoneType.Battlefield);
comp = CardLists.getValidCards(comp, valid, hostCard.getController(), hostCard); comp = CardLists.getValidCards(comp, valid, hostCard.getController(), hostCard);
List<Card> human = ai.getOpponent().getCardsIn(ZoneType.Battlefield); List<Card> human = opp.getCardsIn(ZoneType.Battlefield);
human = CardLists.getValidCards(human, valid, hostCard.getController(), hostCard); human = CardLists.getValidCards(human, valid, hostCard.getController(), hostCard);
// TODO - add blocking situations here also // TODO - add blocking situations here also
// only count creatures that can attack // only count creatures that can attack
human = CardLists.filter(human, new Predicate<Card>() { human = CardLists.filter(human, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
return CombatUtil.canAttack(c); return CombatUtil.canAttack(c, opp);
} }
}); });

View File

@@ -41,6 +41,7 @@ import forge.card.spellability.Target;
import forge.card.trigger.Trigger; import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerHandler; import forge.card.trigger.TriggerHandler;
import forge.card.trigger.TriggerType; import forge.card.trigger.TriggerType;
import forge.game.GameState;
import forge.game.phase.CombatUtil; import forge.game.phase.CombatUtil;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -252,39 +253,41 @@ public class AbilityFactoryEffect {
* @return a boolean. * @return a boolean.
*/ */
public static boolean effectCanPlayAI(final Player ai, final AbilityFactory af, final SpellAbility sa) { public static boolean effectCanPlayAI(final Player ai, final AbilityFactory af, final SpellAbility sa) {
final GameState game = Singletons.getModel().getGame();
final Random r = MyRandom.getRandom(); final Random r = MyRandom.getRandom();
final HashMap<String, String> params = af.getMapParams(); final HashMap<String, String> params = af.getMapParams();
boolean randomReturn = r.nextFloat() <= .6667; boolean randomReturn = r.nextFloat() <= .6667;
final Player opp = ai.getOpponent();
String logic = ""; String logic = "";
if (params.containsKey("AILogic")) { if (params.containsKey("AILogic")) {
logic = params.get("AILogic"); logic = params.get("AILogic");
final PhaseHandler phase = Singletons.getModel().getGame().getPhaseHandler(); final PhaseHandler phase = game.getPhaseHandler();
if (logic.equals("BeginningOfOppTurn")) { if (logic.equals("BeginningOfOppTurn")) {
if (phase.isPlayerTurn(ai.getOpponent()) || phase.getPhase().isAfter(PhaseType.DRAW)) { if (phase.isPlayerTurn(ai.getOpponent()) || phase.getPhase().isAfter(PhaseType.DRAW)) {
return false; return false;
} }
randomReturn = true; randomReturn = true;
} else if (logic.equals("Fog")) { } else if (logic.equals("Fog")) {
if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) { if (game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) {
return false; return false;
} }
if (!Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) {
return false; return false;
} }
if (Singletons.getModel().getGame().getStack().size() != 0) { if (game.getStack().size() != 0) {
return false; return false;
} }
if (Singletons.getModel().getGame().getPhaseHandler().isPreventCombatDamageThisTurn()) { if (game.getPhaseHandler().isPreventCombatDamageThisTurn()) {
return false; return false;
} }
if (!CombatUtil.lifeInDanger(ai, Singletons.getModel().getGame().getCombat())) { if (!CombatUtil.lifeInDanger(ai, game.getCombat())) {
return false; return false;
} }
final Target tgt = sa.getTarget(); final Target tgt = sa.getTarget();
if (tgt != null) { if (tgt != null) {
tgt.resetTargets(); tgt.resetTargets();
List<Card> list = Singletons.getModel().getGame().getCombat().getAttackerList(); List<Card> list = game.getCombat().getAttackerList();
list = CardLists.getValidCards(list, tgt.getValidTgts(), sa.getActivatingPlayer(), sa.getSourceCard()); list = CardLists.getValidCards(list, tgt.getValidTgts(), sa.getActivatingPlayer(), sa.getSourceCard());
list = CardLists.getTargetableCards(list, sa); list = CardLists.getTargetableCards(list, sa);
Card target = CardFactoryUtil.getBestCreatureAI(list); Card target = CardFactoryUtil.getBestCreatureAI(list);
@@ -298,13 +301,13 @@ public class AbilityFactoryEffect {
randomReturn = true; randomReturn = true;
} else if (logic.equals("Evasion")) { } else if (logic.equals("Evasion")) {
List<Card> comp = ai.getCreaturesInPlay(); List<Card> comp = ai.getCreaturesInPlay();
List<Card> human = ai.getOpponent().getCreaturesInPlay(); List<Card> human = opp.getCreaturesInPlay();
// only count creatures that can attack or block // only count creatures that can attack or block
comp = CardLists.filter(comp, new Predicate<Card>() { comp = CardLists.filter(comp, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
return CombatUtil.canAttack(c); return CombatUtil.canAttack(c, opp);
} }
}); });
human = CardLists.filter(human, new Predicate<Card>() { human = CardLists.filter(human, new Predicate<Card>() {

View File

@@ -40,6 +40,7 @@ import forge.card.spellability.AbilitySub;
import forge.card.spellability.Spell; import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target; import forge.card.spellability.Target;
import forge.game.phase.CombatUtil;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.ComputerUtil; import forge.game.player.ComputerUtil;
@@ -998,7 +999,7 @@ public class AbilityFactoryPermanentState {
*/ */
private static boolean tapPrefTargeting(final Player ai, final Card source, final Target tgt, final AbilityFactory af, private static boolean tapPrefTargeting(final Player ai, final Card source, final Target tgt, final AbilityFactory af,
final SpellAbility sa, final boolean mandatory) { final SpellAbility sa, final boolean mandatory) {
Player opp = ai.getOpponent(); final Player opp = ai.getOpponent();
List<Card> tapList = opp.getCardsIn(ZoneType.Battlefield); List<Card> tapList = opp.getCardsIn(ZoneType.Battlefield);
tapList = CardLists.filter(tapList, Presets.UNTAPPED); tapList = CardLists.filter(tapList, Presets.UNTAPPED);
tapList = CardLists.getValidCards(tapList, tgt.getValidTgts(), source.getController(), source); tapList = CardLists.getValidCards(tapList, tgt.getValidTgts(), source.getController(), source);
@@ -1038,7 +1039,12 @@ public class AbilityFactoryPermanentState {
//Combat has already started //Combat has already started
attackers = Singletons.getModel().getGame().getCombat().getAttackerList(); attackers = Singletons.getModel().getGame().getCombat().getAttackerList();
} else { } else {
attackers = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES_CAN_ATTACK); attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CombatUtil.canAttack(c, opp);
}
});
attackers.remove(sa.getSourceCard()); attackers.remove(sa.getSourceCard());
} }
Predicate<Card> findBlockers = CardPredicates.possibleBlockerForAtLeastOne(attackers); Predicate<Card> findBlockers = CardPredicates.possibleBlockerForAtLeastOne(attackers);
@@ -1051,7 +1057,12 @@ public class AbilityFactoryPermanentState {
&& phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) { && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
// Tap creatures possible blockers before combat during AI's turn. // Tap creatures possible blockers before combat during AI's turn.
if (Iterables.any(tapList, CardPredicates.Presets.CREATURES)) { if (Iterables.any(tapList, CardPredicates.Presets.CREATURES)) {
List<Card> creatureList = CardLists.filter(tapList, CardPredicates.Presets.CREATURES_CAN_ATTACK); List<Card> creatureList = CardLists.filter(tapList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.isCreature() && CombatUtil.canAttack(c, opp);
}
});
choice = CardFactoryUtil.getBestCreatureAI(creatureList); choice = CardFactoryUtil.getBestCreatureAI(creatureList);
} else { // no creatures available } else { // no creatures available
choice = CardFactoryUtil.getMostExpensivePermanentAI(tapList, sa, false); choice = CardFactoryUtil.getMostExpensivePermanentAI(tapList, sa, false);

View File

@@ -318,20 +318,20 @@ public class AbilityFactoryPump {
if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) { if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) {
return false; return false;
} else if (keyword.equals("Defender") || keyword.endsWith("CARDNAME can't attack.")) { } else if (keyword.equals("Defender") || keyword.endsWith("CARDNAME can't attack.")) {
if (ph.isPlayerTurn(ai) || !CombatUtil.canAttack(card) if (ph.isPlayerTurn(ai) || !CombatUtil.canAttack(card, human)
|| (card.getNetCombatDamage() <= 0) || (card.getNetCombatDamage() <= 0)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) { || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return false; return false;
} }
} else if (keyword.endsWith("CARDNAME can't attack or block.")) { } else if (keyword.endsWith("CARDNAME can't attack or block.")) {
if (sa.getAbilityFactory().getMapParams().containsKey("UntilYourNextTurn")) { if (sa.getAbilityFactory().getMapParams().containsKey("UntilYourNextTurn")) {
if (CombatUtil.canAttack(card) || CombatUtil.canBlock(card, true)) { if (CombatUtil.canAttack(card, human) || CombatUtil.canBlock(card, true)) {
return true; return true;
} }
return false; return false;
} }
if (ph.isPlayerTurn(human)) { if (ph.isPlayerTurn(human)) {
if (!CombatUtil.canAttack(card) if (!CombatUtil.canAttack(card, human)
|| (card.getNetCombatDamage() <= 0) || (card.getNetCombatDamage() <= 0)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) { || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return false; return false;
@@ -342,7 +342,12 @@ public class AbilityFactoryPump {
return false; return false;
} }
List<Card> attackers = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.possibleAttackers); List<Card> attackers = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return (c.isCreature() && CombatUtil.canAttack(c, human));
}
});
if (!CombatUtil.canBlockAtLeastOne(card, attackers)) { if (!CombatUtil.canBlockAtLeastOne(card, attackers)) {
return false; return false;
} }
@@ -353,7 +358,12 @@ public class AbilityFactoryPump {
return false; return false;
} }
List<Card> attackers = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.possibleAttackers); List<Card> attackers = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return (c.isCreature() && CombatUtil.canAttack(c, human));
}
});
if (!CombatUtil.canBlockAtLeastOne(card, attackers)) { if (!CombatUtil.canBlockAtLeastOne(card, attackers)) {
return false; return false;
} }
@@ -376,7 +386,7 @@ public class AbilityFactoryPump {
return false; return false;
} }
} else if (keyword.endsWith("CARDNAME attacks each turn if able.")) { } else if (keyword.endsWith("CARDNAME attacks each turn if able.")) {
if (ph.isPlayerTurn(ai) || !CombatUtil.canAttack(card) || !CombatUtil.canBeBlocked(card) if (ph.isPlayerTurn(ai) || !CombatUtil.canAttack(card, human) || !CombatUtil.canBeBlocked(card)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) { || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return false; return false;
} }
@@ -418,7 +428,7 @@ public class AbilityFactoryPump {
|| keyword.contains("Bushido")); || keyword.contains("Bushido"));
// give evasive keywords to creatures that can or do attack // give evasive keywords to creatures that can or do attack
if (evasive) { if (evasive) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| cardsCanBlock.isEmpty()) { || cardsCanBlock.isEmpty()) {
@@ -434,7 +444,7 @@ public class AbilityFactoryPump {
return true; return true;
} }
Predicate<Card> flyingOrReach = Predicates.or(CardPredicates.hasKeyword("Flying"), CardPredicates.hasKeyword("Reach")); Predicate<Card> flyingOrReach = Predicates.or(CardPredicates.hasKeyword("Flying"), CardPredicates.hasKeyword("Reach"));
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| card.getNetCombatDamage() <= 0 || !Iterables.any(cardsCanBlock, Predicates.not(flyingOrReach))) { || card.getNetCombatDamage() <= 0 || !Iterables.any(cardsCanBlock, Predicates.not(flyingOrReach))) {
return false; return false;
@@ -447,7 +457,7 @@ public class AbilityFactoryPump {
&& CombatUtil.lifeInDanger(ai, Singletons.getModel().getGame().getCombat())) { && CombatUtil.lifeInDanger(ai, Singletons.getModel().getGame().getCombat())) {
return true; return true;
} }
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getNotKeyword(cardsCanBlock, "Horsemanship").isEmpty()) { || CardLists.getNotKeyword(cardsCanBlock, "Horsemanship").isEmpty()) {
@@ -474,7 +484,7 @@ public class AbilityFactoryPump {
} }
} }
} else if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) } else if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
&& CombatUtil.canAttack(card)) { && CombatUtil.canAttack(card, opp)) {
List<Card> blockers = opp.getCreaturesInPlay(); List<Card> blockers = opp.getCreaturesInPlay();
for (Card blocker : blockers) { for (Card blocker : blockers) {
if (CombatUtil.canBlock(card, blocker, combat) if (CombatUtil.canBlock(card, blocker, combat)
@@ -485,32 +495,32 @@ public class AbilityFactoryPump {
} }
return false; return false;
} else if (combatRelevant) { } else if (combatRelevant) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)
|| (opp.getCreaturesInPlay().size() < 1) || (opp.getCreaturesInPlay().size() < 1)
|| cardsCanBlock.isEmpty()) { || cardsCanBlock.isEmpty()) {
return false; return false;
} }
} else if (keyword.equals("Double Strike")) { } else if (keyword.equals("Double Strike")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) {
return false; return false;
} }
} else if (keyword.startsWith("Rampage")) { } else if (keyword.startsWith("Rampage")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| cardsCanBlock.size() < 2) { || cardsCanBlock.size() < 2) {
return false; return false;
} }
} else if (keyword.startsWith("Flanking")) { } else if (keyword.startsWith("Flanking")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| CardLists.getNotKeyword(cardsCanBlock, "Flanking").isEmpty()) { || CardLists.getNotKeyword(cardsCanBlock, "Flanking").isEmpty()) {
return false; return false;
} }
} else if (keyword.startsWith("Trample")) { } else if (keyword.startsWith("Trample")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| !CombatUtil.canBeBlocked(card) || !CombatUtil.canBeBlocked(card)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| cardsCanBlock.isEmpty() || cardsCanBlock.isEmpty()
@@ -525,7 +535,7 @@ public class AbilityFactoryPump {
return true; return true;
} }
if ((ph.isPlayerTurn(opp)) if ((ph.isPlayerTurn(opp))
|| !(CombatUtil.canAttack(card) || card.isAttacking()) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) {
return false; return false;
} }
@@ -548,7 +558,7 @@ public class AbilityFactoryPump {
return false; return false;
} }
} else if (keyword.equals("Vigilance")) { } else if (keyword.equals("Vigilance")) {
if (ph.isPlayerTurn(opp) || !CombatUtil.canAttack(card) if (ph.isPlayerTurn(opp) || !CombatUtil.canAttack(card, opp)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| CardLists.getNotKeyword(opp.getCreaturesInPlay(), "Defender").size() < 1) { || CardLists.getNotKeyword(opp.getCreaturesInPlay(), "Defender").size() < 1) {
return false; return false;
@@ -584,7 +594,7 @@ public class AbilityFactoryPump {
return false; return false;
} }
} else if (keyword.equals("Islandwalk")) { } else if (keyword.equals("Islandwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getType(opp.getLandsInPlay(), "Island").isEmpty() || CardLists.getType(opp.getLandsInPlay(), "Island").isEmpty()
@@ -592,7 +602,7 @@ public class AbilityFactoryPump {
return false; return false;
} }
} else if (keyword.equals("Swampwalk")) { } else if (keyword.equals("Swampwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getType(opp.getLandsInPlay(), "Swamp").isEmpty() || CardLists.getType(opp.getLandsInPlay(), "Swamp").isEmpty()
@@ -600,7 +610,7 @@ public class AbilityFactoryPump {
return false; return false;
} }
} else if (keyword.equals("Mountainwalk")) { } else if (keyword.equals("Mountainwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getType(opp.getLandsInPlay(), "Mountain").isEmpty() || CardLists.getType(opp.getLandsInPlay(), "Mountain").isEmpty()
@@ -608,7 +618,7 @@ public class AbilityFactoryPump {
return false; return false;
} }
} else if (keyword.equals("Forestwalk")) { } else if (keyword.equals("Forestwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card) || card.isAttacking()) if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getType(opp.getLandsInPlay(), "Forest").isEmpty() || CardLists.getType(opp.getLandsInPlay(), "Forest").isEmpty()
@@ -1810,7 +1820,7 @@ public class AbilityFactoryPump {
if (phase.equals(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) && c.isAttacking()) { if (phase.equals(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) && c.isAttacking()) {
return true; return true;
} }
if (phase.isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && CombatUtil.canAttack(c)) { if (phase.isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && CombatUtil.canAttack(c, opp)) {
return true; return true;
} }
return false; return false;

View File

@@ -291,7 +291,7 @@ public class SpellPermanent extends Spell {
} }
// Wait for Main2 if possible // Wait for Main2 if possible
if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.MAIN1) if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.MAIN1)
&& !ComputerUtil.castPermanentInMain1(this, ai)) { && !ComputerUtil.castPermanentInMain1(ai, this)) {
return false; return false;
} }
// save cards with flash for surprise blocking // save cards with flash for surprise blocking

View File

@@ -3,7 +3,6 @@ package forge.card.trigger;
import java.util.HashMap; import java.util.HashMap;
import forge.Card; import forge.Card;
import forge.card.TriggerReplacementBase;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
/** /**

View File

@@ -546,7 +546,7 @@ public class Combat {
*/ */
public Player getDefendingPlayerRelatedTo(final Card source) { public Player getDefendingPlayerRelatedTo(final Card source) {
Player defender = Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().getOpponent(); Player defender = getDefenderPlayerByAttacker(source);
Card attacker = source; Card attacker = source;
if (source.isAura()) { if (source.isAura()) {
attacker = source.getEnchantingCard(); attacker = source.getEnchantingCard();

View File

@@ -810,32 +810,9 @@ public class CombatUtil {
if (cntAttackers > 0 && Singletons.getModel().getGame().isCardInPlay("Dueling Grounds")) { if (cntAttackers > 0 && Singletons.getModel().getGame().isCardInPlay("Dueling Grounds")) {
return false; return false;
} }
Player defender = c.getController().getOpponent();
if (combat != null) {
final GameEntity def = combat.getDefender();
if (def instanceof Player) {
defender = (Player) def;
} else {
defender = ((Card) def).getController();
}
}
return CombatUtil.canAttack(c, defender); final GameEntity def = combat.getDefender();
} return CombatUtil.canAttack(c, def instanceof Player ? (Player) def : ((Card) def).getController());
// can a creature attack at the moment?
/**
* <p>
* canAttack.
* </p>
*
* @param c
* a {@link forge.Card} object.
* @return a boolean.
*/
public static boolean canAttack(final Card c) {
return canAttack(c, c.getController().getOpponent());
} }
// can a creature attack at the moment? // can a creature attack at the moment?

View File

@@ -1768,8 +1768,7 @@ public class ComputerUtil {
*/ */
public static Combat getAttackers(final Player ai) { public static Combat getAttackers(final Player ai) {
final Player opp = ai.getOpponent(); final Player opp = ai.getOpponent();
final ComputerUtilAttack att = new ComputerUtilAttack(ai.getCardsIn(ZoneType.Battlefield), final ComputerUtilAttack att = new ComputerUtilAttack(ai, opp);
opp.getCardsIn(ZoneType.Battlefield));
return att.getAttackers(ai, opp); return att.getAttackers(ai, opp);
} }
@@ -2040,7 +2039,7 @@ public class ComputerUtil {
* a SpellAbility object. * a SpellAbility object.
* @return a boolean. * @return a boolean.
*/ */
public static boolean castPermanentInMain1(final SpellAbility sa, final Player ai) { public static boolean castPermanentInMain1(final Player ai, final SpellAbility sa) {
final Card card = sa.getSourceCard(); final Card card = sa.getSourceCard();
if (card.getSVar("PlayMain1").equals("TRUE")) { if (card.getSVar("PlayMain1").equals("TRUE")) {
return true; return true;
@@ -2061,7 +2060,7 @@ public class ComputerUtil {
return true; return true;
} }
} }
if (card.isEquipment() && buffedcard.isCreature() && CombatUtil.canAttack(buffedcard)) { if (card.isEquipment() && buffedcard.isCreature() && CombatUtil.canAttack(buffedcard, ai.getOpponent())) {
return true; return true;
} }
if (card.isCreature() && buffedcard.hasKeyword("Soulbond") && !buffedcard.isPaired()) { if (card.isCreature() && buffedcard.hasKeyword("Soulbond") && !buffedcard.isPaired()) {

View File

@@ -26,7 +26,6 @@ import com.google.common.base.Predicate;
import forge.Card; import forge.Card;
import forge.CardLists; import forge.CardLists;
import forge.CardPredicates;
import forge.Counters; import forge.Counters;
import forge.GameEntity; import forge.GameEntity;
import forge.Singletons; import forge.Singletons;
@@ -74,15 +73,16 @@ public class ComputerUtilAttack {
* @param possibleBlockers * @param possibleBlockers
* a {@link forge.CardList} object. * a {@link forge.CardList} object.
*/ */
public ComputerUtilAttack(final List<Card> possibleAttackers, final List<Card> possibleBlockers) { public ComputerUtilAttack(final Player ai, final Player human) {
this.humanList = new ArrayList<Card>(possibleBlockers); this.humanList = human.getCreaturesInPlay();
this.humanList = CardLists.filter(this.humanList, CardPredicates.Presets.CREATURES); this.computerList = ai.getCreaturesInPlay();
this.computerList = new ArrayList<Card>(possibleAttackers); this.attackers = new ArrayList<Card>();
this.computerList = CardLists.filter(this.computerList, CardPredicates.Presets.CREATURES); for(Card c : computerList)
if (CombatUtil.canAttack(c, human))
this.attackers = this.getPossibleAttackers(possibleAttackers); attackers.add(c);
this.blockers = this.getPossibleBlockers(possibleBlockers, this.attackers);
this.blockers = this.getPossibleBlockers(humanList, this.attackers);
} // constructor } // constructor
/** /**
@@ -157,26 +157,6 @@ public class ComputerUtilAttack {
return false; return false;
} }
/**
* <p>
* getPossibleAttackers.
* </p>
*
* @param in
* a {@link forge.CardList} object.
* @return a {@link forge.CardList} object.
*/
public final List<Card> getPossibleAttackers(final List<Card> in) {
List<Card> list = new ArrayList<Card>(in);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CombatUtil.canAttack(c);
}
});
return list;
} // getPossibleAttackers()
/** /**
* <p> * <p>
* getPossibleBlockers. * getPossibleBlockers.

View File

@@ -164,6 +164,7 @@ public class QuestWinLose extends ControlWinLose {
// TODO: We don't have a enum for difficulty? // TODO: We don't have a enum for difficulty?
int difficulty = qData.getAchievements().getDifficulty(); int difficulty = qData.getAchievements().getDifficulty();
final int wins = qData.getAchievements().getWin(); final int wins = qData.getAchievements().getWin();
// Win case // Win case
if (this.wonMatch) { if (this.wonMatch) {
@@ -189,17 +190,17 @@ public class QuestWinLose extends ControlWinLose {
if ((wins > 0) && ((wins % 80) == 0)) { if ((wins > 0) && ((wins % 80) == 0)) {
this.awardJackpot(); this.awardJackpot();
} }
// Unlock new sets?
if (wins % 50 == 49) {
unlockSets();
}
} }
// Lose case // Lose case
else { else {
this.penalizeLoss(); this.penalizeLoss();
} }
// Unlock new sets?
if (this.wonMatch && wins % 50 == 49) {
unlockSets();
}
// Grant booster on a win, or on a loss in easy mode // Grant booster on a win, or on a loss in easy mode
if (this.wonMatch || difficulty == 0) { if (this.wonMatch || difficulty == 0) {
final int outcome = this.wonMatch ? wins : qData.getAchievements().getLost(); final int outcome = this.wonMatch ? wins : qData.getAchievements().getLost();