Arranged code for better implementation of Karn's Ultimate

This commit is contained in:
Maxmtg
2013-05-28 17:50:16 +00:00
parent d58b922009
commit c2df1c4238
12 changed files with 159 additions and 100 deletions

View File

@@ -7,8 +7,10 @@ import java.util.Map.Entry;
import forge.game.GameOutcome;
import forge.game.event.DuelOutcomeEvent;
import forge.game.event.Event;
import forge.game.event.PhaseEvent;
import forge.game.event.PlayerControlEvent;
import forge.game.phase.Combat;
import forge.game.phase.PhaseType;
import forge.game.player.LobbyPlayer;
import forge.game.player.Player;
import forge.game.player.PlayerStatistics;
@@ -32,6 +34,10 @@ public class GameLogFormatter {
message = String.format("%s is controlled by %s", p.getName(), newController.getName());
return new GameLogEntry(GameEventType.PLAYER_CONROL, message);
} else if ( ev instanceof PhaseEvent ) {
Player p = ((PhaseEvent) ev).playerTurn;
PhaseType ph = ((PhaseEvent) ev).phase;
return new GameLogEntry(GameEventType.PHASE, ((PhaseEvent) ev).phaseDesc + Lang.getPossesive(p.getName()) + " " + ph.NameForUi);
}
return null;
}

View File

