2013-04-12 19:32:25 -07:00
|
|
|
package magic.model;
|
|
|
|
|
|
|
|
import magic.data.GeneralConfig;
|
|
|
|
import magic.model.action.MagicAction;
|
|
|
|
import magic.model.action.MagicActionList;
|
|
|
|
import magic.model.action.MagicAddEventAction;
|
2013-07-11 22:43:22 -07:00
|
|
|
import magic.model.action.MagicAddFirstEventAction;
|
2013-04-12 19:32:25 -07:00
|
|
|
import magic.model.action.MagicExecuteFirstEventAction;
|
|
|
|
import magic.model.action.MagicLogMarkerAction;
|
|
|
|
import magic.model.action.MagicMarkerAction;
|
|
|
|
import magic.model.action.MagicPutItemOnStackAction;
|
|
|
|
import magic.model.action.MagicRemoveFromPlayAction;
|
2013-07-02 07:19:34 -07:00
|
|
|
import magic.model.action.MagicMoveCardAction;
|
2013-04-12 19:32:25 -07:00
|
|
|
import magic.model.choice.MagicCombatCreature;
|
|
|
|
import magic.model.choice.MagicDeclareAttackersResult;
|
|
|
|
import magic.model.choice.MagicDeclareBlockersResult;
|
|
|
|
import magic.model.choice.MagicTargetChoice;
|
|
|
|
import magic.model.event.MagicEvent;
|
2013-07-02 07:19:34 -07:00
|
|
|
import magic.model.event.MagicSpellCardEvent;
|
2013-04-12 19:32:25 -07:00
|
|
|
import magic.model.event.MagicEventQueue;
|
2013-06-11 06:21:39 -07:00
|
|
|
import magic.model.event.MagicUniquenessEvent;
|
2013-04-12 19:32:25 -07:00
|
|
|
import magic.model.mstatic.MagicLayer;
|
|
|
|
import magic.model.mstatic.MagicPermanentStatic;
|
|
|
|
import magic.model.mstatic.MagicPermanentStaticMap;
|
|
|
|
import magic.model.mstatic.MagicStatic;
|
|
|
|
import magic.model.phase.MagicGameplay;
|
|
|
|
import magic.model.phase.MagicPhase;
|
|
|
|
import magic.model.phase.MagicPhaseType;
|
|
|
|
import magic.model.phase.MagicStep;
|
|
|
|
import magic.model.stack.MagicItemOnStack;
|
2013-07-02 07:19:34 -07:00
|
|
|
import magic.model.stack.MagicCardOnStack;
|
2013-04-12 19:32:25 -07:00
|
|
|
import magic.model.stack.MagicStack;
|
|
|
|
import magic.model.stack.MagicTriggerOnStack;
|
|
|
|
import magic.model.target.MagicTarget;
|
|
|
|
import magic.model.target.MagicTargetFilter;
|
|
|
|
import magic.model.target.MagicTargetHint;
|
|
|
|
import magic.model.target.MagicTargetNone;
|
|
|
|
import magic.model.target.MagicTargetType;
|
|
|
|
import magic.model.trigger.MagicPermanentTrigger;
|
|
|
|
import magic.model.trigger.MagicPermanentTriggerList;
|
|
|
|
import magic.model.trigger.MagicPermanentTriggerMap;
|
|
|
|
import magic.model.trigger.MagicTrigger;
|
|
|
|
import magic.model.trigger.MagicTriggerType;
|
2013-07-13 07:41:20 -07:00
|
|
|
import magic.model.trigger.MagicWhenOtherComesIntoPlayTrigger;
|
2013-04-12 19:32:25 -07:00
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.SortedSet;
|
|
|
|
import java.util.TreeSet;
|
|
|
|
|
|
|
|
public class MagicGame {
|
|
|
|
|
|
|
|
public static final boolean LOSE_DRAW_EMPTY_LIBRARY=true;
|
|
|
|
private static final long ID_FACTOR=31;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
private static int COUNT;
|
|
|
|
private static MagicGame INSTANCE;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
private final MagicDuel duel;
|
|
|
|
private final MagicPlayer[] players;
|
2013-07-13 07:41:20 -07:00
|
|
|
private MagicPermanentTriggerMap triggers;
|
|
|
|
private final MagicPermanentTriggerMap additionalTriggers;
|
2013-04-12 19:32:25 -07:00
|
|
|
private final MagicPermanentTriggerList turnTriggers;
|
|
|
|
private final MagicPermanentStaticMap statics;
|
|
|
|
private final MagicCardList exiledUntilEndOfTurn;
|
|
|
|
private final MagicEventQueue events;
|
|
|
|
private final MagicStack stack;
|
|
|
|
private final MagicPlayer scorePlayer;
|
2013-07-08 23:40:18 -07:00
|
|
|
private final MagicGameplay gameplay;
|
|
|
|
private final MagicActionList actions;
|
|
|
|
private final MagicActionList delayedActions;
|
2013-04-12 19:32:25 -07:00
|
|
|
private final boolean sound;
|
|
|
|
private int score;
|
|
|
|
private int turn=1;
|
|
|
|
private int startTurn;
|
|
|
|
private int mainPhaseCount=100000000;
|
|
|
|
private int landPlayed;
|
|
|
|
private int maxLand;
|
|
|
|
private int spellsPlayed;
|
2013-07-08 23:40:18 -07:00
|
|
|
private int priorityPassedCount;
|
2013-04-12 19:32:25 -07:00
|
|
|
private boolean creatureDiedThisTurn;
|
|
|
|
private boolean priorityPassed;
|
|
|
|
private boolean skipTurn;
|
|
|
|
private boolean stateCheckRequired;
|
|
|
|
private boolean artificial;
|
|
|
|
private boolean fastChoices;
|
|
|
|
private boolean immediate;
|
|
|
|
private boolean disableLog;
|
|
|
|
private MagicPlayer visiblePlayer;
|
|
|
|
private MagicPlayer turnPlayer;
|
|
|
|
private MagicPlayer losingPlayer = MagicPlayer.NONE;
|
|
|
|
private MagicPhase phase;
|
|
|
|
private MagicStep step;
|
2013-06-23 18:33:35 -07:00
|
|
|
private MagicPayedCost payedCost;
|
2013-04-12 19:32:25 -07:00
|
|
|
private MagicActionList undoPoints;
|
|
|
|
private MagicLogBook logBook;
|
|
|
|
private MagicLogMessageBuilder logMessageBuilder;
|
2013-07-08 23:40:18 -07:00
|
|
|
private MagicSource activeSource = MagicEvent.NO_SOURCE;
|
2013-04-12 19:32:25 -07:00
|
|
|
private long[] keys;
|
|
|
|
private long stateId;
|
|
|
|
private long time = 1000000;
|
|
|
|
|
|
|
|
|
|
|
|
public static MagicGame getInstance() {
|
|
|
|
return INSTANCE;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
static int getCount() {
|
|
|
|
return COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MagicGame create(
|
|
|
|
final MagicDuel duel,
|
|
|
|
final MagicGameplay gameplay,
|
|
|
|
final MagicPlayer[] players,
|
|
|
|
final MagicPlayer startPlayer,
|
|
|
|
final boolean sound) {
|
|
|
|
COUNT++;
|
|
|
|
INSTANCE = new MagicGame(duel, gameplay, players, startPlayer, sound);
|
|
|
|
return INSTANCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
private MagicGame(
|
|
|
|
final MagicDuel aDuel,
|
|
|
|
final MagicGameplay aGameplay,
|
|
|
|
final MagicPlayer[] aPlayers,
|
|
|
|
final MagicPlayer startPlayer,
|
|
|
|
final boolean aSound) {
|
|
|
|
|
|
|
|
artificial=false;
|
|
|
|
duel = aDuel;
|
|
|
|
gameplay = aGameplay;
|
|
|
|
players = aPlayers;
|
|
|
|
for (final MagicPlayer player : players) {
|
|
|
|
player.setGame(this);
|
|
|
|
}
|
|
|
|
sound = aSound;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
triggers=new MagicPermanentTriggerMap();
|
2013-07-13 07:41:20 -07:00
|
|
|
additionalTriggers=new MagicPermanentTriggerMap();
|
2013-04-12 19:32:25 -07:00
|
|
|
turnTriggers=new MagicPermanentTriggerList();
|
|
|
|
statics = new MagicPermanentStaticMap();
|
|
|
|
exiledUntilEndOfTurn=new MagicCardList();
|
|
|
|
events=new MagicEventQueue();
|
|
|
|
stack=new MagicStack();
|
|
|
|
visiblePlayer=players[0];
|
|
|
|
scorePlayer=visiblePlayer;
|
|
|
|
turnPlayer=startPlayer;
|
|
|
|
actions=new MagicActionList();
|
|
|
|
delayedActions=new MagicActionList();
|
|
|
|
undoPoints=new MagicActionList();
|
|
|
|
logBook=new MagicLogBook();
|
|
|
|
logMessageBuilder=new MagicLogMessageBuilder(this);
|
|
|
|
payedCost=new MagicPayedCost();
|
|
|
|
changePhase(gameplay.getStartPhase(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
public MagicGame(final MagicGame game,final MagicPlayer aScorePlayer) {
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
artificial=true;
|
|
|
|
sound=false;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
//copy the reference, these are singletons
|
|
|
|
duel=game.duel;
|
|
|
|
gameplay=game.gameplay;
|
|
|
|
phase=game.phase;
|
|
|
|
step=game.step;
|
|
|
|
|
|
|
|
//copying primitives, array of primitive
|
|
|
|
time = game.time;
|
|
|
|
turn = game.turn;
|
|
|
|
startTurn = game.startTurn;
|
|
|
|
landPlayed = game.landPlayed;
|
|
|
|
maxLand = game.maxLand;
|
|
|
|
spellsPlayed = game.spellsPlayed;
|
|
|
|
creatureDiedThisTurn = game.creatureDiedThisTurn;
|
|
|
|
priorityPassed = game.priorityPassed;
|
|
|
|
priorityPassedCount = game.priorityPassedCount;
|
|
|
|
stateCheckRequired = game.stateCheckRequired;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
//copied and stored in copyMap
|
2013-06-23 18:33:35 -07:00
|
|
|
final MagicCopyMap copyMap=new MagicCopyMap();
|
|
|
|
players=copyMap.copyObjects(game.players,MagicPlayer.class);
|
2013-04-12 19:32:25 -07:00
|
|
|
for (final MagicPlayer player : players) {
|
|
|
|
player.setGame(this);
|
|
|
|
}
|
|
|
|
scorePlayer=copyMap.copy(aScorePlayer);
|
|
|
|
visiblePlayer=copyMap.copy(game.visiblePlayer);
|
|
|
|
turnPlayer=copyMap.copy(game.turnPlayer);
|
|
|
|
losingPlayer=copyMap.copy(game.losingPlayer);
|
2013-06-19 06:16:08 -07:00
|
|
|
payedCost=copyMap.copy(game.payedCost);
|
2013-07-08 23:40:18 -07:00
|
|
|
activeSource=copyMap.copy(game.activeSource);
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
//construct a new object using copyMap to copy internals
|
|
|
|
events=new MagicEventQueue(copyMap, game.events);
|
|
|
|
stack=new MagicStack(copyMap, game.stack);
|
|
|
|
triggers=new MagicPermanentTriggerMap(copyMap, game.triggers);
|
2013-07-13 07:41:20 -07:00
|
|
|
additionalTriggers=new MagicPermanentTriggerMap(copyMap, game.additionalTriggers);
|
2013-04-12 19:32:25 -07:00
|
|
|
statics=new MagicPermanentStaticMap(copyMap, game.statics);
|
|
|
|
exiledUntilEndOfTurn=new MagicCardList(copyMap, game.exiledUntilEndOfTurn);
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
//construct a new object
|
|
|
|
turnTriggers=new MagicPermanentTriggerList(triggers, game.turnTriggers);
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
//the following are NOT copied when game state is cloned
|
|
|
|
//fastChoices
|
|
|
|
//immediate
|
|
|
|
//skipTurn
|
|
|
|
//mainPhaseCount
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
//score is RESET to zero
|
|
|
|
score=0;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
//historical actions are not carried over
|
|
|
|
actions=new MagicActionList();
|
|
|
|
|
|
|
|
//there should be no pending actions
|
2013-06-23 18:33:35 -07:00
|
|
|
assert game.delayedActions.isEmpty() : "delayedActions: " + game.delayedActions;
|
2013-04-12 19:32:25 -07:00
|
|
|
delayedActions=new MagicActionList();
|
|
|
|
|
|
|
|
//no logging
|
|
|
|
disableLog = true;
|
|
|
|
undoPoints=null;
|
|
|
|
logBook=null;
|
|
|
|
logMessageBuilder=null;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setSkipTurn(final boolean skip) {
|
|
|
|
skipTurn = skip;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean getSkipTurn() {
|
|
|
|
return skipTurn;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setScore(final int aScore) {
|
|
|
|
score = aScore;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void changeScore(final int amount) {
|
|
|
|
score+=amount;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public int getScore() {
|
|
|
|
return score;
|
|
|
|
}
|
|
|
|
|
|
|
|
public long getUniqueId() {
|
|
|
|
time++;
|
|
|
|
return time;
|
|
|
|
}
|
|
|
|
|
|
|
|
//follow factors in MagicMarkerAction
|
|
|
|
public long getStateId() {
|
2013-06-23 18:33:35 -07:00
|
|
|
keys = new long[] {
|
2013-04-12 19:32:25 -07:00
|
|
|
turn,
|
|
|
|
phase.hashCode(),
|
|
|
|
step.hashCode(),
|
|
|
|
turnPlayer.getIndex(),
|
|
|
|
landPlayed,
|
|
|
|
maxLand,
|
|
|
|
spellsPlayed,
|
|
|
|
priorityPassedCount,
|
|
|
|
(creatureDiedThisTurn ? 1L : -1L),
|
|
|
|
(priorityPassed ? 1L : -1L),
|
|
|
|
(stateCheckRequired ? 1L : -1L),
|
|
|
|
payedCost.getX(),
|
2013-06-19 06:16:08 -07:00
|
|
|
payedCost.getKicker(),
|
2013-04-12 19:32:25 -07:00
|
|
|
//payedCost.getTarget().getId(),
|
|
|
|
stack.getStateId(),
|
|
|
|
events.getStateId(),
|
|
|
|
players[0].getStateId(),
|
|
|
|
players[1].getStateId(),
|
|
|
|
//triggers.getStateId(),
|
|
|
|
//statics.getStateId(),
|
|
|
|
exiledUntilEndOfTurn.getUnorderedStateId(),
|
|
|
|
};
|
|
|
|
stateId = magic.MurmurHash3.hash(keys);
|
|
|
|
return stateId;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String toString() {
|
2013-06-23 18:33:35 -07:00
|
|
|
return "GAME: " +
|
2013-04-12 19:32:25 -07:00
|
|
|
"id=" + stateId + " " +
|
2013-06-23 18:33:35 -07:00
|
|
|
"t=" + turn + " " +
|
|
|
|
"p=" + phase.getType() + " " +
|
|
|
|
"s=" + step + " " +
|
2013-04-12 19:32:25 -07:00
|
|
|
"tp=" + turnPlayer.getIndex() + " " +
|
|
|
|
"lp=" + landPlayed + " " +
|
|
|
|
"ppc=" + priorityPassedCount + " " +
|
|
|
|
"pp=" + priorityPassed + " " +
|
|
|
|
"sc=" + stateCheckRequired + " " +
|
|
|
|
"x=" + getPayedCost().getX() + " " +
|
|
|
|
"e=" + events.size() + " " +
|
|
|
|
"s=" + stack.size();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public String getIdString() {
|
|
|
|
final StringBuilder sb = new StringBuilder(toString());
|
|
|
|
sb.append('\n');
|
|
|
|
sb.append(keys[0]);
|
|
|
|
for (int i = 1; i < keys.length; i++) {
|
|
|
|
sb.append(' ');
|
|
|
|
sb.append(keys[i]);
|
|
|
|
}
|
|
|
|
sb.append('\n');
|
|
|
|
sb.append(players[0].getIdString());
|
|
|
|
sb.append('\n');
|
|
|
|
sb.append(players[1].getIdString());
|
|
|
|
return sb.toString();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public long getGameId(final int pruneScore) {
|
2013-06-23 18:33:35 -07:00
|
|
|
long id=0;
|
2013-04-12 19:32:25 -07:00
|
|
|
id = id*ID_FACTOR + turn;
|
|
|
|
id = id*ID_FACTOR + phase.getType().ordinal();
|
|
|
|
id = id*ID_FACTOR + score + pruneScore;
|
|
|
|
id = players[0].getPlayerId(id);
|
|
|
|
id = players[1].getPlayerId(id);
|
|
|
|
return id;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public static boolean canSkipSingleChoice() {
|
|
|
|
return GeneralConfig.getInstance().getSkipSingle();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public static boolean canSkipSingleManaChoice() {
|
|
|
|
return GeneralConfig.getInstance().getSkipSingle();
|
|
|
|
}
|
|
|
|
|
|
|
|
//human is declaring blockers, skip if AI is not attacking
|
|
|
|
public boolean canSkipDeclareBlockersSingleChoice() {
|
|
|
|
return GeneralConfig.getInstance().getSkipSingle() && turnPlayer.getNrOfAttackers() == 0;
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean canAlwaysPass() {
|
|
|
|
if (GeneralConfig.getInstance().getAlwaysPass()) {
|
2013-06-23 18:33:35 -07:00
|
|
|
return phase.getType() == MagicPhaseType.Draw ||
|
2013-04-12 19:32:25 -07:00
|
|
|
phase.getType() == MagicPhaseType.BeginOfCombat;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
private int getArtificialLevel() {
|
|
|
|
return duel.getDifficulty();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public int getArtificialLevel(final int idx) {
|
|
|
|
return duel.getDifficulty(idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isArtificial() {
|
|
|
|
return artificial;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean isReal() {
|
|
|
|
return !artificial;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setArtificial(final boolean art) {
|
|
|
|
artificial = art;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean isSound() {
|
|
|
|
return sound;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setFastChoices(final boolean aFastChoices) {
|
|
|
|
fastChoices = aFastChoices;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean getFastChoices() {
|
|
|
|
return fastChoices;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setTurn(final int aTurn) {
|
|
|
|
turn = aTurn;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public int getTurn() {
|
|
|
|
return turn;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setMainPhases(final int count) {
|
|
|
|
startTurn=turn;
|
|
|
|
mainPhaseCount=count;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public int getRelativeTurn() {
|
|
|
|
return startTurn>0?turn-startTurn:0;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void decreaseMainPhaseCount() {
|
|
|
|
mainPhaseCount--;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setMainPhaseCount(final int count) {
|
|
|
|
mainPhaseCount=count;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public int getMainPhaseCount() {
|
|
|
|
return mainPhaseCount;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setPhase(final MagicPhase aPhase) {
|
|
|
|
phase = aPhase;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void nextPhase() {
|
|
|
|
changePhase(gameplay.getNextPhase(this));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
private void changePhase(final MagicPhase aPhase) {
|
|
|
|
phase = aPhase;
|
|
|
|
step=MagicStep.Begin;
|
|
|
|
priorityPassedCount=0;
|
|
|
|
players[0].getActivationPriority().clear();
|
|
|
|
players[1].getActivationPriority().clear();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPhase getPhase() {
|
|
|
|
return phase;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void executePhase() {
|
|
|
|
phase.executePhase(this);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean isPhase(final MagicPhaseType type) {
|
|
|
|
return phase.getType()==type;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean isMainPhase() {
|
|
|
|
return phase.getType().isMain();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean isCombatPhase() {
|
|
|
|
return phase.getType().isCombat();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setStep(final MagicStep aStep) {
|
|
|
|
step = aStep;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicStep getStep() {
|
|
|
|
return step;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void resolve() {
|
|
|
|
if (stack.isEmpty()) {
|
|
|
|
step=MagicStep.NextPhase;
|
|
|
|
} else {
|
|
|
|
step=MagicStep.Resolve;
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-06-19 06:16:08 -07:00
|
|
|
public void resetPayedCost() {
|
|
|
|
payedCost = new MagicPayedCost();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-06-19 06:16:08 -07:00
|
|
|
public void setPayedCost(final MagicPayedCost aPayedCost) {
|
|
|
|
payedCost = aPayedCost;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPayedCost getPayedCost() {
|
2013-06-19 06:16:08 -07:00
|
|
|
return new MagicPayedCost(payedCost);
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
/** Determines if game score should be cached for this game state. */
|
|
|
|
public boolean cacheState() {
|
|
|
|
switch (phase.getType()) {
|
|
|
|
case FirstMain:
|
|
|
|
case EndOfCombat:
|
|
|
|
case Cleanup:
|
|
|
|
return step==MagicStep.NextPhase;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Tells gameplay that it can skip certain parts during AI processing. */
|
|
|
|
public boolean canSkip() {
|
|
|
|
return stack.isEmpty() && artificial;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean isFinished() {
|
|
|
|
return losingPlayer.isValid() || mainPhaseCount <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public MagicLogBook getLogBook() {
|
|
|
|
return logBook;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void hideHiddenCards() {
|
|
|
|
getOpponent(scorePlayer).setHandToUnknown();
|
|
|
|
for (final MagicPlayer player : players) {
|
|
|
|
player.getLibrary().setKnown(false);
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void showRandomizedHiddenCards() {
|
|
|
|
getOpponent(scorePlayer).showRandomizedHandAndLibrary();
|
|
|
|
scorePlayer.getLibrary().shuffle(MagicRandom.nextInt(999999));
|
|
|
|
scorePlayer.getLibrary().setKnown(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Collection<MagicAction> getActions() {
|
|
|
|
return actions;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getNumActions() {
|
|
|
|
return actions.size();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void startActions() {
|
|
|
|
doAction(new MagicMarkerAction());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addDelayedAction(final MagicAction action) {
|
|
|
|
delayedActions.add(action);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void doAction(final MagicAction action) {
|
|
|
|
actions.add(action);
|
|
|
|
|
|
|
|
try {
|
|
|
|
action.doAction(this);
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
MagicGameReport.buildReport(this, Thread.currentThread(), ex);
|
|
|
|
System.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//performing actions update the score
|
|
|
|
score += action.getScore(scorePlayer);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void update() {
|
|
|
|
doDelayedActions();
|
|
|
|
MagicPermanent.update(this);
|
2013-07-13 07:41:20 -07:00
|
|
|
|
|
|
|
// add Soulbond trigger here
|
|
|
|
triggers = new MagicPermanentTriggerMap(additionalTriggers);
|
|
|
|
triggers.add(new MagicPermanentTrigger(0,MagicPermanent.NONE,MagicWhenOtherComesIntoPlayTrigger.Soulbond));
|
|
|
|
|
|
|
|
for (final MagicPlayer player : players) {
|
|
|
|
for (final MagicPermanent perm : player.getPermanents()) {
|
|
|
|
for (final MagicTrigger<?> trigger : perm.getTriggers()) {
|
|
|
|
triggers.add(new MagicPermanentTrigger(perm.getId(), perm, trigger));
|
|
|
|
}}}
|
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
MagicPlayer.update(this);
|
|
|
|
MagicGame.update(this);
|
|
|
|
doDelayedActions();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void apply(final MagicLayer layer) {
|
|
|
|
switch (layer) {
|
|
|
|
case Game:
|
|
|
|
maxLand = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new RuntimeException("No case for " + layer + " in MagicGame.apply");
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
private void apply(final MagicPermanent source, final MagicStatic mstatic) {
|
|
|
|
final MagicLayer layer = mstatic.getLayer();
|
|
|
|
switch (layer) {
|
|
|
|
case Game:
|
|
|
|
mstatic.modGame(source, this);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new RuntimeException("No case for " + layer + " in MagicGame.apply");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void update(final MagicGame game) {
|
|
|
|
game.apply(MagicLayer.Game);
|
|
|
|
for (final MagicPermanentStatic mpstatic : game.getStatics(MagicLayer.Game)) {
|
|
|
|
final MagicStatic mstatic = mpstatic.getStatic();
|
|
|
|
final MagicPermanent source = mpstatic.getPermanent();
|
|
|
|
if (mstatic.accept(game, source, source)) {
|
|
|
|
game.apply(source, mstatic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void doDelayedActions() {
|
|
|
|
while (!delayedActions.isEmpty()) {
|
|
|
|
final MagicAction action = delayedActions.removeFirst();
|
|
|
|
doAction(action);
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void undoActions() {
|
|
|
|
//undo each action up to and including the first MagicMarkerAction
|
|
|
|
MagicAction action;
|
|
|
|
do {
|
|
|
|
action = actions.removeLast();
|
|
|
|
try {
|
|
|
|
action.undoAction(this);
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
MagicGameReport.buildReport(INSTANCE, Thread.currentThread(), ex);
|
|
|
|
if (this != INSTANCE) {
|
|
|
|
MagicGameReport.buildReport(this, Thread.currentThread(), ex);
|
|
|
|
}
|
|
|
|
System.exit(1);
|
|
|
|
}
|
|
|
|
} while (!(action instanceof MagicMarkerAction));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void undoAllActions() {
|
2013-06-23 18:33:35 -07:00
|
|
|
assert actions.isEmpty() : "actions: " + actions;
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void createUndoPoint() {
|
|
|
|
final MagicAction markerAction=new MagicMarkerAction();
|
|
|
|
doAction(markerAction);
|
|
|
|
doAction(new MagicLogMarkerAction());
|
|
|
|
undoPoints.addLast(markerAction);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void gotoLastUndoPoint() {
|
|
|
|
final MagicAction markerAction = undoPoints.removeLast();
|
|
|
|
MagicAction action;
|
|
|
|
do {
|
|
|
|
action = actions.removeLast();
|
|
|
|
action.undoAction(this);
|
|
|
|
} while (!(action == markerAction));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public int getNrOfUndoPoints() {
|
|
|
|
return undoPoints.size();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean hasUndoPoints() {
|
|
|
|
return !undoPoints.isEmpty();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void clearUndoPoints() {
|
|
|
|
undoPoints.clear();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void clearMessages() {
|
|
|
|
logMessageBuilder.clearMessages();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void logMessages() {
|
|
|
|
if (disableLog) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
logMessageBuilder.logMessages();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void logAppendEvent(final MagicEvent event,final Object[] choiceResults) {
|
|
|
|
if (disableLog) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final String message=event.getDescription(choiceResults);
|
|
|
|
if (message.length() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
logMessageBuilder.appendMessage(event.getPlayer(),message);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void logAppendMessage(final MagicPlayer player,final String message) {
|
|
|
|
if (disableLog) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
logMessageBuilder.appendMessage(player,message);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void logMessage(final MagicPlayer player,final String message) {
|
|
|
|
if (disableLog) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
logBook.add(new MagicMessage(this,player,message));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void logAttackers(final MagicPlayer player,final MagicDeclareAttackersResult result) {
|
|
|
|
if (disableLog || result.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final SortedSet<String> names=new TreeSet<String>();
|
|
|
|
for (final MagicPermanent attacker : result) {
|
|
|
|
names.add(attacker.getName());
|
|
|
|
}
|
|
|
|
final StringBuilder builder = new StringBuilder(player + " attacks with ");
|
|
|
|
MagicMessage.addNames(builder,names);
|
|
|
|
builder.append('.');
|
|
|
|
logBook.add(new MagicMessage(this,player,builder.toString()));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void logBlockers(final MagicPlayer player,final MagicDeclareBlockersResult result) {
|
|
|
|
if (disableLog) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final SortedSet<String> names=new TreeSet<String>();
|
|
|
|
for (final MagicCombatCreature[] creatures : result) {
|
|
|
|
for (int index=1;index<creatures.length;index++) {
|
|
|
|
names.add(creatures[index].getName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (names.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final StringBuilder builder = new StringBuilder(player + " blocks with ");
|
|
|
|
MagicMessage.addNames(builder,names);
|
|
|
|
builder.append('.');
|
|
|
|
logBook.add(new MagicMessage(this,player,builder.toString()));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void executeEvent(final MagicEvent event,final Object[] choiceResults) {
|
|
|
|
if (choiceResults == null) {
|
|
|
|
throw new RuntimeException("choiceResults is null");
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
logAppendEvent(event,choiceResults);
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-07-02 02:58:11 -07:00
|
|
|
// Payed cost
|
2013-07-02 18:50:05 -07:00
|
|
|
if (event.getManaChoiceResultIndex() >= 0) {
|
2013-07-02 02:58:11 -07:00
|
|
|
payedCost.set(choiceResults[event.getManaChoiceResultIndex()]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Target in cost
|
2013-07-02 18:50:05 -07:00
|
|
|
if (event.getTargetChoiceResultIndex() >= 0) {
|
2013-07-02 02:58:11 -07:00
|
|
|
payedCost.set(choiceResults[event.getTargetChoiceResultIndex()]);
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-07-08 23:40:18 -07:00
|
|
|
activeSource = event.getSource();
|
2013-04-12 19:32:25 -07:00
|
|
|
event.executeEvent(this,choiceResults);
|
|
|
|
update();
|
2013-07-02 07:19:34 -07:00
|
|
|
|
|
|
|
// Move card to move location that is not play
|
|
|
|
if (event.isSpellCardEvent()) {
|
|
|
|
doAction(new MagicMoveCardAction(event.getCardOnStack()));
|
|
|
|
}
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public MagicEventQueue getEvents() {
|
|
|
|
return events;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean hasNextEvent() {
|
|
|
|
return !events.isEmpty();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicEvent getNextEvent() {
|
|
|
|
return events.getFirst();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void addEvent(final MagicEvent event) {
|
|
|
|
doAction(new MagicAddEventAction(event));
|
|
|
|
}
|
2013-07-11 22:43:22 -07:00
|
|
|
|
|
|
|
public void addFirstEvent(final MagicEvent event) {
|
|
|
|
doAction(new MagicAddFirstEventAction(event));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void executeNextEvent(final Object[] choiceResults) {
|
|
|
|
doAction(new MagicExecuteFirstEventAction(choiceResults));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-05-04 22:32:10 -07:00
|
|
|
public void executeNextEvent() {
|
|
|
|
doAction(new MagicExecuteFirstEventAction(MagicEvent.NO_CHOICE_RESULTS));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicDuel getDuel() {
|
|
|
|
return duel;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void advanceDuel() {
|
|
|
|
duel.advance(losingPlayer!=players[0],this);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPlayer[] getPlayers() {
|
|
|
|
return players;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPlayer getPlayer(final int index) {
|
|
|
|
return players[index];
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
MagicPlayer getOpponent(final MagicPlayer player) {
|
2013-06-23 18:33:35 -07:00
|
|
|
return players[1-player.getIndex()];
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setVisiblePlayer(final MagicPlayer aVisiblePlayer) {
|
|
|
|
visiblePlayer = aVisiblePlayer;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPlayer getVisiblePlayer() {
|
|
|
|
return visiblePlayer;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setTurnPlayer(final MagicPlayer aTurnPlayer) {
|
|
|
|
turnPlayer = aTurnPlayer;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPlayer getTurnPlayer() {
|
|
|
|
return turnPlayer;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-06-05 22:57:29 -07:00
|
|
|
public MagicPlayer getAttackingPlayer() {
|
|
|
|
return turnPlayer;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-06-05 22:57:29 -07:00
|
|
|
public MagicPlayer getDefendingPlayer() {
|
|
|
|
return turnPlayer.getOpponent();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPlayer getPriorityPlayer() {
|
|
|
|
return step == MagicStep.ActivePlayer ? turnPlayer : getOpponent(turnPlayer);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPlayer getScorePlayer() {
|
|
|
|
return scorePlayer;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setLosingPlayer(final MagicPlayer player) {
|
|
|
|
losingPlayer = player;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPlayer getLosingPlayer() {
|
|
|
|
return losingPlayer;
|
|
|
|
}
|
2013-07-08 23:40:18 -07:00
|
|
|
|
|
|
|
public MagicSource getActiveSource() {
|
|
|
|
return activeSource;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean hasTurn(final MagicPlayer player) {
|
|
|
|
return player == turnPlayer;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public int getNrOfPermanents(final MagicType type) {
|
2013-06-23 18:33:35 -07:00
|
|
|
return players[0].getNrOfPermanentsWithType(type) +
|
2013-04-12 19:32:25 -07:00
|
|
|
players[1].getNrOfPermanentsWithType(type);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean canPlaySorcery(final MagicPlayer controller) {
|
2013-06-23 18:33:35 -07:00
|
|
|
return phase.getType().isMain() &&
|
|
|
|
stack.isEmpty() &&
|
2013-04-12 19:32:25 -07:00
|
|
|
turnPlayer == controller;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean canPlayLand(final MagicPlayer controller) {
|
|
|
|
return landPlayed < maxLand && canPlaySorcery(controller);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getLandPlayed() {
|
|
|
|
return landPlayed;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void incLandPlayed() {
|
|
|
|
landPlayed++;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void resetLandPlayed() {
|
|
|
|
landPlayed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setLandPlayed(final int lp) {
|
|
|
|
landPlayed = lp;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void incMaxLand() {
|
|
|
|
maxLand++;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void resetMaxLand() {
|
|
|
|
maxLand = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getSpellsPlayed() {
|
|
|
|
return spellsPlayed;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setSpellsPlayed(final int spells) {
|
|
|
|
spellsPlayed = spells;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void incSpellsPlayed() {
|
|
|
|
spellsPlayed++;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean getCreatureDiedThisTurn() {
|
|
|
|
return creatureDiedThisTurn;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setCreatureDiedThisTurn(final boolean died) {
|
|
|
|
creatureDiedThisTurn = died;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicStack getStack() {
|
|
|
|
return stack;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setPriorityPassed(final boolean passed) {
|
|
|
|
priorityPassed=passed;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean getPriorityPassed() {
|
|
|
|
return priorityPassed;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void incrementPriorityPassedCount() {
|
|
|
|
priorityPassedCount++;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setPriorityPassedCount(final int count) {
|
|
|
|
priorityPassedCount=count;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public int getPriorityPassedCount() {
|
|
|
|
return priorityPassedCount;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPermanent createPermanent(final MagicCard card,final MagicPlayer controller) {
|
|
|
|
return new MagicPermanent(getUniqueId(),card,controller);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicCardList getExiledUntilEndOfTurn() {
|
|
|
|
return exiledUntilEndOfTurn;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setStateCheckRequired(final boolean required) {
|
|
|
|
stateCheckRequired = required;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void setStateCheckRequired() {
|
|
|
|
stateCheckRequired = true;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public boolean getStateCheckRequired() {
|
|
|
|
return stateCheckRequired;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void checkState() {
|
|
|
|
while (stateCheckRequired) {
|
|
|
|
stateCheckRequired = false;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
// Check if a player has lost
|
|
|
|
for (final MagicPlayer player : players) {
|
|
|
|
player.generateStateBasedActions();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check permanents' state
|
|
|
|
for (final MagicPlayer player : players) {
|
|
|
|
for (final MagicPermanent permanent : player.getPermanents()) {
|
|
|
|
permanent.generateStateBasedActions();
|
|
|
|
}}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
update();
|
|
|
|
// some action may set stateCheckRequired to true, if so loop again
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void checkUniquenessRule(final MagicPermanent permanent) {
|
|
|
|
// 704.5k "legend rule"
|
|
|
|
if (permanent.hasType(MagicType.Legendary)) {
|
2013-06-11 06:21:39 -07:00
|
|
|
final MagicTargetFilter<MagicPermanent> targetFilter=new MagicTargetFilter.LegendaryCopiesFilter(permanent.getName());
|
2013-04-12 19:32:25 -07:00
|
|
|
final Collection<MagicPermanent> targets=filterPermanents(permanent.getController(),targetFilter);
|
|
|
|
if (targets.size() > 1) {
|
2013-06-11 06:21:39 -07:00
|
|
|
addEvent(new MagicUniquenessEvent(permanent, targetFilter));
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 704.5j "planeswalker uniqueness rule."
|
|
|
|
if (permanent.hasType(MagicType.Planeswalker)) {
|
2013-06-11 06:21:39 -07:00
|
|
|
final MagicTargetFilter<MagicPermanent> targetFilter=new MagicTargetFilter.PlaneswalkerCopiesFilter(permanent);
|
|
|
|
final Collection<MagicPermanent> targets=filterPermanents(permanent.getController(),targetFilter);
|
|
|
|
if (targets.size() > 1) {
|
|
|
|
addEvent(new MagicUniquenessEvent(permanent, targetFilter));
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public Object[] map(final Object[] data) {
|
|
|
|
final int length=data.length;
|
|
|
|
final Object[] mappedData=new Object[length];
|
|
|
|
for (int index=0;index<length;index++) {
|
|
|
|
final Object obj=data[index];
|
|
|
|
if (obj != null && obj instanceof MagicMappable) {
|
|
|
|
mappedData[index]=((MagicMappable)obj).map(this);
|
|
|
|
} else {
|
|
|
|
mappedData[index]=obj;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
2013-04-12 19:32:25 -07:00
|
|
|
return mappedData;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
// ***** TARGETTING *****
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public List<MagicPermanent> filterPermanents(final MagicPlayer player,final MagicTargetFilter<MagicPermanent> targetFilter) {
|
|
|
|
return targetFilter.filter(this, player, MagicTargetHint.None);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public List<MagicCard> filterCards(final MagicPlayer player,final MagicTargetFilter<MagicCard> targetFilter) {
|
|
|
|
return targetFilter.filter(this, player, MagicTargetHint.None);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public List<MagicItemOnStack> filterItemOnStack(final MagicPlayer player,final MagicTargetFilter<MagicItemOnStack> targetFilter) {
|
|
|
|
return targetFilter.filter(this, player, MagicTargetHint.None);
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasLegalTargets(
|
|
|
|
final MagicPlayer player,
|
|
|
|
final MagicSource source,
|
|
|
|
final MagicTargetChoice targetChoice,
|
|
|
|
final boolean hints) {
|
|
|
|
|
|
|
|
if (targetChoice == MagicTargetChoice.NONE) {
|
|
|
|
return true;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
final Collection<? extends MagicTarget> targets = targetChoice.getTargetFilter().filter(
|
|
|
|
this,
|
|
|
|
player,
|
|
|
|
targetChoice.getTargetHint(hints)
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!targetChoice.isTargeted()) {
|
|
|
|
return !targets.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (final MagicTarget target : targets) {
|
|
|
|
if (target.isValidTarget(source)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public List<MagicTarget> getLegalTargets(
|
|
|
|
final MagicPlayer player,
|
|
|
|
final MagicSource source,
|
|
|
|
final MagicTargetChoice targetChoice,
|
|
|
|
final MagicTargetHint targetHint) {
|
|
|
|
|
|
|
|
final Collection<? extends MagicTarget> targets = targetChoice.getTargetFilter().filter(
|
|
|
|
this,
|
|
|
|
player,
|
|
|
|
targetHint
|
|
|
|
);
|
|
|
|
|
|
|
|
final List<MagicTarget> options;
|
|
|
|
if (targetChoice.isTargeted()) {
|
|
|
|
options=new ArrayList<MagicTarget>();
|
|
|
|
for (final MagicTarget target : targets) {
|
|
|
|
if (target.isValidTarget(source)) {
|
|
|
|
options.add(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
options=new ArrayList<MagicTarget>(targets);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
if (options.isEmpty()) {
|
|
|
|
// Try again without using hints
|
|
|
|
if (targetHint != MagicTargetHint.None) {
|
|
|
|
return getLegalTargets(player, source, targetChoice, MagicTargetHint.None);
|
|
|
|
// Add none when there are no legal targets. Only for triggers.
|
|
|
|
} else {
|
|
|
|
options.add(MagicTargetNone.getInstance());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return options;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public <T extends MagicTarget> boolean isLegalTarget(
|
|
|
|
final MagicPlayer player,
|
|
|
|
final MagicSource source,
|
|
|
|
final MagicTargetChoice targetChoice,
|
|
|
|
final T target) {
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
MagicTargetFilter<T> targetFilter = (MagicTargetFilter<T>)targetChoice.getTargetFilter();
|
2013-06-23 18:33:35 -07:00
|
|
|
|
|
|
|
if (target==null ||
|
|
|
|
target==MagicTargetNone.getInstance() ||
|
2013-04-12 19:32:25 -07:00
|
|
|
!targetFilter.accept(this,player,target)) {
|
|
|
|
return false;
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
if (target.isLegalTarget(player, targetFilter)) {
|
|
|
|
return !targetChoice.isTargeted() || target.isValidTarget(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
// ***** STATICS *****
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void addStatics(final MagicPermanent permanent) {
|
|
|
|
for (final MagicStatic mstatic : permanent.getStatics()) {
|
|
|
|
addStatic(permanent, mstatic);
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public Collection<MagicPermanentStatic> removeStatics(final MagicPermanent permanent) {
|
|
|
|
return statics.remove(permanent);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void addStatic(final MagicPermanent permanent, final MagicStatic mstatic) {
|
|
|
|
addStatic(new MagicPermanentStatic(getUniqueId(),permanent,mstatic));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void addStatic(final MagicPermanentStatic permanentStatic) {
|
|
|
|
statics.add(permanentStatic);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addStatics(final Collection<MagicPermanentStatic> aStatics) {
|
|
|
|
for (final MagicPermanentStatic mpstatic : aStatics) {
|
|
|
|
addStatic(mpstatic);
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public Collection<MagicPermanentStatic> getStatics(final MagicLayer layer) {
|
|
|
|
return statics.get(layer);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public Collection<MagicPermanentStatic> removeTurnStatics() {
|
|
|
|
return statics.removeTurn();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void removeStatic(final MagicPermanent permanent,final MagicStatic mstatic) {
|
|
|
|
statics.remove(permanent, mstatic);
|
|
|
|
}
|
|
|
|
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
// ***** TRIGGERS *****
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
/** Executes triggers immediately when they have no choices, otherwise ignore them. */
|
|
|
|
public void setImmediate(final boolean aImmediate) {
|
|
|
|
immediate = aImmediate;
|
|
|
|
}
|
2013-07-13 18:38:42 -07:00
|
|
|
|
2013-07-13 18:39:23 -07:00
|
|
|
public boolean isImmediate() {
|
2013-07-13 18:38:42 -07:00
|
|
|
return immediate;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPermanentTrigger addTrigger(final MagicPermanent permanent, final MagicTrigger<?> trigger) {
|
|
|
|
return addTrigger(new MagicPermanentTrigger(getUniqueId(),permanent,trigger));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPermanentTrigger addTrigger(final MagicPermanentTrigger permanentTrigger) {
|
2013-07-13 07:41:20 -07:00
|
|
|
additionalTriggers.add(permanentTrigger);
|
2013-04-12 19:32:25 -07:00
|
|
|
return permanentTrigger;
|
|
|
|
}
|
|
|
|
|
|
|
|
public MagicPermanentTrigger addTurnTrigger(final MagicPermanent permanent,final MagicTrigger<?> trigger) {
|
|
|
|
final MagicPermanentTrigger permanentTrigger = addTrigger(permanent,trigger);
|
|
|
|
turnTriggers.add(permanentTrigger);
|
|
|
|
return permanentTrigger;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void addTurnTriggers(final List<MagicPermanentTrigger> triggersList) {
|
|
|
|
for (final MagicPermanentTrigger permanentTrigger : triggersList) {
|
|
|
|
addTrigger(permanentTrigger);
|
|
|
|
}
|
|
|
|
turnTriggers.addAll(triggersList);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void removeTurnTrigger(final MagicPermanentTrigger permanentTrigger) {
|
2013-07-13 07:41:20 -07:00
|
|
|
additionalTriggers.remove(permanentTrigger);
|
2013-04-12 19:32:25 -07:00
|
|
|
turnTriggers.remove(permanentTrigger);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public void removeTrigger(final MagicPermanentTrigger permanentTrigger) {
|
2013-07-13 07:41:20 -07:00
|
|
|
additionalTriggers.remove(permanentTrigger);
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public MagicPermanentTrigger removeTrigger(final MagicPermanent permanent, MagicTrigger<?> trigger) {
|
2013-07-13 07:41:20 -07:00
|
|
|
return additionalTriggers.remove(permanent, trigger);
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public List<MagicPermanentTrigger> removeTurnTriggers() {
|
|
|
|
if (turnTriggers.isEmpty()) {
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
|
|
|
final MagicPermanentTriggerList removedTriggers = new MagicPermanentTriggerList(turnTriggers);
|
|
|
|
for (final MagicPermanentTrigger permanentTrigger : removedTriggers) {
|
|
|
|
removeTurnTrigger(permanentTrigger);
|
|
|
|
}
|
|
|
|
return removedTriggers;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public Collection<MagicPermanentTrigger> removeTriggers(final MagicPermanent permanent) {
|
2013-07-13 07:41:20 -07:00
|
|
|
return additionalTriggers.remove(permanent);
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public <T> void executeTrigger(
|
|
|
|
final MagicTrigger<T> trigger,
|
|
|
|
final MagicPermanent permanent,
|
|
|
|
final MagicSource source,
|
|
|
|
final T data) {
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-07-07 22:17:04 -07:00
|
|
|
if (trigger.accept(permanent, data) == false) {
|
2013-04-12 19:32:25 -07:00
|
|
|
return;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
final MagicEvent event=trigger.executeTrigger(this,permanent,data);
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-07-07 22:17:04 -07:00
|
|
|
if (event.isValid() == false) {
|
2013-04-12 19:32:25 -07:00
|
|
|
return;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-05-04 22:32:10 -07:00
|
|
|
if (immediate) {
|
|
|
|
if (event.hasChoice()) {
|
|
|
|
// ignore
|
2013-05-05 02:10:07 -07:00
|
|
|
} else if (trigger.usesStack()) {
|
2013-05-05 00:36:14 -07:00
|
|
|
doAction(new MagicPutItemOnStackAction(new MagicTriggerOnStack(event)));
|
2013-05-05 02:10:07 -07:00
|
|
|
} else {
|
2013-06-23 18:33:35 -07:00
|
|
|
executeEvent(event, MagicEvent.NO_CHOICE_RESULTS);
|
2013-05-04 22:32:10 -07:00
|
|
|
}
|
2013-04-12 19:32:25 -07:00
|
|
|
} else if (trigger.usesStack()) {
|
|
|
|
doAction(new MagicPutItemOnStackAction(new MagicTriggerOnStack(event)));
|
|
|
|
} else {
|
2013-06-23 18:33:35 -07:00
|
|
|
addEvent(event);
|
2013-04-12 19:32:25 -07:00
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
public <T> void executeTrigger(final MagicTriggerType type,final T data) {
|
2013-07-13 07:41:20 -07:00
|
|
|
final Collection<MagicPermanentTrigger> typeTriggers=triggers.get(type);
|
2013-04-12 19:32:25 -07:00
|
|
|
if (typeTriggers.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-04-12 19:32:25 -07:00
|
|
|
final Collection<MagicPermanentTrigger> copiedTriggers=new ArrayList<MagicPermanentTrigger>(typeTriggers);
|
|
|
|
for (final MagicPermanentTrigger permanentTrigger : copiedTriggers) {
|
|
|
|
final MagicPermanent permanent = permanentTrigger.getPermanent();
|
|
|
|
final MagicTrigger<T> trigger = (MagicTrigger<T>)permanentTrigger.getTrigger();
|
|
|
|
executeTrigger(trigger,permanent,permanent,data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|