From 0052257edd70b04417c2579815cf24e400445541 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sun, 2 Jun 2013 16:01:37 +0000 Subject: [PATCH] PhaseHandler - exracted declareBlockersTurnBaseActions and declateAttackTurnBasedActions, inlined all methods from PhaseUtil --- .gitattributes | 1 - .../java/forge/game/phase/CombatUtil.java | 4 +- .../java/forge/game/phase/PhaseHandler.java | 298 +++++++++++------- src/main/java/forge/game/phase/PhaseUtil.java | 137 -------- 4 files changed, 191 insertions(+), 249 deletions(-) delete mode 100644 src/main/java/forge/game/phase/PhaseUtil.java diff --git a/.gitattributes b/.gitattributes index 8f236249a19..c414c4a8ef3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14296,7 +14296,6 @@ src/main/java/forge/game/phase/ExtraTurn.java -text src/main/java/forge/game/phase/Phase.java svneol=native#text/plain src/main/java/forge/game/phase/PhaseHandler.java -text src/main/java/forge/game/phase/PhaseType.java -text -src/main/java/forge/game/phase/PhaseUtil.java svneol=native#text/plain src/main/java/forge/game/phase/Untap.java -text src/main/java/forge/game/phase/Upkeep.java svneol=native#text/plain src/main/java/forge/game/phase/package-info.java svneol=native#text/plain diff --git a/src/main/java/forge/game/phase/CombatUtil.java b/src/main/java/forge/game/phase/CombatUtil.java index 4a359c55272..d8d2b51a0f4 100644 --- a/src/main/java/forge/game/phase/CombatUtil.java +++ b/src/main/java/forge/game/phase/CombatUtil.java @@ -47,7 +47,6 @@ import forge.card.staticability.StaticAbility; import forge.card.trigger.TriggerType; import forge.game.Game; import forge.game.GlobalRuleChange; -import forge.game.ai.ComputerUtilCard; import forge.game.player.Player; import forge.game.player.PlayerController.ManaPaymentPurpose; import forge.game.zone.PlayerZone; @@ -1302,6 +1301,7 @@ public class CombatUtil { } } + /* public static void souverignsOfAlara2ndAbility(final Game game, final Card attacker) { final Ability ability4 = new Ability(attacker, ManaCost.ZERO) { @Override @@ -1352,6 +1352,8 @@ public class CombatUtil { game.getStack().addSimultaneousStackEntry(ability4); } + */ + /** * executes Rampage abilities for a given card. diff --git a/src/main/java/forge/game/phase/PhaseHandler.java b/src/main/java/forge/game/phase/PhaseHandler.java index f6b59b7dc41..38d66a86882 100644 --- a/src/main/java/forge/game/phase/PhaseHandler.java +++ b/src/main/java/forge/game/phase/PhaseHandler.java @@ -17,18 +17,24 @@ */ package forge.game.phase; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import org.apache.commons.lang.time.StopWatch; +import com.google.common.base.Predicate; + import forge.Card; import forge.CardLists; import forge.FThreads; import forge.GameEntity; import forge.Singletons; import forge.CardPredicates.Presets; +import forge.card.cost.Cost; +import forge.card.mana.ManaCost; +import forge.card.staticability.StaticAbility; import forge.card.trigger.TriggerType; import forge.game.GameAge; import forge.game.Game; @@ -42,6 +48,7 @@ import forge.game.event.GameEventGameRestarted; import forge.game.event.GameEventManaBurn; import forge.game.event.GameEventTurnPhase; import forge.game.player.Player; +import forge.game.player.PlayerController.ManaPaymentPurpose; import forge.game.zone.ZoneType; import forge.gui.framework.SDisplayUtil; import forge.gui.match.CMatchUI; @@ -208,8 +215,58 @@ public class PhaseHandler implements java.io.Serializable { game.fireEvent(new GameEventTurnPhase(this.getPlayerTurn(), this.getPhase(), phaseType)); + if (this.phase == PhaseType.UNTAP) { + // Here's what happens on new turn, regardless of skipped phases + game.getCombat().reset(playerTurn); + + // Tokens starting game in play should suffer from Sum. Sickness + final List list = playerTurn.getCardsIncludePhasingIn(ZoneType.Battlefield); + for (final Card c : list) { + if (playerTurn.getTurn() > 0 || !c.isStartsGameInPlay()) { + c.setSickness(false); + } + } + playerTurn.incrementTurn(); + + game.getAction().resetActivationsPerTurn(); + + final List lands = CardLists.filter(playerTurn.getLandsInPlay(), Presets.UNTAPPED); + playerTurn.setNumPowerSurgeLands(lands.size()); + } + } + private boolean isSkippingPhase(PhaseType phase) { + switch(phase) { + case UNTAP: + if (playerTurn.hasKeyword("Skip your next untap step.")) { + playerTurn.removeKeyword("Skip your next untap step."); + return true; + } + return playerTurn.hasKeyword("Skip the untap step of this turn.") || playerTurn.hasKeyword("Skip your untap step."); + + case UPKEEP: + return getPlayerTurn().hasKeyword("Skip your upkeep step."); + + case DRAW: + return getPlayerTurn().isSkippingDraw() || getTurn() == 1 && game.getPlayers().size() == 2; + + case COMBAT_BEGIN: + case COMBAT_DECLARE_ATTACKERS: + return playerTurn.isSkippingCombat(); + + case COMBAT_DECLARE_BLOCKERS: + case COMBAT_FIRST_STRIKE_DAMAGE: + case COMBAT_DAMAGE: + return !this.inCombat(); + + default: + return false; + } + + } + + private final void onPhaseBegin() { boolean skipped = false; @@ -222,33 +279,9 @@ public class PhaseHandler implements java.io.Serializable { // Perform turn-based actions switch(this.getPhase()) { case UNTAP: - //SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc()); givePriorityToPlayer = false; - - game.getCombat().reset(playerTurn); - - // Tokens starting game in play should suffer from Sum. Sickness - final List list = playerTurn.getCardsIncludePhasingIn(ZoneType.Battlefield); - for (final Card c : list) { - if (playerTurn.getTurn() > 0 || !c.isStartsGameInPlay()) { - c.setSickness(false); - } - } - playerTurn.incrementTurn(); - - game.getAction().resetActivationsPerTurn(); - - final List lands = CardLists.filter(playerTurn.getLandsInPlay(), Presets.UNTAPPED); - playerTurn.setNumPowerSurgeLands(lands.size()); - - // anything before this point happens regardless of whether the Untap - // phase is skipped - - if (!PhaseUtil.isSkipUntap(playerTurn)) { - game.getUntap().executeUntil(playerTurn); - game.getUntap().executeAt(); - } - + game.getUntap().executeUntil(playerTurn); + game.getUntap().executeAt(); break; case UPKEEP: @@ -273,53 +306,7 @@ public class PhaseHandler implements java.io.Serializable { case COMBAT_DECLARE_ATTACKERS: game.getStack().freezeStack(); - - playerTurn.getController().declareAttackers(); - - game.getCombat().removeAbsentCombatants(); - CombatUtil.checkAttackOrBlockAlone(game.getCombat()); - - // TODO move propaganda to happen as the Attacker is Declared - for (final Card c2 : game.getCombat().getAttackers()) { - boolean canAttack = CombatUtil.checkPropagandaEffects(game, c2); - if ( canAttack ) { - if (!c2.hasKeyword("Vigilance")) - c2.tap(); - } else { - game.getCombat().removeFromCombat(c2); - } - } - - // Prepare and fire event 'attackers declared' - MapOfLists attackersMap = new HashMapOfLists(CollectionSuppliers.arrayLists()); - for(GameEntity ge : game.getCombat().getDefenders()) attackersMap.addAll(ge, game.getCombat().getAttackersOf(ge)); - game.fireEvent(new GameEventAttackersDeclared(playerTurn, attackersMap)); - - // This Exalted handler should be converted to script - if (game.getCombat().getAttackers().size() == 1) { - final Player attackingPlayer = game.getCombat().getAttackingPlayer(); - final Card attacker = game.getCombat().getAttackers().get(0); - for (Card card : attackingPlayer.getCardsIn(ZoneType.Battlefield)) { - int exaltedMagnitude = card.getKeywordAmount("Exalted"); - if (exaltedMagnitude > 0) { - CombatUtil.executeExaltedAbility(game, attacker, exaltedMagnitude, card); - } - -// if ("Sovereigns of Lost Alara".equals(card.getName())) { -// CombatUtil.souverignsOfAlara2ndAbility(game, attacker); -// } - } - } - - // fire trigger - final HashMap runParams = new HashMap(); - runParams.put("Attackers", game.getCombat().getAttackers()); - runParams.put("AttackingPlayer", game.getCombat().getAttackingPlayer()); - game.getTriggerHandler().runTrigger(TriggerType.AttackersDeclared, runParams, false); - - for (final Card c : game.getCombat().getAttackers()) { - CombatUtil.checkDeclareAttackers(game, c); - } + declateAttackTurnBasedActions(); game.getStack().unfreezeStack(); this.bCombat = !game.getCombat().getAttackers().isEmpty(); @@ -331,26 +318,7 @@ public class PhaseHandler implements java.io.Serializable { game.getCombat().removeAbsentCombatants(); game.getStack().freezeStack(); - Player p = playerTurn; - do { - p = game.getNextPlayerAfter(p); - if ( game.getCombat().isPlayerAttacked(p) ) - p.getController().declareBlockers(); - } while(p != playerTurn); - - game.getCombat().removeAbsentCombatants(); - PhaseUtil.handleDeclareBlockers(game); - - // map: defender => (many) attacker => (many) blocker - Map> blockers = new HashMap>(); - for(GameEntity ge : game.getCombat().getDefenders()) { - MapOfLists protectThisDefender = new HashMapOfLists(CollectionSuppliers.arrayLists()); - for(Card att : game.getCombat().getAttackersOf(ge)) { - protectThisDefender.addAll(att, game.getCombat().getBlockers(att)); - } - blockers.put(ge, protectThisDefender); - } - game.fireEvent(new GameEventBlockersDeclared(blockers)); + declareBlockersTurnBaseActions(); game.getStack().unfreezeStack(); break; @@ -500,27 +468,137 @@ public class PhaseHandler implements java.io.Serializable { } - private boolean isSkippingPhase(PhaseType phase) { - switch(phase) { - case UPKEEP: - return getPlayerTurn().hasKeyword("Skip your upkeep step."); + private void declateAttackTurnBasedActions() { + playerTurn.getController().declareAttackers(); + + game.getCombat().removeAbsentCombatants(); + CombatUtil.checkAttackOrBlockAlone(game.getCombat()); + + // TODO move propaganda to happen as the Attacker is Declared + for (final Card c2 : game.getCombat().getAttackers()) { + boolean canAttack = CombatUtil.checkPropagandaEffects(game, c2); + if ( canAttack ) { + if (!c2.hasKeyword("Vigilance")) + c2.tap(); + } else { + game.getCombat().removeFromCombat(c2); + } + } + + // Prepare and fire event 'attackers declared' + MapOfLists attackersMap = new HashMapOfLists(CollectionSuppliers.arrayLists()); + for(GameEntity ge : game.getCombat().getDefenders()) attackersMap.addAll(ge, game.getCombat().getAttackersOf(ge)); + game.fireEvent(new GameEventAttackersDeclared(playerTurn, attackersMap)); + + // This Exalted handler should be converted to script + if (game.getCombat().getAttackers().size() == 1) { + final Player attackingPlayer = game.getCombat().getAttackingPlayer(); + final Card attacker = game.getCombat().getAttackers().get(0); + for (Card card : attackingPlayer.getCardsIn(ZoneType.Battlefield)) { + int exaltedMagnitude = card.getKeywordAmount("Exalted"); + if (exaltedMagnitude > 0) { + CombatUtil.executeExaltedAbility(game, attacker, exaltedMagnitude, card); + } + + // if ("Sovereigns of Lost Alara".equals(card.getName())) { + // CombatUtil.souverignsOfAlara2ndAbility(game, attacker); + // } + } + } + + // fire trigger + final HashMap runParams = new HashMap(); + runParams.put("Attackers", game.getCombat().getAttackers()); + runParams.put("AttackingPlayer", game.getCombat().getAttackingPlayer()); + game.getTriggerHandler().runTrigger(TriggerType.AttackersDeclared, runParams, false); + + for (final Card c : game.getCombat().getAttackers()) { + CombatUtil.checkDeclareAttackers(game, c); + } + } - case DRAW: - return getPlayerTurn().isSkippingDraw() || getTurn() == 1 && game.getPlayers().size() == 2; - case COMBAT_BEGIN: - case COMBAT_DECLARE_ATTACKERS: - return playerTurn.isSkippingCombat(); - - case COMBAT_DECLARE_BLOCKERS: - case COMBAT_FIRST_STRIKE_DAMAGE: - case COMBAT_DAMAGE: - return !this.inCombat(); - - default: - return false; + private void declareBlockersTurnBaseActions() { + final Combat combat = game.getCombat(); + + Player p = playerTurn; + do { + p = game.getNextPlayerAfter(p); + if ( combat.isPlayerAttacked(p) ) + p.getController().declareBlockers(); + } while(p != playerTurn); + + combat.removeAbsentCombatants(); + + + // Handles removing cards like Mogg Flunkies from combat if group block + // didn't occur + final List filterList = combat.getAllBlockers(); + for (Card blocker : filterList) { + final List attackers = new ArrayList(combat.getAttackersBlockedBy(blocker)); + for (Card attacker : attackers) { + boolean hasPaid = payRequiredBlockCosts(game, blocker, attacker); + + if ( !hasPaid ) { + combat.removeBlockAssignment(attacker, blocker); + } + } + } + for (Card c : filterList) { + if (c.hasKeyword("CARDNAME can't attack or block alone.") && c.isBlocking()) { + if (combat.getAllBlockers().size() < 2) { + combat.undoBlockingAssignment(c); + } + } } + combat.setUnblockedAttackers(); + + List list = combat.getAllBlockers(); + + list = CardLists.filter(list, new Predicate() { + @Override + public boolean apply(final Card c) { + return !c.getDamageHistory().getCreatureBlockedThisCombat(); + } + }); + + CombatUtil.checkDeclareBlockers(game, list); + + for (final Card a : combat.getAttackers()) { + CombatUtil.checkBlockedAttackers(game, a, combat.getBlockers(a)); + } + + // map: defender => (many) attacker => (many) blocker + Map> blockers = new HashMap>(); + for(GameEntity ge : game.getCombat().getDefenders()) { + MapOfLists protectThisDefender = new HashMapOfLists(CollectionSuppliers.arrayLists()); + for(Card att : game.getCombat().getAttackersOf(ge)) { + protectThisDefender.addAll(att, game.getCombat().getBlockers(att)); + } + blockers.put(ge, protectThisDefender); + } + game.fireEvent(new GameEventBlockersDeclared(blockers)); + } + + + private static boolean payRequiredBlockCosts(Game game, Card blocker, Card attacker) { + Cost blockCost = new Cost(ManaCost.ZERO, true); + // Sort abilities to apply them in proper order + for (Card card : game.getCardsIn(ZoneType.Battlefield)) { + final ArrayList staticAbilities = card.getStaticAbilities(); + for (final StaticAbility stAb : staticAbilities) { + Cost c1 = stAb.getBlockCost(blocker, attacker); + if ( c1 != null ) + blockCost.add(c1); + } + } + + boolean hasPaid = blockCost.getTotalMana().isZero() && blockCost.isOnlyManaCost(); // true if needless to pay + if (!hasPaid) { + hasPaid = blocker.getController().getController().payManaOptional(blocker, blockCost, "Pay cost to declare " + blocker + " a blocker", ManaPaymentPurpose.DeclareBlocker); + } + return hasPaid; } /** diff --git a/src/main/java/forge/game/phase/PhaseUtil.java b/src/main/java/forge/game/phase/PhaseUtil.java deleted file mode 100644 index a4aa69e5e9f..00000000000 --- a/src/main/java/forge/game/phase/PhaseUtil.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Forge Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.game.phase; - -import java.util.ArrayList; -import java.util.List; - -import com.google.common.base.Predicate; - -import forge.Card; -import forge.CardLists; -import forge.card.cost.Cost; -import forge.card.mana.ManaCost; -import forge.card.staticability.StaticAbility; -import forge.game.Game; -import forge.game.player.Player; -import forge.game.player.PlayerController.ManaPaymentPurpose; -import forge.game.zone.ZoneType; - -/** - *

