PhaseHandler - exracted declareBlockersTurnBaseActions and declateAttackTurnBasedActions, inlined all methods from PhaseUtil

This commit is contained in:
Maxmtg
2013-06-02 16:01:37 +00:00
parent 11061585da
commit 0052257edd
4 changed files with 191 additions and 249 deletions

View File

@@ -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.

View File

@@ -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<Card> 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<Card> 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<Card> 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<Card> 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<GameEntity, Card> attackersMap = new HashMapOfLists<GameEntity, Card>(CollectionSuppliers.<Card>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<String, Object> runParams = new HashMap<String, Object>();
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<GameEntity, MapOfLists<Card, Card>> blockers = new HashMap<GameEntity, MapOfLists<Card,Card>>();
for(GameEntity ge : game.getCombat().getDefenders()) {
MapOfLists<Card, Card> protectThisDefender = new HashMapOfLists<Card, Card>(CollectionSuppliers.<Card>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<GameEntity, Card> attackersMap = new HashMapOfLists<GameEntity, Card>(CollectionSuppliers.<Card>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<String, Object> runParams = new HashMap<String, Object>();
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<Card> filterList = combat.getAllBlockers();
for (Card blocker : filterList) {
final List<Card> attackers = new ArrayList<Card>(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<Card> list = combat.getAllBlockers();
list = CardLists.filter(list, new Predicate<Card>() {
@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<GameEntity, MapOfLists<Card, Card>> blockers = new HashMap<GameEntity, MapOfLists<Card,Card>>();
for(GameEntity ge : game.getCombat().getDefenders()) {
MapOfLists<Card, Card> protectThisDefender = new HashMapOfLists<Card, Card>(CollectionSuppliers.<Card>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<StaticAbility> 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;
}
/**

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
/**
* <p>
* PhaseUtil class.
* </p>
*
* @author Forge
* @version $Id$
*/
public class PhaseUtil {
// ******* UNTAP PHASE *****
/**
* <p>
* skipUntap.
* </p>
*
* @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;
}
/**
* <p>
* handleDeclareBlockers.
* </p>
*
* @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<Card> filterList = combat.getAllBlockers();
for (Card blocker : filterList) {
final List<Card> attackers = new ArrayList<Card>(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<Card> list = combat.getAllBlockers();
list = CardLists.filter(list, new Predicate<Card>() {
@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<StaticAbility> 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;
}
}