@@ -11,9 +11,15 @@ import forge.CardLists;
import forge.CardPredicates;
import forge.card.ability.SpellAbilityEffect;
import forge.card.spellability.SpellAbility;
import forge.card.trigger.TriggerHandler;
import forge.card.trigger.TriggerType;
import forge.game.GameAction;
import forge.game.GameAge;
import forge.game.GameNew;
import forge.game.GameState;
import forge.game.RegisteredPlayer;
import forge.game.player.Player;
import forge.game.zone.PlayerZone;
import forge.game.zone.ZoneType;
public class RestartGameEffect extends SpellAbilityEffect {
@@ -47,10 +53,50 @@ public class RestartGameEffect extends SpellAbilityEffect {
newLibrary.addAll(filteredCards);
playerLibraries.put(p, newLibrary);
}
//Card.resetUniqueNumber();
// need this code here, otherwise observables fail
forge.card.trigger.Trigger.resetIDs();
TriggerHandler trigHandler = game.getTriggerHandler();
trigHandler.clearDelayedTrigger();
trigHandler.cleanUpTemporaryTriggers();
trigHandler.suppressMode(TriggerType.ChangesZone);
GameNew.restartGame(game, sa.getActivatingPlayer(), playerLibraries);
// because the caller method (invokeInNewThread) will try to unlock input. Restart has removed that input state.
game.getStack().reset();
GameAction action = game.getAction();
List<Player> gamePlayers = game.getRegisteredPlayers();
for( int i = 0; i < gamePlayers.size(); i++ ) {
final Player player = gamePlayers.get(i);
if( player.hasLost()) continue;
RegisteredPlayer psc = game.getMatch().getPlayers().get(i);
player.setStartingLife(psc.getStartingLife());
player.setNumLandsPlayed(0);
GameNew.putCardsOnBattlefield(player, psc.getCardsOnBattlefield(player));
PlayerZone library = player.getZone(ZoneType.Library);
List<Card> newLibrary = playerLibraries.get(player);
for (Card c : newLibrary) {
action.moveTo(library, c);
}
player.shuffle();
player.getZone(ZoneType.Battlefield).updateObservers();
player.updateObservers();
player.getZone(ZoneType.Hand).updateObservers();
}
trigHandler.clearSuppression(TriggerType.ChangesZone);
game.setAge(GameAge.RestartedByKarn);
game.getPhaseHandler().setPlayerTurn(sa.getActivatingPlayer());
// Set turn number?
// The rest is handled by phaseHandler
}
/* (non-Javadoc)

View File

@@ -46,7 +46,10 @@ import forge.game.ai.AiProfileUtil;
import forge.game.event.CardsAntedEvent;
import forge.game.event.DuelFinishedEvent;
import forge.game.event.Event;
import forge.game.event.PhaseEvent;
import forge.game.event.PlayerControlEvent;
import forge.game.phase.PhaseType;
import forge.game.phase.PhaseUtil;
import forge.game.player.LobbyPlayer;
import forge.game.player.Player;
import forge.gui.GuiDialog;
@@ -414,7 +417,7 @@ public enum FControl {
}
@Subscribe
public void receiveGameEvent(Event ev) {
public void receiveGameEvent(final Event ev) {
if( ev instanceof DuelFinishedEvent ) {
FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() {
@@ -438,6 +441,12 @@ public enum FControl {
h.getLayoutControl().updateHand();
}
} });
} else if ( ev instanceof PhaseEvent ) {
FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() {
Player p = ((PhaseEvent) ev).playerTurn;
PhaseType ph = ((PhaseEvent) ev).phase;
PhaseUtil.visuallyActivatePhase(p, ph);
} });
}
}
}

View File

@@ -1475,25 +1475,41 @@ public class GameAction {
}
}
}
game.getAction().checkStateEffects();
}
public void startGame(final Player firstPlayer) {
performMulligans(firstPlayer, game.getType() == GameType.Commander);
game.setAge(GameAge.Play);
// THIS CODE WILL WORK WITH PHASE = NULL {
if(game.getType() == GameType.Planechase)
firstPlayer.initPlane();
Player first = firstPlayer;
do {
// Draw <handsize> cards
for (final Player p1 : game.getPlayers()) {
p1.drawCards(p1.getMaxHandSize());
}
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.Mulligan);
performMulligans(first, game.getType() == GameType.Commander);
// should I restore everyting exiled by Karn here, or before Mulligans is fine?
game.setAge(GameAge.Play);
// THIS CODE WILL WORK WITH PHASE = NULL {
if(game.getType() == GameType.Planechase)
firstPlayer.initPlane();
game.getPhaseHandler().startFirstTurn(firstPlayer);
handleLeylinesAndChancellors();
checkStateEffects();
// 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(first);
first = game.getPhaseHandler().getPlayerTurn(); // needed only for restart
} while( game.getAge() == GameAge.RestartedByKarn );
System.out.println(FThreads.prependThreadId("Thread exited game loop due to ... " + ( game.isGameOver() ? "game over" : "interrupt" )));
}
private void performMulligans(final Player firstPlayer, final boolean isCommander) {

View File

@@ -4,5 +4,6 @@ public enum GameAge {
BeforeMulligan,
Mulligan,
Play,
RestartedByKarn,
GameOver
}

View File

@@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
@@ -22,11 +21,9 @@ import forge.CardPredicates;
import forge.GameEventType;
import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerHandler;
import forge.card.trigger.TriggerType;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.phase.PhaseHandler;
import forge.game.player.Player;
import forge.game.player.PlayerType;
import forge.game.zone.PlayerZone;
@@ -52,7 +49,7 @@ public class GameNew {
public static final ForgePreferences preferences = forge.Singletons.getModel().getPreferences();
private static void putCardsOnBattlefield(Player player, Iterable<? extends IPaperCard> cards) {
public static void putCardsOnBattlefield(Player player, Iterable<? extends IPaperCard> cards) {
PlayerZone bf = player.getZone(ZoneType.Battlefield);
if (cards != null) {
for (final IPaperCard cp : cards) {
@@ -331,61 +328,6 @@ public class GameNew {
}
}
// ultimate of Karn the Liberated
public static void restartGame(final GameState game, final Player startingTurn, Map<Player, List<Card>> playerLibraries) {
//Card.resetUniqueNumber();
// need this code here, otherwise observables fail
forge.card.trigger.Trigger.resetIDs();
TriggerHandler trigHandler = game.getTriggerHandler();
trigHandler.clearDelayedTrigger();
trigHandler.cleanUpTemporaryTriggers();
trigHandler.suppressMode(TriggerType.ChangesZone);
game.getStack().reset();
GameAction action = game.getAction();
List<Player> gamePlayers = game.getRegisteredPlayers();
for( int i = 0; i < gamePlayers.size(); i++ ) {
final Player player = gamePlayers.get(i);
if( player.hasLost()) continue;
RegisteredPlayer psc = game.getMatch().getPlayers().get(i);
player.setStartingLife(psc.getStartingLife());
player.setNumLandsPlayed(0);
putCardsOnBattlefield(player, psc.getCardsOnBattlefield(player));
PlayerZone library = player.getZone(ZoneType.Library);
List<Card> newLibrary = playerLibraries.get(player);
for (Card c : newLibrary) {
action.moveTo(library, c);
}
player.shuffle();
player.getZone(ZoneType.Battlefield).updateObservers();
player.updateObservers();
player.getZone(ZoneType.Hand).updateObservers();
}
trigHandler.clearSuppression(TriggerType.ChangesZone);
PhaseHandler phaseHandler = game.getPhaseHandler();
phaseHandler.setPlayerTurn(startingTurn);
game.setAge(GameAge.Mulligan);
// Draw <handsize> cards
for (final Player p : game.getPlayers()) {
p.drawCards(p.getMaxHandSize());
}
game.getAction().startGame(startingTurn);
}
// this is where the computer cheats
// changes AllZone.getComputerPlayer().getZone(Zone.Library)

View File

@@ -302,6 +302,11 @@ public class GameState {
*/
public synchronized void setGameOver(GameEndReason reason) {
this.age = GameAge.GameOver;
for (Player p : allPlayers ) {
if (p.isMindSlaved())
p.releaseControl(); // for correct totals
}
for (Player p : roIngamePlayers) {
p.onGameOver();
}
@@ -617,7 +622,7 @@ public class GameState {
return age;
}
void setAge(GameAge value) {
public void setAge(GameAge value) {
age = value;
}
}

View File

@@ -118,13 +118,6 @@ public class MatchState {
@Override
public void run() {
final Player firstPlayer = determineFirstTurnPlayer(getLastGameOutcome(), currentGame);
// Draw <handsize> cards
for (final Player p1 : currentGame.getPlayers()) {
p1.drawCards(p1.getMaxHandSize());
}
currentGame.setAge(GameAge.Mulligan);
currentGame.getAction().startGame(firstPlayer);
}
});

