mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
Game starts with phase = NULL and turn = 0. This lets us log turn 1 beginning properly.
Some effects may not work during turn 0 (leylines/chancellors) - if they do, convert them to T:Phase Upkeep | Turn$ 1
This commit is contained in:
@@ -43,14 +43,10 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
|
||||
private static final long serialVersionUID = 3955194449319994301L;
|
||||
|
||||
private final BlockingDeque<Input> inputStack = new LinkedBlockingDeque<Input>();
|
||||
private final GameState game;
|
||||
|
||||
|
||||
private final InputLockUI inputLock;
|
||||
|
||||
|
||||
public InputQueue(GameState game0) {
|
||||
game = game0;
|
||||
public InputQueue() {
|
||||
inputLock = new InputLockUI(this);
|
||||
}
|
||||
|
||||
@@ -80,17 +76,6 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
|
||||
return inputStack.isEmpty() ? null : this.inputStack.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* clearInput.
|
||||
* </p>
|
||||
*/
|
||||
public final void clearInput() {
|
||||
this.inputStack.clear();
|
||||
this.updateObservers();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* resetInput.
|
||||
@@ -101,19 +86,11 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
|
||||
*/
|
||||
final void removeInput(Input inp) {
|
||||
FThreads.assertExecutedByEdt(false);
|
||||
|
||||
Input topMostInput = inputStack.isEmpty() ? null : inputStack.pop();
|
||||
|
||||
// StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||
// System.out.printf("%s > Remove input %s -- called from %s%n", FThreads.isEDT() ? "EDT" : "TRD", topMostInput, trace[2].toString());
|
||||
// if( trace[2].toString().contains("InputBase.stop"))
|
||||
// for(StackTraceElement se : trace) {
|
||||
// System.out.println(se.toString());
|
||||
// }
|
||||
|
||||
|
||||
if( topMostInput != inp )
|
||||
throw new RuntimeException("Inputs adding/removal into stack is imbalanced! Check your code again!");
|
||||
|
||||
|
||||
this.updateObservers();
|
||||
}
|
||||
|
||||
@@ -128,7 +105,7 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
|
||||
*
|
||||
* @return a {@link forge.control.input.InputBase} object.
|
||||
*/
|
||||
public final Input getActualInput() {
|
||||
public final Input getActualInput(GameState game) {
|
||||
GameAge age = game.getAge();
|
||||
|
||||
if ( game.isGameOver() )
|
||||
@@ -142,7 +119,7 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
|
||||
return inputLock;
|
||||
|
||||
final PhaseHandler handler = game.getPhaseHandler();
|
||||
final PhaseType phase = handler.getPhase();
|
||||
|
||||
final Player playerTurn = handler.getPlayerTurn();
|
||||
final Player priority = handler.getPriorityPlayer();
|
||||
if (priority == null)
|
||||
@@ -155,6 +132,7 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
|
||||
}
|
||||
|
||||
// Special Inputs needed for the following phases:
|
||||
final PhaseType phase = handler.getPhase();
|
||||
final MagicStack stack = game.getStack();
|
||||
switch (phase) {
|
||||
case COMBAT_DECLARE_ATTACKERS:
|
||||
@@ -168,12 +146,8 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
|
||||
case COMBAT_DECLARE_BLOCKERS:
|
||||
stack.freezeStack();
|
||||
|
||||
if (game.getCombat().isPlayerAttacked(priority)) {
|
||||
return pc.getBlockInput();
|
||||
}
|
||||
|
||||
// noone attacks you
|
||||
return pc.getAutoPassPriorityInput();
|
||||
boolean isAttacked = game.getCombat().isPlayerAttacked(priority);
|
||||
return isAttacked ? pc.getBlockInput() : pc.getAutoPassPriorityInput();
|
||||
|
||||
case CLEANUP:
|
||||
// discard
|
||||
|
||||
@@ -1476,12 +1476,16 @@ public class GameAction {
|
||||
|
||||
public void mulligan(final Player firstPlayer) {
|
||||
performMulligans(firstPlayer, game.getType() == GameType.Commander);
|
||||
handleLeylinesAndChancellors();
|
||||
// Run Trigger beginning of the game
|
||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
||||
game.getTriggerHandler().runTrigger(TriggerType.NewGame, runParams, false);
|
||||
game.setAge(GameAge.Play);
|
||||
game.getInputQueue().clearInput();
|
||||
|
||||
// THIS CODE WILL WORK WITH PHASE = NULL {
|
||||
handleLeylinesAndChancellors();
|
||||
// Run Trigger beginning of the game
|
||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
||||
game.getTriggerHandler().runTrigger(TriggerType.NewGame, runParams, false);
|
||||
// }
|
||||
|
||||
game.getPhaseHandler().startFirstTurn(firstPlayer);
|
||||
}
|
||||
|
||||
private void performMulligans(final Player firstPlayer, final boolean isCommander) {
|
||||
|
||||
@@ -89,7 +89,7 @@ public class GameState {
|
||||
private final MatchController match;
|
||||
private GameAge age = GameAge.BeforeMulligan;
|
||||
|
||||
private final InputQueue inputQueue;
|
||||
private final InputQueue inputQueue = new InputQueue();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -128,8 +128,6 @@ public class GameState {
|
||||
endOfTurn = new EndOfTurn(this);
|
||||
endOfCombat = new EndOfCombat(this);
|
||||
|
||||
inputQueue = new InputQueue(this);
|
||||
|
||||
if ( match0.getGameType() == GameType.Quest)
|
||||
events.register(Singletons.getModel().getQuest()); // this one listens to player's mulligans ATM
|
||||
|
||||
|
||||
@@ -132,7 +132,6 @@ public class MatchController {
|
||||
currentGame.getInputQueue().invokeGameAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
currentGame.getInputQueue().clearInput();
|
||||
if(currentGame.getType() == GameType.Planechase)
|
||||
firstPlayer.initPlane();
|
||||
|
||||
@@ -266,7 +265,6 @@ public class MatchController {
|
||||
|
||||
boolean willPlay = goesFirst.getController().getWillPlayOnFirstTurn(message);
|
||||
goesFirst = willPlay ? goesFirst : goesFirst.getOpponent();
|
||||
game.getPhaseHandler().setPlayerTurn(goesFirst);
|
||||
return goesFirst;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,9 +56,10 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
||||
/** Constant <code>serialVersionUID=5207222278370963197L</code>. */
|
||||
private static final long serialVersionUID = 5207222278370963197L;
|
||||
|
||||
private PhaseType phase = PhaseType.UNTAP;
|
||||
private int turn = 1;
|
||||
// Start turn at 1, since first untap is where we start
|
||||
// Start turn at 0, since we start even before first untap
|
||||
private PhaseType phase = null;
|
||||
private int turn = 0;
|
||||
|
||||
|
||||
private final transient Stack<ExtraTurn> extraTurns = new Stack<ExtraTurn>();
|
||||
private final transient Map<PhaseType, Stack<PhaseType>> extraPhases = new HashMap<PhaseType, Stack<PhaseType>>();
|
||||
@@ -232,38 +233,39 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
||||
p.updateObservers();
|
||||
}
|
||||
|
||||
switch (this.phase) {
|
||||
case UNTAP:
|
||||
this.nCombatsThisTurn = 0;
|
||||
break;
|
||||
|
||||
case COMBAT_DECLARE_ATTACKERS:
|
||||
game.getStack().unfreezeStack();
|
||||
this.nCombatsThisTurn++;
|
||||
break;
|
||||
|
||||
case COMBAT_DECLARE_BLOCKERS:
|
||||
game.getStack().unfreezeStack();
|
||||
break;
|
||||
|
||||
case COMBAT_END:
|
||||
//SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc());
|
||||
game.getCombat().reset(playerTurn);
|
||||
this.getPlayerTurn().resetAttackedThisCombat();
|
||||
this.bCombat.set(false);
|
||||
|
||||
break;
|
||||
|
||||
case CLEANUP:
|
||||
this.bPreventCombatDamageThisTurn = false;
|
||||
if (!this.bRepeatCleanup) {
|
||||
this.setPlayerTurn(this.handleNextTurn());
|
||||
}
|
||||
this.planarDiceRolledthisTurn = 0;
|
||||
// Play the End Turn sound
|
||||
game.getEvents().post(new EndOfTurnEvent());
|
||||
break;
|
||||
default: // no action
|
||||
if( phase != null ) {
|
||||
switch (this.phase) {
|
||||
case UNTAP:
|
||||
this.nCombatsThisTurn = 0;
|
||||
break;
|
||||
|
||||
case COMBAT_DECLARE_ATTACKERS:
|
||||
game.getStack().unfreezeStack();
|
||||
this.nCombatsThisTurn++;
|
||||
break;
|
||||
|
||||
case COMBAT_DECLARE_BLOCKERS:
|
||||
game.getStack().unfreezeStack();
|
||||
break;
|
||||
|
||||
case COMBAT_END:
|
||||
game.getCombat().reset(playerTurn);
|
||||
this.getPlayerTurn().resetAttackedThisCombat();
|
||||
this.bCombat.set(false);
|
||||
|
||||
break;
|
||||
|
||||
case CLEANUP:
|
||||
this.bPreventCombatDamageThisTurn = false;
|
||||
if (!this.bRepeatCleanup) {
|
||||
this.setPlayerTurn(this.handleNextTurn());
|
||||
}
|
||||
this.planarDiceRolledthisTurn = 0;
|
||||
// Play the End Turn sound
|
||||
game.getEvents().post(new EndOfTurnEvent());
|
||||
break;
|
||||
default: // no action
|
||||
}
|
||||
}
|
||||
|
||||
String phaseType = "";
|
||||
@@ -283,7 +285,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
||||
this.phase = nextPhase;
|
||||
phaseType = "Additional ";
|
||||
} else {
|
||||
this.phase = phase.getNextPhase();
|
||||
this.phase = PhaseType.getNext(phase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,15 +714,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
||||
// System.out.println(String.format("%s %s: %s passes priority to %s", playerTurn, phase, actingPlayer, nextPlayer));
|
||||
if (firstAction.equals(nextPlayer)) {
|
||||
if (game.getStack().isEmpty()) {
|
||||
this.setPriority(this.getPlayerTurn()); // this needs to be set early as we exit the phase
|
||||
// end phase
|
||||
setPlayersPriorityPermission(true);
|
||||
nextPhase();
|
||||
// When consecutively skipping phases (like in combat) this section
|
||||
// pushes through that block
|
||||
handleBeginPhase();
|
||||
// it no longer does.
|
||||
updateObservers();
|
||||
advancePhase();
|
||||
} else if (!game.getStack().hasSimultaneousStackEntries()) {
|
||||
game.getStack().resolveStack();
|
||||
game.getStack().chooseOrderOfSimultaneousStackEntryAll();
|
||||
@@ -733,6 +727,26 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void startFirstTurn(Player goesFirst) {
|
||||
if(phase != null)
|
||||
throw new IllegalStateException("Turns already started, call this only once per game");
|
||||
setPlayerTurn(goesFirst);
|
||||
advancePhase();
|
||||
}
|
||||
|
||||
private void advancePhase() { // may be called externally only from gameAction after mulligans
|
||||
|
||||
this.setPriority(this.getPlayerTurn()); // this needs to be set early as we exit the phase
|
||||
// end phase
|
||||
setPlayersPriorityPermission(true);
|
||||
nextPhase();
|
||||
// When consecutively skipping phases (like in combat) this section
|
||||
// pushes through that block
|
||||
handleBeginPhase();
|
||||
// it no longer does.
|
||||
updateObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
||||
@@ -106,9 +106,9 @@ public enum PhaseType {
|
||||
* Get the next PhaseType in turn order.
|
||||
* @return
|
||||
*/
|
||||
public PhaseType getNextPhase() {
|
||||
int iNext = ALL_PHASES.indexOf(this) + 1;
|
||||
while (iNext >= ALL_PHASES.size()) {
|
||||
public static PhaseType getNext(PhaseType current) {
|
||||
int iNext = ALL_PHASES.indexOf(current) + 1;
|
||||
if (iNext >= ALL_PHASES.size()) {
|
||||
iNext = 0;
|
||||
}
|
||||
return ALL_PHASES.get(iNext);
|
||||
|
||||
@@ -43,11 +43,10 @@ public class InputProxy implements Observer {
|
||||
private AtomicReference<Input> input = new AtomicReference<Input>();
|
||||
private GameState game = null;
|
||||
|
||||
private static final boolean INPUT_DEBUG = false;
|
||||
private static final boolean DEBUG_INPUT = false;
|
||||
|
||||
public void setGame(GameState game0) {
|
||||
game = game0;
|
||||
// game.getStack().addObserver(this);
|
||||
game.getPhaseHandler().addObserver(this);
|
||||
game.getInputQueue().addObserver(this);
|
||||
}
|
||||
@@ -58,19 +57,15 @@ public class InputProxy implements Observer {
|
||||
FThreads.assertExecutedByEdt(false);
|
||||
|
||||
final PhaseHandler ph = game.getPhaseHandler();
|
||||
final Input nextInput = game.getInputQueue().getActualInput();
|
||||
final Input nextInput = game.getInputQueue().getActualInput(game);
|
||||
|
||||
|
||||
if(INPUT_DEBUG) {
|
||||
System.out.print(FThreads.debugGetStackTraceItem(6, true) + " ... ");
|
||||
System.out.printf("\t%s on %s, \tstack = %s%n", nextInput == null ? "null" : nextInput.getClass().getSimpleName(), ph.debugPrintState(), game.getInputQueue().printInputStack());
|
||||
}
|
||||
if(DEBUG_INPUT)
|
||||
System.out.printf("%s ... \t%s on %s, \tstack = %s%n", FThreads.debugGetStackTraceItem(6, true), nextInput == null ? "null" : nextInput.getClass().getSimpleName(), ph.debugPrintState(), game.getInputQueue().printInputStack());
|
||||
|
||||
this.input.set(nextInput);
|
||||
Runnable showMessage = new Runnable() {
|
||||
@Override public void run() {
|
||||
//if(INPUT_DEBUG)
|
||||
// System.out.printf("%s > showMessage @ %s/%s during %s%n%n", FThreads.debugGetCurrThreadId(), nextInput.getClass().getSimpleName(), getInput().getClass().getSimpleName(), ph.debugPrintState());
|
||||
// System.out.printf("%s > showMessage @ %s/%s during %s%n%n", FThreads.debugGetCurrThreadId(), nextInput.getClass().getSimpleName(), getInput().getClass().getSimpleName(), ph.debugPrintState());
|
||||
getInput().showMessage(game.getInputQueue());
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user