- * PhaseUtil class. - *

- * - * @author Forge - * @version $Id$ - */ -public class PhaseUtil { - // ******* UNTAP PHASE ***** - /** - *

- * skipUntap. - *

- * - * @param p - * a {@link forge.game.player.Player} object. - * @return a boolean. - */ - static boolean isSkipUntap(final Player p) { - - if (p.hasKeyword("Skip your next untap step.")) { - p.removeKeyword("Skip your next untap step."); - return true; - } - if (p.hasKeyword("Skip the untap step of this turn.") - || p.hasKeyword("Skip your untap step.")) { - return true; - } - - return false; - } - - - /** - *

- * handleDeclareBlockers. - *

- * - * @param game - */ - public static void handleDeclareBlockers(Game game) { - final Combat combat = game.getCombat(); - - // Handles removing cards like Mogg Flunkies from combat if group block - // didn't occur - final List filterList = combat.getAllBlockers(); - for (Card blocker : filterList) { - final List attackers = new ArrayList(combat.getAttackersBlockedBy(blocker)); - for (Card attacker : attackers) { - boolean hasPaid = payRequiredBlockCosts(game, blocker, attacker); - - if ( !hasPaid ) { - combat.removeBlockAssignment(attacker, blocker); - } - } - } - for (Card c : filterList) { - if (c.hasKeyword("CARDNAME can't attack or block alone.") && c.isBlocking()) { - if (combat.getAllBlockers().size() < 2) { - combat.undoBlockingAssignment(c); - } - } - } - - combat.setUnblockedAttackers(); - - List list = combat.getAllBlockers(); - - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - return !c.getDamageHistory().getCreatureBlockedThisCombat(); - } - }); - - CombatUtil.checkDeclareBlockers(game, list); - - for (final Card a : combat.getAttackers()) { - CombatUtil.checkBlockedAttackers(game, a, combat.getBlockers(a)); - } - } - - - private static boolean payRequiredBlockCosts(Game game, Card blocker, Card attacker) { - Cost blockCost = new Cost(ManaCost.ZERO, true); - // Sort abilities to apply them in proper order - for (Card card : game.getCardsIn(ZoneType.Battlefield)) { - final ArrayList staticAbilities = card.getStaticAbilities(); - for (final StaticAbility stAb : staticAbilities) { - Cost c1 = stAb.getBlockCost(blocker, attacker); - if ( c1 != null ) - blockCost.add(c1); - } - } - - boolean hasPaid = blockCost.getTotalMana().isZero() && blockCost.isOnlyManaCost(); // true if needless to pay - if (!hasPaid) { - hasPaid = blocker.getController().getController().payManaOptional(blocker, blockCost, "Pay cost to declare " + blocker + " a blocker", ManaPaymentPurpose.DeclareBlocker); - } - return hasPaid; - } -}