From a04d03512930b8916dcd9a0683ca5a818b144f20 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Mon, 22 Aug 2011 00:02:22 +0000 Subject: [PATCH] Refactored QuestMatchState GameInfo is renamed to GameSummary and is now an observer for game state. It's purpose is now to hold statistic data on game and actions performed by players. The former functionality moved to ColorChanger and Phase (all combat damage prevention due to Fog spell). Since then game turns calculation is done properly (no need to add/substract 1) Total cleanup at Gui_WinLose, removed all references to global objects for quest and match-related entites. Some of quest rewards calculations use now special functions in QuestData class. Tracking of win and lose conditions refactored (see Player and Upkeep classes) --- .gitattributes | 8 +- src/main/java/forge/AllZone.java | 67 ++- src/main/java/forge/Card.java | 5 +- src/main/java/forge/ColorChanger.java | 72 +++ src/main/java/forge/Constant.java | 8 +- src/main/java/forge/EndOfTurn.java | 1 - src/main/java/forge/GameAction.java | 90 ++- src/main/java/forge/GameActionUtil.java | 6 +- src/main/java/forge/GameInfo.java | 194 ------- src/main/java/forge/GuiDisplay4.java | 8 +- src/main/java/forge/Gui_WinLose.java | 544 ++++++++---------- src/main/java/forge/Phase.java | 21 +- src/main/java/forge/PhaseUtil.java | 1 + src/main/java/forge/Player.java | 57 +- src/main/java/forge/Upkeep.java | 12 +- .../abilityFactory/AbilityFactory_Combat.java | 4 +- .../AbilityFactory_EndGameCondition.java | 5 +- .../card/cardFactory/AbstractCardFactory.java | 3 +- .../cardFactory/CardFactory_Creatures.java | 9 +- src/main/java/forge/game/GameEndReason.java | 10 + src/main/java/forge/game/GameLossReason.java | 36 ++ .../java/forge/game/GamePlayerRating.java | 41 ++ src/main/java/forge/game/GameSummary.java | 67 +++ src/main/java/forge/game/PlayerIndex.java | 8 + src/main/java/forge/game/package-info.java | 2 + .../java/forge/gui/input/Input_Mulligan.java | 76 +-- src/main/java/forge/quest/data/QuestData.java | 103 ++-- .../forge/quest/data/QuestMatchState.java | 182 ++---- .../forge/quest/gui/main/QuestMainPanel.java | 4 +- .../java/forge/view/swing/OldGuiNewGame.java | 1 - src/test/java/forge/GuiWinLoseTest.java | 4 +- 31 files changed, 806 insertions(+), 843 deletions(-) create mode 100644 src/main/java/forge/ColorChanger.java delete mode 100644 src/main/java/forge/GameInfo.java create mode 100644 src/main/java/forge/game/GameEndReason.java create mode 100644 src/main/java/forge/game/GameLossReason.java create mode 100644 src/main/java/forge/game/GamePlayerRating.java create mode 100644 src/main/java/forge/game/GameSummary.java create mode 100644 src/main/java/forge/game/PlayerIndex.java create mode 100644 src/main/java/forge/game/package-info.java diff --git a/.gitattributes b/.gitattributes index 002c1b29644..8b053dcbc72 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9449,6 +9449,7 @@ src/main/java/forge/Card_Color.java svneol=native#text/plain src/main/java/forge/Card_PT.java svneol=native#text/plain src/main/java/forge/Card_Type.java svneol=native#text/plain src/main/java/forge/Color.java svneol=native#text/plain +src/main/java/forge/ColorChanger.java -text src/main/java/forge/Combat.java svneol=native#text/plain src/main/java/forge/CombatUtil.java svneol=native#text/plain src/main/java/forge/Command.java svneol=native#text/plain @@ -9480,7 +9481,6 @@ src/main/java/forge/GUI_DeckAnalysis.java svneol=native#text/plain src/main/java/forge/GUI_ImportPicture.java svneol=native#text/plain src/main/java/forge/GameAction.java svneol=native#text/plain src/main/java/forge/GameActionUtil.java svneol=native#text/plain -src/main/java/forge/GameInfo.java svneol=native#text/plain src/main/java/forge/GuiDisplay4.java svneol=native#text/plain src/main/java/forge/GuiDisplayUtil.java svneol=native#text/plain src/main/java/forge/GuiFilter.java svneol=native#text/plain @@ -9663,6 +9663,12 @@ src/main/java/forge/error/BugzReporter.java svneol=native#text/plain src/main/java/forge/error/ErrorViewer.java svneol=native#text/plain src/main/java/forge/error/ExceptionHandler.java svneol=native#text/plain src/main/java/forge/error/package-info.java svneol=native#text/plain +src/main/java/forge/game/GameEndReason.java -text +src/main/java/forge/game/GameLossReason.java -text +src/main/java/forge/game/GamePlayerRating.java -text +src/main/java/forge/game/GameSummary.java svneol=native#text/plain +src/main/java/forge/game/PlayerIndex.java -text +src/main/java/forge/game/package-info.java -text src/main/java/forge/gui/ForgeAction.java svneol=native#text/plain src/main/java/forge/gui/GuiUtils.java svneol=native#text/plain src/main/java/forge/gui/ListChooser.java svneol=native#text/plain diff --git a/src/main/java/forge/AllZone.java b/src/main/java/forge/AllZone.java index 2871340e86b..1ce82889873 100644 --- a/src/main/java/forge/AllZone.java +++ b/src/main/java/forge/AllZone.java @@ -6,9 +6,11 @@ import forge.card.cardFactory.PreloadingCardFactory; import forge.card.mana.ManaPool; import forge.card.trigger.TriggerHandler; import forge.deck.DeckManager; +import forge.game.GameSummary; import forge.gui.input.InputControl; import forge.properties.ForgeProps; import forge.properties.NewConstants; +import forge.quest.data.QuestMatchState; import java.util.HashMap; import java.util.Iterator; @@ -40,6 +42,8 @@ public class AllZone implements NewConstants { private static Quest_Assignment QuestAssignment = null; /** Constant NameChanger */ private static final NameChanger NameChanger = new NameChanger(); + /** Constant ColorChanger */ + private static final ColorChanger colorChanger = new ColorChanger(); /** Constant EndOfTurn */ private static EndOfTurn EndOfTurn = new EndOfTurn(); @@ -62,8 +66,11 @@ public class AllZone implements NewConstants { private static final GameAction GameAction = new GameAction(); /** Constant StaticEffects */ private static final StaticEffects StaticEffects = new StaticEffects(); - /** Constant GameInfo */ - private static final GameInfo GameInfo = new GameInfo(); + + /** Game state observer GameSummary collects statistics and players' performance*/ + private static GameSummary gameInfo = new GameSummary(); + /** Match State for quests are stored in a QuestMatchState class instance*/ + public static QuestMatchState matchState = new QuestMatchState(); /** Constant TriggerHandler */ private static final TriggerHandler TriggerHandler = new TriggerHandler(); @@ -308,11 +315,11 @@ public class AllZone implements NewConstants { /** *

getGameInfo.

* - * @return a {@link forge.GameInfo} object. + * @return a {@link forge.GameSummary} object. * @since 1.0.15 */ - public static GameInfo getGameInfo() { - return GameInfo; + public static GameSummary getGameInfo() { + return gameInfo; } /** @@ -606,4 +613,54 @@ public class AllZone implements NewConstants { timestamp++; return timestamp; } + + /** + *

Resets everything possible to set a new game

+ */ + public static void newGameCleanup() { + + gameInfo = new GameSummary(); + + getHumanPlayer().reset(); + getComputerPlayer().reset(); + + getPhase().reset(); + getStack().reset(); + getCombat().reset(); + getDisplay().showCombat(""); + getDisplay().loadPrefs(); + + getHumanGraveyard().reset(); + getHumanHand().reset(); + getHumanLibrary().reset(); + getHumanBattlefield().reset(); + getHumanExile().reset(); + + getComputerGraveyard().reset(); + getComputerHand().reset(); + getComputerLibrary().reset(); + getComputerBattlefield().reset(); + getComputerExile().reset(); + + getInputControl().clearInput(); + + getStaticEffects().reset(); + getColorChanger().reset(); + + // player.reset() now handles this + //AllZone.getHumanPlayer().clearHandSizeOperations(); + //AllZone.getComputerPlayer().clearHandSizeOperations(); + + getTriggerHandler().clearRegistered(); + + } + + public static QuestMatchState getMatchState() { + return matchState; + } + + public static ColorChanger getColorChanger() { + // TODO Auto-generated method stub + return colorChanger; + } }//AllZone diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index dcc9aaa62ea..b99495e59eb 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -1200,7 +1200,7 @@ public class Card extends MyObservable implements Comparable { return new Card_Color(this); } Card_Color colors = null; - ArrayList globalChanges = AllZone.getGameInfo().getColorChanges(); + ArrayList globalChanges = AllZone.getColorChanger().getColorChanges(); colors = determineColor(globalChanges); colors.fixColorless(); return colors; @@ -1227,7 +1227,8 @@ public class Card extends MyObservable implements Comparable { Card_Color determineColor(ArrayList globalChanges) { Card_Color colors = new Card_Color(this); int i = cardColor.size() - 1; - int j = globalChanges.size() - 1; + int j = -1; + if (globalChanges != null) { j = globalChanges.size() - 1; } // if both have changes, see which one is most recent while (i >= 0 && j >= 0) { Card_Color cc = null; diff --git a/src/main/java/forge/ColorChanger.java b/src/main/java/forge/ColorChanger.java new file mode 100644 index 00000000000..d5addea90aa --- /dev/null +++ b/src/main/java/forge/ColorChanger.java @@ -0,0 +1,72 @@ +package forge; + +import java.util.ArrayList; + +import forge.card.mana.ManaCost; + +public class ColorChanger { + private ArrayList globalColorChanges = new ArrayList(); + + + /** + *

addColorChanges.

+ * + * @param s a {@link java.lang.String} object. + * @param c a {@link forge.Card} object. + * @param addToColors a boolean. + * @param bIncrease a boolean. + * @return a long. + */ + public long addColorChanges(String s, Card c, boolean addToColors, boolean bIncrease) { + if (bIncrease) { + Card_Color.increaseTimestamp(); + } + globalColorChanges.add(new Card_Color(new ManaCost(s), c, addToColors, false)); + return Card_Color.getTimestamp(); + } + + /** + *

removeColorChanges.

+ * + * @param s a {@link java.lang.String} object. + * @param c a {@link forge.Card} object. + * @param addTo a boolean. + * @param timestamp a long. + */ + public final void removeColorChanges(String s, Card c, boolean addTo, long timestamp) { + Card_Color removeCol = null; + for (Card_Color cc : globalColorChanges) { + if (cc.equals(s, c, addTo, timestamp)) { + removeCol = cc; + } + } + + if (removeCol != null) { + globalColorChanges.remove(removeCol); + } + } + + /** + *

reset = clearColorChanges.

+ */ + public final void reset() { + clearColorChanges(); + } + + /** + *

clearColorChanges.

+ */ + public final void clearColorChanges() { + // clear the global color changes at end of each game + globalColorChanges.clear(); + } + + /** + *

getColorChanges.

+ * + * @return a {@link java.util.ArrayList} object. + */ + public final ArrayList getColorChanges() { + return globalColorChanges; + } +} diff --git a/src/main/java/forge/Constant.java b/src/main/java/forge/Constant.java index bfb642a9cfb..d0145a86d64 100644 --- a/src/main/java/forge/Constant.java +++ b/src/main/java/forge/Constant.java @@ -2,7 +2,6 @@ package forge; import forge.deck.Deck; -import forge.quest.data.QuestMatchState; import java.util.Arrays; import java.util.Collections; @@ -24,7 +23,7 @@ public interface Constant { public static final Deck[] HumanDeck = new Deck[1]; public static final Deck[] ComputerDeck = new Deck[1]; public static final String[] GameType = new String[1]; - public static final QuestMatchState matchState = new QuestMatchState(); + public static final boolean[] Smooth = new boolean[1]; public static final boolean[] Mill = new boolean[1]; public static final boolean[] DevMode = new boolean[1]; // one for normal mode one for quest mode @@ -161,6 +160,11 @@ public interface Constant { public static final boolean loaded[] = {false}; public static final Constant_StringArrayList NonStackingList[] = new Constant_StringArrayList[1]; } + + + + + }//Constant diff --git a/src/main/java/forge/EndOfTurn.java b/src/main/java/forge/EndOfTurn.java index 1f70b79c7c7..c315aae9fbf 100644 --- a/src/main/java/forge/EndOfTurn.java +++ b/src/main/java/forge/EndOfTurn.java @@ -61,7 +61,6 @@ public class EndOfTurn implements java.io.Serializable { AllZone.getPhase().getPlayerTurn().setMustAttackEntity(null); GameActionUtil.removeAttackedBlockedThisTurn(); - AllZone.getGameInfo().setPreventCombatDamageThisTurn(false); AllZone.getStaticEffects().rePopulateStateBasedList(); diff --git a/src/main/java/forge/GameAction.java b/src/main/java/forge/GameAction.java index fd04544c3aa..be59cfbfc68 100644 --- a/src/main/java/forge/GameAction.java +++ b/src/main/java/forge/GameAction.java @@ -11,6 +11,9 @@ import forge.card.spellability.*; import forge.card.staticAbility.StaticAbility; import forge.card.trigger.Trigger; import forge.deck.Deck; +import forge.game.GameEndReason; +import forge.game.GameSummary; +import forge.game.PlayerIndex; import forge.gui.GuiUtils; import forge.gui.input.Input_Mulligan; import forge.gui.input.Input_PayManaCost; @@ -559,43 +562,48 @@ public class GameAction { */ public boolean checkEndGameSate() { // Win / Lose + GameSummary game = AllZone.getGameInfo(); boolean humanWins = false; boolean computerWins = false; Player computer = AllZone.getComputerPlayer(); Player human = AllZone.getHumanPlayer(); - int gameWon = Constant.Runtime.matchState.getWin(); - - if (human.hasWon()) { // Winning Conditions can be worth more than losing conditions + if ( human.hasWon() || computer.hasLost() ) { // Winning Conditions can be worth more than losing conditions // Human wins humanWins = true; + if (human.getAltWin()) { - Constant.Runtime.matchState.setWinMethod(gameWon, human.getWinCondition()); + game.end(GameEndReason.WinsGameSpellEffect, PlayerIndex.HUMAN, human.getWinConditionSource()); + } else { + game.end(GameEndReason.AllOpponentsLost, PlayerIndex.HUMAN, null); } - Constant.Runtime.matchState.addWin(); - } else if (computer.hasLost()) { - // Human wins - humanWins = true; - - if (computer.getAltLose()) { - Constant.Runtime.matchState.setWinMethod(gameWon, computer.getLoseCondition()); - } - Constant.Runtime.matchState.addWin(); } if (computer.hasWon() || human.hasLost()) { if (humanWins) { // both players won/lost at the same time. - // TODO: Handle a Draw here + game.end(GameEndReason.Draw, PlayerIndex.DRAW, null); + } else { + computerWins = true; + + if (computer.getAltWin()) { + game.end(GameEndReason.WinsGameSpellEffect, PlayerIndex.AI, computer.getWinConditionSource()); + } else { + game.end(GameEndReason.AllOpponentsLost, PlayerIndex.AI, null); + } + } - - // Computer wins - computerWins = true; - Constant.Runtime.matchState.addLose(); } - return humanWins || computerWins; + boolean isGameDone = humanWins || computerWins; + if (isGameDone) { + game.getPlayerRating(PlayerIndex.AI).setLossReason(computer.getLossState()); + game.getPlayerRating(PlayerIndex.HUMAN).setLossReason(human.getLossState()); + AllZone.getMatchState().addGamePlayed(game); + } + + return isGameDone; } @@ -616,7 +624,7 @@ public class GameAction { if (checkEndGameSate()) { AllZone.getDisplay().savePrefs(); frame.dispose(); - new Gui_WinLose(); + new Gui_WinLose( AllZone.getMatchState(), AllZone.getQuestData(), AllZone.getQuestAssignment() ); return; } @@ -1044,41 +1052,7 @@ public class GameAction { //AllZone.getComputer() = new ComputerAI_Input(new ComputerAI_General()); Constant.Quest.fantasyQuest[0] = false; - AllZone.getGameInfo().setPreventCombatDamageThisTurn(false); - AllZone.getGameInfo().setHumanNumberOfTimesMulliganed(0); - AllZone.getGameInfo().setHumanMulliganedToZero(false); - AllZone.getGameInfo().setComputerStartedThisGame(false); - - AllZone.getHumanPlayer().reset(); - AllZone.getComputerPlayer().reset(); - - AllZone.getPhase().reset(); - AllZone.getStack().reset(); - AllZone.getCombat().reset(); - AllZone.getDisplay().showCombat(""); - AllZone.getDisplay().loadPrefs(); - - AllZone.getHumanGraveyard().reset(); - AllZone.getHumanHand().reset(); - AllZone.getHumanLibrary().reset(); - AllZone.getHumanBattlefield().reset(); - AllZone.getHumanExile().reset(); - - AllZone.getComputerGraveyard().reset(); - AllZone.getComputerHand().reset(); - AllZone.getComputerLibrary().reset(); - AllZone.getComputerBattlefield().reset(); - AllZone.getComputerExile().reset(); - - AllZone.getInputControl().clearInput(); - - AllZone.getStaticEffects().reset(); - - // player.reset() now handles this - //AllZone.getHumanPlayer().clearHandSizeOperations(); - //AllZone.getComputerPlayer().clearHandSizeOperations(); - - AllZone.getTriggerHandler().clearRegistered(); + AllZone.newGameCleanup(); forge.card.trigger.Trigger.resetIDs(); @@ -1216,13 +1190,13 @@ public class GameAction { } // Only cut/coin toss if it's the first game of the match - if (Constant.Runtime.matchState.countWinLose() == 0) { + if (AllZone.getMatchState().getGamesPlayedCount() == 0) { // New code to determine who goes first. Delete this if it doesn't work properly if (isStartCut()) seeWhoPlaysFirst(); else seeWhoPlaysFirst_CoinToss(); - } else if (Constant.Runtime.matchState.didWinRecently()) // if player won last, AI starts + } else if (AllZone.getMatchState().hasHumanWonLastGame()) // if player won last, AI starts computerStartsGame(); for (int i = 0; i < 7; i++) { @@ -1482,7 +1456,7 @@ public class GameAction { */ public void computerStartsGame() { AllZone.getPhase().setPlayerTurn(AllZone.getComputerPlayer()); - AllZone.getGameInfo().setComputerStartedThisGame(true); + AllZone.getGameInfo().setPlayerWhoGotFirstTurn(PlayerIndex.AI); } //if Card had the type "Aura" this method would always return true, since local enchantments are always attached to something diff --git a/src/main/java/forge/GameActionUtil.java b/src/main/java/forge/GameActionUtil.java index 33f7af8c595..7d1cde67ade 100644 --- a/src/main/java/forge/GameActionUtil.java +++ b/src/main/java/forge/GameActionUtil.java @@ -4,6 +4,7 @@ package forge; import forge.card.abilityFactory.AbilityFactory; import forge.card.cardFactory.CardFactoryUtil; import forge.card.spellability.*; +import forge.game.GameLossReason; import forge.gui.GuiUtils; import forge.gui.input.Input; import forge.gui.input.Input_PayManaCostUtil; @@ -632,9 +633,6 @@ public class GameActionUtil { if (c.getCreatureGotBlockedThisCombat()) c.setCreatureGotBlockedThisCombat(false); } - - AllZone.getGameInfo().setAssignedFirstStrikeDamageThisCombat(false); - AllZone.getGameInfo().setResolvedFirstStrikeDamageThisCombat(false); } /** @@ -1025,7 +1023,7 @@ public class GameActionUtil { CardList nonTokens = AllZoneUtil.getPlayerCardsInPlay(player); nonTokens = nonTokens.filter(AllZoneUtil.nonToken); if (nonTokens.size() == 0) { - player.altLoseConditionMet("Lich"); + player.loseConditionMet( GameLossReason.SpellEffect, lich.getName()); } else player.sacrificePermanent("Select a permanent to sacrifice", nonTokens); } } diff --git a/src/main/java/forge/GameInfo.java b/src/main/java/forge/GameInfo.java deleted file mode 100644 index 51c920a5a6e..00000000000 --- a/src/main/java/forge/GameInfo.java +++ /dev/null @@ -1,194 +0,0 @@ -package forge; - -import forge.card.mana.ManaCost; - -import java.util.ArrayList; - -/** - *

GameInfo class.

- * - * @author Forge - * @version $Id$ - */ -public class GameInfo { - private boolean computerStartedThisGame = false; - - private int humanNumberOfTimesMulliganed; - private boolean humanMulliganedToZero; - - private boolean preventCombatDamageThisTurn; - private boolean assignedFirstStrikeDamageThisCombat; - private boolean resolvedFirstStrikeDamageThisCombat; - - private ArrayList globalColorChanges = new ArrayList(); - - /** - *

Getter for the field humanNumberOfTimesMulliganed.

- * - * @return a int. - */ - public int getHumanNumberOfTimesMulliganed() { - return humanNumberOfTimesMulliganed; - } - - /** - *

addHumanNumberOfTimesMulliganed.

- * - * @param n a int. - */ - public void addHumanNumberOfTimesMulliganed(int n) { - humanNumberOfTimesMulliganed += n; - } - - /** - *

Setter for the field humanNumberOfTimesMulliganed.

- * - * @param n a int. - */ - public void setHumanNumberOfTimesMulliganed(int n) { - humanNumberOfTimesMulliganed = n; - } - - /** - *

Getter for the field humanMulliganedToZero.

- * - * @return a boolean. - */ - public boolean getHumanMulliganedToZero() { - return humanMulliganedToZero; - } - - /** - *

Setter for the field humanMulliganedToZero.

- * - * @param b a boolean. - */ - public void setHumanMulliganedToZero(boolean b) { - humanMulliganedToZero = b; - } - - /** - *

Setter for the field preventCombatDamageThisTurn.

- * - * @param b a boolean. - */ - public void setPreventCombatDamageThisTurn(boolean b) { - preventCombatDamageThisTurn = b; - } - - /** - *

isPreventCombatDamageThisTurn.

- * - * @return a boolean. - */ - public boolean isPreventCombatDamageThisTurn() { - return preventCombatDamageThisTurn; - } - - /** - *

Setter for the field assignedFirstStrikeDamageThisCombat.

- * - * @param b a boolean. - */ - public void setAssignedFirstStrikeDamageThisCombat(boolean b) { - assignedFirstStrikeDamageThisCombat = b; - } - - /** - *

Getter for the field assignedFirstStrikeDamageThisCombat.

- * - * @return a boolean. - */ - public boolean getAssignedFirstStrikeDamageThisCombat() { - return assignedFirstStrikeDamageThisCombat; - } - - /** - *

Setter for the field resolvedFirstStrikeDamageThisCombat.

- * - * @param b a boolean. - */ - public void setResolvedFirstStrikeDamageThisCombat(boolean b) { - resolvedFirstStrikeDamageThisCombat = b; - } - - /** - *

Getter for the field resolvedFirstStrikeDamageThisCombat.

- * - * @return a boolean. - */ - public boolean getResolvedFirstStrikeDamageThisCombat() { - return resolvedFirstStrikeDamageThisCombat; - } - - /** - *

Setter for the field computerStartedThisGame.

- * - * @param computerStartedThisGame a boolean. - */ - public void setComputerStartedThisGame(boolean computerStartedThisGame) { - this.computerStartedThisGame = computerStartedThisGame; - } - - /** - *

isComputerStartedThisGame.

- * - * @return a boolean. - */ - public boolean isComputerStartedThisGame() { - return computerStartedThisGame; - } - - /** - *

addColorChanges.

- * - * @param s a {@link java.lang.String} object. - * @param c a {@link forge.Card} object. - * @param addToColors a boolean. - * @param bIncrease a boolean. - * @return a long. - */ - public long addColorChanges(String s, Card c, boolean addToColors, boolean bIncrease) { - if (bIncrease) - Card_Color.increaseTimestamp(); - globalColorChanges.add(new Card_Color(new ManaCost(s), c, addToColors, false)); - return Card_Color.getTimestamp(); - } - - /** - *

removeColorChanges.

- * - * @param s a {@link java.lang.String} object. - * @param c a {@link forge.Card} object. - * @param addTo a boolean. - * @param timestamp a long. - */ - public void removeColorChanges(String s, Card c, boolean addTo, long timestamp) { - Card_Color removeCol = null; - for (Card_Color cc : globalColorChanges) - if (cc.equals(s, c, addTo, timestamp)) - removeCol = cc; - - if (removeCol != null) - globalColorChanges.remove(removeCol); - } - - /** - *

clearColorChanges.

- */ - public void clearColorChanges() { - // clear the global color changes at end of each game - globalColorChanges.clear(); - } - - /** - *

getColorChanges.

- * - * @return a {@link java.util.ArrayList} object. - */ - public ArrayList getColorChanges() { - return globalColorChanges; - } - - -} diff --git a/src/main/java/forge/GuiDisplay4.java b/src/main/java/forge/GuiDisplay4.java index b9a80621810..433b5008b0c 100644 --- a/src/main/java/forge/GuiDisplay4.java +++ b/src/main/java/forge/GuiDisplay4.java @@ -7,6 +7,7 @@ import arcane.ui.ViewPanel; import arcane.ui.util.Animation; import forge.card.cardFactory.CardFactoryUtil; import forge.error.ErrorViewer; +import forge.game.GameLossReason; import forge.gui.ForgeAction; import forge.gui.GuiUtils; import forge.gui.game.CardDetailPanel; @@ -59,7 +60,6 @@ public class GuiDisplay4 extends JFrame implements CardContainer, Display, NewCo Font lifeFont = new Font("Dialog", Font.PLAIN, 40); // Font checkboxFont = new Font("Dialog", Font.PLAIN, 9); - /** Constant greenColor */ public static Color greenColor = new Color(0, 164, 0); @@ -1134,10 +1134,8 @@ public class GuiDisplay4 extends JFrame implements CardContainer, Display, NewCo * Exit the Application */ private void concede() { - savePrefs(); - dispose(); - Constant.Runtime.matchState.addLose(); - new Gui_WinLose(); + AllZone.getHumanPlayer().loseConditionMet(GameLossReason.Conceded, null ); + AllZone.getGameAction().checkStateEffects(); } // ********** Phase stuff in Display ****************** diff --git a/src/main/java/forge/Gui_WinLose.java b/src/main/java/forge/Gui_WinLose.java index 9b12e97ef13..c9b1d2d88fa 100644 --- a/src/main/java/forge/Gui_WinLose.java +++ b/src/main/java/forge/Gui_WinLose.java @@ -1,25 +1,38 @@ package forge; - -import forge.error.ErrorViewer; +import forge.error.E +import forge.game.GameEndReason; +rrorViewer; +import forge.game.GameLossReason; +import forge.game.GamePlayerRating; +import forge.game.GameSummary; +import forge.game.PlayerIndex; import forge.properties.ForgeProps; import forge.properties.NewConstants; import forge.properties.NewConstants.LANG.Gui_WinLose.WINLOSE_TEXT; +import forge.quest.data.QuestData; import forge.quest.data.QuestMatchState; import forge.quest.data.QuestPreferences; import forge.quest.gui.QuestFrame; import forge.view.swing.OldGuiNewGame; import net.miginfocom.swing.MigLayout; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingConstants; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import java.awt.Color; -import java.awt.*; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.WindowEvent; import java.io.File; - +import java.util.ArrayList; /** *

Gui_WinLose class.

@@ -31,14 +44,6 @@ public class Gui_WinLose extends JFrame implements NewConstants { /** Constant serialVersionUID=-5800412940994975483L */ private static final long serialVersionUID = -5800412940994975483L; - //private CardList humanList; - //private CardList computerList; - - //private int humanLife; - //private int computerLife; - - //private boolean fantasyQuest = false; - private JLabel titleLabel = new JLabel(); private JButton continueButton = new JButton(); private JButton restartButton = new JButton(); @@ -52,51 +57,22 @@ public class Gui_WinLose extends JFrame implements NewConstants { // border1 private Border border1; - /** - *

Constructor for Gui_WinLose.

- * - * @param human a {@link forge.CardList} object. - * @param computer a {@link forge.CardList} object. - * @param hLife a int. - * @param cLife a int. - */ - public Gui_WinLose(CardList human, CardList computer, int hLife, int cLife) { - /* - fantasyQuest = true; - - humanList = human; - computerList = computer; - - humanLife = hLife; - computerLife= cLife; - */ - try { - jbInit(); - } catch (Exception ex) { - ErrorViewer.showError(ex); - } - - setup(); - - Dimension screen = this.getToolkit().getScreenSize(); - setBounds(screen.width / 3, 100, //position - 215, 370); //size - setVisible(true); + private class WinLoseModel { + public QuestMatchState match; + public QuestData quest; + public Quest_Assignment qa; } + private WinLoseModel model; + /** *

Constructor for Gui_WinLose.

*/ - public Gui_WinLose() { - /* - fantasyQuest = false; - - humanList = new CardList(); - computerList = new CardList(); - - humanLife = 20; - computerLife= 20; - */ + public Gui_WinLose(final QuestMatchState matchState, final QuestData quest, final Quest_Assignment qa) { + model = new WinLoseModel(); + model.match = matchState; + model.quest = quest; + model.qa = qa; try { jbInit(); @@ -107,8 +83,7 @@ public class Gui_WinLose extends JFrame implements NewConstants { setup(); Dimension screen = this.getToolkit().getScreenSize(); - setBounds(screen.width / 3, 100, //position - 215, 370); //size + setBounds(screen.width / 3, 100 /*position*/, 215, 370 /*size*/); setVisible(true); } @@ -116,47 +91,28 @@ public class Gui_WinLose extends JFrame implements NewConstants { *

setup.

*/ private void setup() { - AllZone.getGameInfo().clearColorChanges(); - QuestMatchState winLose = Constant.Runtime.matchState; Phase.setGameBegins(0); - //3 is the match length, 3 is the number of games - //disable buttons if match is up, or human player won 2 or lost 2 games already - if ((winLose.countWinLose() == 3) || (winLose.getWin() == 2) || (winLose.getLose() == 2)) { + + if (model.match.isMatchOver()) { // editDeckButton.setEnabled(false); continueButton.setEnabled(false); quitButton.grabFocus(); } - if (winLose.getWin() == 2) - restartButton.setEnabled(false); + restartButton.setEnabled(!model.match.isMatchWonByHuman()); //show Wins and Loses - statsLabel.setText(ForgeProps.getLocalized(WINLOSE_TEXT.WON) + winLose.getWin() + ForgeProps.getLocalized(WINLOSE_TEXT.LOST) + winLose.getLose()); + int humanWins = model.match.getGamesCountWonByHuman(); + int humanLosses = model.match.getGamesCountLostByHuman(); + statsLabel.setText(ForgeProps.getLocalized(WINLOSE_TEXT.WON) + humanWins + + ForgeProps.getLocalized(WINLOSE_TEXT.LOST) + humanLosses); + //show "You Won" or "You Lost" - if (winLose.didWinRecently()) { + if (model.match.hasHumanWonLastGame()) { titleLabel.setText(ForgeProps.getLocalized(WINLOSE_TEXT.WIN)); - - int game = 0; - if (winLose.getWinTurns()[0] != 0) - game = 1; - int turn = AllZone.getPhase().getTurn(); - if (AllZone.getGameInfo().isComputerStartedThisGame()) - turn--; - - if (turn < 1) - turn = 1; - - winLose.setWinTurn(game, turn); - winLose.setMulliganedToZero(game, AllZone.getGameInfo().getHumanMulliganedToZero()); - - //winLose.setWinTurn(winLose.countWinLose()-1, AllZone.getPhase().getTurn()); - - //System.out.println("CountwinLose:" + winLose.countWinLose()); - //System.out.println("You won by turn: " + AllZone.getPhase().getTurn()); } else { titleLabel.setText(ForgeProps.getLocalized(WINLOSE_TEXT.LOSE)); - //System.out.println("You lost by turn: " + AllZone.getPhase().getTurn()); } }//setup(); @@ -174,21 +130,15 @@ public class Gui_WinLose extends JFrame implements NewConstants { this.getContentPane().setLayout(new MigLayout("fill")); continueButton.setText(ForgeProps.getLocalized(WINLOSE_TEXT.CONTINUE)); continueButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(ActionEvent e) { - continueButton_actionPerformed(e); - } + public void actionPerformed(ActionEvent e) { continueButton_actionPerformed(e); } }); restartButton.setText(ForgeProps.getLocalized(WINLOSE_TEXT.RESTART)); restartButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(ActionEvent e) { - restartButton_actionPerformed(e); - } + public void actionPerformed(ActionEvent e) { restartButton_actionPerformed(e); } }); quitButton.setText(ForgeProps.getLocalized(WINLOSE_TEXT.QUIT)); quitButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(ActionEvent e) { - quitButton_actionPerformed(e); - } + public void actionPerformed(ActionEvent e) { quitButton_actionPerformed(e); } }); statsLabel.setFont(new java.awt.Font("Dialog", 0, 16)); statsLabel.setHorizontalAlignment(SwingConstants.CENTER); @@ -196,9 +146,7 @@ public class Gui_WinLose extends JFrame implements NewConstants { jPanel2.setLayout(new MigLayout("align center")); this.addWindowListener(new java.awt.event.WindowAdapter() { @Override - public void windowClosing(WindowEvent e) { - this_windowClosing(e); - } + public void windowClosing(WindowEvent e) { this_windowClosing(e); } }); this.getContentPane().add(titleLabel, "align center, grow, wrap"); this.getContentPane().add(statsLabel, "align center, grow, wrap"); @@ -209,26 +157,6 @@ public class Gui_WinLose extends JFrame implements NewConstants { } - /** - *

editDeckButton_actionPerformed.

- * - * @param e a {@link java.awt.event.ActionEvent} object. - */ - void editDeckButton_actionPerformed(ActionEvent e) { - Command exit = new Command() { - private static final long serialVersionUID = 4735992294414389187L; - - public void execute() { - new Gui_WinLose(); - } - }; - Gui_DeckEditor editor = new Gui_DeckEditor(); - - editor.show(exit); - - dispose(); - }//editDeckButton_actionPerformed() - /** *

continueButton_actionPerformed.

* @@ -236,32 +164,36 @@ public class Gui_WinLose extends JFrame implements NewConstants { */ void continueButton_actionPerformed(ActionEvent e) { //open up "Game" screen - //AllZone.getComputerPlay().reset();//sometimes computer has creature in play in the 2nd game of the match - - if (!Constant.Quest.fantasyQuest[0]) - AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0]); - else { + + PrepareForNextRound(); + AllZone.getDisplay().setVisible(true); + dispose(); + } + + void PrepareForNextRound() + { + if (Constant.Quest.fantasyQuest[0]) { int extraLife = 0; - if (AllZone.getQuestAssignment() != null) { - forge.quest.data.QuestUtil.setupQuest(AllZone.getQuestAssignment()); - if (AllZone.getQuestData().getInventory().hasItem("Zeppelin")) + if (model.qa != null) { + forge.quest.data.QuestUtil.setupQuest(model.qa); + if (model.quest.getInventory().hasItem("Zeppelin")) extraLife = 3; } //AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0], humanList, computerList, humanLife, computerLife); - CardList humanList = forge.quest.data.QuestUtil.getHumanPlantAndPet(AllZone.getQuestData(), AllZone.getQuestAssignment()); + CardList humanList = forge.quest.data.QuestUtil.getHumanPlantAndPet(model.quest, model.qa); CardList computerList = new CardList(); - int humanLife = AllZone.getQuestData().getLife() + extraLife; + int humanLife = model.quest.getLife() + extraLife; int computerLife = 20; - if (AllZone.getQuestAssignment() != null) - computerLife = AllZone.getQuestAssignment().getComputerLife(); + if ( model.qa != null ) + computerLife = model.qa.getComputerLife(); - AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0], humanList, computerList, humanLife, computerLife, AllZone.getQuestAssignment()); + AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0], humanList, computerList, humanLife, computerLife, model.qa ); + } else { + AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0]); } - AllZone.getDisplay().setVisible(true); - dispose(); } /** @@ -270,33 +202,9 @@ public class Gui_WinLose extends JFrame implements NewConstants { * @param e a {@link java.awt.event.ActionEvent} object. */ void restartButton_actionPerformed(ActionEvent e) { - Constant.Runtime.matchState.reset(); - - if (!Constant.Quest.fantasyQuest[0]) - AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0]); - else { - int extraLife = 0; - //AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0], humanList, computerList, humanLife, computerLife); - if (AllZone.getQuestAssignment() != null) { - forge.quest.data.QuestUtil.setupQuest(AllZone.getQuestAssignment()); - if (AllZone.getQuestData().getInventory().hasItem("Zeppelin")) - extraLife = 3; - } - - CardList humanList = forge.quest.data.QuestUtil.getHumanPlantAndPet(AllZone.getQuestData(), AllZone.getQuestAssignment()); - //CardList computerList = QuestUtil.getComputerCreatures(AllZone.getQuestData(), AllZone.getQuestAssignment()); - CardList computerList = new CardList(); - - int humanLife = AllZone.getQuestData().getLife() + extraLife; - int computerLife = 20; - - if (AllZone.getQuestAssignment() != null) - computerLife = AllZone.getQuestAssignment().getComputerLife(); - - AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0], humanList, computerList, humanLife, computerLife, AllZone.getQuestAssignment()); - } + model.match.reset(); + PrepareForNextRound(); AllZone.getDisplay().setVisible(true); - dispose(); } @@ -304,88 +212,82 @@ public class Gui_WinLose extends JFrame implements NewConstants { *

getWinText.

* * @param creds a long. - * @param winLose a {@link forge.quest.data.QuestMatchState} object. + * @param matchState a {@link forge.quest.data.QuestMatchState} object. * @param q a {@link forge.quest.data.QuestData} object. * @return a {@link java.lang.String} object. */ - private String getWinText(long creds, QuestMatchState winLose, forge.quest.data.QuestData q) { + private String getCreditsAwardedText(final long creds, final QuestMatchState matchState, final forge.quest.data.QuestData q) { // TODO use q.qdPrefs to write bonus credits in prefs file - StringBuilder sb = new StringBuilder(); - String[] wins = winLose.getWinMethods(); + StringBuilder sb = new StringBuilder(""); - sb.append(""); + boolean hasNeverLost = true; + for (GameSummary game : matchState.getGamesPlayed()) { + if (game.isAIWinner()) { + hasNeverLost = true; + continue; // no rewards for losing a game + } - for (String s : wins) { - if (s != null) { - sb.append("Alternate win condition: "); - sb.append(""); - sb.append(s); - sb.append(""); - sb.append("! Bonus: +"); + GamePlayerRating aiRating = game.getPlayerRating(PlayerIndex.AI); + GamePlayerRating humanRating = game.getPlayerRating(PlayerIndex.HUMAN); + GameLossReason whyAiLost = aiRating.getLossReason(); - if (s.equals("Poison Counters")) - sb.append(QuestPreferences.getMatchRewardPoisonWinBonus()); - else if (s.equals("Milled")) - sb.append(QuestPreferences.getMatchRewardMilledWinBonus()); - else if (s.equals("Battle of Wits") || - s.equals("Felidar Sovereign") || s.equals("Helix Pinnacle") || s.equals("Epic Struggle") || - s.equals("Door to Nothingness") || s.equals("Barren Glory") || s.equals("Near-Death Experience") || - s.equals("Mortal Combat") || s.equals("Test of Endurance")) { - - sb.append(QuestPreferences.getMatchRewardAltWinBonus()); + int rewardAltWinCondition = q.getCreditsRewardForAltWin(whyAiLost); + if (rewardAltWinCondition > 0) { + String winConditionName = "Unknown (bug)"; + if ( game.getWinCondition() == GameEndReason.WinsGameSpellEffect ) { + winConditionName = game.getWinSpellEffect(); + } else { + switch( whyAiLost ) { + case Poisoned: winConditionName = "Poison"; break; + case Milled: winConditionName = "Milled"; break; + default: break; + } } - sb.append(" credits.
"); + String bonus = String.format("Alternate win condition: %s! Bonus: +%d credits.
", + winConditionName, rewardAltWinCondition); + sb.append(bonus); + } + + int winTurn = game.getTurnGameEnded(); + + int turnCredits = q.getCreditsRewardForWinByTurn(winTurn); + + if (winTurn == 0) { // this case should never happen - anyway, no reward if we got here + } else if (winTurn == 1) { sb.append("Won in one turn!"); + } else if (winTurn <= 5) { sb.append("Won by turn 5!"); + } else if (winTurn <= 10) { sb.append("Won by turn 10!"); + } else if (winTurn <= 15) { sb.append("Won by turn 15!"); + } + + if (turnCredits > 0) { + sb.append(String.format(" Bonus: +%d credits.
", turnCredits)); + } + + int cntCardsHumanStartedWith = humanRating.getOpeningHandSize(); + if ( 0 == cntCardsHumanStartedWith ) + { + int reward = QuestPreferences.getMatchMullToZero(); + sb.append(String.format("Mulliganed to zero and still won! Bonus: %d credits.
", reward)); } } - int[] winTurns = winLose.getWinTurns(); - for (int i : winTurns) { - System.out.println("Quest, won by turn:" + i); - - if (i != 0) { - int turnCredits = 0; - - if (i == 1) { - sb.append("Won in one turn!"); - turnCredits += QuestPreferences.getMatchRewardWinFirst(); - } else if (i <= 5) { - sb.append("Won by turn 5!"); - turnCredits += QuestPreferences.getMatchRewardWinByFifth(); - } else if (i <= 10) { - sb.append("Won by turn 10!"); - turnCredits += QuestPreferences.getMatchRewardWinByTen(); - } else if (i <= 15) { - sb.append("Won by turn 15!"); - turnCredits += QuestPreferences.getMatchRewardWinByFifteen(); - } - if (turnCredits > 0) - sb.append(" Bonus: +").append(turnCredits).append(" credits.
"); - } + if (hasNeverLost) { + int reward = QuestPreferences.getMatchRewardNoLosses(); + sb.append(String.format("You have not lost once! Bonus: +%d credits.
", reward)); } - boolean[] mulliganedToZero = winLose.getMulliganedToZero(); + int estatesLevel = q.getInventory().getItemLevel("Estates"); - for (boolean b : mulliganedToZero) { - if (b) { - sb.append("Mulliganed to zero and still won! Bonus: +"); - sb.append(QuestPreferences.getMatchMullToZero()).append(" credits.
"); - } - } - - if (winLose.getLose() == 0) - sb.append("You have not lost once! Bonus: +"); - sb.append(QuestPreferences.getMatchRewardNoLosses()).append(" credits.
"); - - if (q.getInventory().getItemLevel("Estates") == 1) + if (estatesLevel == 1) { sb.append("Estates bonus: 10%.
"); - else if (q.getInventory().getItemLevel("Estates") == 2) + } else if (estatesLevel == 2) { sb.append("Estates bonus: 15%.
"); - else if (q.getInventory().getItemLevel("Estates") == 3) + } else if (estatesLevel == 3) { sb.append("Estates bonus: 20%.
"); - + } sb.append("You have earned " + creds + " credits in total."); sb.append(""); @@ -428,110 +330,30 @@ public class Gui_WinLose extends JFrame implements NewConstants { if (AllZone.getQuestData() == null) { new OldGuiNewGame(); } else { //Quest - QuestMatchState matchState = Constant.Runtime.matchState; - forge.quest.data.QuestData quest = AllZone.getQuestData(); boolean wonMatch = false; - if (matchState.getWin() == 2) { - quest.addWin(); + if (model.match.isMatchWonByHuman()) { + model.quest.addWin(); wonMatch = true; - } else quest.addLost(); + } else { + model.quest.addLost(); + } //System.out.println("QuestData cardpoolsize:" + AllZone.getQuestData().getCardpool().size()); - if (AllZone.getQuestData().getShopList() != null) - AllZone.getQuestData().clearShopList(); - - if (AllZone.getQuestData().getAvailableQuests() != null) - AllZone.getQuestData().clearAvailableQuests(); - - if (quest.shouldAddCards(wonMatch)) { - quest.addCards(); - String fileName = "BookIcon.png"; - ImageIcon icon = getIcon(fileName); - - StringBuilder sb = new StringBuilder(); - sb.append("You have won the following new cards:\n"); - for (int i = 0; i < quest.getAddedCards().size(); i++) - sb.append(quest.getAddedCards().get(i) + "\n"); - - JOptionPane.showMessageDialog(null, sb.toString(), "", JOptionPane.INFORMATION_MESSAGE, icon); + if (model.quest.getShopList() != null) { + model.quest.clearShopList(); } - if (wonMatch) { - long creds = quest.getCreditsToAdd(matchState); - String s = getWinText(creds, matchState, quest); - - String fileName = "GoldIcon.png"; - ImageIcon icon = getIcon(fileName); - - JOptionPane.showMessageDialog(null, s, "", JOptionPane.INFORMATION_MESSAGE, icon); - int wins = quest.getWin(); - if (wins > 0 && wins % 80 == 0) // at every 80 wins, give 10 random rares - { - quest.addRandomRare(10); - fileName = "BoxIcon.png"; - icon = getIcon(fileName); - JOptionPane.showMessageDialog(null, "You just won 10 random rares!", "", JOptionPane.INFORMATION_MESSAGE, icon); - } - - if (AllZone.getQuestAssignment() != null) { - AllZone.getQuestData().addQuestsPlayed(); - Quest_Assignment qa = AllZone.getQuestAssignment(); - - StringBuilder sb = new StringBuilder(); - sb.append("Quest Completed - \r\n"); - - if (qa.getCardRewardList() != null) { - sb.append("You won the following cards:\r\n\r\n"); - for (String cardName : qa.getCardRewardList()) { - sb.append(cardName); - sb.append("\r\n"); - - AllZone.getQuestData().addCard(cardName); - } - AllZone.getQuestData().addToNewList(qa.getCardRewardList()); - sb.append("\r\n"); - } - sb.append("Quest Bounty: "); - sb.append(qa.getCreditsReward()); - - AllZone.getQuestData().addCredits(qa.getCreditsReward()); - - fileName = "BoxIcon.png"; - icon = getIcon(fileName); - JOptionPane.showMessageDialog(null, sb.toString(), "Quest Rewards for " + qa.getName(), JOptionPane.INFORMATION_MESSAGE, icon); - }/* - else if(quest.getDifficultyIndex() == 4) { - Card c = AllZone.getCardFactory().getCard(quest.addRandomRare(), AllZone.getHumanPlayer()); - c.setCurSetCode(c.getMostRecentSet()); - fileName = CardUtil.buildFilename(c) +".jpg"; - icon = getCardIcon(fileName); - - JOptionPane.showMessageDialog(null, "", "You have won a random rare for winning against a very hard deck.", JOptionPane.INFORMATION_MESSAGE, icon); - }*/ - - } else { - quest.subtractCredits(15); - String fileName = "HeartIcon.png"; - ImageIcon icon = getIcon(fileName); - - JOptionPane.showMessageDialog(null, "You lose! You have lost 15 credits.", "Awwww", JOptionPane.INFORMATION_MESSAGE, icon); + if (model.quest.getAvailableQuests() != null) { + model.quest.clearAvailableQuests(); } - if (quest.shouldAddAdditionalCards(wonMatch)) { - Card c = AllZone.getCardFactory().getCard(quest.addRandomRare(), AllZone.getHumanPlayer()); - c.setCurSetCode(c.getMostRecentSet()); - String fileName = CardUtil.buildFilename(c) + ".jpg"; - ImageIcon icon = getCardIcon(fileName); - - JOptionPane.showMessageDialog(null, "", "You have won a random rare.", JOptionPane.INFORMATION_MESSAGE, icon); - } - - matchState.reset(); + giveQuestRewards(wonMatch); + model.match.reset(); AllZone.setQuestAssignment(null); - quest.saveData(); + model.quest.saveData(); new QuestFrame(); }//else - on quest @@ -552,4 +374,106 @@ public class Gui_WinLose extends JFrame implements NewConstants { void this_windowClosing(WindowEvent e) { quitButton_actionPerformed(null); } + + protected void giveQuestRewards(final boolean wonMatch) { + // Award a random booster, as frequent as set in difficulty setup + if (model.quest.shouldAddCards(wonMatch)) { + ArrayList cardsWon = model.quest.addCards(); + + StringBuilder sb = new StringBuilder(); + sb.append("You have won the following new cards:\n"); + for (String cardName : cardsWon) { + sb.append(cardName + "\n"); + } + + String fileName = "BookIcon.png"; + ImageIcon icon = getIcon(fileName); + JOptionPane.showMessageDialog(null, sb.toString(), "", JOptionPane.INFORMATION_MESSAGE, icon); + } + + // Award credits + if (wonMatch) { + long creds = model.quest.getCreditsToAdd(model.match); + model.quest.addCredits(creds); + + String s = getCreditsAwardedText(creds, model.match, model.quest); + String fileName = "GoldIcon.png"; + ImageIcon icon = getIcon(fileName); + + JOptionPane.showMessageDialog(null, s, "", JOptionPane.INFORMATION_MESSAGE, icon); + } + + // Award 10 rares for 80 games won + if (wonMatch) { + int wins = model.quest.getWin(); + if (wins > 0 && wins % 80 == 0) // at every 80 wins, give 10 random rares + { + model.quest.addRandomRare(10); + String fileName = "BoxIcon.png"; + ImageIcon icon = getIcon(fileName); + String title = "You just won 10 random rares!"; + JOptionPane.showMessageDialog(null, title, "", JOptionPane.INFORMATION_MESSAGE, icon); + } + } + + // Rewards from QuestAssignment + if (wonMatch && model.qa != null) { + model.quest.addQuestsPlayed(); + + ArrayList questRewardCards = model.qa.getCardRewardList(); + long questRewardCredits = model.qa.getCreditsReward(); + + StringBuilder sb = new StringBuilder(); + sb.append("Quest Completed - \r\n"); + + if (questRewardCards != null) { + sb.append("You won the following cards:\r\n\r\n"); + for (String cardName : questRewardCards) { + sb.append(cardName); + sb.append("\r\n"); + + model.quest.addCard(cardName); + } + model.quest.addToNewList(questRewardCards); + sb.append("\r\n"); + } + sb.append("Quest Bounty: "); + sb.append(questRewardCredits); + + model.quest.addCredits(questRewardCredits); + + String fileName = "BoxIcon.png"; + ImageIcon icon = getIcon(fileName); + String title = "Quest Rewards for " + model.qa.getName(); + JOptionPane.showMessageDialog(null, sb.toString(), title, JOptionPane.INFORMATION_MESSAGE, icon); + } + /* + else if(quest.getDifficultyIndex() == 4) { + Card c = AllZone.getCardFactory().getCard(quest.addRandomRare(), AllZone.getHumanPlayer()); + c.setCurSetCode(c.getMostRecentSet()); + fileName = CardUtil.buildFilename(c) +".jpg"; + icon = getCardIcon(fileName); + + JOptionPane.showMessageDialog(null, "", "You have won a random rare for winning against a very hard deck.", JOptionPane.INFORMATION_MESSAGE, icon); + }*/ + + // Loss match penalty + if (!wonMatch) { + model.quest.subtractCredits(15); + String fileName = "HeartIcon.png"; + ImageIcon icon = getIcon(fileName); + String text = "You lose! You have lost 15 credits."; + JOptionPane.showMessageDialog(null, text, "Awwww", JOptionPane.INFORMATION_MESSAGE, icon); + } + + // Random rare given at 50% chance (65% with luck upgrade) + if (model.quest.shouldAddAdditionalCards(wonMatch)) { + Card c = AllZone.getCardFactory().getCard(model.quest.addRandomRare(), AllZone.getHumanPlayer()); + c.setCurSetCode(c.getMostRecentSet()); + String fileName = CardUtil.buildFilename(c) + ".jpg"; + ImageIcon icon = getCardIcon(fileName); + String title = "You have won a random rare."; + JOptionPane.showMessageDialog(null, "", title, JOptionPane.INFORMATION_MESSAGE, icon); + } + } } diff --git a/src/main/java/forge/Phase.java b/src/main/java/forge/Phase.java index e2bb50255e3..1ae748d0859 100644 --- a/src/main/java/forge/Phase.java +++ b/src/main/java/forge/Phase.java @@ -46,6 +46,7 @@ public class Phase extends MyObservable implements java.io.Serializable { private int extraCombats; private int nCombatsThisTurn; + private boolean bPreventCombatDamageThisTurn; private Player playerTurn = AllZone.getHumanPlayer(); @@ -247,6 +248,7 @@ public class Phase extends MyObservable implements java.io.Serializable { extraTurns.clear(); nCombatsThisTurn = 0; extraCombats = 0; + bPreventCombatDamageThisTurn = false; bCombat = false; bRepeat = false; this.updateObservers(); @@ -316,7 +318,7 @@ public class Phase extends MyObservable implements java.io.Serializable { AllZone.getPhase().setNeedToNextPhase(true); else { - if (!AllZone.getGameInfo().isPreventCombatDamageThisTurn()) + if (!AllZone.getPhase().isPreventCombatDamageThisTurn()) Combat.dealAssignedDamage(); AllZone.getGameAction().checkStateEffects(); @@ -331,7 +333,7 @@ public class Phase extends MyObservable implements java.io.Serializable { AllZone.getCombat().setAssignedDamage(); - if (!AllZone.getGameInfo().isPreventCombatDamageThisTurn()) + if (!AllZone.getPhase().isPreventCombatDamageThisTurn()) Combat.dealAssignedDamage(); AllZone.getGameAction().checkStateEffects(); @@ -383,6 +385,10 @@ public class Phase extends MyObservable implements java.io.Serializable { resetPriority(); } + public boolean isPreventCombatDamageThisTurn() { + return bPreventCombatDamageThisTurn; + } + /** *

nextPhase.

*/ @@ -420,9 +426,11 @@ public class Phase extends MyObservable implements java.io.Serializable { this.bCombat = false; } - if (phaseOrder[phaseIndex].equals(Constant.Phase.Cleanup)) + if (phaseOrder[phaseIndex].equals(Constant.Phase.Cleanup)) { + bPreventCombatDamageThisTurn = false; if (!bRepeat) AllZone.getPhase().setPlayerTurn(handleNextTurn()); + } if (is(Constant.Phase.Combat_Declare_Blockers)) { AllZone.getStack().unfreezeStack(); @@ -666,9 +674,6 @@ public class Phase extends MyObservable implements java.io.Serializable { if (c.getCreatureBlockedThisCombat()) c.setCreatureBlockedThisCombat(false); if (c.getCreatureGotBlockedThisCombat()) c.setCreatureGotBlockedThisCombat(false); - - AllZone.getGameInfo().setAssignedFirstStrikeDamageThisCombat(false); - AllZone.getGameInfo().setResolvedFirstStrikeDamageThisCombat(false); } } @@ -1026,4 +1031,8 @@ public class Phase extends MyObservable implements java.io.Serializable { static void setComputerInstantSpellCount(int i) { ComputerInstantSpellCount = (i); } + + public void setPreventCombatDamageThisTurn(boolean b) { + bPreventCombatDamageThisTurn = true; + } } diff --git a/src/main/java/forge/PhaseUtil.java b/src/main/java/forge/PhaseUtil.java index afcdbb7d768..ab6088e5458 100644 --- a/src/main/java/forge/PhaseUtil.java +++ b/src/main/java/forge/PhaseUtil.java @@ -38,6 +38,7 @@ public class PhaseUtil { Player turn = AllZone.getPhase().getPlayerTurn(); AllZone.getPhase().turnReset(); + AllZone.getGameInfo().notifyNextTurn(); AllZone.getCombat().reset(); AllZone.getCombat().setAttackingPlayer(turn); diff --git a/src/main/java/forge/Player.java b/src/main/java/forge/Player.java index a4da061ad16..b134810a0fd 100644 --- a/src/main/java/forge/Player.java +++ b/src/main/java/forge/Player.java @@ -1,5 +1,6 @@ package forge; +import forge.game.GameLossReason; import forge.card.cardFactory.CardFactoryUtil; import forge.card.mana.ManaPool; import forge.card.spellability.Ability; @@ -24,9 +25,10 @@ public abstract class Player extends MyObservable { protected int numPowerSurgeLands; protected boolean altWin = false; - protected String winCondition = ""; + protected String altWinSourceName; protected boolean altLose = false; - protected String loseCondition = ""; + protected GameLossReason lossState = GameLossReason.DidNotLoseYet; + protected String loseConditionSpell; protected int nTurns = 0; protected boolean skipNextUntap = false; @@ -43,6 +45,7 @@ public abstract class Player extends MyObservable { protected ManaPool manaPool = null; protected Object mustAttackEntity = null; + /** *

Constructor for Player.

@@ -81,9 +84,10 @@ public abstract class Player extends MyObservable { slowtripList = new CardList(); nTurns = 0; altWin = false; + altWinSourceName = null; altLose = false; - winCondition = ""; - loseCondition = ""; + lossState = GameLossReason.DidNotLoseYet; + loseConditionSpell = null; maxLandsToPlay = 1; numLandsPlayed = 0; @@ -907,7 +911,8 @@ public abstract class Player extends MyObservable { //lose: else if (!Constant.Runtime.DevMode[0] || AllZone.getDisplay().canLoseByDecking()) { // if devMode is off, or canLoseByDecking is Enabled, run Lose Condition - if (altLoseConditionMet("Milled")) { + if (!cantLose()) { + loseConditionMet(GameLossReason.Milled, null); AllZone.getGameAction().checkStateEffects(); } } @@ -1424,22 +1429,14 @@ public abstract class Player extends MyObservable { return altWin; } - /** - *

Getter for the field altLose.

- * - * @return a boolean. - */ - public boolean getAltLose() { - return altLose; - } - /** *

Getter for the field winCondition.

* * @return a {@link java.lang.String} object. */ - public String getWinCondition() { - return winCondition; + public String getWinConditionSource() + { + return altWinSourceName; } /** @@ -1447,8 +1444,8 @@ public abstract class Player extends MyObservable { * * @return a {@link java.lang.String} object. */ - public String getLoseCondition() { - return loseCondition; + public GameLossReason getLossState() { + return lossState; } /** @@ -1456,13 +1453,13 @@ public abstract class Player extends MyObservable { * * @param s a {@link java.lang.String} object. */ - public void altWinConditionMet(String s) { + public void altWinBySpellEffect( String sourceName ) { if (cantWin()) { System.out.println("Tried to win, but currently can't."); return; } altWin = true; - winCondition = s; + altWinSourceName = sourceName; } /** @@ -1471,15 +1468,17 @@ public abstract class Player extends MyObservable { * @param s a {@link java.lang.String} object. * @return a boolean. */ - public boolean altLoseConditionMet(String s) { + public boolean loseConditionMet(GameLossReason state, String spellName ) { if (cantLose()) { System.out.println("Tried to lose, but currently can't."); return false; } - altLose = true; - loseCondition = s; + lossState = state; + loseConditionSpell = spellName; return true; } + + /** *

cantLose.

@@ -1539,12 +1538,12 @@ public abstract class Player extends MyObservable { if (cantLose()) return false; - if (altLose) { + if (lossState != GameLossReason.DidNotLoseYet) { return true; } if (poisonCounters >= 10) { - altLoseConditionMet("Poison Counters"); + loseConditionMet( GameLossReason.Poisoned, null ); return true; } @@ -1552,7 +1551,13 @@ public abstract class Player extends MyObservable { return false; } - return getLife() <= 0; + boolean hasNoLife = getLife() <= 0; + if (hasNoLife) { + loseConditionMet( GameLossReason.LifeReachedZero, null); + return true; + } + + return false; } diff --git a/src/main/java/forge/Upkeep.java b/src/main/java/forge/Upkeep.java index bec2c6db9ca..3cf9aa33e20 100644 --- a/src/main/java/forge/Upkeep.java +++ b/src/main/java/forge/Upkeep.java @@ -2345,7 +2345,7 @@ public class Upkeep implements java.io.Serializable { @Override public void resolve() { if (player.getLife() >= 40) - player.altWinConditionMet(source.getName()); + player.altWinBySpellEffect(source.getName()); } };// Ability @@ -2377,7 +2377,7 @@ public class Upkeep implements java.io.Serializable { CardList grave = AllZoneUtil.getPlayerGraveyard(player); grave = grave.filter(AllZoneUtil.creatures); if (grave.size() >= 20) - player.altWinConditionMet(source.getName()); + player.altWinBySpellEffect(source.getName()); } };// Ability @@ -2405,7 +2405,7 @@ public class Upkeep implements java.io.Serializable { @Override public void resolve() { if (c.getCounters(Counters.TOWER) >= 100) - player.altWinConditionMet(c.getName()); + player.altWinBySpellEffect(c.getName()); } };// Ability @@ -2435,7 +2435,7 @@ public class Upkeep implements java.io.Serializable { @Override public void resolve() { if (player.getLife() == 1) - player.altWinConditionMet(source.getName()); + player.altWinBySpellEffect(source.getName()); } };// Ability @@ -2465,7 +2465,7 @@ public class Upkeep implements java.io.Serializable { @Override public void resolve() { if (player.getLife() >= 50) - player.altWinConditionMet(source.getName()); + player.altWinBySpellEffect(source.getName()); } };// Ability @@ -2507,7 +2507,7 @@ public class Upkeep implements java.io.Serializable { playList.remove(source); if (playList.size() == 0 && handList.size() == 0) - player.altWinConditionMet(source.getName()); + player.altWinBySpellEffect(source.getName()); } };// Ability diff --git a/src/main/java/forge/card/abilityFactory/AbilityFactory_Combat.java b/src/main/java/forge/card/abilityFactory/AbilityFactory_Combat.java index 1e837e2ecdc..9b4b0b39253 100644 --- a/src/main/java/forge/card/abilityFactory/AbilityFactory_Combat.java +++ b/src/main/java/forge/card/abilityFactory/AbilityFactory_Combat.java @@ -166,7 +166,7 @@ public class AbilityFactory_Combat { if (AllZone.getStack().size() != 0) return false; // Don't cast it, if the effect is already in place - if (AllZone.getGameInfo().isPreventCombatDamageThisTurn()) return false; + if (AllZone.getPhase().isPreventCombatDamageThisTurn()) return false; Ability_Sub subAb = sa.getSubAbility(); if (subAb != null) @@ -234,7 +234,7 @@ public class AbilityFactory_Combat { public static void fogResolve(final AbilityFactory af, final SpellAbility sa) { // Expand Fog keyword here depending on what we need out of it. - AllZone.getGameInfo().setPreventCombatDamageThisTurn(true); + AllZone.getPhase().setPreventCombatDamageThisTurn(true); } //************************************************************** diff --git a/src/main/java/forge/card/abilityFactory/AbilityFactory_EndGameCondition.java b/src/main/java/forge/card/abilityFactory/AbilityFactory_EndGameCondition.java index 66260e34be9..ff4fddfe713 100644 --- a/src/main/java/forge/card/abilityFactory/AbilityFactory_EndGameCondition.java +++ b/src/main/java/forge/card/abilityFactory/AbilityFactory_EndGameCondition.java @@ -5,6 +5,7 @@ import forge.Card; import forge.ComputerUtil; import forge.Player; import forge.card.spellability.*; +import forge.game.GameLossReason; import java.util.ArrayList; @@ -213,7 +214,7 @@ public class AbilityFactory_EndGameCondition { ArrayList players = AbilityFactory.getDefinedPlayers(card, af.getMapParams().get("Defined"), sa); for (Player p : players) - p.altWinConditionMet(card.getName()); + p.altWinBySpellEffect(card.getName()); } // *********************************************************************************************** @@ -449,7 +450,7 @@ public class AbilityFactory_EndGameCondition { } for (Player p : players) - p.altLoseConditionMet(card.getName()); + p.loseConditionMet( GameLossReason.SpellEffect, card.getName()); } } diff --git a/src/main/java/forge/card/cardFactory/AbstractCardFactory.java b/src/main/java/forge/card/cardFactory/AbstractCardFactory.java index 3fc83b39993..e9bf5375c3e 100644 --- a/src/main/java/forge/card/cardFactory/AbstractCardFactory.java +++ b/src/main/java/forge/card/cardFactory/AbstractCardFactory.java @@ -26,6 +26,7 @@ import forge.PlayerZone; import forge.card.abilityFactory.AbilityFactory; import forge.card.spellability.*; import forge.card.trigger.Trigger; +import forge.game.GameLossReason; import forge.gui.GuiUtils; import forge.gui.input.Input; import forge.gui.input.Input_PayManaCost; @@ -1804,7 +1805,7 @@ public abstract class AbstractCardFactory implements NewConstants, CardFactoryIn final SpellAbility loseGame = new Ability(card, "0") { @Override public void resolve() { - card.getController().altLoseConditionMet(card.getName()); + card.getController().loseConditionMet( GameLossReason.SpellEffect, card.getName()); } }; diff --git a/src/main/java/forge/card/cardFactory/CardFactory_Creatures.java b/src/main/java/forge/card/cardFactory/CardFactory_Creatures.java index c3498f523cd..56a528e678a 100644 --- a/src/main/java/forge/card/cardFactory/CardFactory_Creatures.java +++ b/src/main/java/forge/card/cardFactory/CardFactory_Creatures.java @@ -876,7 +876,6 @@ public class CardFactory_Creatures { Object o = GuiUtils.getChoice("Choose color", colors); color[0] = (String) o; - card.setChosenColor(color[0]); } else { // AI chooses the color that appears in the keywords of the most cards in its deck, hand and on battlefield CardList list = new CardList(); @@ -895,11 +894,11 @@ public class CardFactory_Creatures { color[0] = c; } } - card.setChosenColor(color[0]); } - + card.setChosenColor(color[0]); String s = CardUtil.getShortColor(color[0]); - timeStamp[0] = AllZone.getGameInfo().addColorChanges(s, card, true, true); + + timeStamp[0] = AllZone.getColorChanger().addColorChanges(s, card, true, true); } };//Command @@ -908,7 +907,7 @@ public class CardFactory_Creatures { public void execute() { String s = CardUtil.getShortColor(color[0]); - AllZone.getGameInfo().removeColorChanges(s, card, true, timeStamp[0]); + AllZone.getColorChanger().removeColorChanges(s, card, true, timeStamp[0]); } }; diff --git a/src/main/java/forge/game/GameEndReason.java b/src/main/java/forge/game/GameEndReason.java new file mode 100644 index 00000000000..8c0bf5fd596 --- /dev/null +++ b/src/main/java/forge/game/GameEndReason.java @@ -0,0 +1,10 @@ +package forge.game; + +public enum GameEndReason { + AllOpponentsLost, + // Noone won + Draw, // Having little idea how they can reach a draw, so I didn't enumerate possible reasons here + // Special conditions, they force one player to win and thus end the game + + WinsGameSpellEffect // ones that could be both hardcoded (felidar) and scripted ( such as Mayael's Aria ) +} diff --git a/src/main/java/forge/game/GameLossReason.java b/src/main/java/forge/game/GameLossReason.java new file mode 100644 index 00000000000..d18f1e89abd --- /dev/null +++ b/src/main/java/forge/game/GameLossReason.java @@ -0,0 +1,36 @@ +package forge.game; + +public enum GameLossReason { + + DidNotLoseYet, // a winner must have this status by the end of the game + + Conceded, // rule 104.3a + LifeReachedZero, // rule 104.3b + Milled, // 104.3c + Poisoned, // 104.3d + + // 104.3e and others + SpellEffect + + /*DoorToNothingness, // Door To Nothingness's ability activated + + // TODO: Implement game logics for the ones below + Transcendence20Life, // When you have 20 or more life, you lose the game. + FailedToPayPactUpkeep, // Pacts from Future Sight series (cost 0 but you must pay their real cost at next turn's upkeep, otherwise GL) + PhageTheUntouchableDamage, // Whenever Phage deals combat damage to a player, that player loses the game. + PhageTheUntouchableWrongETB, // When Phage the Untouchable ETB, if you didn't cast it from your hand, you lose the game. + NefariousLichLeavesTB, // When Nefarious Lich leaves the battlefield, you lose the game. + NefariousLichCannotExileGrave, // If damage would be dealt to you, exile that many cards from your graveyard instead. If you can't, you lose the game. + LichWasPutToGraveyard, // When Lich is put into a graveyard from the battlefield, you lose the game. + FinalFortune, // same as Warrior's Oath - lose at the granted extra turn's end step + ImmortalCoilEmptyGraveyard, // When there are no cards in your graveyard, you lose the game. + ForbiddenCryptEmptyGraveyard, // If you would draw a card, return a card from your graveyard to your hand instead. If you can't, you lose the game. + + // Amulet of quoz skipped for using ante, + // Form of the Squirrel and Rocket-Powered Turbo Slug skipped for being part of UN- set + + */ + + // refer to http://gatherer.wizards.com/Pages/Search/Default.aspx?output=standard&text=+[%22lose+the+game%22] for more cards when they are printed +} + diff --git a/src/main/java/forge/game/GamePlayerRating.java b/src/main/java/forge/game/GamePlayerRating.java new file mode 100644 index 00000000000..65bca34d053 --- /dev/null +++ b/src/main/java/forge/game/GamePlayerRating.java @@ -0,0 +1,41 @@ +package forge.game; + +/** + * + * @author Max + * + */ +public class GamePlayerRating { + boolean hasWonTheCoin; + + protected int turnsMade = 0; + protected int openingHandSize = 7; + protected int timesMulliganed = 0; + + protected GameLossReason lossReason = GameLossReason.DidNotLoseYet; + + public final GameLossReason getLossReason() { + return lossReason; + } + public void setLossReason(GameLossReason loseCondition) { + lossReason = loseCondition; + } + + public final int getOpeningHandSize() { + return openingHandSize; + } + + public final void notifyHasMulliganed() { + timesMulliganed++; + } + + public final int getMulliganCount() { + return timesMulliganed; + } + + public final void notifyOpeningHandSize(final int newHand) { + openingHandSize = newHand; + } + + +} diff --git a/src/main/java/forge/game/GameSummary.java b/src/main/java/forge/game/GameSummary.java new file mode 100644 index 00000000000..c1076630078 --- /dev/null +++ b/src/main/java/forge/game/GameSummary.java @@ -0,0 +1,67 @@ +package forge.game; + + +/** + *

GameInfo class.

+ * + * @author Forge + * @version $Id$ + */ + +// This should be divided into two: the very summary (immutable with only getters) and +// GameObserver class - who should be notified of any considerable ingame event +public class GameSummary { + protected int playerWinner = PlayerIndex.UNDEFINED; + protected int playerGotFirstTurn = PlayerIndex.UNDEFINED; + protected int lastTurnNumber = 0; + + protected GameEndReason winCondition; + protected String spellEffectWin; + protected GamePlayerRating playerRating[] = new GamePlayerRating[2/*players*/]; + + public GameSummary() + { + playerRating[PlayerIndex.AI] = new GamePlayerRating(); + playerRating[PlayerIndex.HUMAN] = new GamePlayerRating(); + } + + public final void end( final GameEndReason condition, int iPlayerWinner, String spellEffectWin ) + { + winCondition = condition; + playerWinner = iPlayerWinner; + this.spellEffectWin = spellEffectWin; + } + + public final boolean isHumanWinner() { return PlayerIndex.HUMAN == playerWinner; } + public final boolean isAIWinner() { return PlayerIndex.AI == playerWinner; } + public final boolean isDraw() { return PlayerIndex.DRAW == playerWinner; } + + public GameEndReason getWinCondition() { return winCondition; } + public GamePlayerRating getPlayerRating(int iPlayer) { + if (iPlayer >= 0 && iPlayer < playerRating.length) { + return playerRating[iPlayer]; + } + return null; + } + + public int getTurnGameEnded() { + return lastTurnNumber; + } + + public final void setPlayerWhoGotFirstTurn(int iPlayer) + { + playerGotFirstTurn = iPlayer; + } + + public void notifyNextTurn() { + lastTurnNumber++; + } + + public String getWinSpellEffect() { + return spellEffectWin; + } + + + + +} diff --git a/src/main/java/forge/game/PlayerIndex.java b/src/main/java/forge/game/PlayerIndex.java new file mode 100644 index 00000000000..8a7b054bb68 --- /dev/null +++ b/src/main/java/forge/game/PlayerIndex.java @@ -0,0 +1,8 @@ +package forge.game; + +public interface PlayerIndex { + int UNDEFINED = Integer.MIN_VALUE; + int DRAW = -1; + int HUMAN = 0; + int AI = 1; +} diff --git a/src/main/java/forge/game/package-info.java b/src/main/java/forge/game/package-info.java new file mode 100644 index 00000000000..abf03bdb001 --- /dev/null +++ b/src/main/java/forge/game/package-info.java @@ -0,0 +1,2 @@ +/** Forge Card Game */ +package forge.game; diff --git a/src/main/java/forge/gui/input/Input_Mulligan.java b/src/main/java/forge/gui/input/Input_Mulligan.java index f02a1dfe611..21f9278864d 100644 --- a/src/main/java/forge/gui/input/Input_Mulligan.java +++ b/src/main/java/forge/gui/input/Input_Mulligan.java @@ -1,6 +1,9 @@ package forge.gui.input; import forge.*; +import forge.game.GamePlayerRating; +import forge.game.PlayerIndex; +import forge.quest.data.QuestData; /** *

Input_Mulligan class.

@@ -11,6 +14,9 @@ import forge.*; public class Input_Mulligan extends Input { /** Constant serialVersionUID=-8112954303001155622L */ private static final long serialVersionUID = -8112954303001155622L; + + private static final int MAGIC_NUMBER_OF_SHUFFLES = 100; + private static final int AI_MULLIGAN_THRESHOLD = 5; /** {@inheritDoc} */ @Override @@ -27,31 +33,32 @@ public class Input_Mulligan extends Input { end(); } + public int doMulligan( Player player, GamePlayerRating playerRating ) { + CardList hand = AllZoneUtil.getPlayerHand(player); + for (Card c : hand) { AllZone.getGameAction().moveToLibrary(c); } + for (int i = 0; i < MAGIC_NUMBER_OF_SHUFFLES; i++) { player.shuffle(); } + int newHand = hand.size() - 1; + for (int i = 0; i < newHand; i++) { player.drawCard(); } + playerRating.notifyHasMulliganed(); + playerRating.notifyOpeningHandSize(newHand); + return newHand; + } + /** {@inheritDoc} */ @Override public void selectButtonCancel() { - AllZone.getGameInfo().setHumanMulliganedToZero(false); + GamePlayerRating humanRating = AllZone.getGameInfo().getPlayerRating(PlayerIndex.HUMAN); + Player humanPlayer = AllZone.getHumanPlayer(); - CardList hand = AllZoneUtil.getPlayerHand(AllZone.getHumanPlayer()); - for (Card c : hand) - AllZone.getGameAction().moveToLibrary(c); + int newHand = doMulligan(humanPlayer, humanRating); - for (int i = 0; i < 100; i++) - AllZone.getHumanPlayer().shuffle(); - - int newHand = hand.size() - 1; - - AllZone.getGameInfo().addHumanNumberOfTimesMulliganed(1); - - if (AllZone.getQuestData() != null) { - if (AllZone.getQuestData().getInventory().hasItem("Sleight") && AllZone.getGameInfo().getHumanNumberOfTimesMulliganed() == 1) - newHand++; - } - for (int i = 0; i < newHand; i++) + QuestData quest = AllZone.getQuestData(); + if (quest != null && quest.getInventory().hasItem("Sleight") && humanRating.getMulliganCount() == 1) { AllZone.getHumanPlayer().drawCard(); + humanRating.notifyOpeningHandSize(newHand + 1); + } if (newHand == 0) { - AllZone.getGameInfo().setHumanMulliganedToZero(true); end(); } }//selectButtonOK() @@ -61,29 +68,27 @@ public class Input_Mulligan extends Input { */ void end() { //Computer mulligan - CardList CHandList = AllZoneUtil.getPlayerHand(AllZone.getComputerPlayer()); - - Card dummy = CHandList.get(0); + Player aiPlayer = AllZone.getComputerPlayer(); + GamePlayerRating aiRating = AllZone.getGameInfo().getPlayerRating(PlayerIndex.AI); + boolean aiTakesMulligan = true; + //Computer mulligans if there are no cards with converted mana cost of 0 in its hand - while (CHandList.size() > 5 && CHandList.getValidCards("Card.cmcEQ0", AllZone.getComputerPlayer(), dummy).size() < 2) { - for (Card c : CHandList) - AllZone.getGameAction().moveToLibrary(c); + while (aiTakesMulligan) { - for (int i = 0; i < 100; i++) - AllZone.getComputerPlayer().shuffle(); + CardList handList = AllZoneUtil.getPlayerHand(aiPlayer); + boolean hasLittleCmc0Cards = handList.getValidCards("Card.cmcEQ0", aiPlayer, null).size() < 2; + aiTakesMulligan = handList.size() > AI_MULLIGAN_THRESHOLD && hasLittleCmc0Cards; - int newHand = CHandList.size() - 1; - for (int i = 0; i < newHand; i++) - AllZone.getComputerPlayer().drawCard(); - - CHandList = AllZoneUtil.getPlayerHand(AllZone.getComputerPlayer()); + if (aiTakesMulligan) { + doMulligan(aiPlayer, aiRating); + } } //Human Leylines ButtonUtil.reset(); - CardList HHandList = AllZoneUtil.getPlayerHand(AllZone.getHumanPlayer()); + CardList humanOpeningHand = AllZoneUtil.getPlayerHand(AllZone.getHumanPlayer()); - for (Card c : HHandList) { + for (Card c : humanOpeningHand) { if (c.getName().startsWith("Leyline")) { if (GameActionUtil.showYesNoDialog(c, "Put onto Battlefield?")) AllZone.getGameAction().moveToPlay(c); @@ -91,7 +96,8 @@ public class Input_Mulligan extends Input { } //Computer Leylines - for (Card c : CHandList) { + CardList aiOpeningHand = AllZoneUtil.getPlayerHand(AllZone.getComputerPlayer()); + for (Card c : aiOpeningHand) { if (c.getName().startsWith("Leyline") && !(c.getName().startsWith("Leyline of Singularity") && AllZoneUtil.getCardsInPlay("Leyline of Singularity").size() > 0)) { AllZone.getGameAction().moveToPlay(c); @@ -99,8 +105,8 @@ public class Input_Mulligan extends Input { } } - if (AllZone.getGameAction().isStartCut() && !(HHandList.contains(AllZone.getGameAction().getHumanCut()) - || CHandList.contains(AllZone.getGameAction().getComputerCut()))) { + if (AllZone.getGameAction().isStartCut() && !(humanOpeningHand.contains(AllZone.getGameAction().getHumanCut()) + || aiOpeningHand.contains(AllZone.getGameAction().getComputerCut()))) { AllZone.getGameAction().moveTo(AllZone.getZone(Constant.Zone.Library, AllZone.getHumanPlayer()), AllZone.getGameAction().getHumanCut()); AllZone.getGameAction().moveTo(AllZone.getZone(Constant.Zone.Library, AllZone.getComputerPlayer()), AllZone.getGameAction().getComputerCut()); } diff --git a/src/main/java/forge/quest/data/QuestData.java b/src/main/java/forge/quest/data/QuestData.java index c3522f156dd..51f1b50a4c9 100644 --- a/src/main/java/forge/quest/data/QuestData.java +++ b/src/main/java/forge/quest/data/QuestData.java @@ -3,6 +3,10 @@ package forge.quest.data; import forge.*; import forge.deck.Deck; import forge.error.ErrorViewer; +import forge.game.GameLossReason; +import forge.game.GamePlayerRating; +import forge.game.GameSummary; +import forge.game.PlayerIndex; import forge.properties.ForgeProps; import forge.properties.NewConstants; import forge.quest.data.item.QuestInventory; @@ -482,63 +486,80 @@ public class QuestData { } } + + public final int getCreditsRewardForAltWin(final GameLossReason whyAiLost) { + int rewardAltWinCondition = 0; + switch (whyAiLost) { + case LifeReachedZero: + break; // nothing special here, ordinary kill + case Milled: + rewardAltWinCondition = QuestPreferences.getMatchRewardMilledWinBonus(); + break; + case Poisoned: + rewardAltWinCondition = QuestPreferences.getMatchRewardPoisonWinBonus(); + break; + case DidNotLoseYet: // must be player's alternate win condition: felidar, helix pinnacle and like this + rewardAltWinCondition = QuestPreferences.getMatchRewardAltWinBonus(); + break; + default: // this .checkstyle forces us to write some idiotic code + rewardAltWinCondition = 0; + } + return rewardAltWinCondition; + } + + public final int getCreditsRewardForWinByTurn(final int iTurn) { + if (iTurn == 1) { + return QuestPreferences.getMatchRewardWinFirst(); + } else if (iTurn <= 5) { + return QuestPreferences.getMatchRewardWinByFifth(); + } else if (iTurn <= 10) { + return QuestPreferences.getMatchRewardWinByTen(); + } else if (iTurn <= 15) { + return QuestPreferences.getMatchRewardWinByFifteen(); + } + return 0; + } + /** *

getCreditsToAdd.

* * @param matchState a {@link forge.quest.data.QuestMatchState} object. * @return a long. */ - public long getCreditsToAdd(QuestMatchState matchState) { - long creds = (long) (QuestPreferences.getMatchRewardBase() + (QuestPreferences.getMatchRewardTotalWins() * win)); - String[] wins = matchState.getWinMethods(); - int[] winTurns = matchState.getWinTurns(); - boolean[] mulliganedToZero = matchState.getMulliganedToZero(); + public final long getCreditsToAdd(final QuestMatchState matchState) { + long creds = (long) (QuestPreferences.getMatchRewardBase() + + (QuestPreferences.getMatchRewardTotalWins() * win)); - if (matchState.getLose() == 0) { - creds += QuestPreferences.getMatchRewardNoLosses(); - } - - for (String s : wins) { - if (s != null) { - if (s.equals("Poison Counters")) { - creds += QuestPreferences.getMatchRewardPoisonWinBonus(); - } else if (s.equals("Milled")) { - creds += QuestPreferences.getMatchRewardMilledWinBonus(); - } else if (s.equals("Battle of Wits") || s.equals("Felidar Sovereign") || s.equals("Helix Pinnacle") || - s.equals("Epic Struggle") || s.equals("Door to Nothingness") || s.equals("Barren Glory") || - s.equals("Near-Death Experience") || s.equals("Mortal Combat") || s.equals("Test of Endurance")) { - creds += QuestPreferences.getMatchRewardAltWinBonus(); - } + boolean hasNeverLost = true; + for (GameSummary game : matchState.getGamesPlayed()) { + if (game.isAIWinner()) { + hasNeverLost = true; + continue; // no rewards for losing a game } - } - for (int i : winTurns) { - if (i == 1) { - creds += QuestPreferences.getMatchRewardWinFirst(); - } else if (i <= 5) { - creds += QuestPreferences.getMatchRewardWinByFifth(); - } else if (i <= 10) { - creds += QuestPreferences.getMatchRewardWinByTen(); - } else if (i <= 15) { - creds += QuestPreferences.getMatchRewardWinByFifteen(); - } - } + GamePlayerRating aiRating = game.getPlayerRating(PlayerIndex.AI); + GamePlayerRating humanRating = game.getPlayerRating(PlayerIndex.HUMAN); + GameLossReason whyAiLost = aiRating.getLossReason(); - for (boolean b : mulliganedToZero) { - if (b == true) { + creds += getCreditsRewardForAltWin(whyAiLost); + creds += getCreditsRewardForWinByTurn(game.getTurnGameEnded()); + + int cntCardsHumanStartedWith = humanRating.getOpeningHandSize(); + if (0 == cntCardsHumanStartedWith) { creds += QuestPreferences.getMatchMullToZero(); } } - if (inventory.getItemLevel("Estates") == 1) { - creds *= 1.1; - } else if (inventory.getItemLevel("Estates") == 2) { - creds *= 1.15; - } else if (inventory.getItemLevel("Estates") == 3) { - creds *= 1.2; + if (hasNeverLost) { + creds += QuestPreferences.getMatchRewardNoLosses(); } - this.addCredits(creds); + switch(inventory.getItemLevel("Estates")) { + case 1: creds *= 1.1; break; + case 2: creds *= 1.15; break; + case 3: creds *= 1.2; break; + default: break; + } return creds; } diff --git a/src/main/java/forge/quest/data/QuestMatchState.java b/src/main/java/forge/quest/data/QuestMatchState.java index 37204ccd118..e94366cdb34 100644 --- a/src/main/java/forge/quest/data/QuestMatchState.java +++ b/src/main/java/forge/quest/data/QuestMatchState.java @@ -1,163 +1,79 @@ package forge.quest.data; +import java.util.ArrayList; +import java.util.List; + +import forge.game.GameSummary; + + /** *

QuestMatchState class.

* * @author Forge * @version $Id$ */ + + public class QuestMatchState { - //the way wins were achieved: - //Damage - //Poison Counters - //Battle of Wits - //Mortal Combat - //Milled - //Felidar Sovereign - //... - // - private String[] winMethods = new String[2]; - private int[] winTurns = new int[2]; + public static final int GAMES_PER_MATCH = 3; + public static final int MIN_GAMES_TO_WIN_MATCH = 2; - private boolean[] mulliganedToZero = new boolean[2]; + private List gamesPlayed = new ArrayList(); + //ArrayList - private int win; - private int lose; - private boolean winRecently; - - /** - *

reset.

- */ - public void reset() { - win = 0; - lose = 0; - winMethods = new String[2]; + public final void addGamePlayed(final GameSummary completedGame) { + gamesPlayed.add(completedGame); } - /** - *

addWin.

- */ - public void addWin() { - win++; - winRecently = true; + public final GameSummary[] getGamesPlayed() { + return gamesPlayed.toArray(new GameSummary[gamesPlayed.size()]); } - /** - *

addLose.

- */ - public void addLose() { - lose++; - winRecently = false; + public final int getGamesPlayedCount() { + return gamesPlayed.size(); } - /** - *

Getter for the field win.

- * - * @return a int. - */ - public int getWin() { - return win; + public final boolean hasHumanWonLastGame() { + int iLastGame = gamesPlayed.size() - 1; + return iLastGame >= 0 ? gamesPlayed.get(iLastGame).isHumanWinner() : false; } - /** - *

Getter for the field lose.

- * - * @return a int. - */ - public int getLose() { - return lose; + public final boolean isMatchOver() { + int winsHuman = 0; + int winsAI = 0; + int totalGames = 0; + + for (GameSummary game : gamesPlayed) { + if (game.isAIWinner()) { winsAI++; } + if (game.isHumanWinner()) { winsHuman++; } + totalGames++; + } + + return winsAI >= MIN_GAMES_TO_WIN_MATCH || winsHuman >= MIN_GAMES_TO_WIN_MATCH || totalGames >= GAMES_PER_MATCH; } - /** - *

countWinLose.

- * - * @return a int. - */ - public int countWinLose() { - return win + lose; + public final int getGamesCountWonByHuman() { + int winsHuman = 0; + for (GameSummary game : gamesPlayed) { + if (game.isHumanWinner()) { winsHuman++; } + } + return winsHuman; } - /** - *

setWinMethod.

- * - * @param gameNumber a int. - * @param method a {@link java.lang.String} object. - */ - public void setWinMethod(int gameNumber, String method) { - winMethods[gameNumber] = method; + public final int getGamesCountLostByHuman() { + int lossHuman = 0; + for (GameSummary game : gamesPlayed) { + if (!game.isHumanWinner()) { lossHuman++; } + } + return lossHuman; } - /** - *

Getter for the field winMethods.

- * - * @return an array of {@link java.lang.String} objects. - */ - public String[] getWinMethods() { - return winMethods; + public final boolean isMatchWonByHuman() { + return getGamesCountWonByHuman() >= MIN_GAMES_TO_WIN_MATCH; } - /** - *

setWinTurn.

- * - * @param gameNumber a int. - * @param turns a int. - */ - public void setWinTurn(int gameNumber, int turns) { - winTurns[gameNumber] = turns; + public final void reset() { + gamesPlayed.clear(); } - - /** - *

Getter for the field winTurns.

- * - * @return an array of int. - */ - public int[] getWinTurns() { - return winTurns; - } - - /** - *

Getter for the field mulliganedToZero.

- * - * @return an array of boolean. - */ - public boolean[] getMulliganedToZero() { - return mulliganedToZero; - } - - /** - *

Setter for the field mulliganedToZero.

- * - * @param gameNumber a int. - * @param b a boolean. - */ - public void setMulliganedToZero(int gameNumber, boolean b) { - mulliganedToZero[gameNumber] = b; - } - - /** - *

didWinRecently.

- * - * @return a boolean. - */ - public boolean didWinRecently() { - return winRecently; - } - - /** - *

isMatchOver.

- * @return whether match is complete - */ - public boolean isMatchOver() - { - return win == 2 || lose == 2; - } - /** - *

isMatchOver.

- * @return whether match is won - */ - public boolean isMatchWon() - { - return win == 2; - } } diff --git a/src/main/java/forge/quest/gui/main/QuestMainPanel.java b/src/main/java/forge/quest/gui/main/QuestMainPanel.java index ffcb0ad1d86..14a77a4928a 100644 --- a/src/main/java/forge/quest/gui/main/QuestMainPanel.java +++ b/src/main/java/forge/quest/gui/main/QuestMainPanel.java @@ -149,7 +149,7 @@ public class QuestMainPanel extends QuestAbstractPanel { */ private JPanel createSidePanel() { JPanel panel = new JPanel(); - JPanel optionsPanel;//Create options checkbox list + JPanel optionsPanel; //Create options checkbox list optionsPanel = createOptionsPanel(); List eastComponents = new ArrayList(); @@ -659,7 +659,7 @@ public class QuestMainPanel extends QuestAbstractPanel { Constant.Runtime.Smooth[0] = smoothLandCheckBox.isSelected(); - + AllZone.getMatchState().reset(); if (isShowingQuests) { setupQuest(humanDeck); } else { diff --git a/src/main/java/forge/view/swing/OldGuiNewGame.java b/src/main/java/forge/view/swing/OldGuiNewGame.java index 2d4919c330e..8700fd46ad2 100644 --- a/src/main/java/forge/view/swing/OldGuiNewGame.java +++ b/src/main/java/forge/view/swing/OldGuiNewGame.java @@ -126,7 +126,6 @@ public class OldGuiNewGame extends JFrame implements NewConstants, NewConstants. AllZone.setQuestData(null); allDecks = getDecks(); - Constant.Runtime.matchState.reset(); if (Constant.Runtime.width[0] == 0) { Constant.Runtime.width[0] = 70; diff --git a/src/test/java/forge/GuiWinLoseTest.java b/src/test/java/forge/GuiWinLoseTest.java index 113bcfd4d69..6da80b80cad 100644 --- a/src/test/java/forge/GuiWinLoseTest.java +++ b/src/test/java/forge/GuiWinLoseTest.java @@ -3,6 +3,8 @@ package forge; import org.testng.Assert; import org.testng.annotations.Test; +import forge.quest.data.QuestMatchState; + /** * Created by IntelliJ IDEA. * User: dhudson @@ -15,7 +17,7 @@ public class GuiWinLoseTest { */ @Test(groups = {"UnitTest", "fast"}) public void GuiWinLoseTest1() { - Gui_WinLose dialog = new Gui_WinLose(); + Gui_WinLose dialog = new Gui_WinLose( new QuestMatchState(), null, null ); dialog.setVisible(true); Assert.assertNotNull(dialog); dialog.dispose();