mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Support updating game view
This commit is contained in:
@@ -97,7 +97,7 @@ public class Game {
|
|||||||
private GameOutcome outcome;
|
private GameOutcome outcome;
|
||||||
private boolean disableAutoYields;
|
private boolean disableAutoYields;
|
||||||
|
|
||||||
private final GameView view = new GameView();
|
private final GameView view;
|
||||||
|
|
||||||
public Game(List<RegisteredPlayer> players0, GameRules rules0, Match match0) { /* no more zones to map here */
|
public Game(List<RegisteredPlayer> players0, GameRules rules0, Match match0) { /* no more zones to map here */
|
||||||
rules = rules0;
|
rules = rules0;
|
||||||
@@ -147,6 +147,8 @@ public class Game {
|
|||||||
endOfTurn = new EndOfTurn(this);
|
endOfTurn = new EndOfTurn(this);
|
||||||
endOfCombat = new Phase(PhaseType.COMBAT_END);
|
endOfCombat = new Phase(PhaseType.COMBAT_END);
|
||||||
|
|
||||||
|
view = new GameView(this);
|
||||||
|
|
||||||
subscribeToEvents(gameLog.getEventVisitor());
|
subscribeToEvents(gameLog.getEventVisitor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,10 +156,15 @@ public class Game {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the players who are still fighting to win.
|
||||||
|
*/
|
||||||
|
public final List<Player> getPlayers() {
|
||||||
|
return roIngamePlayers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the players who are still fighting to win, in turn order.
|
* Gets the players who are still fighting to win, in turn order.
|
||||||
*
|
|
||||||
* @return the players
|
|
||||||
*/
|
*/
|
||||||
public final List<Player> getPlayersInTurnOrder() {
|
public final List<Player> getPlayersInTurnOrder() {
|
||||||
if (turnOrder.isDefaultDirection()) {
|
if (turnOrder.isDefaultDirection()) {
|
||||||
@@ -166,129 +173,72 @@ public class Game {
|
|||||||
return roIngamePlayersReversed;
|
return roIngamePlayersReversed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the players who are still fighting to win.
|
|
||||||
*
|
|
||||||
* @return the players
|
|
||||||
*/
|
|
||||||
public final List<Player> getPlayers() {
|
|
||||||
return roIngamePlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the players who participated in match (regardless of outcome).
|
* Gets the players who participated in match (regardless of outcome).
|
||||||
* <i>Use this in UI and after match calculations</i>
|
* <i>Use this in UI and after match calculations</i>
|
||||||
*
|
|
||||||
* @return the players
|
|
||||||
*/
|
*/
|
||||||
public final List<Player> getRegisteredPlayers() {
|
public final List<Player> getRegisteredPlayers() {
|
||||||
return allPlayers;
|
return allPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public final Untap getUntap() {
|
||||||
* Gets the cleanup step.
|
return untap;
|
||||||
*
|
}
|
||||||
* @return the cleanup step
|
public final Upkeep getUpkeep() {
|
||||||
*/
|
return upkeep;
|
||||||
|
}
|
||||||
|
public final Phase getEndOfCombat() {
|
||||||
|
return endOfCombat;
|
||||||
|
}
|
||||||
|
public final EndOfTurn getEndOfTurn() {
|
||||||
|
return endOfTurn;
|
||||||
|
}
|
||||||
public final Phase getCleanup() {
|
public final Phase getCleanup() {
|
||||||
return cleanup;
|
return cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the end of turn.
|
|
||||||
*
|
|
||||||
* @return the endOfTurn
|
|
||||||
*/
|
|
||||||
public final EndOfTurn getEndOfTurn() {
|
|
||||||
return endOfTurn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the end of combat.
|
|
||||||
*
|
|
||||||
* @return the endOfCombat
|
|
||||||
*/
|
|
||||||
public final Phase getEndOfCombat() {
|
|
||||||
return endOfCombat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the upkeep.
|
|
||||||
*
|
|
||||||
* @return the upkeep
|
|
||||||
*/
|
|
||||||
public final Upkeep getUpkeep() {
|
|
||||||
return upkeep;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the untap.
|
|
||||||
*
|
|
||||||
* @return the upkeep
|
|
||||||
*/
|
|
||||||
public final Untap getUntap() {
|
|
||||||
return untap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the phaseHandler.
|
|
||||||
*
|
|
||||||
* @return the phaseHandler
|
|
||||||
*/
|
|
||||||
public final PhaseHandler getPhaseHandler() {
|
public final PhaseHandler getPhaseHandler() {
|
||||||
return phaseHandler;
|
return phaseHandler;
|
||||||
}
|
}
|
||||||
|
public final void updateTurnForView() {
|
||||||
|
view.updateTurn(phaseHandler);
|
||||||
|
}
|
||||||
|
public final void updatePhaseForView() {
|
||||||
|
view.updatePhase(phaseHandler);
|
||||||
|
}
|
||||||
|
public final void updatePlayerTurnForView() {
|
||||||
|
view.updatePlayerTurn(phaseHandler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the stack.
|
|
||||||
*
|
|
||||||
* @return the stack
|
|
||||||
*/
|
|
||||||
public final MagicStack getStack() {
|
public final MagicStack getStack() {
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
public final void updateStackForView() {
|
||||||
|
view.updateStack(stack);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the static effects.
|
|
||||||
*
|
|
||||||
* @return the staticEffects
|
|
||||||
*/
|
|
||||||
public final StaticEffects getStaticEffects() {
|
public final StaticEffects getStaticEffects() {
|
||||||
return staticEffects;
|
return staticEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the trigger handler.
|
|
||||||
*
|
|
||||||
* @return the triggerHandler
|
|
||||||
*/
|
|
||||||
public final TriggerHandler getTriggerHandler() {
|
public final TriggerHandler getTriggerHandler() {
|
||||||
return triggerHandler;
|
return triggerHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the combat.
|
|
||||||
*
|
|
||||||
* @return the combat
|
|
||||||
*/
|
|
||||||
public final Combat getCombat() {
|
public final Combat getCombat() {
|
||||||
return getPhaseHandler().getCombat();
|
return getPhaseHandler().getCombat();
|
||||||
}
|
}
|
||||||
|
public final void updateCombatForView() {
|
||||||
|
view.updateCombat(getCombat());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the game log.
|
|
||||||
*
|
|
||||||
* @return the game log
|
|
||||||
*/
|
|
||||||
public final GameLog getGameLog() {
|
public final GameLog getGameLog() {
|
||||||
return gameLog;
|
return gameLog;
|
||||||
}
|
}
|
||||||
|
public final void updateGameLogForView() {
|
||||||
|
view.updateGameLog(gameLog);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the stack zone.
|
|
||||||
*
|
|
||||||
* @return the stackZone
|
|
||||||
*/
|
|
||||||
public final Zone getStackZone() {
|
public final Zone getStackZone() {
|
||||||
return stackZone;
|
return stackZone;
|
||||||
}
|
}
|
||||||
@@ -311,37 +261,25 @@ public class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the turn order.
|
* The Direction in which the turn order of this Game currently proceeds.
|
||||||
* @return the Direction in which the turn order of this Game currently
|
|
||||||
* proceeds.
|
|
||||||
*/
|
*/
|
||||||
public final Direction getTurnOrder() {
|
public final Direction getTurnOrder() {
|
||||||
return turnOrder;
|
return turnOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void reverseTurnOrder() {
|
public final void reverseTurnOrder() {
|
||||||
turnOrder = turnOrder.getOtherDirection();
|
turnOrder = turnOrder.getOtherDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void resetTurnOrder() {
|
public final void resetTurnOrder() {
|
||||||
turnOrder = Direction.getDefaultDirection();
|
turnOrder = Direction.getDefaultDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and return the next timestamp.
|
* Create and return the next timestamp.
|
||||||
*
|
|
||||||
* @return the next timestamp
|
|
||||||
*/
|
*/
|
||||||
public final long getNextTimestamp() {
|
public final long getNextTimestamp() {
|
||||||
timestamp = getTimestamp() + 1;
|
timestamp = getTimestamp() + 1;
|
||||||
return getTimestamp();
|
return getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the timestamp.
|
|
||||||
*
|
|
||||||
* @return the timestamp
|
|
||||||
*/
|
|
||||||
public final long getTimestamp() {
|
public final long getTimestamp() {
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
@@ -350,24 +288,14 @@ public class Game {
|
|||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the replacementHandler
|
|
||||||
*/
|
|
||||||
public ReplacementHandler getReplacementHandler() {
|
public ReplacementHandler getReplacementHandler() {
|
||||||
return replacementHandler;
|
return replacementHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the gameOver
|
|
||||||
*/
|
|
||||||
public synchronized boolean isGameOver() {
|
public synchronized boolean isGameOver() {
|
||||||
return age == GameStage.GameOver;
|
return age == GameStage.GameOver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param reason
|
|
||||||
* @param go the gameOver to set
|
|
||||||
*/
|
|
||||||
public synchronized void setGameOver(GameEndReason reason) {
|
public synchronized void setGameOver(GameEndReason reason) {
|
||||||
age = GameStage.GameOver;
|
age = GameStage.GameOver;
|
||||||
for (Player p : allPlayers) {
|
for (Player p : allPlayers) {
|
||||||
@@ -384,6 +312,8 @@ public class Game {
|
|||||||
outcome = result;
|
outcome = result;
|
||||||
match.addGamePlayed(this);
|
match.addGamePlayed(this);
|
||||||
|
|
||||||
|
view.updateGameOver(this);
|
||||||
|
|
||||||
// The log shall listen to events and generate text internally
|
// The log shall listen to events and generate text internally
|
||||||
fireEvent(new GameEventGameOutcome(result, match.getPlayedGames()));
|
fireEvent(new GameEventGameOutcome(result, match.getPlayedGames()));
|
||||||
}
|
}
|
||||||
@@ -544,10 +474,6 @@ public class Game {
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
* @param p
|
|
||||||
*/
|
|
||||||
public void onPlayerLost(Player p) {
|
public void onPlayerLost(Player p) {
|
||||||
ingamePlayers.remove(p);
|
ingamePlayers.remove(p);
|
||||||
|
|
||||||
@@ -571,23 +497,13 @@ public class Game {
|
|||||||
events.register(subscriber);
|
events.register(subscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the type of game (Constructed/Limited/Planechase/etc...)
|
|
||||||
*/
|
|
||||||
public GameRules getRules() {
|
public GameRules getRules() {
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the activePlane
|
|
||||||
*/
|
|
||||||
public List<Card> getActivePlanes() {
|
public List<Card> getActivePlanes() {
|
||||||
return activePlanes;
|
return activePlanes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param activePlane0 the activePlane to set
|
|
||||||
*/
|
|
||||||
public void setActivePlanes(List<Card> activePlane0) {
|
public void setActivePlanes(List<Card> activePlane0) {
|
||||||
activePlanes = activePlane0;
|
activePlanes = activePlane0;
|
||||||
}
|
}
|
||||||
@@ -604,7 +520,7 @@ public class Game {
|
|||||||
Card c = getCardsIn(ZoneType.Command).get(i);
|
Card c = getCardsIn(ZoneType.Command).get(i);
|
||||||
if (c.isScheme() && !c.isType("Ongoing")) {
|
if (c.isScheme() && !c.isType("Ongoing")) {
|
||||||
boolean foundonstack = false;
|
boolean foundonstack = false;
|
||||||
for (SpellAbilityStackInstance si : getStack()) {
|
for (SpellAbilityStackInstance si : stack) {
|
||||||
if (si.getSourceCard().equals(c)) {
|
if (si.getSourceCard().equals(c)) {
|
||||||
foundonstack = true;
|
foundonstack = true;
|
||||||
break;
|
break;
|
||||||
@@ -719,7 +635,6 @@ public class Game {
|
|||||||
chooseRandomCardsForAnte(player, anteed);
|
chooseRandomCardsForAnte(player, anteed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return anteed;
|
return anteed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,28 +7,109 @@ import forge.game.card.CardView;
|
|||||||
import forge.game.combat.AttackingBand;
|
import forge.game.combat.AttackingBand;
|
||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.combat.CombatView;
|
import forge.game.combat.CombatView;
|
||||||
|
import forge.game.phase.PhaseHandler;
|
||||||
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.game.spellability.SpellAbilityView;
|
import forge.game.spellability.SpellAbilityView;
|
||||||
import forge.game.spellability.StackItemView;
|
import forge.game.spellability.StackItemView;
|
||||||
|
import forge.game.zone.MagicStack;
|
||||||
import forge.trackable.TrackableIndex;
|
import forge.trackable.TrackableIndex;
|
||||||
|
import forge.trackable.TrackableObject;
|
||||||
|
import forge.trackable.TrackableProperty;
|
||||||
|
|
||||||
public class GameView {
|
public class GameView extends TrackableObject {
|
||||||
private final TrackableIndex<CardView> cards = new TrackableIndex<CardView>();
|
private final TrackableIndex<CardView> cards = new TrackableIndex<CardView>();
|
||||||
private final TrackableIndex<PlayerView> players = new TrackableIndex<PlayerView>();
|
private final TrackableIndex<PlayerView> players = new TrackableIndex<PlayerView>();
|
||||||
private final TrackableIndex<SpellAbilityView> spellAbilities = new TrackableIndex<SpellAbilityView>();
|
private final TrackableIndex<SpellAbilityView> spellAbilities = new TrackableIndex<SpellAbilityView>();
|
||||||
private final TrackableIndex<StackItemView> stackItems = new TrackableIndex<StackItemView>();
|
private final TrackableIndex<StackItemView> stackItems = new TrackableIndex<StackItemView>();
|
||||||
private CombatView combatView;
|
private CombatView combatView;
|
||||||
|
|
||||||
public GameView() {
|
public GameView(Game game) {
|
||||||
|
super(-1); //ID not needed
|
||||||
|
set(TrackableProperty.WinningTeam, -1);
|
||||||
|
|
||||||
|
GameRules rules = game.getRules();
|
||||||
|
set(TrackableProperty.Commander, rules.hasAppliedVariant(GameType.Commander));
|
||||||
|
set(TrackableProperty.GameType, rules.getGameType());
|
||||||
|
set(TrackableProperty.PoisonCountersToLose, rules.getPoisonCountersToLose());
|
||||||
|
set(TrackableProperty.NumGamesInMatch, rules.getGamesPerMatch());
|
||||||
|
|
||||||
|
set(TrackableProperty.GameLog, game.getGameLog());
|
||||||
|
set(TrackableProperty.NumPlayedGamesInMatch, game.getMatch().getPlayedGames().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CombatView getCombatView() {
|
public boolean isCommander() {
|
||||||
|
return get(TrackableProperty.Commander);
|
||||||
|
}
|
||||||
|
public GameType getGameType() {
|
||||||
|
return get(TrackableProperty.GameType);
|
||||||
|
}
|
||||||
|
public int getPoisonCountersToLose() {
|
||||||
|
return get(TrackableProperty.PoisonCountersToLose);
|
||||||
|
}
|
||||||
|
public int getNumGamesInMatch() {
|
||||||
|
return get(TrackableProperty.NumGamesInMatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTurn() {
|
||||||
|
return get(TrackableProperty.Turn);
|
||||||
|
}
|
||||||
|
void updateTurn(PhaseHandler phaseHandler) {
|
||||||
|
set(TrackableProperty.Turn, phaseHandler.getTurn());
|
||||||
|
}
|
||||||
|
public PhaseType getPhase() {
|
||||||
|
return get(TrackableProperty.Phase);
|
||||||
|
}
|
||||||
|
void updatePhase(PhaseHandler phaseHandler) {
|
||||||
|
set(TrackableProperty.Phase, phaseHandler.getPhase());
|
||||||
|
}
|
||||||
|
public PlayerView getPlayerTurn() {
|
||||||
|
return get(TrackableProperty.PlayerTurn);
|
||||||
|
}
|
||||||
|
void updatePlayerTurn(PhaseHandler phaseHandler) {
|
||||||
|
set(TrackableProperty.PlayerTurn, PlayerView.get(phaseHandler.getPlayerTurn()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStormCount() {
|
||||||
|
return get(TrackableProperty.StormCount);
|
||||||
|
}
|
||||||
|
void updateStack(MagicStack stack) {
|
||||||
|
set(TrackableProperty.StormCount, stack.getSpellsCastThisTurn().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFirstGameInMatch() {
|
||||||
|
return getNumPlayedGamesInMatch() == 0;
|
||||||
|
}
|
||||||
|
public int getNumPlayedGamesInMatch() {
|
||||||
|
return get(TrackableProperty.NumPlayedGamesInMatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGameOver() {
|
||||||
|
return get(TrackableProperty.GameOver);
|
||||||
|
}
|
||||||
|
public boolean isMatchOver() {
|
||||||
|
return get(TrackableProperty.MatchOver);
|
||||||
|
}
|
||||||
|
public int getWinningTeam() {
|
||||||
|
return get(TrackableProperty.WinningTeam);
|
||||||
|
}
|
||||||
|
void updateGameOver(Game game) {
|
||||||
|
set(TrackableProperty.GameOver, game.isGameOver());
|
||||||
|
set(TrackableProperty.MatchOver, game.getMatch().isMatchOver());
|
||||||
|
set(TrackableProperty.WinningTeam, game.getOutcome() == null ? -1 : game.getOutcome().getWinningTeam());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameLog getGameLog() {
|
||||||
|
return get(TrackableProperty.GameLog);
|
||||||
|
}
|
||||||
|
void updateGameLog(GameLog gameLog) {
|
||||||
|
flagAsChanged(TrackableProperty.GameLog); //don't need to set the property since it won't change
|
||||||
|
}
|
||||||
|
|
||||||
|
public CombatView getCombat() {
|
||||||
return combatView;
|
return combatView;
|
||||||
}
|
}
|
||||||
|
void updateCombat(Combat combat) {
|
||||||
public void refreshCombat(Game game) {
|
|
||||||
final Combat combat = game.getCombat();
|
|
||||||
if (combat == null) {
|
if (combat == null) {
|
||||||
combatView = null;
|
combatView = null;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -27,26 +27,20 @@ public class Match {
|
|||||||
private final List<GameOutcome> gamesPlayed = new ArrayList<GameOutcome>();
|
private final List<GameOutcome> gamesPlayed = new ArrayList<GameOutcome>();
|
||||||
private final List<GameOutcome> gamesPlayedRo;
|
private final List<GameOutcome> gamesPlayedRo;
|
||||||
|
|
||||||
public Match(GameRules rules, List<RegisteredPlayer> players0) {
|
public Match(GameRules rules0, List<RegisteredPlayer> players0) {
|
||||||
gamesPlayedRo = Collections.unmodifiableList(gamesPlayed);
|
gamesPlayedRo = Collections.unmodifiableList(gamesPlayed);
|
||||||
players = Collections.unmodifiableList(Lists.newArrayList(players0));
|
players = Collections.unmodifiableList(Lists.newArrayList(players0));
|
||||||
this.rules = rules;
|
rules = rules0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameRules getRules() {
|
public GameRules getRules() {
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the games played.
|
|
||||||
*
|
|
||||||
* @return the games played
|
|
||||||
*/
|
|
||||||
public final List<GameOutcome> getPlayedGames() {
|
public final List<GameOutcome> getPlayedGames() {
|
||||||
return this.gamesPlayedRo;
|
return gamesPlayedRo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addGamePlayed(Game finished) {
|
public void addGamePlayed(Game finished) {
|
||||||
if (!finished.isGameOver()) {
|
if (!finished.isGameOver()) {
|
||||||
throw new IllegalStateException("Game is not over yet.");
|
throw new IllegalStateException("Game is not over yet.");
|
||||||
@@ -54,17 +48,11 @@ public class Match {
|
|||||||
gamesPlayed.add(finished.getOutcome());
|
gamesPlayed.add(finished.getOutcome());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
*/
|
|
||||||
public Game createGame() {
|
public Game createGame() {
|
||||||
Game game = new Game(players, rules, this);
|
Game game = new Game(players, rules, this);
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
*/
|
|
||||||
public void startGame(final Game game) {
|
public void startGame(final Game game) {
|
||||||
prepareAllZones(game);
|
prepareAllZones(game);
|
||||||
if (rules.useAnte()) { // Deciding which cards go to ante
|
if (rules.useAnte()) { // Deciding which cards go to ante
|
||||||
@@ -103,11 +91,6 @@ public class Match {
|
|||||||
return gamesPlayedRo;
|
return gamesPlayedRo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isMatchOver() {
|
public boolean isMatchOver() {
|
||||||
int[] victories = new int[players.size()];
|
int[] victories = new int[players.size()];
|
||||||
for (GameOutcome go : gamesPlayed) {
|
for (GameOutcome go : gamesPlayed) {
|
||||||
@@ -130,12 +113,6 @@ public class Match {
|
|||||||
return gamesPlayed.size() >= rules.getGamesPerMatch();
|
return gamesPlayed.size() >= rules.getGamesPerMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
*
|
|
||||||
* @param questPlayer
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public int getGamesWonBy(LobbyPlayer questPlayer) {
|
public int getGamesWonBy(LobbyPlayer questPlayer) {
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (GameOutcome go : gamesPlayed) {
|
for (GameOutcome go : gamesPlayed) {
|
||||||
@@ -146,12 +123,6 @@ public class Match {
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
*
|
|
||||||
* @param questPlayer
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isWonBy(LobbyPlayer questPlayer) {
|
public boolean isWonBy(LobbyPlayer questPlayer) {
|
||||||
return getGamesWonBy(questPlayer) >= rules.getGamesToWinMatch();
|
return getGamesWonBy(questPlayer) >= rules.getGamesToWinMatch();
|
||||||
}
|
}
|
||||||
@@ -170,7 +141,6 @@ public class Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return myRemovedAnteCards;
|
return myRemovedAnteCards;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +244,6 @@ public class Match {
|
|||||||
private void executeAnte(Game lastGame) {
|
private void executeAnte(Game lastGame) {
|
||||||
GameOutcome outcome = lastGame.getOutcome();
|
GameOutcome outcome = lastGame.getOutcome();
|
||||||
|
|
||||||
|
|
||||||
// remove all the lost cards from owners' decks
|
// remove all the lost cards from owners' decks
|
||||||
List<PaperCard> losses = new ArrayList<PaperCard>();
|
List<PaperCard> losses = new ArrayList<PaperCard>();
|
||||||
int cntPlayers = players.size();
|
int cntPlayers = players.size();
|
||||||
@@ -358,7 +327,6 @@ public class Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other game types (like Quest) need to do something in their own calls to actually update data
|
// Other game types (like Quest) need to do something in their own calls to actually update data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4029,7 +4029,7 @@ public class Card extends GameEntity implements Comparable<Card>, IIdentifiable
|
|||||||
if (!CardUtil.getColors(this).hasAnyColor(mask))
|
if (!CardUtil.getColors(this).hasAnyColor(mask))
|
||||||
return false;
|
return false;
|
||||||
} else if (restriction.equals("LastCastThisTurn")) {
|
} else if (restriction.equals("LastCastThisTurn")) {
|
||||||
final List<Card> c = game.getStack().getCardsCastThisTurn();
|
final List<Card> c = game.getStack().getSpellsCastThisTurn();
|
||||||
if (c.isEmpty() || !sharesColorWith(c.get(c.size() - 1))) {
|
if (c.isEmpty() || !sharesColorWith(c.get(c.size() - 1))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1029,7 +1029,7 @@ public class CardFactoryUtil {
|
|||||||
return doXMath(c.getFirstSpellAbility().getTotalManaSpent(), m, c);
|
return doXMath(c.getFirstSpellAbility().getTotalManaSpent(), m, c);
|
||||||
}
|
}
|
||||||
if (sq[0].equals("StormCount")) {
|
if (sq[0].equals("StormCount")) {
|
||||||
return doXMath(game.getStack().getCardsCastThisTurn().size() - 1, m, c);
|
return doXMath(game.getStack().getSpellsCastThisTurn().size() - 1, m, c);
|
||||||
}
|
}
|
||||||
if (sq[0].equals("DamageDoneThisTurn")) {
|
if (sq[0].equals("DamageDoneThisTurn")) {
|
||||||
return doXMath(c.getDamageDoneThisTurn(), m, c);
|
return doXMath(c.getDamageDoneThisTurn(), m, c);
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ public final class CardUtil {
|
|||||||
public static List<Card> getThisTurnCast(final String valid, final Card src) {
|
public static List<Card> getThisTurnCast(final String valid, final Card src) {
|
||||||
List<Card> res = new ArrayList<Card>();
|
List<Card> res = new ArrayList<Card>();
|
||||||
final Game game = src.getGame();
|
final Game game = src.getGame();
|
||||||
res.addAll(game.getStack().getCardsCastThisTurn());
|
res.addAll(game.getStack().getSpellsCastThisTurn());
|
||||||
|
|
||||||
res = CardLists.getValidCards(res, valid, src.getController(), src);
|
res = CardLists.getValidCards(res, valid, src.getController(), src);
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ public final class CardUtil {
|
|||||||
public static List<Card> getLastTurnCast(final String valid, final Card src) {
|
public static List<Card> getLastTurnCast(final String valid, final Card src) {
|
||||||
List<Card> res = new ArrayList<Card>();
|
List<Card> res = new ArrayList<Card>();
|
||||||
final Game game = src.getGame();
|
final Game game = src.getGame();
|
||||||
res.addAll(game.getStack().getCardsCastLastTurn());
|
res.addAll(game.getStack().getSpellsCastLastTurn());
|
||||||
|
|
||||||
res = CardLists.getValidCards(res, valid, src.getController(), src);
|
res = CardLists.getValidCards(res, valid, src.getController(), src);
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ public class Combat {
|
|||||||
// List holds creatures who have dealt 1st strike damage to disallow them deal damage on regular basis (unless they have double-strike KW)
|
// List holds creatures who have dealt 1st strike damage to disallow them deal damage on regular basis (unless they have double-strike KW)
|
||||||
private List<Card> combatantsThatDealtFirstStrikeDamage = Lists.newArrayList();
|
private List<Card> combatantsThatDealtFirstStrikeDamage = Lists.newArrayList();
|
||||||
|
|
||||||
|
|
||||||
public Combat(Player attacker) {
|
public Combat(Player attacker) {
|
||||||
playerWhoAttacks = attacker;
|
playerWhoAttacks = attacker;
|
||||||
|
|
||||||
@@ -83,7 +82,7 @@ public class Combat {
|
|||||||
|
|
||||||
public final List<GameEntity> getDefendersControlledBy(Player who) {
|
public final List<GameEntity> getDefendersControlledBy(Player who) {
|
||||||
List<GameEntity> res = Lists.newArrayList();
|
List<GameEntity> res = Lists.newArrayList();
|
||||||
for(GameEntity ge : attackableEntries) {
|
for (GameEntity ge : attackableEntries) {
|
||||||
// if defender is the player himself or his cards
|
// if defender is the player himself or his cards
|
||||||
if (ge == who || ge instanceof Card && ((Card) ge).getController() == who)
|
if (ge == who || ge instanceof Card && ((Card) ge).getController() == who)
|
||||||
res.add(ge);
|
res.add(ge);
|
||||||
@@ -107,7 +106,7 @@ public class Combat {
|
|||||||
|
|
||||||
public final List<Card> getAttackersOf(GameEntity defender) {
|
public final List<Card> getAttackersOf(GameEntity defender) {
|
||||||
List<Card> result = new ArrayList<Card>();
|
List<Card> result = new ArrayList<Card>();
|
||||||
for(AttackingBand v : attackedByBands.get(defender)) {
|
for (AttackingBand v : attackedByBands.get(defender)) {
|
||||||
result.addAll(v.getAttackers());
|
result.addAll(v.getAttackers());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -133,7 +132,8 @@ public class Combat {
|
|||||||
if (band == null || !attackersOfDefender.contains(band)) {
|
if (band == null || !attackersOfDefender.contains(band)) {
|
||||||
band = new AttackingBand(c, defender);
|
band = new AttackingBand(c, defender);
|
||||||
attackersOfDefender.add(band);
|
attackersOfDefender.add(band);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
band.addAttacker(c);
|
band.addAttacker(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,9 +143,10 @@ public class Combat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final GameEntity getDefenderByAttacker(final AttackingBand c) {
|
public final GameEntity getDefenderByAttacker(final AttackingBand c) {
|
||||||
for(Entry<GameEntity, AttackingBand> e : attackedByBands.entries()) {
|
for (Entry<GameEntity, AttackingBand> e : attackedByBands.entries()) {
|
||||||
if ( e.getValue() == c )
|
if (e.getValue() == c) {
|
||||||
return e.getKey();
|
return e.getKey();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -167,8 +168,8 @@ public class Combat {
|
|||||||
|
|
||||||
// takes LKI into consideration, should use it at all times (though a single iteration over multimap seems faster)
|
// takes LKI into consideration, should use it at all times (though a single iteration over multimap seems faster)
|
||||||
public final AttackingBand getBandOfAttacker(final Card c) {
|
public final AttackingBand getBandOfAttacker(final Card c) {
|
||||||
for(AttackingBand ab : attackedByBands.values()) {
|
for (AttackingBand ab : attackedByBands.values()) {
|
||||||
if ( ab.contains(c) )
|
if (ab.contains(c))
|
||||||
return ab;
|
return ab;
|
||||||
}
|
}
|
||||||
CombatLki lki = lkiCache.get(c);
|
CombatLki lki = lkiCache.get(c);
|
||||||
@@ -186,16 +187,19 @@ public class Combat {
|
|||||||
|
|
||||||
public boolean isAttacking(Card card, GameEntity defender) {
|
public boolean isAttacking(Card card, GameEntity defender) {
|
||||||
AttackingBand ab = getBandOfAttacker(card);
|
AttackingBand ab = getBandOfAttacker(card);
|
||||||
for(Entry<GameEntity, AttackingBand> ee : attackedByBands.entries())
|
for (Entry<GameEntity, AttackingBand> ee : attackedByBands.entries()) {
|
||||||
if ( ee.getValue() == ab )
|
if (ee.getValue() == ab) {
|
||||||
return ee.getKey() == defender;
|
return ee.getKey() == defender;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final List<Card> getAttackers() {
|
public final List<Card> getAttackers() {
|
||||||
List<Card> result = Lists.newArrayList();
|
List<Card> result = Lists.newArrayList();
|
||||||
for(AttackingBand ab : attackedByBands.values())
|
for (AttackingBand ab : attackedByBands.values()) {
|
||||||
result.addAll(ab.getAttackers());
|
result.addAll(ab.getAttackers());
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +234,7 @@ public class Combat {
|
|||||||
public final void removeBlockAssignment(final Card attacker, final Card blocker) {
|
public final void removeBlockAssignment(final Card attacker, final Card blocker) {
|
||||||
AttackingBand band = getBandOfAttacker(attacker);
|
AttackingBand band = getBandOfAttacker(attacker);
|
||||||
Collection<Card> cc = blockedBands.get(band);
|
Collection<Card> cc = blockedBands.get(band);
|
||||||
if( cc != null)
|
if (cc != null)
|
||||||
cc.remove(blocker);
|
cc.remove(blocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,8 +246,8 @@ public class Combat {
|
|||||||
|
|
||||||
public final List<Card> getAllBlockers() {
|
public final List<Card> getAllBlockers() {
|
||||||
List<Card> result = new ArrayList<Card>();
|
List<Card> result = new ArrayList<Card>();
|
||||||
for(Card blocker : blockedBands.values()) {
|
for (Card blocker : blockedBands.values()) {
|
||||||
if(!result.contains(blocker))
|
if (!result.contains(blocker))
|
||||||
result.add(blocker);
|
result.add(blocker);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -254,19 +258,19 @@ public class Combat {
|
|||||||
return blockers == null ? Lists.<Card>newArrayList() : Lists.newArrayList(blockers);
|
return blockers == null ? Lists.<Card>newArrayList() : Lists.newArrayList(blockers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public final List<Card> getAttackersBlockedBy(final Card blocker) {
|
public final List<Card> getAttackersBlockedBy(final Card blocker) {
|
||||||
List<Card> blocked = new ArrayList<Card>();
|
List<Card> blocked = new ArrayList<Card>();
|
||||||
for(Entry<AttackingBand, Card> s : blockedBands.entries()) {
|
for (Entry<AttackingBand, Card> s : blockedBands.entries()) {
|
||||||
if (s.getValue().equals(blocker))
|
if (s.getValue().equals(blocker)) {
|
||||||
blocked.addAll(s.getKey().getAttackers());
|
blocked.addAll(s.getKey().getAttackers());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return blocked;
|
return blocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final List<AttackingBand> getAttackingBandsBlockedBy(Card blocker) {
|
public final List<AttackingBand> getAttackingBandsBlockedBy(Card blocker) {
|
||||||
List<AttackingBand> bands = Lists.newArrayList();
|
List<AttackingBand> bands = Lists.newArrayList();
|
||||||
for( Entry<AttackingBand, Card> kv : blockedBands.entries()) {
|
for (Entry<AttackingBand, Card> kv : blockedBands.entries()) {
|
||||||
if (kv.getValue().equals(blocker))
|
if (kv.getValue().equals(blocker))
|
||||||
bands.add(kv.getKey());
|
bands.add(kv.getKey());
|
||||||
}
|
}
|
||||||
@@ -277,9 +281,11 @@ public class Combat {
|
|||||||
Card attacker = source;
|
Card attacker = source;
|
||||||
if (source.isAura()) {
|
if (source.isAura()) {
|
||||||
attacker = source.getEnchantingCard();
|
attacker = source.getEnchantingCard();
|
||||||
} else if (source.isEquipment()) {
|
}
|
||||||
|
else if (source.isEquipment()) {
|
||||||
attacker = source.getEquipping();
|
attacker = source.getEquipping();
|
||||||
} else if (source.isFortification()) {
|
}
|
||||||
|
else if (source.isFortification()) {
|
||||||
attacker = source.getFortifying();
|
attacker = source.getFortifying();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,16 +298,16 @@ public class Combat {
|
|||||||
|
|
||||||
List<Pair<Card, List<Card>>> blockersNeedManualOrdering = new ArrayList<>();
|
List<Pair<Card, List<Card>>> blockersNeedManualOrdering = new ArrayList<>();
|
||||||
|
|
||||||
for(AttackingBand band : attackedByBands.values())
|
for (AttackingBand band : attackedByBands.values())
|
||||||
{
|
{
|
||||||
if (band.isEmpty()) continue;
|
if (band.isEmpty()) continue;
|
||||||
|
|
||||||
Collection<Card> blockers = blockedBands.get(band);
|
Collection<Card> blockers = blockedBands.get(band);
|
||||||
if ( blockers == null || blockers.isEmpty() )
|
if (blockers == null || blockers.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for(Card attacker : band.getAttackers()) {
|
for (Card attacker : band.getAttackers()) {
|
||||||
if ( blockers.size() <= 1 )
|
if (blockers.size() <= 1)
|
||||||
blockersOrderedForDamageAssignment.put(attacker, Lists.newArrayList(blockers));
|
blockersOrderedForDamageAssignment.put(attacker, Lists.newArrayList(blockers));
|
||||||
else // process it a bit later
|
else // process it a bit later
|
||||||
blockersNeedManualOrdering.add(Pair.of(attacker, (List<Card>)blockers)); // we know there's a list
|
blockersNeedManualOrdering.add(Pair.of(attacker, (List<Card>)blockers)); // we know there's a list
|
||||||
@@ -309,7 +315,7 @@ public class Combat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// brought this out of iteration on bands to avoid concurrency problems
|
// brought this out of iteration on bands to avoid concurrency problems
|
||||||
for(Pair<Card, List<Card>> pair : blockersNeedManualOrdering){
|
for (Pair<Card, List<Card>> pair : blockersNeedManualOrdering){
|
||||||
// Damage Ordering needs to take cards like Melee into account, is that happening?
|
// Damage Ordering needs to take cards like Melee into account, is that happening?
|
||||||
List<Card> orderedBlockers = playerWhoAttacks.getController().orderBlockers(pair.getLeft(), pair.getRight()); // we know there's a list
|
List<Card> orderedBlockers = playerWhoAttacks.getController().orderBlockers(pair.getLeft(), pair.getRight()); // we know there's a list
|
||||||
blockersOrderedForDamageAssignment.put(pair.getLeft(), orderedBlockers);
|
blockersOrderedForDamageAssignment.put(pair.getLeft(), orderedBlockers);
|
||||||
@@ -358,7 +364,7 @@ public class Combat {
|
|||||||
blockersOrderedForDamageAssignment.remove(c);
|
blockersOrderedForDamageAssignment.remove(c);
|
||||||
|
|
||||||
Collection<Card> blockers = blockedBands.get(ab);
|
Collection<Card> blockers = blockedBands.get(ab);
|
||||||
if ( blockers != null ) {
|
if (blockers != null) {
|
||||||
for (Card b : blockers) {
|
for (Card b : blockers) {
|
||||||
// Clear removed attacker from assignment order
|
// Clear removed attacker from assignment order
|
||||||
if (this.attackersOrderedForDamageAssignment.containsKey(b)) {
|
if (this.attackersOrderedForDamageAssignment.containsKey(b)) {
|
||||||
@@ -372,7 +378,7 @@ public class Combat {
|
|||||||
// removes references to this defender from all indices and orders
|
// removes references to this defender from all indices and orders
|
||||||
private void unregisterDefender(final Card c, AttackingBand bandBeingBlocked) {
|
private void unregisterDefender(final Card c, AttackingBand bandBeingBlocked) {
|
||||||
this.attackersOrderedForDamageAssignment.remove(c);
|
this.attackersOrderedForDamageAssignment.remove(c);
|
||||||
for(Card atk : bandBeingBlocked.getAttackers()) {
|
for (Card atk : bandBeingBlocked.getAttackers()) {
|
||||||
if (this.blockersOrderedForDamageAssignment.containsKey(atk)) {
|
if (this.blockersOrderedForDamageAssignment.containsKey(atk)) {
|
||||||
this.blockersOrderedForDamageAssignment.get(atk).remove(c);
|
this.blockersOrderedForDamageAssignment.get(atk).remove(c);
|
||||||
}
|
}
|
||||||
@@ -388,49 +394,52 @@ public class Combat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if not found in attackers, look for this card in blockers
|
// if not found in attackers, look for this card in blockers
|
||||||
for(Entry<AttackingBand, Card> be : blockedBands.entries()) {
|
for (Entry<AttackingBand, Card> be : blockedBands.entries()) {
|
||||||
if(be.getValue().equals(c)) {
|
if (be.getValue().equals(c)) {
|
||||||
unregisterDefender(c, be.getKey());
|
unregisterDefender(c, be.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove card from map
|
// remove card from map
|
||||||
while(blockedBands.values().remove(c));
|
while(blockedBands.values().remove(c));
|
||||||
|
|
||||||
} // removeFromCombat()
|
} // removeFromCombat()
|
||||||
|
|
||||||
public final void removeAbsentCombatants() {
|
public final boolean removeAbsentCombatants() {
|
||||||
// iterate all attackers and remove them
|
// iterate all attackers and remove them
|
||||||
List<Card> missingCombatants = new ArrayList<>();
|
List<Card> missingCombatants = new ArrayList<>();
|
||||||
for(Entry<GameEntity, AttackingBand> ee : attackedByBands.entries()) {
|
for (Entry<GameEntity, AttackingBand> ee : attackedByBands.entries()) {
|
||||||
List<Card> atk = ee.getValue().getAttackers();
|
List<Card> atk = ee.getValue().getAttackers();
|
||||||
for(int i = atk.size() - 1; i >= 0; i--) { // might remove items from collection, so no iterators
|
for (int i = atk.size() - 1; i >= 0; i--) { // might remove items from collection, so no iterators
|
||||||
Card c = atk.get(i);
|
Card c = atk.get(i);
|
||||||
if ( !c.isInPlay() || !c.isCreature() ) {
|
if (!c.isInPlay() || !c.isCreature()) {
|
||||||
missingCombatants.add(c);
|
missingCombatants.add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Entry<AttackingBand, Card> be : blockedBands.entries()) {
|
for (Entry<AttackingBand, Card> be : blockedBands.entries()) {
|
||||||
Card blocker = be.getValue();
|
Card blocker = be.getValue();
|
||||||
if ( !blocker.isInPlay() || !blocker.isCreature() ) {
|
if (!blocker.isInPlay() || !blocker.isCreature()) {
|
||||||
missingCombatants.add(blocker);
|
missingCombatants.add(blocker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (missingCombatants.isEmpty()) { return false; }
|
||||||
|
|
||||||
for (Card c : missingCombatants) {
|
for (Card c : missingCombatants) {
|
||||||
removeFromCombat(c);
|
removeFromCombat(c);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this method right after turn-based action of declare blockers has been performed
|
// Call this method right after turn-based action of declare blockers has been performed
|
||||||
public final void fireTriggersForUnblockedAttackers() {
|
public final void fireTriggersForUnblockedAttackers() {
|
||||||
for(AttackingBand ab : attackedByBands.values()) {
|
for (AttackingBand ab : attackedByBands.values()) {
|
||||||
Collection<Card> blockers = blockedBands.get(ab);
|
Collection<Card> blockers = blockedBands.get(ab);
|
||||||
boolean isBlocked = blockers != null && !blockers.isEmpty();
|
boolean isBlocked = blockers != null && !blockers.isEmpty();
|
||||||
ab.setBlocked(isBlocked);
|
ab.setBlocked(isBlocked);
|
||||||
|
|
||||||
if (!isBlocked )
|
if (!isBlocked) {
|
||||||
for (Card attacker : ab.getAttackers()) {
|
for (Card attacker : ab.getAttackers()) {
|
||||||
// Run Unblocked Trigger
|
// Run Unblocked Trigger
|
||||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
||||||
@@ -438,6 +447,7 @@ public class Combat {
|
|||||||
runParams.put("Defender",this.getDefenderByAttacker(attacker));
|
runParams.put("Defender",this.getDefenderByAttacker(attacker));
|
||||||
attacker.getGame().getTriggerHandler().runTrigger(TriggerType.AttackerUnblocked, runParams, false);
|
attacker.getGame().getTriggerHandler().runTrigger(TriggerType.AttackerUnblocked, runParams, false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,12 +483,11 @@ public class Combat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return assignedDamage;
|
return assignedDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final boolean assignAttackersDamage(boolean firstStrikeDamage) {
|
private final boolean assignAttackersDamage(boolean firstStrikeDamage) {
|
||||||
// Assign damage by Attackers
|
// Assign damage by Attackers
|
||||||
this.defendingDamageMap.clear(); // this should really happen in deal damage
|
this.defendingDamageMap.clear(); // this should really happen in deal damage
|
||||||
List<Card> orderedBlockers = null;
|
List<Card> orderedBlockers = null;
|
||||||
final List<Card> attackers = this.getAttackers();
|
final List<Card> attackers = this.getAttackers();
|
||||||
@@ -511,27 +520,28 @@ public class Combat {
|
|||||||
if (trampler || !band.isBlocked()) { // this is called after declare blockers, no worries 'bout nulls in isBlocked
|
if (trampler || !band.isBlocked()) { // this is called after declare blockers, no worries 'bout nulls in isBlocked
|
||||||
this.addDefendingDamage(damageDealt, attacker);
|
this.addDefendingDamage(damageDealt, attacker);
|
||||||
} // No damage happens if blocked but no blockers left
|
} // No damage happens if blocked but no blockers left
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
GameEntity defender = getDefenderByAttacker(band);
|
GameEntity defender = getDefenderByAttacker(band);
|
||||||
Player assigningPlayer = this.getAttackingPlayer();
|
Player assigningPlayer = this.getAttackingPlayer();
|
||||||
// Defensive Formation is very similar to Banding with Blockers
|
// Defensive Formation is very similar to Banding with Blockers
|
||||||
// It allows the defending player to assign damage instead of the attacking player
|
// It allows the defending player to assign damage instead of the attacking player
|
||||||
if (defender instanceof Player && defender.hasKeyword("You assign combat damage of each creature attacking you.")) {
|
if (defender instanceof Player && defender.hasKeyword("You assign combat damage of each creature attacking you.")) {
|
||||||
assigningPlayer = (Player)defender;
|
assigningPlayer = (Player)defender;
|
||||||
} else if ( AttackingBand.isValidBand(orderedBlockers, true)){
|
}
|
||||||
|
else if (AttackingBand.isValidBand(orderedBlockers, true)){
|
||||||
assigningPlayer = orderedBlockers.get(0).getController();
|
assigningPlayer = orderedBlockers.get(0).getController();
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(attacker, orderedBlockers, damageDealt, defender, this.getAttackingPlayer() != assigningPlayer);
|
Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(attacker, orderedBlockers, damageDealt, defender, this.getAttackingPlayer() != assigningPlayer);
|
||||||
for (Entry<Card, Integer> dt : map.entrySet()) {
|
for (Entry<Card, Integer> dt : map.entrySet()) {
|
||||||
if( dt.getKey() == null) {
|
if (dt.getKey() == null) {
|
||||||
if (dt.getValue() > 0)
|
if (dt.getValue() > 0)
|
||||||
addDefendingDamage(dt.getValue(), attacker);
|
addDefendingDamage(dt.getValue(), attacker);
|
||||||
} else {
|
} else {
|
||||||
dt.getKey().addAssignedDamage(dt.getValue(), attacker);
|
dt.getKey().addAssignedDamage(dt.getValue(), attacker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // if !hasFirstStrike ...
|
} // if !hasFirstStrike ...
|
||||||
} // for
|
} // for
|
||||||
return assignedDamage;
|
return assignedDamage;
|
||||||
@@ -540,12 +550,12 @@ public class Combat {
|
|||||||
private final boolean dealDamageThisPhase(Card combatant, boolean firstStrikeDamage) {
|
private final boolean dealDamageThisPhase(Card combatant, boolean firstStrikeDamage) {
|
||||||
// During first strike damage, double strike and first strike deal damage
|
// During first strike damage, double strike and first strike deal damage
|
||||||
// During regular strike damage, double strike and anyone who hasn't dealt damage deal damage
|
// During regular strike damage, double strike and anyone who hasn't dealt damage deal damage
|
||||||
if (combatant.hasDoubleStrike())
|
if (combatant.hasDoubleStrike()) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (firstStrikeDamage && combatant.hasFirstStrike())
|
if (firstStrikeDamage && combatant.hasFirstStrike()) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return !firstStrikeDamage && !this.combatantsThatDealtFirstStrikeDamage.contains(combatant);
|
return !firstStrikeDamage && !this.combatantsThatDealtFirstStrikeDamage.contains(combatant);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,13 +566,13 @@ public class Combat {
|
|||||||
if (ge instanceof Card) {
|
if (ge instanceof Card) {
|
||||||
final Card planeswalker = (Card) ge;
|
final Card planeswalker = (Card) ge;
|
||||||
planeswalker.addAssignedDamage(n, source);
|
planeswalker.addAssignedDamage(n, source);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.defendingDamageMap.containsKey(source)) {
|
if (!this.defendingDamageMap.containsKey(source)) {
|
||||||
this.defendingDamageMap.put(source, n);
|
this.defendingDamageMap.put(source, n);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this.defendingDamageMap.put(source, this.defendingDamageMap.get(source) + n);
|
this.defendingDamageMap.put(source, this.defendingDamageMap.get(source) + n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -577,14 +587,8 @@ public class Combat {
|
|||||||
return assignedDamage;
|
return assignedDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* dealAssignedDamage.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public void dealAssignedDamage() {
|
public void dealAssignedDamage() {
|
||||||
// This function handles both Regular and First Strike combat assignment
|
// This function handles both Regular and First Strike combat assignment
|
||||||
|
|
||||||
final HashMap<Card, Integer> defMap = this.defendingDamageMap;
|
final HashMap<Card, Integer> defMap = this.defendingDamageMap;
|
||||||
final HashMap<GameEntity, List<Card>> wasDamaged = new HashMap<GameEntity, List<Card>>();
|
final HashMap<GameEntity, List<Card>> wasDamaged = new HashMap<GameEntity, List<Card>>();
|
||||||
|
|
||||||
@@ -600,11 +604,13 @@ public class Combat {
|
|||||||
wasDamaged.put(defender, l);
|
wasDamaged.put(defender, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (defender instanceof Card) { // planeswalker
|
}
|
||||||
|
else if (defender instanceof Card) { // planeswalker
|
||||||
if (((Card) defender).getController().addCombatDamage(entry.getValue(), entry.getKey())) {
|
if (((Card) defender).getController().addCombatDamage(entry.getValue(), entry.getKey())) {
|
||||||
if (wasDamaged.containsKey(defender)) {
|
if (wasDamaged.containsKey(defender)) {
|
||||||
wasDamaged.get(defender).add(entry.getKey());
|
wasDamaged.get(defender).add(entry.getKey());
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
List<Card> l = new ArrayList<Card>();
|
List<Card> l = new ArrayList<Card>();
|
||||||
l.add(entry.getKey());
|
l.add(entry.getKey());
|
||||||
wasDamaged.put(defender, l);
|
wasDamaged.put(defender, l);
|
||||||
@@ -649,59 +655,42 @@ public class Combat {
|
|||||||
runParams.put("DamageTarget", ge);
|
runParams.put("DamageTarget", ge);
|
||||||
ge.getGame().getTriggerHandler().runTrigger(TriggerType.CombatDamageDoneOnce, runParams, false);
|
ge.getGame().getTriggerHandler().runTrigger(TriggerType.CombatDamageDoneOnce, runParams, false);
|
||||||
}
|
}
|
||||||
|
// This was deeper before, but that resulted in the stack entry acting like before.
|
||||||
// This was deeper before, but that resulted in the stack entry acting
|
|
||||||
// like before.
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isUnblocked.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param att
|
|
||||||
* a {@link forge.game.card.Card} object.
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isUnblocked(final Card att) {
|
public final boolean isUnblocked(final Card att) {
|
||||||
AttackingBand band = getBandOfAttacker(att);
|
AttackingBand band = getBandOfAttacker(att);
|
||||||
return band == null ? false : Boolean.FALSE.equals(band.isBlocked());
|
return band == null ? false : Boolean.FALSE.equals(band.isBlocked());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* getUnblockedAttackers.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return an array of {@link forge.game.card.Card} objects.
|
|
||||||
*/
|
|
||||||
public final List<Card> getUnblockedAttackers() {
|
public final List<Card> getUnblockedAttackers() {
|
||||||
List<Card> unblocked = new ArrayList<Card>();
|
List<Card> unblocked = new ArrayList<Card>();
|
||||||
for (AttackingBand ab : attackedByBands.values())
|
for (AttackingBand ab : attackedByBands.values()) {
|
||||||
if ( Boolean.TRUE.equals(ab.isBlocked()) )
|
if (Boolean.TRUE.equals(ab.isBlocked())) {
|
||||||
unblocked.addAll(ab.getAttackers());
|
unblocked.addAll(ab.getAttackers());
|
||||||
|
}
|
||||||
|
}
|
||||||
return unblocked;
|
return unblocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPlayerAttacked(Player who) {
|
public boolean isPlayerAttacked(Player who) {
|
||||||
for(GameEntity defender : attackedByBands.keySet() ) {
|
for (GameEntity defender : attackedByBands.keySet()) {
|
||||||
Card defenderAsCard = defender instanceof Card ? (Card)defender : null;
|
Card defenderAsCard = defender instanceof Card ? (Card)defender : null;
|
||||||
if ((null != defenderAsCard && defenderAsCard.getController() != who ) ||
|
if ((null != defenderAsCard && defenderAsCard.getController() != who) ||
|
||||||
(null == defenderAsCard && defender != who) )
|
(null == defenderAsCard && defender != who)) {
|
||||||
continue; // defender is not related to player 'who'
|
continue; // defender is not related to player 'who'
|
||||||
|
}
|
||||||
for(AttackingBand ab : attackedByBands.get(defender)) {
|
for (AttackingBand ab : attackedByBands.get(defender)) {
|
||||||
if ( !ab.isEmpty() )
|
if (!ab.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBlocking(Card blocker) {
|
public boolean isBlocking(Card blocker) {
|
||||||
if ( !blocker.isInPlay() ) {
|
if (!blocker.isInPlay()) {
|
||||||
CombatLki lki = lkiCache.get(blocker);
|
CombatLki lki = lkiCache.get(blocker);
|
||||||
return null != lki && !lki.isAttacker; // was blocking something anyway
|
return null != lki && !lki.isAttacker; // was blocking something anyway
|
||||||
}
|
}
|
||||||
@@ -710,7 +699,7 @@ public class Combat {
|
|||||||
|
|
||||||
public boolean isBlocking(Card blocker, Card attacker) {
|
public boolean isBlocking(Card blocker, Card attacker) {
|
||||||
AttackingBand ab = getBandOfAttacker(attacker);
|
AttackingBand ab = getBandOfAttacker(attacker);
|
||||||
if ( !blocker.isInPlay() ) {
|
if (!blocker.isInPlay()) {
|
||||||
CombatLki lki = lkiCache.get(blocker);
|
CombatLki lki = lkiCache.get(blocker);
|
||||||
return null != lki && !lki.isAttacker && lki.relatedBands.contains(ab); // was blocking that very band
|
return null != lki && !lki.isAttacker && lki.relatedBands.contains(ab); // was blocking that very band
|
||||||
}
|
}
|
||||||
@@ -718,21 +707,17 @@ public class Combat {
|
|||||||
return blockers != null && blockers.contains(blocker);
|
return blockers != null && blockers.contains(blocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
* @param lastKnownInfo
|
|
||||||
*/
|
|
||||||
public void saveLKI(Card lastKnownInfo) {
|
public void saveLKI(Card lastKnownInfo) {
|
||||||
List<AttackingBand> attackersBlocked = null;
|
List<AttackingBand> attackersBlocked = null;
|
||||||
AttackingBand attackingBand = getBandOfAttacker(lastKnownInfo);
|
AttackingBand attackingBand = getBandOfAttacker(lastKnownInfo);
|
||||||
boolean isAttacker = attackingBand != null;
|
boolean isAttacker = attackingBand != null;
|
||||||
if ( !isAttacker ) {
|
if (!isAttacker) {
|
||||||
attackersBlocked= getAttackingBandsBlockedBy(lastKnownInfo);
|
attackersBlocked= getAttackingBandsBlockedBy(lastKnownInfo);
|
||||||
if ( attackersBlocked.isEmpty() )
|
if (attackersBlocked.isEmpty()) {
|
||||||
return; // card was not even in combat
|
return; // card was not even in combat
|
||||||
|
}
|
||||||
}
|
}
|
||||||
List<AttackingBand> relatedBands = isAttacker ? Lists.newArrayList(attackingBand) : attackersBlocked;
|
List<AttackingBand> relatedBands = isAttacker ? Lists.newArrayList(attackingBand) : attackersBlocked;
|
||||||
lkiCache.put(lastKnownInfo, new CombatLki(isAttacker, relatedBands));
|
lkiCache.put(lastKnownInfo, new CombatLki(isAttacker, relatedBands));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} // Class Combat
|
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ public class ManaCostAdjustment {
|
|||||||
if (activator == null ) {
|
if (activator == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (CardLists.filterControlledBy(activator.getGame().getStack().getCardsCastThisTurn(),
|
if (CardLists.filterControlledBy(activator.getGame().getStack().getSpellsCastThisTurn(),
|
||||||
activator).size() > 0) {
|
activator).size() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -368,7 +368,7 @@ public class ManaCostAdjustment {
|
|||||||
if (activator == null ) {
|
if (activator == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (CardLists.filterControlledBy(activator.getGame().getStack().getCardsCastThisTurn(),
|
if (CardLists.filterControlledBy(activator.getGame().getStack().getSpellsCastThisTurn(),
|
||||||
activator).size() > 0) {
|
activator).size() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,15 +57,12 @@ import java.util.*;
|
|||||||
* @version $Id: PhaseHandler.java 13001 2012-01-08 12:25:25Z Sloth $
|
* @version $Id: PhaseHandler.java 13001 2012-01-08 12:25:25Z Sloth $
|
||||||
*/
|
*/
|
||||||
public class PhaseHandler implements java.io.Serializable {
|
public class PhaseHandler implements java.io.Serializable {
|
||||||
|
|
||||||
/** Constant <code>serialVersionUID=5207222278370963197L</code>. */
|
|
||||||
private static final long serialVersionUID = 5207222278370963197L;
|
private static final long serialVersionUID = 5207222278370963197L;
|
||||||
|
|
||||||
// Start turn at 0, since we start even before first untap
|
// Start turn at 0, since we start even before first untap
|
||||||
private PhaseType phase = null;
|
private PhaseType phase = null;
|
||||||
private int turn = 0;
|
private int turn = 0;
|
||||||
|
|
||||||
|
|
||||||
private final transient Stack<ExtraTurn> extraTurns = new Stack<ExtraTurn>();
|
private final transient Stack<ExtraTurn> extraTurns = new Stack<ExtraTurn>();
|
||||||
private final transient Map<PhaseType, Stack<PhaseType>> extraPhases = new HashMap<PhaseType, Stack<PhaseType>>();
|
private final transient Map<PhaseType, Stack<PhaseType>> extraPhases = new HashMap<PhaseType, Stack<PhaseType>>();
|
||||||
|
|
||||||
@@ -93,97 +90,70 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
private final transient Game game;
|
private final transient Game game;
|
||||||
|
|
||||||
public PhaseHandler(final Game game0) {
|
public PhaseHandler(final Game game0) {
|
||||||
|
|
||||||
game = game0;
|
game = game0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final PhaseType getPhase() {
|
||||||
|
return phase;
|
||||||
|
}
|
||||||
|
private final void setPhase(final PhaseType phase0) {
|
||||||
|
if (phase == phase0) { return; }
|
||||||
|
phase = phase0;
|
||||||
|
game.updatePhaseForView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getTurn() {
|
||||||
|
return turn;
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean isPlayerTurn(final Player player) {
|
public final boolean isPlayerTurn(final Player player) {
|
||||||
return player.equals(this.playerTurn);
|
return player.equals(playerTurn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void setPlayerTurn(final Player s) {
|
|
||||||
this.playerTurn = s;
|
|
||||||
this.setPriority(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Getter for the field <code>playerTurn</code>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a {@link forge.game.player.Player} object.
|
|
||||||
*/
|
|
||||||
public final Player getPlayerTurn() {
|
public final Player getPlayerTurn() {
|
||||||
return this.playerTurn;
|
return playerTurn;
|
||||||
|
}
|
||||||
|
private final void setPlayerTurn(final Player playerTurn0) {
|
||||||
|
if (playerTurn == playerTurn0) { return; }
|
||||||
|
playerTurn = playerTurn0;
|
||||||
|
game.updatePlayerTurnForView();
|
||||||
|
setPriority(playerTurn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// priority player
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* getPriorityPlayer.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a {@link forge.game.player.Player} object.
|
|
||||||
*/
|
|
||||||
public final Player getPriorityPlayer() {
|
public final Player getPriorityPlayer() {
|
||||||
return this.pPlayerPriority;
|
return pPlayerPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* setPriority.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param p
|
|
||||||
* a {@link forge.game.player.Player} object.
|
|
||||||
*/
|
|
||||||
public final void setPriority(final Player p) {
|
public final void setPriority(final Player p) {
|
||||||
this.pFirstPriority = p;
|
pFirstPriority = p;
|
||||||
this.pPlayerPriority = p;
|
pPlayerPriority = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* resetPriority.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public final void resetPriority() {
|
public final void resetPriority() {
|
||||||
this.setPriority(this.playerTurn);
|
setPriority(playerTurn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* inCombat.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean inCombat() { return combat != null; }
|
public final boolean inCombat() { return combat != null; }
|
||||||
public final Combat getCombat() { return this.combat; }
|
public final Combat getCombat() { return combat; }
|
||||||
|
|
||||||
private void advanceToNextPhase() {
|
private void advanceToNextPhase() {
|
||||||
PhaseType oldPhase = phase;
|
PhaseType oldPhase = phase;
|
||||||
|
|
||||||
if (this.bRepeatCleanup) { // for when Cleanup needs to repeat itself
|
if (bRepeatCleanup) { // for when Cleanup needs to repeat itself
|
||||||
this.bRepeatCleanup = false;
|
bRepeatCleanup = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If the phase that's ending has a stack of additional phases
|
// If the phase that's ending has a stack of additional phases
|
||||||
// Take the LIFO one and move to that instead of the normal one
|
// Take the LIFO one and move to that instead of the normal one
|
||||||
if (this.extraPhases.containsKey(phase)) {
|
if (extraPhases.containsKey(phase)) {
|
||||||
PhaseType nextPhase = this.extraPhases.get(phase).pop();
|
PhaseType nextPhase = extraPhases.get(phase).pop();
|
||||||
// If no more additional phases are available, remove it from the map
|
// If no more additional phases are available, remove it from the map
|
||||||
// and let the next add, reput the key
|
// and let the next add, reput the key
|
||||||
if (this.extraPhases.get(phase).isEmpty()) {
|
if (extraPhases.get(phase).isEmpty()) {
|
||||||
this.extraPhases.remove(phase);
|
extraPhases.remove(phase);
|
||||||
}
|
}
|
||||||
this.phase = nextPhase;
|
setPhase(nextPhase);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.phase = PhaseType.getNext(phase);
|
setPhase(PhaseType.getNext(phase));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +161,9 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
|
|
||||||
String phaseType = oldPhase == phase ? "Repeat" : phase == PhaseType.getNext(oldPhase) ? "" : "Additional";
|
String phaseType = oldPhase == phase ? "Repeat" : phase == PhaseType.getNext(oldPhase) ? "" : "Additional";
|
||||||
|
|
||||||
if (this.phase == PhaseType.UNTAP) {
|
if (phase == PhaseType.UNTAP) {
|
||||||
this.turn++;
|
turn++;
|
||||||
|
game.updateTurnForView();
|
||||||
game.fireEvent(new GameEventTurnBegan(playerTurn, turn));
|
game.fireEvent(new GameEventTurnBegan(playerTurn, turn));
|
||||||
|
|
||||||
// Tokens starting game in play should suffer from Sum. Sickness
|
// Tokens starting game in play should suffer from Sum. Sickness
|
||||||
@@ -210,7 +181,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
playerTurn.setNumPowerSurgeLands(lands.size());
|
playerTurn.setNumPowerSurgeLands(lands.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
game.fireEvent(new GameEventTurnPhase(this.getPlayerTurn(), this.getPhase(), phaseType));
|
game.fireEvent(new GameEventTurnPhase(playerTurn, phase, phaseType));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSkippingPhase(PhaseType phase) {
|
private boolean isSkippingPhase(PhaseType phase) {
|
||||||
@@ -224,10 +195,10 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
return playerTurn.hasKeyword("Skip the untap step of this turn.") || playerTurn.hasKeyword("Skip your untap step.");
|
return playerTurn.hasKeyword("Skip the untap step of this turn.") || playerTurn.hasKeyword("Skip your untap step.");
|
||||||
|
|
||||||
case UPKEEP:
|
case UPKEEP:
|
||||||
return getPlayerTurn().hasKeyword("Skip your upkeep step.");
|
return playerTurn.hasKeyword("Skip your upkeep step.");
|
||||||
|
|
||||||
case DRAW:
|
case DRAW:
|
||||||
return getPlayerTurn().isSkippingDraw() || getTurn() == 1 && game.getPlayers().size() == 2;
|
return playerTurn.isSkippingDraw() || turn == 1 && game.getPlayers().size() == 2;
|
||||||
|
|
||||||
case COMBAT_BEGIN:
|
case COMBAT_BEGIN:
|
||||||
case COMBAT_DECLARE_ATTACKERS:
|
case COMBAT_DECLARE_ATTACKERS:
|
||||||
@@ -236,7 +207,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
case COMBAT_DECLARE_BLOCKERS:
|
case COMBAT_DECLARE_BLOCKERS:
|
||||||
case COMBAT_FIRST_STRIKE_DAMAGE:
|
case COMBAT_FIRST_STRIKE_DAMAGE:
|
||||||
case COMBAT_DAMAGE:
|
case COMBAT_DAMAGE:
|
||||||
return !this.inCombat();
|
return !inCombat();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -256,7 +227,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Perform turn-based actions
|
// Perform turn-based actions
|
||||||
switch(this.getPhase()) {
|
switch (phase) {
|
||||||
case UNTAP:
|
case UNTAP:
|
||||||
givePriorityToPlayer = false;
|
givePriorityToPlayer = false;
|
||||||
game.getUntap().executeUntil(playerTurn);
|
game.getUntap().executeUntil(playerTurn);
|
||||||
@@ -264,19 +235,19 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case UPKEEP:
|
case UPKEEP:
|
||||||
this.nUpkeepsThisTurn++;
|
nUpkeepsThisTurn++;
|
||||||
this.nUpkeepsThisGame++;
|
nUpkeepsThisGame++;
|
||||||
game.getUpkeep().executeUntil(this.getPlayerTurn());
|
game.getUpkeep().executeUntil(playerTurn);
|
||||||
game.getUpkeep().executeAt();
|
game.getUpkeep().executeAt();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRAW:
|
case DRAW:
|
||||||
this.getPlayerTurn().drawCard();
|
playerTurn.drawCard();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MAIN1:
|
case MAIN1:
|
||||||
if (this.getPlayerTurn().isArchenemy() && this.isPreCombatMain()) {
|
if (playerTurn.isArchenemy() && isPreCombatMain()) {
|
||||||
this.getPlayerTurn().setSchemeInMotion();
|
playerTurn.setSchemeInMotion();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -294,6 +265,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
if (combat != null && combat.getAttackers().isEmpty()
|
if (combat != null && combat.getAttackers().isEmpty()
|
||||||
&& !game.getTriggerHandler().hasDelayedTriggers()) {
|
&& !game.getTriggerHandler().hasDelayedTriggers()) {
|
||||||
combat = null;
|
combat = null;
|
||||||
|
game.updateCombatForView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,11 +280,13 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case COMBAT_FIRST_STRIKE_DAMAGE:
|
case COMBAT_FIRST_STRIKE_DAMAGE:
|
||||||
combat.removeAbsentCombatants();
|
if (combat.removeAbsentCombatants()) {
|
||||||
|
game.updateCombatForView();
|
||||||
|
}
|
||||||
|
|
||||||
// no first strikers, skip this step
|
// no first strikers, skip this step
|
||||||
if (!combat.assignCombatDamage(true)) {
|
if (!combat.assignCombatDamage(true)) {
|
||||||
this.givePriorityToPlayer = false;
|
givePriorityToPlayer = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
combat.dealAssignedDamage();
|
combat.dealAssignedDamage();
|
||||||
@@ -320,10 +294,12 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case COMBAT_DAMAGE:
|
case COMBAT_DAMAGE:
|
||||||
combat.removeAbsentCombatants();
|
if (combat.removeAbsentCombatants()) {
|
||||||
|
game.updateCombatForView();
|
||||||
|
}
|
||||||
|
|
||||||
if (!combat.assignCombatDamage(false)) {
|
if (!combat.assignCombatDamage(false)) {
|
||||||
this.givePriorityToPlayer = false;
|
givePriorityToPlayer = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
combat.dealAssignedDamage();
|
combat.dealAssignedDamage();
|
||||||
@@ -374,9 +350,9 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
player.onCleanupPhase();
|
player.onCleanupPhase();
|
||||||
player.getController().autoPassCancel(); // autopass won't wrap to next turn
|
player.getController().autoPassCancel(); // autopass won't wrap to next turn
|
||||||
}
|
}
|
||||||
this.getPlayerTurn().removeKeyword("Skip all combat phases of this turn.");
|
playerTurn.removeKeyword("Skip all combat phases of this turn.");
|
||||||
game.getCleanup().executeUntil(this.getNextTurn());
|
game.getCleanup().executeUntil(getNextTurn());
|
||||||
this.nUpkeepsThisTurn = 0;
|
nUpkeepsThisTurn = 0;
|
||||||
|
|
||||||
// Rule 514.3
|
// Rule 514.3
|
||||||
givePriorityToPlayer = false;
|
givePriorityToPlayer = false;
|
||||||
@@ -393,8 +369,8 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
if (!skipped) {
|
if (!skipped) {
|
||||||
// Run triggers if phase isn't being skipped
|
// Run triggers if phase isn't being skipped
|
||||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
||||||
runParams.put("Phase", this.getPhase().nameForScripts);
|
runParams.put("Phase", phase.nameForScripts);
|
||||||
runParams.put("Player", this.getPlayerTurn());
|
runParams.put("Player", playerTurn);
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.Phase, runParams, false);
|
game.getTriggerHandler().runTrigger(TriggerType.Phase, runParams, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +384,6 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void onPhaseEnd() {
|
private void onPhaseEnd() {
|
||||||
// If the Stack isn't empty why is nextPhase being called?
|
// If the Stack isn't empty why is nextPhase being called?
|
||||||
if (!game.getStack().isEmpty()) {
|
if (!game.getStack().isEmpty()) {
|
||||||
@@ -428,19 +403,19 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (this.phase) {
|
switch (phase) {
|
||||||
case UNTAP:
|
case UNTAP:
|
||||||
this.nCombatsThisTurn = 0;
|
nCombatsThisTurn = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UPKEEP:
|
case UPKEEP:
|
||||||
for (Card c : game.getCardsIn(ZoneType.Battlefield)) {
|
for (Card c : game.getCardsIn(ZoneType.Battlefield)) {
|
||||||
c.getDamageHistory().setNotAttackedSinceLastUpkeepOf(this.getPlayerTurn());
|
c.getDamageHistory().setNotAttackedSinceLastUpkeepOf(playerTurn);
|
||||||
c.getDamageHistory().setNotBlockedSinceLastUpkeepOf(this.getPlayerTurn());
|
c.getDamageHistory().setNotBlockedSinceLastUpkeepOf(playerTurn);
|
||||||
c.getDamageHistory().setNotBeenBlockedSinceLastUpkeepOf(this.getPlayerTurn());
|
c.getDamageHistory().setNotBeenBlockedSinceLastUpkeepOf(playerTurn);
|
||||||
}
|
}
|
||||||
game.getUpkeep().executeUntilEndOfPhase(this.getPlayerTurn());
|
game.getUpkeep().executeUntilEndOfPhase(playerTurn);
|
||||||
game.getUpkeep().registerUntilEndCommand(this.getPlayerTurn());
|
game.getUpkeep().registerUntilEndCommand(playerTurn);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMBAT_END:
|
case COMBAT_END:
|
||||||
@@ -451,7 +426,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
eventEndCombat = new GameEventCombatEnded(attackers, blockers);
|
eventEndCombat = new GameEventCombatEnded(attackers, blockers);
|
||||||
}
|
}
|
||||||
combat = null;
|
combat = null;
|
||||||
this.getPlayerTurn().resetAttackedThisCombat();
|
playerTurn.resetAttackedThisCombat();
|
||||||
|
|
||||||
if (eventEndCombat != null) {
|
if (eventEndCombat != null) {
|
||||||
game.fireEvent(eventEndCombat);
|
game.fireEvent(eventEndCombat);
|
||||||
@@ -459,11 +434,11 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CLEANUP:
|
case CLEANUP:
|
||||||
this.bPreventCombatDamageThisTurn = false;
|
bPreventCombatDamageThisTurn = false;
|
||||||
if (!this.bRepeatCleanup) {
|
if (!bRepeatCleanup) {
|
||||||
this.setPlayerTurn(this.handleNextTurn());
|
setPlayerTurn(handleNextTurn());
|
||||||
}
|
}
|
||||||
this.planarDiceRolledthisTurn = 0;
|
planarDiceRolledthisTurn = 0;
|
||||||
// Play the End Turn sound
|
// Play the End Turn sound
|
||||||
game.fireEvent(new GameEventTurnEnded());
|
game.fireEvent(new GameEventTurnEnded());
|
||||||
break;
|
break;
|
||||||
@@ -498,7 +473,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nCombatsThisTurn++;
|
nCombatsThisTurn++;
|
||||||
|
|
||||||
// Prepare and fire event 'attackers declared'
|
// Prepare and fire event 'attackers declared'
|
||||||
Multimap<GameEntity, Card> attackersMap = ArrayListMultimap.create();
|
Multimap<GameEntity, Card> attackersMap = ArrayListMultimap.create();
|
||||||
@@ -544,11 +519,10 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
game.getTriggerHandler().resetActiveTriggers();
|
game.getTriggerHandler().resetActiveTriggers();
|
||||||
|
game.updateCombatForView();
|
||||||
game.fireEvent(new GameEventCombatChanged());
|
game.fireEvent(new GameEventCombatChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void declareBlockersTurnBasedAction() {
|
private void declareBlockersTurnBasedAction() {
|
||||||
Player p = playerTurn;
|
Player p = playerTurn;
|
||||||
|
|
||||||
@@ -688,10 +662,10 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
a.getDamageHistory().setCreatureGotBlockedThisCombat(true);
|
a.getDamageHistory().setCreatureGotBlockedThisCombat(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game.updateCombatForView();
|
||||||
game.fireEvent(new GameEventCombatChanged());
|
game.fireEvent(new GameEventCombatChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static boolean payRequiredBlockCosts(Game game, Card blocker, Card attacker) {
|
private static boolean payRequiredBlockCosts(Game game, Card blocker, Card attacker) {
|
||||||
Cost blockCost = new Cost(ManaCost.ZERO, true);
|
Cost blockCost = new Cost(ManaCost.ZERO, true);
|
||||||
// Sort abilities to apply them in proper order
|
// Sort abilities to apply them in proper order
|
||||||
@@ -711,24 +685,11 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
return noCost || blocker.getController().getController().payManaOptional(blocker, blockCost, fakeSA, "Pay cost to declare " + blocker + " a blocker. ", ManaPaymentPurpose.DeclareBlocker);
|
return noCost || blocker.getController().getController().payManaOptional(blocker, blockCost, fakeSA, "Pay cost to declare " + blocker + " a blocker. ", ManaPaymentPurpose.DeclareBlocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if is prevent combat damage this turn.
|
|
||||||
*
|
|
||||||
* @return true, if is prevent combat damage this turn
|
|
||||||
*/
|
|
||||||
public final boolean isPreventCombatDamageThisTurn() {
|
public final boolean isPreventCombatDamageThisTurn() {
|
||||||
return this.bPreventCombatDamageThisTurn;
|
return bPreventCombatDamageThisTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* handleNextTurn.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a {@link forge.game.player.Player} object.
|
|
||||||
*/
|
|
||||||
private Player handleNextTurn() {
|
private Player handleNextTurn() {
|
||||||
|
|
||||||
game.getStack().onNextTurn();
|
game.getStack().onNextTurn();
|
||||||
|
|
||||||
for (final Player p1 : game.getPlayers()) {
|
for (final Player p1 : game.getPlayers()) {
|
||||||
@@ -762,35 +723,28 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* getNextActivePlayer.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a {@link forge.game.player.Player} object.
|
|
||||||
*/
|
|
||||||
private Player getNextActivePlayer() {
|
private Player getNextActivePlayer() {
|
||||||
|
ExtraTurn extraTurn = !extraTurns.isEmpty() ? extraTurns.pop() : null;
|
||||||
ExtraTurn extraTurn = !this.extraTurns.isEmpty() ? this.extraTurns.pop() : null;
|
Player nextPlayer = extraTurn != null ? extraTurn.getPlayer() : game.getNextPlayerAfter(playerTurn);
|
||||||
Player nextPlayer = extraTurn != null ? extraTurn.getPlayer() : game.getNextPlayerAfter(this.getPlayerTurn());
|
|
||||||
|
|
||||||
if (extraTurn != null) {
|
if (extraTurn != null) {
|
||||||
// The bottom of the extra turn stack is the normal turn
|
// The bottom of the extra turn stack is the normal turn
|
||||||
nextPlayer.setExtraTurn(!this.extraTurns.isEmpty());
|
nextPlayer.setExtraTurn(!extraTurns.isEmpty());
|
||||||
if (nextPlayer.hasKeyword("If you would begin an extra turn, skip that turn instead.")) {
|
if (nextPlayer.hasKeyword("If you would begin an extra turn, skip that turn instead.")) {
|
||||||
return getNextActivePlayer();
|
return getNextActivePlayer();
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
nextPlayer.setExtraTurn(false);
|
nextPlayer.setExtraTurn(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (nextPlayer.hasKeyword("Skip your next turn.")) {
|
if (nextPlayer.hasKeyword("Skip your next turn.")) {
|
||||||
nextPlayer.removeKeyword("Skip your next turn.");
|
nextPlayer.removeKeyword("Skip your next turn.");
|
||||||
if( null == extraTurn )
|
if( null == extraTurn )
|
||||||
this.setPlayerTurn(nextPlayer);
|
setPlayerTurn(nextPlayer);
|
||||||
return getNextActivePlayer();
|
return getNextActivePlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -808,7 +762,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
crd.untap();
|
crd.untap();
|
||||||
if( null == extraTurn )
|
if( null == extraTurn )
|
||||||
this.setPlayerTurn(nextPlayer);
|
setPlayerTurn(nextPlayer);
|
||||||
return getNextActivePlayer();
|
return getNextActivePlayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -824,152 +778,55 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
nextPlayer.addKeyword("Schemes can't be set in motion this turn.");
|
nextPlayer.addKeyword("Schemes can't be set in motion this turn.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextPlayer;
|
return nextPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public final synchronized boolean is(final PhaseType phase0, final Player player0) {
|
||||||
* <p>
|
return phase == phase0 && playerTurn.equals(player0);
|
||||||
* is.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param phase
|
|
||||||
* a {@link java.lang.String} object.
|
|
||||||
* @param player
|
|
||||||
* a {@link forge.game.player.Player} object.
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final synchronized boolean is(final PhaseType phase, final Player player) {
|
|
||||||
return this.getPhase() == phase && this.getPlayerTurn().equals(player);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* is.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param phase0
|
|
||||||
* a {@link forge.game.phase.PhaseType} object.
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final synchronized boolean is(final PhaseType phase0) {
|
public final synchronized boolean is(final PhaseType phase0) {
|
||||||
return this.getPhase() == phase0;
|
return phase == phase0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* getPhase.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a {@link java.lang.String} object.
|
|
||||||
*/
|
|
||||||
public final PhaseType getPhase() {
|
|
||||||
return phase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Getter for the field <code>turn</code>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a int.
|
|
||||||
*/
|
|
||||||
public final int getTurn() {
|
|
||||||
return this.turn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* getNextTurn.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a {@link forge.game.player.Player} object.
|
|
||||||
*/
|
|
||||||
public final Player getNextTurn() {
|
public final Player getNextTurn() {
|
||||||
if (this.extraTurns.isEmpty()) {
|
if (extraTurns.isEmpty()) {
|
||||||
return game.getNextPlayerAfter(this.getPlayerTurn());
|
return game.getNextPlayerAfter(playerTurn);
|
||||||
}
|
}
|
||||||
|
return extraTurns.peek().getPlayer();
|
||||||
return this.extraTurns.peek().getPlayer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* addExtraTurn.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param player
|
|
||||||
* a {@link forge.game.player.Player} object.
|
|
||||||
*/
|
|
||||||
public final ExtraTurn addExtraTurn(final Player player) {
|
public final ExtraTurn addExtraTurn(final Player player) {
|
||||||
// use a stack to handle extra turns, make sure the bottom of the stack
|
// use a stack to handle extra turns, make sure the bottom of the stack
|
||||||
// restores original turn order
|
// restores original turn order
|
||||||
if (this.extraTurns.isEmpty()) {
|
if (extraTurns.isEmpty()) {
|
||||||
this.extraTurns.push(new ExtraTurn(game.getNextPlayerAfter(this.getPlayerTurn())));
|
extraTurns.push(new ExtraTurn(game.getNextPlayerAfter(playerTurn)));
|
||||||
}
|
}
|
||||||
|
return extraTurns.push(new ExtraTurn(player));
|
||||||
return this.extraTurns.push(new ExtraTurn(player));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* addExtraPhase.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public final void addExtraPhase(final PhaseType afterPhase, final PhaseType extraPhase) {
|
public final void addExtraPhase(final PhaseType afterPhase, final PhaseType extraPhase) {
|
||||||
// 500.8. Some effects can add phases to a turn. They do this by adding the phases directly after the specified phase.
|
// 500.8. Some effects can add phases to a turn. They do this by adding the phases directly after the specified phase.
|
||||||
// If multiple extra phases are created after the same phase, the most recently created phase will occur first.
|
// If multiple extra phases are created after the same phase, the most recently created phase will occur first.
|
||||||
if (!this.extraPhases.containsKey(afterPhase)) {
|
if (!extraPhases.containsKey(afterPhase)) {
|
||||||
this.extraPhases.put(afterPhase, new Stack<PhaseType>());
|
extraPhases.put(afterPhase, new Stack<PhaseType>());
|
||||||
}
|
}
|
||||||
|
extraPhases.get(afterPhase).push(extraPhase);
|
||||||
this.extraPhases.get(afterPhase).push(extraPhase);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isFirstCombat.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isFirstCombat() {
|
public final boolean isFirstCombat() {
|
||||||
return (this.nCombatsThisTurn == 1);
|
return (nCombatsThisTurn == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isFirstUpkeep.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isFirstUpkeep() {
|
public final boolean isFirstUpkeep() {
|
||||||
return (this.nUpkeepsThisTurn == 0);
|
return (nUpkeepsThisTurn == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isFirstUpkeepThisGame.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isFirstUpkeepThisGame() {
|
public final boolean isFirstUpkeepThisGame() {
|
||||||
return (this.nUpkeepsThisGame == 0);
|
return (nUpkeepsThisGame == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isPreCombatMain.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isPreCombatMain() {
|
public final boolean isPreCombatMain() {
|
||||||
return (this.nCombatsThisTurn == 0);
|
return (nCombatsThisTurn == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static boolean DEBUG_PHASES = false;
|
private final static boolean DEBUG_PHASES = false;
|
||||||
@@ -996,7 +853,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
sw.start();
|
sw.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
game.fireEvent(new GameEventPlayerPriority(getPlayerTurn(), getPhase(), getPriorityPlayer()));
|
game.fireEvent(new GameEventPlayerPriority(playerTurn, phase, getPriorityPlayer()));
|
||||||
SpellAbility chosenSa = null;
|
SpellAbility chosenSa = null;
|
||||||
|
|
||||||
int loopCount = 0;
|
int loopCount = 0;
|
||||||
@@ -1017,7 +874,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
if (playerTurn.hasLost() && pPlayerPriority.equals(playerTurn) && pFirstPriority.equals(playerTurn)) {
|
if (playerTurn.hasLost() && pPlayerPriority.equals(playerTurn) && pFirstPriority.equals(playerTurn)) {
|
||||||
// If the active player has lost, and they have priority, set the next player to have priority
|
// If the active player has lost, and they have priority, set the next player to have priority
|
||||||
System.out.println("Active player is no longer in the game...");
|
System.out.println("Active player is no longer in the game...");
|
||||||
pPlayerPriority = game.getNextPlayerAfter(this.getPriorityPlayer());
|
pPlayerPriority = game.getNextPlayerAfter(getPriorityPlayer());
|
||||||
pFirstPriority = pPlayerPriority;
|
pFirstPriority = pPlayerPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1045,13 +902,13 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (DEBUG_PHASES){
|
else if (DEBUG_PHASES){
|
||||||
System.out.print(" >> (no priority given to " + this.getPriorityPlayer() + ")\n");
|
System.out.print(" >> (no priority given to " + getPriorityPlayer() + ")\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// actingPlayer is the player who may act
|
// actingPlayer is the player who may act
|
||||||
// the firstAction is the player who gained Priority First in this segment
|
// the firstAction is the player who gained Priority First in this segment
|
||||||
// of Priority
|
// of Priority
|
||||||
Player nextPlayer = game.getNextPlayerAfter(this.getPriorityPlayer());
|
Player nextPlayer = game.getNextPlayerAfter(getPriorityPlayer());
|
||||||
|
|
||||||
if (game.isGameOver() || nextPlayer == null) { return; } // conceded?
|
if (game.isGameOver() || nextPlayer == null) { return; } // conceded?
|
||||||
|
|
||||||
@@ -1060,13 +917,13 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
if (pFirstPriority == nextPlayer) {
|
if (pFirstPriority == nextPlayer) {
|
||||||
if (game.getStack().isEmpty()) {
|
if (game.getStack().isEmpty()) {
|
||||||
if (playerTurn.hasLost()) {
|
if (playerTurn.hasLost()) {
|
||||||
this.setPriority(game.getNextPlayerAfter(playerTurn));
|
setPriority(game.getNextPlayerAfter(playerTurn));
|
||||||
} else {
|
} else {
|
||||||
this.setPriority(playerTurn);
|
setPriority(playerTurn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// end phase
|
// end phase
|
||||||
this.givePriorityToPlayer = true;
|
givePriorityToPlayer = true;
|
||||||
onPhaseEnd();
|
onPhaseEnd();
|
||||||
advanceToNextPhase();
|
advanceToNextPhase();
|
||||||
onPhaseBegin();
|
onPhaseBegin();
|
||||||
@@ -1075,12 +932,13 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// pass the priority to other player
|
// pass the priority to other player
|
||||||
this.pPlayerPriority = nextPlayer;
|
pPlayerPriority = nextPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If ever the karn's ultimate resolved
|
// If ever the karn's ultimate resolved
|
||||||
if (game.getAge() == GameStage.RestartedByKarn) {
|
if (game.getAge() == GameStage.RestartedByKarn) {
|
||||||
phase = null;
|
setPhase(null);
|
||||||
|
game.updatePhaseForView();
|
||||||
game.fireEvent(new GameEventGameRestarted(playerTurn));
|
game.fireEvent(new GameEventGameRestarted(playerTurn));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1090,53 +948,50 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
// this is a hack for the setup game state mode, do not use outside of devSetupGameState code
|
// this is a hack for the setup game state mode, do not use outside of devSetupGameState code
|
||||||
// as it avoids calling any of the phase effects that may be necessary in a less enforced context
|
// as it avoids calling any of the phase effects that may be necessary in a less enforced context
|
||||||
public final void devModeSet(final PhaseType phase0, final Player player0) {
|
public final void devModeSet(final PhaseType phase0, final Player player0) {
|
||||||
if (null != phase0) this.phase = phase0;
|
if (phase0 != null) {
|
||||||
if (null != player0) {
|
setPhase(phase0);
|
||||||
|
}
|
||||||
|
if (player0 != null) {
|
||||||
setPlayerTurn(player0);
|
setPlayerTurn(player0);
|
||||||
}
|
}
|
||||||
|
|
||||||
game.fireEvent(new GameEventTurnPhase(this.getPlayerTurn(), this.getPhase(), ""));
|
game.fireEvent(new GameEventTurnPhase(playerTurn, phase, ""));
|
||||||
combat = null; // not-null can be created only when declare attackers phase begins
|
combat = null; // not-null can be created only when declare attackers phase begins
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void endTurnByEffect() {
|
public final void endTurnByEffect() {
|
||||||
this.combat = null;
|
combat = null;
|
||||||
this.extraPhases.clear();
|
extraPhases.clear();
|
||||||
this.phase = PhaseType.CLEANUP;
|
setPhase(PhaseType.CLEANUP);
|
||||||
this.onPhaseBegin();
|
onPhaseBegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public final void setPreventCombatDamageThisTurn(final boolean b) {
|
public final void setPreventCombatDamageThisTurn(final boolean b) {
|
||||||
this.bPreventCombatDamageThisTurn = true;
|
bPreventCombatDamageThisTurn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the planarDiceRolledthisTurn
|
|
||||||
*/
|
|
||||||
public int getPlanarDiceRolledthisTurn() {
|
public int getPlanarDiceRolledthisTurn() {
|
||||||
return planarDiceRolledthisTurn;
|
return planarDiceRolledthisTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incPlanarDiceRolledthisTurn() {
|
public void incPlanarDiceRolledthisTurn() {
|
||||||
this.planarDiceRolledthisTurn++;
|
planarDiceRolledthisTurn++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String debugPrintState(boolean hasPriority) {
|
public String debugPrintState(boolean hasPriority) {
|
||||||
return String.format("%s's %s [%sP] %s", getPlayerTurn(), getPhase().nameForUi, hasPriority ? "+" : "-", getPriorityPlayer());
|
return String.format("%s's %s [%sP] %s", playerTurn, phase.nameForUi, hasPriority ? "+" : "-", getPriorityPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
// just to avoid exposing variable to oute classes
|
// just to avoid exposing variable to outer classes
|
||||||
public void onStackResolved() {
|
public void onStackResolved() {
|
||||||
givePriorityToPlayer = true;
|
givePriorityToPlayer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setPlayerDeclaresBlockers(Player player) {
|
public final void setPlayerDeclaresAttackers(Player player) {
|
||||||
this.playerDeclaresBlockers = player;
|
playerDeclaresAttackers = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setPlayerDeclaresAttackers(Player player) {
|
public final void setPlayerDeclaresBlockers(Player player) {
|
||||||
this.playerDeclaresAttackers = player;
|
playerDeclaresBlockers = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endCombat() {
|
public void endCombat() {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class StaticAbilityCantBeCast {
|
|||||||
if (params.containsKey("NumLimitEachTurn") && activator != null) {
|
if (params.containsKey("NumLimitEachTurn") && activator != null) {
|
||||||
int limit = Integer.parseInt(params.get("NumLimitEachTurn"));
|
int limit = Integer.parseInt(params.get("NumLimitEachTurn"));
|
||||||
String valid = params.containsKey("ValidCard") ? params.get("ValidCard") : "Card";
|
String valid = params.containsKey("ValidCard") ? params.get("ValidCard") : "Card";
|
||||||
List<Card> thisTurnCast = CardLists.getValidCards(card.getGame().getStack().getCardsCastThisTurn(),
|
List<Card> thisTurnCast = CardLists.getValidCards(card.getGame().getStack().getSpellsCastThisTurn(),
|
||||||
valid, card.getController(), card);
|
valid, card.getController(), card);
|
||||||
if (CardLists.filterControlledBy(thisTurnCast, activator).size() < limit) {
|
if (CardLists.filterControlledBy(thisTurnCast, activator).size() < limit) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -80,62 +80,31 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
|
|
||||||
private final Game game;
|
private final Game game;
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for Constructor.
|
|
||||||
* @param gameState
|
|
||||||
*/
|
|
||||||
public MagicStack(Game gameState) {
|
public MagicStack(Game gameState) {
|
||||||
game = gameState;
|
game = gameState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isFrozen.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isFrozen() {
|
public final boolean isFrozen() {
|
||||||
return this.frozen;
|
return frozen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Setter for the field <code>frozen</code>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param frozen0
|
|
||||||
* a boolean.
|
|
||||||
*/
|
|
||||||
public final void setFrozen(final boolean frozen0) {
|
public final void setFrozen(final boolean frozen0) {
|
||||||
this.frozen = frozen0;
|
frozen = frozen0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* reset.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public final void reset() {
|
public final void reset() {
|
||||||
this.clear();
|
clear();
|
||||||
this.simultaneousStackEntryList.clear();
|
simultaneousStackEntryList.clear();
|
||||||
this.frozen = false;
|
frozen = false;
|
||||||
this.lastTurnCast.clear();
|
lastTurnCast.clear();
|
||||||
this.thisTurnCast.clear();
|
thisTurnCast.clear();
|
||||||
this.curResolvingCard = null;
|
curResolvingCard = null;
|
||||||
this.frozenStack.clear();
|
frozenStack.clear();
|
||||||
this.clearUndoStack();
|
clearUndoStack();
|
||||||
|
game.updateStackForView();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isSplitSecondOnStack.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isSplitSecondOnStack() {
|
public final boolean isSplitSecondOnStack() {
|
||||||
for(SpellAbilityStackInstance si : this.stack) {
|
for(SpellAbilityStackInstance si : stack) {
|
||||||
if (si.isSpell() && si.getSourceCard().hasKeyword("Split second")) {
|
if (si.isSpell() && si.getSourceCard().hasKeyword("Split second")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -143,23 +112,10 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* freezeStack.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public final void freezeStack() {
|
public final void freezeStack() {
|
||||||
this.frozen = true;
|
frozen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* addAndUnfreeze.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param ability
|
|
||||||
* a {@link forge.game.spellability.SpellAbility} object.
|
|
||||||
*/
|
|
||||||
public final void addAndUnfreeze(final SpellAbility ability) {
|
public final void addAndUnfreeze(final SpellAbility ability) {
|
||||||
ability.getRestrictions().abilityActivated();
|
ability.getRestrictions().abilityActivated();
|
||||||
ability.checkActivationResloveSubs();
|
ability.checkActivationResloveSubs();
|
||||||
@@ -174,80 +130,39 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Always add the ability here and always unfreeze the stack
|
// Always add the ability here and always unfreeze the stack
|
||||||
this.add(ability);
|
add(ability);
|
||||||
this.unfreezeStack();
|
unfreezeStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* unfreezeStack.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public final void unfreezeStack() {
|
public final void unfreezeStack() {
|
||||||
this.frozen = false;
|
frozen = false;
|
||||||
|
|
||||||
// Add all Frozen Abilities onto the stack
|
// Add all Frozen Abilities onto the stack
|
||||||
while (!this.frozenStack.isEmpty()) {
|
while (!frozenStack.isEmpty()) {
|
||||||
final SpellAbility sa = this.frozenStack.pop().getSpellAbility(true);
|
final SpellAbility sa = frozenStack.pop().getSpellAbility(true);
|
||||||
this.add(sa);
|
add(sa);
|
||||||
}
|
}
|
||||||
// Add all waiting triggers onto the stack
|
// Add all waiting triggers onto the stack
|
||||||
game.getTriggerHandler().runWaitingTriggers();
|
game.getTriggerHandler().runWaitingTriggers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* clearFrozen.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public final void clearFrozen() {
|
public final void clearFrozen() {
|
||||||
// TODO: frozen triggered abilities and undoable costs have nasty
|
// TODO: frozen triggered abilities and undoable costs have nasty
|
||||||
// consequences
|
// consequences
|
||||||
this.frozen = false;
|
frozen = false;
|
||||||
this.frozenStack.clear();
|
frozenStack.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* setResolving.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param b
|
|
||||||
* a boolean.
|
|
||||||
*/
|
|
||||||
public final void setResolving(final boolean b) {
|
|
||||||
this.bResolving = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* getResolving.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isResolving() {
|
public final boolean isResolving() {
|
||||||
return this.bResolving;
|
return bResolving;
|
||||||
|
}
|
||||||
|
public final void setResolving(final boolean b) {
|
||||||
|
bResolving = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* undo.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean canUndo(Player player) {
|
public final boolean canUndo(Player player) {
|
||||||
return undoStackOwner == player;
|
return undoStackOwner == player;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* undo.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean undo() {
|
public final boolean undo() {
|
||||||
if (undoStack.isEmpty()) { return false; }
|
if (undoStack.isEmpty()) { return false; }
|
||||||
|
|
||||||
@@ -259,26 +174,12 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* clearUndoStack.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public final void clearUndoStack() {
|
public final void clearUndoStack() {
|
||||||
if (undoStackOwner == null) { return; }
|
if (undoStackOwner == null) { return; }
|
||||||
undoStack.clear();
|
undoStack.clear();
|
||||||
undoStackOwner = null;
|
undoStackOwner = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* add.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param sp
|
|
||||||
* a {@link forge.game.spellability.SpellAbility} object.
|
|
||||||
*/
|
|
||||||
public final void add(final SpellAbility sp) {
|
public final void add(final SpellAbility sp) {
|
||||||
SpellAbilityStackInstance si = null;
|
SpellAbilityStackInstance si = null;
|
||||||
final Card source = sp.getHostCard();
|
final Card source = sp.getHostCard();
|
||||||
@@ -327,9 +228,9 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.frozen) {
|
if (frozen) {
|
||||||
si = new SpellAbilityStackInstance(sp);
|
si = new SpellAbilityStackInstance(sp);
|
||||||
this.frozenStack.push(si);
|
frozenStack.push(si);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int totManaSpent = sp.getPayingMana().size();
|
int totManaSpent = sp.getPayingMana().size();
|
||||||
@@ -344,7 +245,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
source.addOptionalCostPaid(s);
|
source.addOptionalCostPaid(s);
|
||||||
}
|
}
|
||||||
if (sp.isCopied()) {
|
if (sp.isCopied()) {
|
||||||
si = this.push(sp);
|
si = push(sp);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (sp.isSpell() && source.isCreature() && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
|
if (sp.isSpell() && source.isCreature() && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
|
||||||
@@ -383,7 +284,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The ability is added to stack HERE
|
// The ability is added to stack HERE
|
||||||
si = this.push(sp);
|
si = push(sp);
|
||||||
|
|
||||||
if (sp.isSpell() && (source.hasStartOfKeyword("Replicate")
|
if (sp.isSpell() && (source.hasStartOfKeyword("Replicate")
|
||||||
|| ((source.isInstant() || source.isSorcery()) && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
|
|| ((source.isInstant() || source.isSorcery()) && Iterables.any(activator.getCardsIn(ZoneType.Battlefield),
|
||||||
@@ -426,13 +327,13 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
runParams.put("Activator", sp.getActivatingPlayer());
|
runParams.put("Activator", sp.getActivatingPlayer());
|
||||||
runParams.put("CastSA", si.getSpellAbility(true));
|
runParams.put("CastSA", si.getSpellAbility(true));
|
||||||
runParams.put("CastSACMC", si.getSpellAbility(true).getHostCard().getCMC());
|
runParams.put("CastSACMC", si.getSpellAbility(true).getHostCard().getCMC());
|
||||||
runParams.put("CurrentStormCount", game.getStack().getCardsCastThisTurn().size());
|
runParams.put("CurrentStormCount", thisTurnCast.size());
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.SpellAbilityCast, runParams, true);
|
game.getTriggerHandler().runTrigger(TriggerType.SpellAbilityCast, runParams, true);
|
||||||
|
|
||||||
// Run SpellCast triggers
|
// Run SpellCast triggers
|
||||||
if (sp.isSpell()) {
|
if (sp.isSpell()) {
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.SpellCast, runParams, true);
|
game.getTriggerHandler().runTrigger(TriggerType.SpellCast, runParams, true);
|
||||||
this.executeCastCommand(si.getSpellAbility(true).getHostCard());
|
executeCastCommand(si.getSpellAbility(true).getHostCard());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run AbilityCast triggers
|
// Run AbilityCast triggers
|
||||||
@@ -488,26 +389,12 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* size.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a int.
|
|
||||||
*/
|
|
||||||
public final int size() {
|
public final int size() {
|
||||||
return this.stack.size();
|
return stack.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isEmpty.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isEmpty() {
|
public final boolean isEmpty() {
|
||||||
return this.stack.isEmpty();
|
return stack.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push should only be used by add.
|
// Push should only be used by add.
|
||||||
@@ -519,8 +406,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
|
|
||||||
final SpellAbilityStackInstance si = new SpellAbilityStackInstance(sp);
|
final SpellAbilityStackInstance si = new SpellAbilityStackInstance(sp);
|
||||||
|
|
||||||
this.stack.addFirst(si);
|
stack.addFirst(si);
|
||||||
game.fireEvent(new GameEventSpellAbilityCast(sp, false));
|
|
||||||
|
|
||||||
// 2012-07-21 the following comparison needs to move below the pushes but somehow screws up priority
|
// 2012-07-21 the following comparison needs to move below the pushes but somehow screws up priority
|
||||||
// When it's down there. That makes absolutely no sense to me, so i'm putting it back for now
|
// When it's down there. That makes absolutely no sense to me, so i'm putting it back for now
|
||||||
@@ -530,31 +416,28 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sp.isSpell() && !sp.isCopied()) {
|
if (sp.isSpell() && !sp.isCopied()) {
|
||||||
this.thisTurnCast.add(sp.getHostCard());
|
thisTurnCast.add(sp.getHostCard());
|
||||||
sp.getActivatingPlayer().addSpellCastThisTurn();
|
sp.getActivatingPlayer().addSpellCastThisTurn();
|
||||||
}
|
}
|
||||||
if (sp.isAbility() && sp.getRestrictions().isPwAbility()) {
|
if (sp.isAbility() && sp.getRestrictions().isPwAbility()) {
|
||||||
sp.getActivatingPlayer().setActivateLoyaltyAbilityThisTurn(true);
|
sp.getActivatingPlayer().setActivateLoyaltyAbilityThisTurn(true);
|
||||||
}
|
}
|
||||||
|
game.updateStackForView();
|
||||||
|
game.fireEvent(new GameEventSpellAbilityCast(sp, false));
|
||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* resolveStack.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public final void resolveStack() {
|
public final void resolveStack() {
|
||||||
// Resolving the Stack
|
// Resolving the Stack
|
||||||
|
|
||||||
// freeze the stack while we're in the middle of resolving
|
// freeze the stack while we're in the middle of resolving
|
||||||
this.freezeStack();
|
freezeStack();
|
||||||
this.setResolving(true);
|
setResolving(true);
|
||||||
|
|
||||||
// The SpellAbility isn't removed from the Stack until it finishes resolving
|
// The SpellAbility isn't removed from the Stack until it finishes resolving
|
||||||
// temporarily reverted removing SAs after resolution
|
// temporarily reverted removing SAs after resolution
|
||||||
final SpellAbility sa = this.peekAbility();
|
final SpellAbility sa = peekAbility();
|
||||||
//final SpellAbility sa = this.pop();
|
//final SpellAbility sa = pop();
|
||||||
|
|
||||||
// ActivePlayer gains priority first after Resolve
|
// ActivePlayer gains priority first after Resolve
|
||||||
game.getPhaseHandler().resetPriority();
|
game.getPhaseHandler().resetPriority();
|
||||||
@@ -562,7 +445,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
curResolvingCard = source;
|
curResolvingCard = source;
|
||||||
|
|
||||||
boolean thisHasFizzled = this.hasFizzled(sa, source, false);
|
boolean thisHasFizzled = hasFizzled(sa, source, false);
|
||||||
|
|
||||||
if (thisHasFizzled) { // Fizzle
|
if (thisHasFizzled) { // Fizzle
|
||||||
if (sa.hasParam("Bestow")) {
|
if (sa.hasParam("Bestow")) {
|
||||||
@@ -585,7 +468,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
|
|
||||||
game.fireEvent(new GameEventSpellResolved(sa, thisHasFizzled));
|
game.fireEvent(new GameEventSpellResolved(sa, thisHasFizzled));
|
||||||
this.finishResolving(sa, thisHasFizzled);
|
finishResolving(sa, thisHasFizzled);
|
||||||
|
|
||||||
if (source.hasStartOfKeyword("Haunt") && !source.isCreature() && game.getZoneOf(source).is(ZoneType.Graveyard)) {
|
if (source.hasStartOfKeyword("Haunt") && !source.isCreature() && game.getZoneOf(source).is(ZoneType.Graveyard)) {
|
||||||
handleHauntForNonPermanents(sa);
|
handleHauntForNonPermanents(sa);
|
||||||
@@ -599,7 +482,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
@Override
|
@Override
|
||||||
public void resolve() {
|
public void resolve() {
|
||||||
game.getAction().exile(source);
|
game.getAction().exile(source);
|
||||||
this.getTargetCard().addHauntedBy(source);
|
getTargetCard().addHauntedBy(source);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (int i = 0; i < creats.size(); i++) {
|
for (int i = 0; i < creats.size(); i++) {
|
||||||
@@ -614,32 +497,31 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
haunterDiesWork.setTargetRestrictions(new TargetRestrictions("", "Creature".split(" "), "1", "1"));
|
haunterDiesWork.setTargetRestrictions(new TargetRestrictions("", "Creature".split(" "), "1", "1"));
|
||||||
final Card targetCard = source.getController().getController().chooseSingleEntityForEffect(creats, new SpellAbility.EmptySa(ApiType.InternalHaunt, source), "Choose target creature to haunt.");
|
final Card targetCard = source.getController().getController().chooseSingleEntityForEffect(creats, new SpellAbility.EmptySa(ApiType.InternalHaunt, source), "Choose target creature to haunt.");
|
||||||
haunterDiesWork.setTargetCard(targetCard);
|
haunterDiesWork.setTargetCard(targetCard);
|
||||||
this.add(haunterDiesWork);
|
add(haunterDiesWork);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final void finishResolving(final SpellAbility sa, final boolean fizzle) {
|
private final void finishResolving(final SpellAbility sa, final boolean fizzle) {
|
||||||
|
|
||||||
// remove SA and card from the stack
|
// remove SA and card from the stack
|
||||||
this.removeCardFromStack(sa, fizzle);
|
removeCardFromStack(sa, fizzle);
|
||||||
// SpellAbility is removed from the stack here
|
// SpellAbility is removed from the stack here
|
||||||
// temporarily removed removing SA after resolution
|
// temporarily removed removing SA after resolution
|
||||||
final SpellAbilityStackInstance si = this.getInstanceFromSpellAbility(sa);
|
final SpellAbilityStackInstance si = getInstanceFromSpellAbility(sa);
|
||||||
|
|
||||||
if (si != null) {
|
if (si != null) {
|
||||||
this.remove(si);
|
remove(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
// After SA resolves we have to do a handful of things
|
// After SA resolves we have to do a handful of things
|
||||||
this.setResolving(false);
|
setResolving(false);
|
||||||
this.unfreezeStack();
|
unfreezeStack();
|
||||||
sa.resetOnceResolved();
|
sa.resetOnceResolved();
|
||||||
|
|
||||||
//game.getAction().checkStaticAbilities();
|
//game.getAction().checkStaticAbilities();
|
||||||
game.getPhaseHandler().onStackResolved();
|
game.getPhaseHandler().onStackResolved();
|
||||||
|
|
||||||
this.curResolvingCard = null;
|
curResolvingCard = null;
|
||||||
|
|
||||||
// TODO: this is a huge hack. Why is this necessary?
|
// TODO: this is a huge hack. Why is this necessary?
|
||||||
// hostCard in AF is not the same object that's on the battlefield
|
// hostCard in AF is not the same object that's on the battlefield
|
||||||
@@ -660,21 +542,23 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
private final void removeCardFromStack(final SpellAbility sa, final boolean fizzle) {
|
private final void removeCardFromStack(final SpellAbility sa, final boolean fizzle) {
|
||||||
Card source = sa.getHostCard();
|
Card source = sa.getHostCard();
|
||||||
|
|
||||||
// do nothing
|
|
||||||
if (sa.getHostCard().isCopiedSpell() || sa.isAbility()) {
|
if (sa.getHostCard().isCopiedSpell() || sa.isAbility()) {
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
// Handle cards that need to be moved differently
|
|
||||||
else if (sa.isBuyBackAbility() && !fizzle) {
|
else if (sa.isBuyBackAbility() && !fizzle) {
|
||||||
|
// Handle cards that need to be moved differently
|
||||||
game.getAction().moveToHand(source);
|
game.getAction().moveToHand(source);
|
||||||
} else if (sa.isFlashBackAbility()) {
|
}
|
||||||
|
else if (sa.isFlashBackAbility()) {
|
||||||
game.getAction().exile(source);
|
game.getAction().exile(source);
|
||||||
sa.setFlashBackAbility(false);
|
sa.setFlashBackAbility(false);
|
||||||
} else if (source.hasKeyword("Rebound")
|
}
|
||||||
|
else if (source.hasKeyword("Rebound")
|
||||||
&& source.getCastFrom() == ZoneType.Hand
|
&& source.getCastFrom() == ZoneType.Hand
|
||||||
&& game.getZoneOf(source).is(ZoneType.Stack)
|
&& game.getZoneOf(source).is(ZoneType.Stack)
|
||||||
&& source.getOwner().equals(source.getController())) //"If you cast this spell from your hand"
|
&& source.getOwner().equals(source.getController())) //"If you cast this spell from your hand"
|
||||||
{
|
{
|
||||||
|
|
||||||
//Move rebounding card to exile
|
//Move rebounding card to exile
|
||||||
source = game.getAction().exile(source);
|
source = game.getAction().exile(source);
|
||||||
|
|
||||||
@@ -689,27 +573,14 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
|
|
||||||
game.getTriggerHandler().registerDelayedTrigger(reboundTrigger);
|
game.getTriggerHandler().registerDelayedTrigger(reboundTrigger);
|
||||||
}
|
}
|
||||||
|
else if (!source.isCopiedSpell() &&
|
||||||
// If Spell and still on the Stack then let it goto the graveyard or
|
(source.isInstant() || source.isSorcery() || fizzle) &&
|
||||||
// replace its own movement
|
source.isInZone(ZoneType.Stack)) {
|
||||||
else if (!source.isCopiedSpell() && (source.isInstant() || source.isSorcery() || fizzle)
|
// If Spell and still on the Stack then let it goto the graveyard or replace its own movement
|
||||||
&& source.isInZone(ZoneType.Stack)) {
|
|
||||||
game.getAction().moveToGraveyard(source);
|
game.getAction().moveToGraveyard(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* hasFizzled.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param sa
|
|
||||||
* a {@link forge.game.spellability.SpellAbility} object.
|
|
||||||
* @param source
|
|
||||||
* a {@link forge.game.card.Card} object.
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
private final boolean hasFizzled(final SpellAbility sa, final Card source, final boolean parentFizzled) {
|
private final boolean hasFizzled(final SpellAbility sa, final Card source, final boolean parentFizzled) {
|
||||||
// Can't fizzle unless there are some targets
|
// Can't fizzle unless there are some targets
|
||||||
boolean fizzle = false;
|
boolean fizzle = false;
|
||||||
@@ -768,27 +639,26 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
return fizzle;
|
return fizzle;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasFizzled(sa.getSubAbility(), source, fizzle) && fizzle;
|
return hasFizzled(sa.getSubAbility(), source, fizzle) && fizzle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final SpellAbilityStackInstance peek() {
|
public final SpellAbilityStackInstance peek() {
|
||||||
return this.stack.peekFirst();
|
return stack.peekFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final SpellAbility peekAbility() {
|
public final SpellAbility peekAbility() {
|
||||||
return this.stack.peekFirst().getSpellAbility(true);
|
return stack.peekFirst().getSpellAbility(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void remove(final SpellAbilityStackInstance si) {
|
public final void remove(final SpellAbilityStackInstance si) {
|
||||||
this.stack.remove(si);
|
stack.remove(si);
|
||||||
this.frozenStack.remove(si);
|
frozenStack.remove(si);
|
||||||
game.fireEvent(new GameEventSpellRemovedFromStack(si.getSpellAbility(true)));
|
game.fireEvent(new GameEventSpellRemovedFromStack(si.getSpellAbility(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final SpellAbilityStackInstance getInstanceFromSpellAbility(final SpellAbility sa) {
|
public final SpellAbilityStackInstance getInstanceFromSpellAbility(final SpellAbility sa) {
|
||||||
// TODO: Confirm this works!
|
// TODO: Confirm this works!
|
||||||
for (final SpellAbilityStackInstance si : this.stack) {
|
for (final SpellAbilityStackInstance si : stack) {
|
||||||
if (si.compareToSpellAbility(sa)) {
|
if (si.compareToSpellAbility(sa)) {
|
||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
@@ -797,15 +667,15 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasSimultaneousStackEntries() {
|
public final boolean hasSimultaneousStackEntries() {
|
||||||
return !this.simultaneousStackEntryList.isEmpty();
|
return !simultaneousStackEntryList.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void clearSimultaneousStack() {
|
public final void clearSimultaneousStack() {
|
||||||
this.simultaneousStackEntryList.clear();
|
simultaneousStackEntryList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void addSimultaneousStackEntry(final SpellAbility sa) {
|
public final void addSimultaneousStackEntry(final SpellAbility sa) {
|
||||||
this.simultaneousStackEntryList.add(sa);
|
simultaneousStackEntryList.add(sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addAllTriggeredAbilitiesToStack() {
|
public boolean addAllTriggeredAbilitiesToStack() {
|
||||||
@@ -826,24 +696,24 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final boolean chooseOrderOfSimultaneousStackEntry(final Player activePlayer) {
|
private final boolean chooseOrderOfSimultaneousStackEntry(final Player activePlayer) {
|
||||||
if (this.simultaneousStackEntryList.isEmpty()) {
|
if (simultaneousStackEntryList.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<SpellAbility> activePlayerSAs = new ArrayList<SpellAbility>();
|
final List<SpellAbility> activePlayerSAs = new ArrayList<SpellAbility>();
|
||||||
for (int i = 0; i < this.simultaneousStackEntryList.size(); i++) {
|
for (int i = 0; i < simultaneousStackEntryList.size(); i++) {
|
||||||
SpellAbility sa = this.simultaneousStackEntryList.get(i);
|
SpellAbility sa = simultaneousStackEntryList.get(i);
|
||||||
Player activator = sa.getActivatingPlayer();
|
Player activator = sa.getActivatingPlayer();
|
||||||
if (activator == null) {
|
if (activator == null) {
|
||||||
if (sa.getHostCard().getController().equals(activePlayer)) {
|
if (sa.getHostCard().getController().equals(activePlayer)) {
|
||||||
activePlayerSAs.add(sa);
|
activePlayerSAs.add(sa);
|
||||||
this.simultaneousStackEntryList.remove(i);
|
simultaneousStackEntryList.remove(i);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (activator.equals(activePlayer)) {
|
if (activator.equals(activePlayer)) {
|
||||||
activePlayerSAs.add(sa);
|
activePlayerSAs.add(sa);
|
||||||
this.simultaneousStackEntryList.remove(i);
|
simultaneousStackEntryList.remove(i);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -856,73 +726,58 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
*
|
|
||||||
* @param triggerID
|
|
||||||
* the trigger id
|
|
||||||
* @return true, if successful
|
|
||||||
*/
|
|
||||||
public final boolean hasStateTrigger(final int triggerID) {
|
public final boolean hasStateTrigger(final int triggerID) {
|
||||||
for (final SpellAbilityStackInstance sasi : this.stack) {
|
for (final SpellAbilityStackInstance sasi : stack) {
|
||||||
if (sasi.isStateTrigger(triggerID)) {
|
if (sasi.isStateTrigger(triggerID)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final SpellAbilityStackInstance sasi : this.frozenStack) {
|
for (final SpellAbilityStackInstance sasi : frozenStack) {
|
||||||
if (sasi.isStateTrigger(triggerID)) {
|
if (sasi.isStateTrigger(triggerID)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final SpellAbility sa : this.simultaneousStackEntryList) {
|
for (final SpellAbility sa : simultaneousStackEntryList) {
|
||||||
if (sa.getSourceTrigger() == triggerID) {
|
if (sa.getSourceTrigger() == triggerID) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public final List<Card> getSpellsCastThisTurn() {
|
||||||
* Accessor for the field thisTurnCast.
|
return thisTurnCast;
|
||||||
*
|
|
||||||
* @return a CardList.
|
|
||||||
*/
|
|
||||||
public final List<Card> getCardsCastThisTurn() {
|
|
||||||
return this.thisTurnCast;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* clearCardsCastThisTurn.
|
|
||||||
*/
|
|
||||||
public final void onNextTurn() {
|
public final void onNextTurn() {
|
||||||
this.lastTurnCast = new ArrayList<Card>(this.thisTurnCast);
|
if (thisTurnCast.isEmpty()) {
|
||||||
this.thisTurnCast.clear();
|
lastTurnCast = new ArrayList<Card>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastTurnCast = new ArrayList<Card>(thisTurnCast);
|
||||||
|
thisTurnCast.clear();
|
||||||
|
game.updateStackForView();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public final List<Card> getSpellsCastLastTurn() {
|
||||||
* Accessor for the field lastTurnCast.
|
return lastTurnCast;
|
||||||
*
|
|
||||||
* @return a CardList.
|
|
||||||
*/
|
|
||||||
public final List<Card> getCardsCastLastTurn() {
|
|
||||||
return this.lastTurnCast;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void addCastCommand(final String valid, final GameCommand c) {
|
public final void addCastCommand(final String valid, final GameCommand c) {
|
||||||
if (this.commandList.containsKey(valid)) {
|
if (commandList.containsKey(valid)) {
|
||||||
this.commandList.get(valid).add(0, c);
|
commandList.get(valid).add(0, c);
|
||||||
} else {
|
}
|
||||||
this.commandList.put(valid, Lists.newArrayList(c));
|
else {
|
||||||
|
commandList.put(valid, Lists.newArrayList(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeCastCommand(final Card cast) {
|
private void executeCastCommand(final Card cast) {
|
||||||
for (Entry<String, List<GameCommand>> ev : this.commandList.entrySet()) {
|
for (Entry<String, List<GameCommand>> ev : commandList.entrySet()) {
|
||||||
if (cast.isType(ev.getKey())) {
|
if (cast.isType(ev.getKey())) {
|
||||||
this.execute(ev.getValue());
|
execute(ev.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -934,23 +789,13 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if is resolving.
|
|
||||||
*
|
|
||||||
* @param c the c
|
|
||||||
* @return true, if is resolving
|
|
||||||
*/
|
|
||||||
public final boolean isResolving(Card c) {
|
public final boolean isResolving(Card c) {
|
||||||
if (!this.isResolving() || this.curResolvingCard == null) {
|
if (!isResolving() || curResolvingCard == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return c.equals(curResolvingCard);
|
||||||
return c.equals(this.curResolvingCard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see java.lang.Iterable#iterator()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<SpellAbilityStackInstance> iterator() {
|
public Iterator<SpellAbilityStackInstance> iterator() {
|
||||||
return stack.iterator();
|
return stack.iterator();
|
||||||
@@ -960,11 +805,10 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
return stack.descendingIterator();
|
return stack.descendingIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this method.
|
|
||||||
*/
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
if (stack.isEmpty()) { return; }
|
||||||
stack.clear();
|
stack.clear();
|
||||||
|
game.updateStackForView();
|
||||||
game.fireEvent(new GameEventSpellRemovedFromStack(null));
|
game.fireEvent(new GameEventSpellRemovedFromStack(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package forge.trackable;
|
package forge.trackable;
|
||||||
|
|
||||||
import forge.card.CardRarity;
|
import forge.card.CardRarity;
|
||||||
|
import forge.game.GameType;
|
||||||
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.trackable.TrackableTypes;
|
import forge.trackable.TrackableTypes;
|
||||||
import forge.trackable.TrackableTypes.TrackableType;
|
import forge.trackable.TrackableTypes.TrackableType;
|
||||||
@@ -114,7 +116,20 @@ public enum TrackableProperty {
|
|||||||
BandsWithDefenders(null),
|
BandsWithDefenders(null),
|
||||||
BandsWithBlockers(null),
|
BandsWithBlockers(null),
|
||||||
AttackersWithPlannedBlockers(null),
|
AttackersWithPlannedBlockers(null),
|
||||||
BandsWithPlannedBlockers(null);
|
BandsWithPlannedBlockers(null),
|
||||||
|
|
||||||
|
GameType(TrackableTypes.EnumType(GameType.class)),
|
||||||
|
Turn(TrackableTypes.IntegerType),
|
||||||
|
WinningTeam(TrackableTypes.IntegerType),
|
||||||
|
MatchOver(TrackableTypes.BooleanType),
|
||||||
|
NumGamesInMatch(TrackableTypes.IntegerType),
|
||||||
|
NumPlayedGamesInMatch(TrackableTypes.IntegerType),
|
||||||
|
StormCount(TrackableTypes.IntegerType),
|
||||||
|
GameOver(TrackableTypes.BooleanType),
|
||||||
|
PoisonCountersToLose(TrackableTypes.IntegerType),
|
||||||
|
GameLog(TrackableTypes.PlayerViewType),
|
||||||
|
PlayerTurn(TrackableTypes.PlayerViewType),
|
||||||
|
Phase(TrackableTypes.EnumType(PhaseType.class));
|
||||||
|
|
||||||
private final TrackableType<?> type;
|
private final TrackableType<?> type;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user