Deleted 2 steps that never existed in original game rules: COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY and COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY

This commit is contained in:
Maxmtg
2013-06-02 06:41:12 +00:00
parent d89c998b66
commit 0db4131009
31 changed files with 130 additions and 141 deletions

View File

@@ -60,7 +60,7 @@ public class AnimateAi extends SpellAbilityAi {
// don't use instant speed animate abilities outside humans // don't use instant speed animate abilities outside humans
// Combat_Declare_Attackers_InstantAbility step // Combat_Declare_Attackers_InstantAbility step
if ((!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) if ((!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| (game.getCombat().getAttackers().isEmpty())) || (game.getCombat().getAttackers().isEmpty()))
&& game.getPhaseHandler().isPlayerTurn(opponent)) { && game.getPhaseHandler().isPlayerTurn(opponent)) {
return false; return false;

View File

@@ -77,7 +77,7 @@ public class AttachAi extends SpellAbilityAi {
source.setSVar("PayX", Integer.toString(xPay)); source.setSVar("PayX", Integer.toString(xPay));
} }
if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& !"Curse".equals(sa.getParam("AILogic"))) { && !"Curse".equals(sa.getParam("AILogic"))) {
return false; return false;
} }

View File

@@ -22,7 +22,7 @@ public class BecomesBlockedAi extends SpellAbilityAi {
final Target tgt = sa.getTarget(); final Target tgt = sa.getTarget();
final Game game = aiPlayer.getGame(); final Game game = aiPlayer.getGame();
if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)
|| !game.getPhaseHandler().getPlayerTurn().isOpponentOf(aiPlayer)) { || !game.getPhaseHandler().getPlayerTurn().isOpponentOf(aiPlayer)) {
return false; return false;
} }

View File

@@ -743,7 +743,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
} }
// Save combatants // Save combatants
else if (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { else if (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
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);
@@ -799,7 +799,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")))
&& !(ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || sa && !(ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS) || sa
.isAbility())) { .isAbility())) {
return false; return false;
} }

View File