View File

@@ -0,0 +1,17 @@
package forge.game.event;
import forge.game.player.Player;
/**
* TODO: Write javadoc for this type.
*
*/
public class GameRestartedEvent extends Event {
public final Player whoRestarted;
public GameRestartedEvent(Player playerTurn) {
whoRestarted = playerTurn;
}
}

View File

@@ -0,0 +1,22 @@
package forge.game.event;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
/**
* TODO: Write javadoc for this type.
*
*/
public class PhaseEvent extends Event {
public final Player playerTurn;
public final PhaseType phase;
public final String phaseDesc;
public PhaseEvent(Player player, PhaseType ph, String desc) {
playerTurn = player;
phase = ph;
phaseDesc = desc;
}
}

View File

@@ -34,17 +34,19 @@ import forge.GameEventType;
import forge.Singletons;
import forge.CardPredicates.Presets;
import forge.card.trigger.TriggerType;
import forge.game.GameAge;
import forge.game.GameState;
import forge.game.GameType;
import forge.game.event.EndOfTurnEvent;
import forge.game.event.GameRestartedEvent;
import forge.game.event.ManaBurnEvent;
import forge.game.event.PhaseEvent;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.gui.framework.SDisplayUtil;
import forge.gui.match.CMatchUI;
import forge.gui.match.nonsingleton.VField;
import forge.properties.ForgePreferences.FPref;
import forge.util.Lang;
import forge.util.MyObservable;
@@ -300,9 +302,8 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
this.turn++;
game.getGameLog().add(GameEventType.TURN, "Turn " + this.turn + " (" + this.getPlayerTurn() + ")");
}
game.getGameLog().add(GameEventType.PHASE, phaseType + Lang.getPossesive(this.getPlayerTurn().getName()) + " " + this.getPhase().NameForUi);
PhaseUtil.visuallyActivatePhase(this.getPlayerTurn(), this.getPhase());
game.getEvents().post(new PhaseEvent(this.getPlayerTurn(), this.getPhase(), phaseType));
}
private final void handleBeginPhase() {
@@ -499,12 +500,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
// This line fixes Combat Damage triggers not going off when they should
game.getStack().unfreezeStack();
// UNTAP
if (this.getPhase() != PhaseType.UNTAP) {
// during untap
this.resetPriority();
}
}
/**
@@ -726,10 +722,9 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
throw new IllegalStateException("Turns already started, call this only once per game");
setPlayerTurn(goesFirst);
advancePhase();
pPlayerPriority.getController().takePriority();
// don't even offer priority, because it's untap of 1st turn now
// This is main game loop. It will hang waiting for player's input.
while (!game.isGameOver()) { // stop game if it's outcome is clear.
while (!game.isGameOver()) { // loop only while is playing
final Player actingPlayer = this.getPriorityPlayer();
final Player firstAction = this.getFirstPriority();
@@ -754,6 +749,13 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
updateObservers();
}
// If ever the karn's ultimate resolved
if( game.getAge() == GameAge.RestartedByKarn) {
phase = null;
game.getEvents().post(new GameRestartedEvent(playerTurn));
return;
}
// Time to handle priority to next player.
if ( phase == PhaseType.COMBAT_DECLARE_ATTACKERS || phase == PhaseType.COMBAT_DECLARE_BLOCKERS)
@@ -786,8 +788,6 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
System.out.print(" >>\n");
}
}
System.out.println(FThreads.prependThreadId("Thread exited game loop due to ... " + ( game.isGameOver() ? "game over" : "interrupt" )));
}