@@ -62,7 +62,7 @@ public class ChooseCardAi extends SpellAbilityAi {
} else if (sa.getParam("AILogic").equals("Never")) { } else if (sa.getParam("AILogic").equals("Never")) {
return false; return false;
} else if (sa.getParam("AILogic").equals("NeedsPrevention")) { } else if (sa.getParam("AILogic").equals("NeedsPrevention")) {
if (!game.getPhaseHandler().getPhase() .equals(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (!game.getPhaseHandler().getPhase() .equals(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
return false; return false;
} }
choices = CardLists.filter(choices, new Predicate<Card>() { choices = CardLists.filter(choices, new Predicate<Card>() {

View File

@@ -99,8 +99,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
} }
return true; return true;
} }
if (!game.getPhaseHandler().getPhase() if (game.getPhaseHandler().getPhase() != PhaseType.COMBAT_DECLARE_BLOCKERS) {
.equals(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) {
return false; return false;
} }
List<Card> choices = game.getCardsIn(ZoneType.Battlefield); List<Card> choices = game.getCardsIn(ZoneType.Battlefield);

View File

@@ -45,7 +45,7 @@ public class CloneAi extends SpellAbilityAi {
// don't use instant speed clone abilities outside humans // don't use instant speed clone abilities outside humans
// Combat_Declare_Attackers_InstantAbility step // Combat_Declare_Attackers_InstantAbility step
if ((!phase.is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) if ((!phase.is(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| game.getCombat().getAttackers().isEmpty()) || game.getCombat().getAttackers().isEmpty())
&& !phase.isPlayerTurn(ai)) { && !phase.isPlayerTurn(ai)) {
return false; return false;

View File

@@ -108,7 +108,7 @@ public class CountersPutAllAi extends SpellAbilityAi {
&& sa.getPayCosts() != null && sa.getPayCosts().hasTapCost() && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost()
&& sa instanceof AbilitySub && sa instanceof AbilitySub
&& (!phase.getNextTurn().equals(ai) && (!phase.getNextTurn().equals(ai)
|| phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY))) { || phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
boolean combatants = false; boolean combatants = false;
for (Card c : hList) { for (Card c : hList) {
if (!c.equals(source) && c.isUntapped()) { if (!c.equals(source) && c.isUntapped()) {

View File

@@ -65,7 +65,7 @@ public class DamagePreventAi extends SpellAbilityAi {
} }
} else { } else {
PhaseHandler handler = game.getPhaseHandler(); PhaseHandler handler = game.getPhaseHandler();
if (handler.is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (handler.is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
boolean flag = false; boolean flag = false;
for (final Object o : objects) { for (final Object o : objects) {
if (o instanceof Card) { if (o instanceof Card) {
@@ -119,7 +119,7 @@ public class DamagePreventAi extends SpellAbilityAi {
} }
} // Protect combatants } // Protect combatants
else if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { else if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
if (sa.canTarget(ai) && ComputerUtilCombat.wouldLoseLife(ai, game.getCombat()) if (sa.canTarget(ai) && ComputerUtilCombat.wouldLoseLife(ai, game.getCombat())
&& (ComputerUtilCombat.lifeInDanger(ai, game.getCombat()) || sa.isAbility()) && (ComputerUtilCombat.lifeInDanger(ai, game.getCombat()) || sa.isAbility())
&& game.getPhaseHandler().isPlayerTurn(ai.getOpponent())) { && game.getPhaseHandler().isPlayerTurn(ai.getOpponent())) {
@@ -198,7 +198,7 @@ public class DamagePreventAi extends SpellAbilityAi {
if (compTargetables.size() > 0) { if (compTargetables.size() > 0) {
final List<Card> combatants = CardLists.filter(compTargetables, CardPredicates.Presets.CREATURES); final List<Card> combatants = CardLists.filter(compTargetables, CardPredicates.Presets.CREATURES);
CardLists.sortByEvaluateCreature(combatants); CardLists.sortByEvaluateCreature(combatants);
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
for (final Card c : combatants) { for (final Card c : combatants) {
if (ComputerUtilCombat.combatantWouldBeDestroyed(ai, c)) { if (ComputerUtilCombat.combatantWouldBeDestroyed(ai, c)) {
tgt.addTarget(c); tgt.addTarget(c);

View File

@@ -43,7 +43,7 @@ public class DamagePreventAllAi extends SpellAbilityAi {
// control // control
} // Protect combatants } // Protect combatants
else if (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { else if (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
// TODO // TODO
} }

View File

@@ -53,8 +53,8 @@ public class DebuffAi extends SpellAbilityAi {
final PhaseHandler ph = ai.getGame().getPhaseHandler(); final PhaseHandler ph = ai.getGame().getPhaseHandler();
// Phase Restrictions // Phase Restrictions
if (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) if (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|| !ai.getGame().getStack().isEmpty()) { || !ai.getGame().getStack().isEmpty()) {
// Instant-speed pumps should not be cast outside of combat when the // Instant-speed pumps should not be cast outside of combat when the
// stack is empty // stack is empty
@@ -124,7 +124,7 @@ public class DebuffAi extends SpellAbilityAi {
*/ */
private boolean debuffTgtAI(final Player ai, final SpellAbility sa, final List<String> kws, final boolean mandatory) { private boolean debuffTgtAI(final Player ai, final SpellAbility sa, final List<String> kws, final boolean mandatory) {
// this would be for evasive things like Flying, Unblockable, etc // this would be for evasive things like Flying, Unblockable, etc
if (!mandatory && ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (!mandatory && ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
return false; return false;
} }

View File

@@ -46,7 +46,7 @@ public class EffectAi extends SpellAbilityAi {
if (game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) { if (game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) {
return false; return false;
} }
if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
return false; return false;
} }
if (!game.getStack().isEmpty()) { if (!game.getStack().isEmpty()) {

View File

@@ -20,7 +20,7 @@ public class FogAi extends SpellAbilityAi {
if (game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) { if (game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) {
return false; return false;
} }
if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (!game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
return false; return false;
} }

View File

@@ -172,7 +172,7 @@ public class ProtectAi extends SpellAbilityAi {
private boolean protectTgtAI(final Player ai, final SpellAbility sa, final boolean mandatory) { private boolean protectTgtAI(final Player ai, final SpellAbility sa, final boolean mandatory) {
final Game game = ai.getGame(); final Game game = ai.getGame();
if (!mandatory && game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (!mandatory && game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
return false; return false;
} }

View File

@@ -186,7 +186,7 @@ public class PumpAi extends PumpAiBase {
if (!mandatory if (!mandatory
&& !sa.isTrigger() && !sa.isTrigger()
&& game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) && game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& !(sa.isCurse() && (defense < 0)) && !(sa.isCurse() && (defense < 0))
&& !this.containsNonCombatKeyword(keywords) && !this.containsNonCombatKeyword(keywords)
&& !sa.hasParam("UntilYourNextTurn")) { && !sa.hasParam("UntilYourNextTurn")) {

View File

@@ -117,7 +117,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|| keyword.endsWith("Prevent all damage that would be dealt by CARDNAME.")) { || keyword.endsWith("Prevent all damage that would be dealt by CARDNAME.")) {
if (ph.isPlayerTurn(ai) && (!(CombatUtil.canBlock(card) || card.isBlocking()) if (ph.isPlayerTurn(ai) && (!(CombatUtil.canBlock(card) || card.isBlocking())
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|| ph.getPhase().isBefore(PhaseType.MAIN1) || ph.getPhase().isBefore(PhaseType.MAIN1)
|| CardLists.getNotKeyword(ai.getCreaturesInPlay(), "Defender").isEmpty())) { || CardLists.getNotKeyword(ai.getCreaturesInPlay(), "Defender").isEmpty())) {
return false; return false;
@@ -172,14 +172,14 @@ public abstract class PumpAiBase extends SpellAbilityAi {
// 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, opp) || 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)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
return false; return false;
} }
} else if (keyword.endsWith("Flying")) { } else if (keyword.endsWith("Flying")) {
if (ph.isPlayerTurn(opp) if (ph.isPlayerTurn(opp)
&& ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) && ph.getPhase() == PhaseType.COMBAT_DECLARE_ATTACKERS
&& !CardLists.getKeyword(game.getCombat().getAttackers(), "Flying").isEmpty() && !CardLists.getKeyword(game.getCombat().getAttackers(), "Flying").isEmpty()
&& !card.hasKeyword("Reach") && !card.hasKeyword("Reach")
&& CombatUtil.canBlock(card) && CombatUtil.canBlock(card)
@@ -188,7 +188,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
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, opp) || 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)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| !Iterables.any(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), || !Iterables.any(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)),
Predicates.not(flyingOrReach))) { Predicates.not(flyingOrReach))) {
@@ -196,14 +196,14 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} else if (keyword.endsWith("Horsemanship")) { } else if (keyword.endsWith("Horsemanship")) {
if (ph.isPlayerTurn(opp) if (ph.isPlayerTurn(opp)
&& ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) && ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)
&& !CardLists.getKeyword(game.getCombat().getAttackers(), "Horsemanship").isEmpty() && !CardLists.getKeyword(game.getCombat().getAttackers(), "Horsemanship").isEmpty()
&& CombatUtil.canBlock(card) && CombatUtil.canBlock(card)
&& ComputerUtilCombat.lifeInDanger(ai, game.getCombat())) { && ComputerUtilCombat.lifeInDanger(ai, game.getCombat())) {
return true; return true;
} }
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), || CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)),
"Horsemanship").isEmpty()) { "Horsemanship").isEmpty()) {
@@ -221,7 +221,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
return true; return true;
} else if (keyword.endsWith("Deathtouch")) { } else if (keyword.endsWith("Deathtouch")) {
Combat combat = game.getCombat(); Combat combat = game.getCombat();
if (ph.isPlayerTurn(opp) && ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) { if (ph.isPlayerTurn(opp) && ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
List<Card> attackers = combat.getAttackers(); List<Card> attackers = combat.getAttackers();
for (Card attacker : attackers) { for (Card attacker : attackers) {
if (CombatUtil.canBlock(attacker, card, combat) if (CombatUtil.canBlock(attacker, card, combat)
@@ -242,7 +242,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
return false; return false;
} else if (combatRelevant) { } else if (combatRelevant) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| (opp.getCreaturesInPlay().size() < 1) || (opp.getCreaturesInPlay().size() < 1)
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
return false; return false;
@@ -250,18 +250,18 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} else if (keyword.equals("Double Strike")) { } else if (keyword.equals("Double Strike")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)) {
return false; return false;
} }
} else if (keyword.startsWith("Rampage")) { } else if (keyword.startsWith("Rampage")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).size() < 2) { || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).size() < 2) {
return false; return false;
} }
} else if (keyword.startsWith("Flanking")) { } else if (keyword.startsWith("Flanking")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), || CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)),
"Flanking").isEmpty()) { "Flanking").isEmpty()) {
return false; return false;
@@ -269,7 +269,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} else if (keyword.startsWith("Trample")) { } else if (keyword.startsWith("Trample")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| card.getNetCombatDamage() + attack <= 1 || card.getNetCombatDamage() + attack <= 1
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
return false; return false;
@@ -283,7 +283,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
if ((ph.isPlayerTurn(opp)) if ((ph.isPlayerTurn(opp))
|| !(CombatUtil.canAttack(card, opp) || card.isAttacking()) || !(CombatUtil.canAttack(card, opp) || card.isAttacking())
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
return false; return false;
} }
} else if (keyword.endsWith("Wither")) { } else if (keyword.endsWith("Wither")) {
@@ -312,7 +312,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} else if (keyword.equals("Reach")) { } else if (keyword.equals("Reach")) {
if (ph.isPlayerTurn(ai) if (ph.isPlayerTurn(ai)
|| !ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || !ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| CardLists.getKeyword(game.getCombat().getAttackers(), "Flying").isEmpty() || CardLists.getKeyword(game.getCombat().getAttackers(), "Flying").isEmpty()
|| card.hasKeyword("Flying") || card.hasKeyword("Flying")
|| !CombatUtil.canBlock(card)) { || !CombatUtil.canBlock(card)) {
@@ -320,7 +320,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} else if (keyword.endsWith("CARDNAME can block an additional creature.")) { } else if (keyword.endsWith("CARDNAME can block an additional creature.")) {
if (ph.isPlayerTurn(ai) if (ph.isPlayerTurn(ai)
|| !ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) { || !ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return false; return false;
} }
int canBlockNum = 1 + card.getKeywordAmount("CARDNAME can block an additional creature."); int canBlockNum = 1 + card.getKeywordAmount("CARDNAME can block an additional creature.");
@@ -342,7 +342,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} else if (keyword.equals("Islandwalk")) { } else if (keyword.equals("Islandwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getType(opp.getLandsInPlay(), "Island").isEmpty() || CardLists.getType(opp.getLandsInPlay(), "Island").isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
@@ -350,7 +350,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} else if (keyword.equals("Swampwalk")) { } else if (keyword.equals("Swampwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getType(opp.getLandsInPlay(), "Swamp").isEmpty() || CardLists.getType(opp.getLandsInPlay(), "Swamp").isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
@@ -358,7 +358,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} else if (keyword.equals("Mountainwalk")) { } else if (keyword.equals("Mountainwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getType(opp.getLandsInPlay(), "Mountain").isEmpty() || CardLists.getType(opp.getLandsInPlay(), "Mountain").isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
@@ -366,7 +366,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} else if (keyword.equals("Forestwalk")) { } else if (keyword.equals("Forestwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || 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)
|| card.getNetCombatDamage() <= 0 || card.getNetCombatDamage() <= 0
|| CardLists.getType(opp.getLandsInPlay(), "Forest").isEmpty() || CardLists.getType(opp.getLandsInPlay(), "Forest").isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) {
@@ -422,7 +422,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
// is the creature blocking and unable to destroy the attacker // is the creature blocking and unable to destroy the attacker
// or would be destroyed itself? // or would be destroyed itself?
if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) && c.isBlocking()) { if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && c.isBlocking()) {
if (defense > 0 && ComputerUtilCombat.blockerWouldBeDestroyed(ai, c)) { if (defense > 0 && ComputerUtilCombat.blockerWouldBeDestroyed(ai, c)) {
return true; return true;
} }
@@ -435,13 +435,13 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
// is the creature unblocked and the spell will pump its power? // is the creature unblocked and the spell will pump its power?
if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& game.getCombat().isAttacking(c) && game.getCombat().isUnblocked(c) && attack > 0) { && game.getCombat().isAttacking(c) && game.getCombat().isUnblocked(c) && attack > 0) {
return true; return true;
} }
// is the creature blocked and the blocker would survive // is the creature blocked and the blocker would survive
if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) && attack > 0 if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && attack > 0
&& game.getCombat().isAttacking(c) && game.getCombat().isAttacking(c)
&& game.getCombat().isBlocked(c) && game.getCombat().isBlocked(c)
&& game.getCombat().getBlockers(c) != null && game.getCombat().getBlockers(c) != null
@@ -457,7 +457,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
attackerHasTrample |= b.hasKeyword("Trample"); attackerHasTrample |= b.hasKeyword("Trample");
} }
if (phase.getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) if (phase.getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& phase.isPlayerTurn(ai.getOpponent()) && phase.isPlayerTurn(ai.getOpponent())
&& c.isBlocking() && c.isBlocking()
&& defense > 0 && defense > 0

View File

@@ -78,8 +78,8 @@ public class PumpAllAi extends PumpAiBase {
}); // leaves all creatures that will be destroyed }); // leaves all creatures that will be destroyed
} // -X/-X end } // -X/-X end
else if (power < 0) { // -X/-0 else if (power < 0) { // -X/-0
if (phase.isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) if (phase.isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|| phase.isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || phase.isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer()) || game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())
|| game.getPhaseHandler().isPreventCombatDamageThisTurn()) { || game.getPhaseHandler().isPreventCombatDamageThisTurn()) {
return false; return false;
@@ -90,7 +90,7 @@ public class PumpAllAi extends PumpAiBase {
continue; continue;
} }
totalPower += Math.min(c.getNetAttack(), power * -1); totalPower += Math.min(c.getNetAttack(), power * -1);
if (phase == PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY if (phase == PhaseType.COMBAT_DECLARE_BLOCKERS
&& game.getCombat().getUnblockedAttackers().contains(c)) { && game.getCombat().getUnblockedAttackers().contains(c)) {
if (ComputerUtilCombat.lifeInDanger(sa.getActivatingPlayer(), game.getCombat())) { if (ComputerUtilCombat.lifeInDanger(sa.getActivatingPlayer(), game.getCombat())) {
return true; return true;
@@ -113,7 +113,7 @@ public class PumpAllAi extends PumpAiBase {
} // end Curse } // end Curse
// don't use non curse PumpAll after Combat_Begin until AI is improved // don't use non curse PumpAll after Combat_Begin until AI is improved
if (phase.isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || phase.isBefore(PhaseType.MAIN1)) { if (phase.isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || phase.isBefore(PhaseType.MAIN1)) {
return false; return false;
} }
@@ -124,7 +124,7 @@ public class PumpAllAi extends PumpAiBase {
if (power <= 0 && !containsUsefulKeyword(ai, keywords, c, sa, power)) { if (power <= 0 && !containsUsefulKeyword(ai, keywords, c, sa, power)) {
return false; return false;
} }
if (phase.equals(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) && c.isAttacking()) { if (phase.equals(PhaseType.COMBAT_DECLARE_ATTACKERS) && c.isAttacking()) {
return true; return true;
} }
if (phase.isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && CombatUtil.canAttack(c, opp)) { if (phase.isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && CombatUtil.canAttack(c, opp)) {

View File

@@ -92,7 +92,7 @@ public class RegenerateAi extends SpellAbilityAi {
} }
} }
} else { } else {
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
boolean flag = false; boolean flag = false;
for (final Card c : list) { for (final Card c : list) {
@@ -136,7 +136,7 @@ public class RegenerateAi extends SpellAbilityAi {
chance = true; chance = true;
} }
} else { } else {
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
final List<Card> combatants = CardLists.filter(targetables, CardPredicates.Presets.CREATURES); final List<Card> combatants = CardLists.filter(targetables, CardPredicates.Presets.CREATURES);
CardLists.sortByEvaluateCreature(combatants); CardLists.sortByEvaluateCreature(combatants);
@@ -194,7 +194,7 @@ public class RegenerateAi extends SpellAbilityAi {
if (compTargetables.size() > 0) { if (compTargetables.size() > 0) {
final List<Card> combatants = CardLists.filter(compTargetables, CardPredicates.Presets.CREATURES); final List<Card> combatants = CardLists.filter(compTargetables, CardPredicates.Presets.CREATURES);
CardLists.sortByEvaluateCreature(combatants); CardLists.sortByEvaluateCreature(combatants);
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
for (final Card c : combatants) { for (final Card c : combatants) {
if ((c.getShield() == 0) && ComputerUtilCombat.combatantWouldBeDestroyed(ai, c)) { if ((c.getShield() == 0) && ComputerUtilCombat.combatantWouldBeDestroyed(ai, c)) {
tgt.addTarget(c); tgt.addTarget(c);
@@ -207,7 +207,7 @@ public class RegenerateAi extends SpellAbilityAi {
// can target // can target
// choose my best X without regen // choose my best X without regen
if (CardLists.getNotType(compTargetables, "Creature").size() == 0) { if (CardLists.getNotType(compTargetables, "Creature").isEmpty()) {
for (final Card c : combatants) { for (final Card c : combatants) {
if (c.getShield() == 0) { if (c.getShield() == 0) {
tgt.addTarget(c); tgt.addTarget(c);

View File

@@ -65,7 +65,7 @@ public class RegenerateAllAi extends SpellAbilityAi {
} }
} }
} else { } else {
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) { if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
final List<Card> combatants = CardLists.filter(list, CardPredicates.Presets.CREATURES); final List<Card> combatants = CardLists.filter(list, CardPredicates.Presets.CREATURES);
for (final Card c : combatants) { for (final Card c : combatants) {

View File

@@ -111,7 +111,7 @@ public class TokenAi extends SpellAbilityAi {
} }
if ((ph.isPlayerTurn(ai) if ((ph.isPlayerTurn(ai)
|| ph.getPhase().isBefore( || ph.getPhase().isBefore(
PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) PhaseType.COMBAT_DECLARE_ATTACKERS))
&& !sa.hasParam("ActivationPhases") && !sa.hasParam("PlayerTurn") && !sa.hasParam("ActivationPhases") && !sa.hasParam("PlayerTurn")
&& !SpellAbilityAi.isSorcerySpeed(sa) && !haste) { && !SpellAbilityAi.isSorcerySpeed(sa) && !haste) {
return false; return false;
@@ -170,7 +170,7 @@ public class TokenAi extends SpellAbilityAi {
return true; return true;
} }
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) { if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return true; return true;
} }
if (sa.isAbility()) { if (sa.isAbility()) {

View File

@@ -49,7 +49,7 @@ public class UnattachAllAi extends SpellAbilityAi {
source.setSVar("PayX", Integer.toString(xPay)); source.setSVar("PayX", Integer.toString(xPay));
} }
if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& !"Curse".equals(sa.getParam("AILogic"))) { && !"Curse".equals(sa.getParam("AILogic"))) {
return false; return false;
} }

View File

@@ -128,7 +128,7 @@ public class SpellPermanent extends Spell {
&& (ai.isUnlimitedHandSize() || ai.getCardsIn(ZoneType.Hand).size() <= ai.getMaxHandSize()) && (ai.isUnlimitedHandSize() || ai.getCardsIn(ZoneType.Hand).size() <= ai.getMaxHandSize())
&& ai.getManaPool().totalMana() <= 0 && ai.getManaPool().totalMana() <= 0
&& (game.getPhaseHandler().isPlayerTurn(ai) && (game.getPhaseHandler().isPlayerTurn(ai)
|| game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
&& !card.hasETBTrigger()) && !card.hasETBTrigger())
&& !ComputerUtil.castPermanentInMain1(ai, this)) { && !ComputerUtil.castPermanentInMain1(ai, this)) {
return false; return false;

View File

@@ -68,8 +68,8 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
switch(ev.phase) { switch(ev.phase) {
case COMBAT_END: case COMBAT_END:
case COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY: case COMBAT_DECLARE_ATTACKERS:
case COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY: case COMBAT_DECLARE_BLOCKERS:
if( fc.getObservedGame().getPhaseHandler().inCombat() ) if( fc.getObservedGame().getPhaseHandler().inCombat() )
pauseForEvent(combatDelay); pauseForEvent(combatDelay);
break; break;

View File

@@ -787,16 +787,6 @@ public class AiController {
public void onPriorityRecieved() { public void onPriorityRecieved() {
final PhaseType phase = game.getPhaseHandler().getPhase(); final PhaseType phase = game.getPhaseHandler().getPhase();
switch(phase) { switch(phase) {
case COMBAT_DECLARE_ATTACKERS:
declareAttackers();
break;
case COMBAT_DECLARE_BLOCKERS:
final List<Card> blockers = player.getCreaturesInPlay();
game.setCombat(ComputerUtilBlock.getBlockers(player, game.getCombat(), blockers));
CombatUtil.orderMultipleCombatants(game.getCombat());
break;
case MAIN1: case MAIN1:
case MAIN2: case MAIN2:
Log.debug("Computer " + phase.nameForUi); Log.debug("Computer " + phase.nameForUi);
@@ -809,9 +799,15 @@ public class AiController {
break; break;
} }
} }
public void declateBlockers() {
final List<Card> blockers = player.getCreaturesInPlay();
game.setCombat(ComputerUtilBlock.getBlockers(player, game.getCombat(), blockers));
CombatUtil.orderMultipleCombatants(game.getCombat());
}
private void declareAttackers() { public void declareAttackers() {
// 12/2/10(sol) the decision making here has moved to getAttackers() // 12/2/10(sol) the decision making here has moved to getAttackers()
game.setCombat(new AiAttackController(player, player.getOpponent()).getAttackers()); game.setCombat(new AiAttackController(player, player.getOpponent()).getAttackers());

View File

@@ -1017,7 +1017,7 @@ public class ComputerUtil {
return (sa.getSourceCard().isCreature() return (sa.getSourceCard().isCreature()
&& sa.getPayCosts().hasTapCost() && sa.getPayCosts().hasTapCost()
&& (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) && (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)
|| !ph.getNextTurn().equals(sa.getActivatingPlayer()))); || !ph.getNextTurn().equals(sa.getActivatingPlayer())));
} }

View File

@@ -264,17 +264,30 @@ public class PhaseHandler implements java.io.Serializable {
break; break;
case COMBAT_DECLARE_ATTACKERS: case COMBAT_DECLARE_ATTACKERS:
break; game.getStack().freezeStack();
case COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY: playerTurn.getController().declareAttackers();
PhaseUtil.handleDeclareAttackers(game); PhaseUtil.handleDeclareAttackers(game);
this.bCombat = !game.getCombat().getAttackers().isEmpty();
game.getStack().unfreezeStack();
this.nCombatsThisTurn++;
break; break;
case COMBAT_DECLARE_BLOCKERS: case COMBAT_DECLARE_BLOCKERS:
game.getCombat().verifyCreaturesInPlay(); game.getCombat().verifyCreaturesInPlay();
break; game.getStack().freezeStack();
case COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY: Player p = playerTurn;
do {
p = game.getNextPlayerAfter(p);
if ( game.getCombat().isPlayerAttacked(p) )
p.getController().declareBlockers();
} while(p != playerTurn);
game.getStack().unfreezeStack();
PhaseUtil.handleDeclareBlockers(game); PhaseUtil.handleDeclareBlockers(game);
break; break;
@@ -402,17 +415,7 @@ public class PhaseHandler implements java.io.Serializable {
case UNTAP: case UNTAP:
this.nCombatsThisTurn = 0; this.nCombatsThisTurn = 0;
break; break;
case COMBAT_DECLARE_ATTACKERS:
this.bCombat = !game.getCombat().getAttackers().isEmpty();
game.getStack().unfreezeStack();
this.nCombatsThisTurn++;
break;
case COMBAT_DECLARE_BLOCKERS:
game.getStack().unfreezeStack();
break;
case COMBAT_END: case COMBAT_END:
game.getCombat().reset(playerTurn); game.getCombat().reset(playerTurn);
this.getPlayerTurn().resetAttackedThisCombat(); this.getPlayerTurn().resetAttackedThisCombat();
@@ -445,9 +448,7 @@ public class PhaseHandler implements java.io.Serializable {
case COMBAT_DECLARE_ATTACKERS: case COMBAT_DECLARE_ATTACKERS:
return playerTurn.isSkippingCombat(); return playerTurn.isSkippingCombat();
case COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY:
case COMBAT_DECLARE_BLOCKERS: case COMBAT_DECLARE_BLOCKERS:
case COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY:
case COMBAT_FIRST_STRIKE_DAMAGE: case COMBAT_FIRST_STRIKE_DAMAGE:
case COMBAT_DAMAGE: case COMBAT_DAMAGE:
return !this.inCombat(); return !this.inCombat();
@@ -684,20 +685,13 @@ public class PhaseHandler implements java.io.Serializable {
while (!game.isGameOver()) { // loop only while is playing while (!game.isGameOver()) { // loop only while is playing
boolean givePriority = givePriorityToPlayer ;
if ( phase == PhaseType.COMBAT_DECLARE_BLOCKERS)
givePriority = game.getCombat().isPlayerAttacked(pPlayerPriority);
if ( phase == PhaseType.COMBAT_DECLARE_ATTACKERS && playerTurn != pPlayerPriority )
givePriority = false;
if( DEBUG_PHASES ) { if( DEBUG_PHASES ) {
System.out.println("\t\tStack: " + game.getStack()); System.out.println("\t\tStack: " + game.getStack());
System.out.print(FThreads.prependThreadId(debugPrintState(givePriority))); System.out.print(FThreads.prependThreadId(debugPrintState(givePriorityToPlayer)));
} }
if( givePriority ) { if( givePriorityToPlayer ) {
if( DEBUG_PHASES ) if( DEBUG_PHASES )
sw.start(); sw.start();
@@ -747,13 +741,6 @@ public class PhaseHandler implements java.io.Serializable {
game.fireEvent(new GameEventGameRestarted(playerTurn)); game.fireEvent(new GameEventGameRestarted(playerTurn));
return; return;
} }
// Time to handle priority to next player.
if ( phase == PhaseType.COMBAT_DECLARE_ATTACKERS || phase == PhaseType.COMBAT_DECLARE_BLOCKERS)
game.getStack().freezeStack();
} }
} }

View File

@@ -15,9 +15,9 @@ public enum PhaseType {
MAIN1("Main, precombat", "Main1"), MAIN1("Main, precombat", "Main1"),
COMBAT_BEGIN("Begin Combat", "BeginCombat"), COMBAT_BEGIN("Begin Combat", "BeginCombat"),
COMBAT_DECLARE_ATTACKERS("Declare Attackers"), COMBAT_DECLARE_ATTACKERS("Declare Attackers"),
COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY("Declare Attackers - Play Instants and Abilities"), //COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY("Declare Attackers - Play Instants and Abilities"),
COMBAT_DECLARE_BLOCKERS("Declare Blockers"), COMBAT_DECLARE_BLOCKERS("Declare Blockers"),
COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY("Declare Blockers - Play Instants and Abilities"), //COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY("Declare Blockers - Play Instants and Abilities"),
COMBAT_FIRST_STRIKE_DAMAGE("First Strike Damage"), COMBAT_FIRST_STRIKE_DAMAGE("First Strike Damage"),
COMBAT_DAMAGE("Combat Damage"), COMBAT_DAMAGE("Combat Damage"),
COMBAT_END("End Combat", "EndCombat"), COMBAT_END("End Combat", "EndCombat"),
@@ -28,8 +28,8 @@ public enum PhaseType {
public static final List<PhaseType> ALL_PHASES = Collections.unmodifiableList( public static final List<PhaseType> ALL_PHASES = Collections.unmodifiableList(
Arrays.asList( Arrays.asList(
UNTAP, UPKEEP, DRAW, MAIN1, UNTAP, UPKEEP, DRAW, MAIN1,
COMBAT_BEGIN, COMBAT_DECLARE_ATTACKERS, COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY, COMBAT_BEGIN, COMBAT_DECLARE_ATTACKERS, //COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY,
COMBAT_DECLARE_BLOCKERS, COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY, COMBAT_DECLARE_BLOCKERS, // COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY,
COMBAT_FIRST_STRIKE_DAMAGE, COMBAT_DAMAGE, COMBAT_END, COMBAT_FIRST_STRIKE_DAMAGE, COMBAT_DAMAGE, COMBAT_END,
MAIN2, END_OF_TURN, CLEANUP MAIN2, END_OF_TURN, CLEANUP
) )

View File

@@ -135,7 +135,10 @@ public abstract class PlayerController {
public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question); public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question);
public abstract List<Card> getCardsToMulligan(boolean isCommander, Player firstPlayer); public abstract List<Card> getCardsToMulligan(boolean isCommander, Player firstPlayer);
public abstract void declareAttackers();
public abstract void declareBlockers();
public abstract void takePriority(); public abstract void takePriority();
public abstract List<Card> chooseCardsToDiscardToMaximumHandSize(int numDiscard); public abstract List<Card> chooseCardsToDiscardToMaximumHandSize(int numDiscard);
public abstract boolean payManaOptional(Card card, Cost cost, String prompt, ManaPaymentPurpose purpose); public abstract boolean payManaOptional(Card card, Cost cost, String prompt, ManaPaymentPurpose purpose);
} }

View File

@@ -286,6 +286,17 @@ public class PlayerControllerAi extends PlayerController {
return ComputerUtil.getPartialParisCandidates(player); return ComputerUtil.getPartialParisCandidates(player);
} }
@Override
public void declareAttackers() {
brains.declareAttackers();
}
@Override
public void declareBlockers() {
brains.declateBlockers();
}
@Override @Override
public void takePriority() { public void takePriority() {
if ( !game.isGameOver() ) if ( !game.isGameOver() )

View File

@@ -469,19 +469,21 @@ public class PlayerControllerHuman extends PlayerController {
return inp.isKeepHand() ? null : isCommander ? inp.getSelectedCards() : player.getCardsIn(ZoneType.Hand); return inp.isKeepHand() ? null : isCommander ? inp.getSelectedCards() : player.getCardsIn(ZoneType.Hand);
} }
@Override
private void showDefaultInput() { public void declareAttackers() {
SpellAbility chosenSa = null; game.getCombat().initiatePossibleDefenders(player.getOpponents());
do { // This input should not modify combat object itself, but should return user choice
if (chosenSa != null) { InputSynchronized inpAttack = new InputAttack(player, game.getCombat());
HumanPlay.playSpellAbility(player, chosenSa); Singletons.getControl().getInputQueue().setInputAndWait(inpAttack);
}
InputPassPriority defaultInput = new InputPassPriority(player);
Singletons.getControl().getInputQueue().setInputAndWait(defaultInput);
chosenSa = defaultInput.getChosenSa();
} while( chosenSa != null );
} }
@Override
public void declareBlockers() {
// This input should not modify combat object itself, but should return user choice
InputSynchronized inpBlock = new InputBlock(player, game.getCombat());
Singletons.getControl().getInputQueue().setInputAndWait(inpBlock);
}
@Override @Override
public void takePriority() { public void takePriority() {
@@ -492,22 +494,15 @@ public class PlayerControllerHuman extends PlayerController {
} else } else
autoPassCancel(); // probably cancel, since something has happened autoPassCancel(); // probably cancel, since something has happened
switch(phase) { SpellAbility chosenSa = null;
do {
case COMBAT_DECLARE_ATTACKERS: if (chosenSa != null) {
game.getCombat().initiatePossibleDefenders(player.getOpponents()); HumanPlay.playSpellAbility(player, chosenSa);
InputSynchronized inpAttack = new InputAttack(player, game.getCombat()); }
Singletons.getControl().getInputQueue().setInputAndWait(inpAttack); InputPassPriority defaultInput = new InputPassPriority(player);
return; Singletons.getControl().getInputQueue().setInputAndWait(defaultInput);
chosenSa = defaultInput.getChosenSa();
case COMBAT_DECLARE_BLOCKERS: } while( chosenSa != null );
InputSynchronized inpBlock = new InputBlock(player, game.getCombat());
Singletons.getControl().getInputQueue().setInputAndWait(inpBlock);
return;
default:
showDefaultInput();
}
} }
@Override @Override

View File

@@ -532,10 +532,8 @@ public class VField implements IVDoc<CField> {
case COMBAT_BEGIN: case COMBAT_BEGIN:
return this.getLblBeginCombat(); return this.getLblBeginCombat();
case COMBAT_DECLARE_ATTACKERS: case COMBAT_DECLARE_ATTACKERS:
case COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY:
return this.getLblDeclareAttackers(); return this.getLblDeclareAttackers();
case COMBAT_DECLARE_BLOCKERS: case COMBAT_DECLARE_BLOCKERS:
case COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY:
return this.getLblDeclareBlockers(); return this.getLblDeclareBlockers();
case COMBAT_DAMAGE: case COMBAT_DAMAGE:
return this.getLblCombatDamage(); return this.getLblCombatDamage();