From 8bc45fe0206e8c33f51603dd2416018f71d1684d Mon Sep 17 00:00:00 2001 From: Fnoed Date: Sat, 17 Mar 2012 23:50:58 +0000 Subject: [PATCH] Fixed ClassCastException at the end of quest games --- .../gui/home/quest/SubmenuQuestUtil.java | 651 ++++---- src/main/java/forge/quest/QuestUtil.java | 15 +- .../forge/view/match/QuestWinLoseHandler.java | 1400 ++++++++--------- 3 files changed, 1024 insertions(+), 1042 deletions(-) diff --git a/src/main/java/forge/gui/home/quest/SubmenuQuestUtil.java b/src/main/java/forge/gui/home/quest/SubmenuQuestUtil.java index 25c2ff90d23..92002d80ba3 100644 --- a/src/main/java/forge/gui/home/quest/SubmenuQuestUtil.java +++ b/src/main/java/forge/gui/home/quest/SubmenuQuestUtil.java @@ -1,327 +1,324 @@ -package forge.gui.home.quest; - -import java.io.File; -import java.util.Set; - -import javax.swing.ImageIcon; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; - -import org.apache.commons.lang3.StringUtils; - -import net.miginfocom.swing.MigLayout; -import forge.AllZone; -import forge.Command; -import forge.Constant; -import forge.Singletons; -import forge.control.FControl; -import forge.deck.Deck; -import forge.game.GameNew; -import forge.game.GameType; -import forge.gui.OverlayUtils; -import forge.gui.deckeditor.QuestCardShop; -import forge.gui.toolbox.FLabel; -import forge.gui.toolbox.FPanel; -import forge.gui.toolbox.FSkin; -import forge.gui.toolbox.FTextArea; -import forge.properties.ForgeProps; -import forge.properties.NewConstants; -import forge.quest.QuestChallenge; -import forge.quest.QuestController; -import forge.quest.QuestEvent; -import forge.quest.QuestEvent.QuestEventType; -import forge.quest.QuestUtil; -import forge.quest.data.QuestAchievements; -import forge.quest.data.QuestAssets; -import forge.quest.data.QuestMode; -import forge.quest.data.QuestPreferences.QPref; -import forge.quest.data.item.QuestItemType; -import forge.quest.data.pet.QuestPetAbstract; - -/** - * Utilities for the quest submenu, all over the MVC spectrum. - * If a piece of code can be reused, it's dumped here. - */ -public class SubmenuQuestUtil { - private static SelectablePanel selectedOpponent; - - /** - *

- * nextChallengeInWins. - *

- * - * @return a int. - */ - public static int nextChallengeInWins() { - final QuestController qData = AllZone.getQuest(); - final int challengesPlayed = qData.getAchievements().getChallengesPlayed(); - - int mul = 5; - if (qData.getAssets().hasItem(QuestItemType.ZEPPELIN)) { - mul = 3; - } else if (qData.getAssets().hasItem(QuestItemType.MAP)) { - mul = 4; - } - - final int wins = qData.getAchievements().getWin(); - final int delta = (wins < 20 ? 20 - wins : (challengesPlayed * mul) - wins); - - return (delta > 0) ? delta : 0; - } - - /** Updates stats, pets panels for both duels and challenges. */ - public static void updateStatsAndPet() { - final QuestController qData = AllZone.getQuest(); - final QuestAchievements qA = qData.getAchievements(); - final QuestAssets qS = qData.getAssets(); - - if (qA == null) { return; } - - final IStatsAndPet[] viewsToUpdate = new IStatsAndPet[] { - VSubmenuDuels.SINGLETON_INSTANCE, - VSubmenuChallenges.SINGLETON_INSTANCE - }; - - - for (final IStatsAndPet view : viewsToUpdate) { - // Fantasy UI display - view.getLblNextChallengeInWins().setVisible(true); - view.getBtnBazaar().setVisible(true); - view.getLblLife().setVisible(true); - - // Stats panel - view.getLblCredits().setText("Credits: " + qS.getCredits()); - view.getLblLife().setText("Life: " + qS.getLife(qData.getMode())); - view.getLblWins().setText("Wins: " + qA.getWin()); - view.getLblLosses().setText("Losses: " + qA.getLost()); - view.updateCurrentDeckStatus(); - - final int num = SubmenuQuestUtil.nextChallengeInWins(); - if (num == 0) { - view.getLblNextChallengeInWins().setText("Next challenge available now."); - } - else { - view.getLblNextChallengeInWins().setText("Next challenge available in " + num + " wins."); - } - - view.getLblWinStreak().setText( - "Win streak: " + qA.getWinStreakCurrent() - + " (Best:" + qA.getWinStreakBest() + ")"); - - // Start panel: pet, plant, zep. - if (qData.getMode() == QuestMode.Fantasy) { - final Set petList = qS.getPetManager().getAvailablePetNames(); - final QuestPetAbstract currentPet = qS.getPetManager().getSelectedPet(); - - view.getCbxPet().removeAllItems(); - // Pet list visibility - if (petList.size() > 0) { - view.getCbxPet().setEnabled(true); - view.getCbxPet().addItem("Don't summon a pet"); - for (final String pet : petList) { - view.getCbxPet().addItem("Summon " + pet); - } - - if (currentPet != null) { view.getCbxPet().setSelectedItem("Summon " + currentPet.getName()); } - } else { - view.getCbxPet().setVisible(false); - } - - // Plant visiblity - if (qS.getPetManager().getPlant().getLevel() == 0) { - view.getCbPlant().setVisible(false); - } - else { - view.getCbPlant().setVisible(true); - view.getCbPlant().setSelected(qS.getPetManager().shouldPlantBeUsed()); - } - - view.getCbZep().setVisible(qS.hasItem(QuestItemType.ZEPPELIN)); - } - else { - // Classic mode display changes - view.getCbxPet().setVisible(false); - view.getCbPlant().setVisible(false); - view.getCbZep().setVisible(false); - view.getLblNextChallengeInWins().setVisible(false); - view.getBtnBazaar().setVisible(false); - view.getLblLife().setVisible(false); - } - } - } - - /** @return {@link forge.view.home.ViewQuest.SelectablePanel} */ - public static SelectablePanel getSelectedOpponent() { - return selectedOpponent; - } - - /** @return {@link forge.deck.Deck} */ - public static Deck getCurrentDeck() { - Deck d = null; - - if (AllZone.getQuest().getAssets() != null) { - d = AllZone.getQuest().getMyDecks().get( - Singletons.getModel().getQuestPreferences().getPreference(QPref.CURRENT_DECK)); - } - - return d; - } - - /** */ - @SuppressWarnings("serial") - public static void showSpellShop() { - final Command exit = new Command() { - @Override - public void execute() { - AllZone.getQuest().save(); - updateStatsAndPet(); - } - }; - - final QuestCardShop g = new QuestCardShop(AllZone.getQuest()); - g.show(exit); - g.setVisible(true); - } - - /** */ - public static void showBazaar() { - Singletons.getControl().changeState(FControl.QUEST_BAZAAR); - Singletons.getView().getFrame().validate(); - } - - /** */ - public static void startGame() { - final QuestController qData = AllZone.getQuest(); - final QuestEvent event = selectedOpponent.getEvent(); - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - OverlayUtils.startGameOverlay(); - OverlayUtils.showOverlay(); - } - }); - - final SwingWorker worker = new SwingWorker() { - @Override - public Object doInBackground() { - Constant.Runtime.HUMAN_DECK[0] = SubmenuQuestUtil.getCurrentDeck(); - Constant.Runtime.COMPUTER_DECK[0] = event.getEventDeck(); - Constant.Runtime.setGameType(GameType.Quest); - - qData.getEventManager().randomizeOpponents(); - qData.setCurrentEvent(event); - qData.save(); - - if (qData.getMode() == QuestMode.Fantasy) { - int lifeAI = 20; - int lifeHuman = 20; - - if (selectedOpponent.getEvent().getEventType().equals(QuestEventType.CHALLENGE)) { - int extraLife = 0; - - // If zeppelin has been purchased, gear will be at level 2. - if (qData.getAssets().hasItem(QuestItemType.ZEPPELIN) - && VSubmenuChallenges.SINGLETON_INSTANCE.getCbZep().isSelected()) { - extraLife = 3; - } - lifeAI = ((QuestChallenge) event).getAILife(); - lifeHuman = qData.getAssets().getLife(qData.getMode()) + extraLife; - } - - GameNew.newGame( - Constant.Runtime.HUMAN_DECK[0], - Constant.Runtime.COMPUTER_DECK[0], - QuestUtil.getHumanStartingCards(qData.getAssets(), event), - QuestUtil.getComputerStartingCards(event), - lifeHuman, - lifeAI, - event.getIconFilename()); - } // End isFantasy - else { - GameNew.newGame(SubmenuQuestUtil.getCurrentDeck(), event.getEventDeck()); - } - return null; - } - - @Override - public void done() { - OverlayUtils.hideOverlay(); - } - }; - worker.execute(); - } - - /** Selectable panels for duels and challenges. */ - @SuppressWarnings("serial") - public static class SelectablePanel extends FPanel { - private final QuestEvent event; - - /** @param e0   QuestEvent */ - public SelectablePanel(final QuestEvent e0) { - super(); - this.event = e0; - this.setSelectable(true); - this.setHoverable(true); - this.setLayout(new MigLayout("insets 0, gap 0")); - - this.setCommand(new Command() { - @Override - public void execute() { - if (selectedOpponent != null) { - selectedOpponent.setSelected(false); - } - - if (VSubmenuDuels.SINGLETON_INSTANCE.getPanel().isShowing() && getCurrentDeck() != null) { - VSubmenuDuels.SINGLETON_INSTANCE.getBtnStart().setEnabled(true); - VSubmenuChallenges.SINGLETON_INSTANCE.getBtnStart().setEnabled(false); - } - else if (VSubmenuChallenges.SINGLETON_INSTANCE.getPanel().isShowing() && getCurrentDeck() != null) { - VSubmenuDuels.SINGLETON_INSTANCE.getBtnStart().setEnabled(false); - VSubmenuChallenges.SINGLETON_INSTANCE.getBtnStart().setEnabled(true); - } - - selectedOpponent = SubmenuQuestUtil.SelectablePanel.this; - } - }); - - // Icon - final File base = ForgeProps.getFile(NewConstants.IMAGE_ICON); - final File file = new File(base, event.getIconFilename()); - - final FLabel lblIcon = new FLabel.Builder().iconScaleFactor(1).build(); - if (!file.exists()) { - lblIcon.setIcon(FSkin.getIcon(FSkin.ForgeIcons.ICO_UNKNOWN)); - } - else { - lblIcon.setIcon(new ImageIcon(file.toString())); - } - this.add(lblIcon, "h 60px!, w 60px!, gap 10px 10px 10px 0, span 1 2"); - - // Name - final FLabel lblName = new FLabel.Builder().hoverable(false).build(); - if (event.getEventType().equals(QuestEventType.CHALLENGE)) { - lblName.setText(event.getTitle() + ": " - + StringUtils.capitalize(event.getDifficulty()) - + (((QuestChallenge) event).isRepeatable() ? ", Repeatable" : "")); - } - else { - lblName.setText(event.getTitle() + ": " - + StringUtils.capitalize(event.getDifficulty())); - } - this.add(lblName, "h 31px!, gap 0 0 10px 5px, wrap"); - - // Description - final FTextArea tarDesc = new FTextArea(); - tarDesc.setText(event.getDescription()); - - tarDesc.setFont(FSkin.getItalicFont(12)); - this.add(tarDesc, "w 80%!, h 30px!"); - } - - /** @return QuestEvent */ - public QuestEvent getEvent() { - return event; - } - } -} +package forge.gui.home.quest; + +import forge.AllZone; +import forge.Command; +import forge.Constant; +import forge.Singletons; +import forge.control.FControl; +import forge.deck.Deck; +import forge.game.GameNew; +import forge.game.GameType; +import forge.gui.OverlayUtils; +import forge.gui.deckeditor.QuestCardShop; +import forge.gui.toolbox.FLabel; +import forge.gui.toolbox.FPanel; +import forge.gui.toolbox.FSkin; +import forge.gui.toolbox.FTextArea; +import forge.properties.ForgeProps; +import forge.properties.NewConstants; +import forge.quest.QuestChallenge; +import forge.quest.QuestController; +import forge.quest.QuestEvent; +import forge.quest.QuestUtil; +import forge.quest.data.QuestAchievements; +import forge.quest.data.QuestAssets; +import forge.quest.data.QuestMode; +import forge.quest.data.QuestPreferences.QPref; +import forge.quest.data.item.QuestItemType; +import forge.quest.data.pet.QuestPetAbstract; +import net.miginfocom.swing.MigLayout; +import org.apache.commons.lang3.StringUtils; + +import javax.swing.*; +import java.io.File; +import java.util.Set; + +import static forge.quest.QuestEvent.QuestEventType.CHALLENGE; + +/** + * Utilities for the quest submenu, all over the MVC spectrum. + * If a piece of code can be reused, it's dumped here. + */ +public class SubmenuQuestUtil { + private static SelectablePanel selectedOpponent; + + /** + *

+ * nextChallengeInWins. + *

+ * + * @return a int. + */ + public static int nextChallengeInWins() { + final QuestController qData = AllZone.getQuest(); + final int challengesPlayed = qData.getAchievements().getChallengesPlayed(); + + int mul = 5; + if (qData.getAssets().hasItem(QuestItemType.ZEPPELIN)) { + mul = 3; + } else if (qData.getAssets().hasItem(QuestItemType.MAP)) { + mul = 4; + } + + final int wins = qData.getAchievements().getWin(); + final int delta = (wins < 20 ? 20 - wins : (challengesPlayed * mul) - wins); + + return (delta > 0) ? delta : 0; + } + + /** Updates stats, pets panels for both duels and challenges. */ + public static void updateStatsAndPet() { + final QuestController qData = AllZone.getQuest(); + final QuestAchievements qA = qData.getAchievements(); + final QuestAssets qS = qData.getAssets(); + + if (qA == null) { return; } + + final IStatsAndPet[] viewsToUpdate = new IStatsAndPet[] { + VSubmenuDuels.SINGLETON_INSTANCE, + VSubmenuChallenges.SINGLETON_INSTANCE + }; + + + for (final IStatsAndPet view : viewsToUpdate) { + // Fantasy UI display + view.getLblNextChallengeInWins().setVisible(true); + view.getBtnBazaar().setVisible(true); + view.getLblLife().setVisible(true); + + // Stats panel + view.getLblCredits().setText("Credits: " + qS.getCredits()); + view.getLblLife().setText("Life: " + qS.getLife(qData.getMode())); + view.getLblWins().setText("Wins: " + qA.getWin()); + view.getLblLosses().setText("Losses: " + qA.getLost()); + view.updateCurrentDeckStatus(); + + final int num = SubmenuQuestUtil.nextChallengeInWins(); + if (num == 0) { + view.getLblNextChallengeInWins().setText("Next challenge available now."); + } + else { + view.getLblNextChallengeInWins().setText("Next challenge available in " + num + " wins."); + } + + view.getLblWinStreak().setText( + "Win streak: " + qA.getWinStreakCurrent() + + " (Best:" + qA.getWinStreakBest() + ")"); + + // Start panel: pet, plant, zep. + if (qData.getMode() == QuestMode.Fantasy) { + final Set petList = qS.getPetManager().getAvailablePetNames(); + final QuestPetAbstract currentPet = qS.getPetManager().getSelectedPet(); + + view.getCbxPet().removeAllItems(); + // Pet list visibility + if (petList.size() > 0) { + view.getCbxPet().setEnabled(true); + view.getCbxPet().addItem("Don't summon a pet"); + for (final String pet : petList) { + view.getCbxPet().addItem("Summon " + pet); + } + + if (currentPet != null) { view.getCbxPet().setSelectedItem("Summon " + currentPet.getName()); } + } else { + view.getCbxPet().setVisible(false); + } + + // Plant visiblity + if (qS.getPetManager().getPlant().getLevel() == 0) { + view.getCbPlant().setVisible(false); + } + else { + view.getCbPlant().setVisible(true); + view.getCbPlant().setSelected(qS.getPetManager().shouldPlantBeUsed()); + } + + view.getCbZep().setVisible(qS.hasItem(QuestItemType.ZEPPELIN)); + } + else { + // Classic mode display changes + view.getCbxPet().setVisible(false); + view.getCbPlant().setVisible(false); + view.getCbZep().setVisible(false); + view.getLblNextChallengeInWins().setVisible(false); + view.getBtnBazaar().setVisible(false); + view.getLblLife().setVisible(false); + } + } + } + + /** @return {@link forge.view.home.ViewQuest.SelectablePanel} */ + public static SelectablePanel getSelectedOpponent() { + return selectedOpponent; + } + + /** @return {@link forge.deck.Deck} */ + public static Deck getCurrentDeck() { + Deck d = null; + + if (AllZone.getQuest().getAssets() != null) { + d = AllZone.getQuest().getMyDecks().get( + Singletons.getModel().getQuestPreferences().getPreference(QPref.CURRENT_DECK)); + } + + return d; + } + + /** */ + @SuppressWarnings("serial") + public static void showSpellShop() { + final Command exit = new Command() { + @Override + public void execute() { + AllZone.getQuest().save(); + updateStatsAndPet(); + } + }; + + final QuestCardShop g = new QuestCardShop(AllZone.getQuest()); + g.show(exit); + g.setVisible(true); + } + + /** */ + public static void showBazaar() { + Singletons.getControl().changeState(FControl.QUEST_BAZAAR); + Singletons.getView().getFrame().validate(); + } + + /** */ + public static void startGame() { + final QuestController qData = AllZone.getQuest(); + final QuestEvent event = selectedOpponent.getEvent(); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + OverlayUtils.startGameOverlay(); + OverlayUtils.showOverlay(); + } + }); + + final SwingWorker worker = new SwingWorker() { + @Override + public Object doInBackground() { + Constant.Runtime.HUMAN_DECK[0] = SubmenuQuestUtil.getCurrentDeck(); + Constant.Runtime.COMPUTER_DECK[0] = event.getEventDeck(); + Constant.Runtime.setGameType(GameType.Quest); + + qData.getEventManager().randomizeOpponents(); + qData.setCurrentEvent(event); + qData.save(); + + if (qData.getMode() == QuestMode.Fantasy) { + int lifeAI = 20; + int lifeHuman = 20; + + if (selectedOpponent.getEvent().getEventType() == CHALLENGE) { + int extraLife = 0; + + // If zeppelin has been purchased, gear will be at level 2. + if (qData.getAssets().hasItem(QuestItemType.ZEPPELIN) + && VSubmenuChallenges.SINGLETON_INSTANCE.getCbZep().isSelected()) { + extraLife = 3; + } + lifeAI = ((QuestChallenge) event).getAILife(); + lifeHuman = qData.getAssets().getLife(qData.getMode()) + extraLife; + } + + GameNew.newGame( + Constant.Runtime.HUMAN_DECK[0], + Constant.Runtime.COMPUTER_DECK[0], + QuestUtil.getHumanStartingCards(qData.getAssets(), event), + QuestUtil.getComputerStartingCards(event), + lifeHuman, + lifeAI, + event.getIconFilename()); + } // End isFantasy + else { + GameNew.newGame(SubmenuQuestUtil.getCurrentDeck(), event.getEventDeck()); + } + return null; + } + + @Override + public void done() { + OverlayUtils.hideOverlay(); + } + }; + worker.execute(); + } + + /** Selectable panels for duels and challenges. */ + @SuppressWarnings("serial") + public static class SelectablePanel extends FPanel { + private final QuestEvent event; + + /** @param e0   QuestEvent */ + public SelectablePanel(final QuestEvent e0) { + super(); + this.event = e0; + this.setSelectable(true); + this.setHoverable(true); + this.setLayout(new MigLayout("insets 0, gap 0")); + + this.setCommand(new Command() { + @Override + public void execute() { + if (selectedOpponent != null) { + selectedOpponent.setSelected(false); + } + + if (VSubmenuDuels.SINGLETON_INSTANCE.getPanel().isShowing() && getCurrentDeck() != null) { + VSubmenuDuels.SINGLETON_INSTANCE.getBtnStart().setEnabled(true); + VSubmenuChallenges.SINGLETON_INSTANCE.getBtnStart().setEnabled(false); + } + else if (VSubmenuChallenges.SINGLETON_INSTANCE.getPanel().isShowing() && getCurrentDeck() != null) { + VSubmenuDuels.SINGLETON_INSTANCE.getBtnStart().setEnabled(false); + VSubmenuChallenges.SINGLETON_INSTANCE.getBtnStart().setEnabled(true); + } + + selectedOpponent = SubmenuQuestUtil.SelectablePanel.this; + } + }); + + // Icon + final File base = ForgeProps.getFile(NewConstants.IMAGE_ICON); + final File file = new File(base, event.getIconFilename()); + + final FLabel lblIcon = new FLabel.Builder().iconScaleFactor(1).build(); + if (!file.exists()) { + lblIcon.setIcon(FSkin.getIcon(FSkin.ForgeIcons.ICO_UNKNOWN)); + } + else { + lblIcon.setIcon(new ImageIcon(file.toString())); + } + this.add(lblIcon, "h 60px!, w 60px!, gap 10px 10px 10px 0, span 1 2"); + + // Name + final FLabel lblName = new FLabel.Builder().hoverable(false).build(); + if (event.getEventType() == CHALLENGE) { + lblName.setText(event.getTitle() + ": " + + StringUtils.capitalize(event.getDifficulty()) + + (((QuestChallenge) event).isRepeatable() ? ", Repeatable" : "")); + } + else { + lblName.setText(event.getTitle() + ": " + + StringUtils.capitalize(event.getDifficulty())); + } + this.add(lblName, "h 31px!, gap 0 0 10px 5px, wrap"); + + // Description + final FTextArea tarDesc = new FTextArea(); + tarDesc.setText(event.getDescription()); + + tarDesc.setFont(FSkin.getItalicFont(12)); + this.add(tarDesc, "w 80%!, h 30px!"); + } + + /** @return QuestEvent */ + public QuestEvent getEvent() { + return event; + } + } +} diff --git a/src/main/java/forge/quest/QuestUtil.java b/src/main/java/forge/quest/QuestUtil.java index 6f9507e10f5..6c965163917 100644 --- a/src/main/java/forge/quest/QuestUtil.java +++ b/src/main/java/forge/quest/QuestUtil.java @@ -17,15 +17,12 @@ */ package forge.quest; +import forge.*; +import forge.quest.data.QuestAssets; + import java.util.List; -import forge.AllZone; -import forge.Card; -import forge.CardList; -import forge.CardUtil; -import forge.Player; -import forge.quest.QuestEvent.QuestEventType; -import forge.quest.data.QuestAssets; +import static forge.quest.QuestEvent.QuestEventType.CHALLENGE; /** *

@@ -65,7 +62,7 @@ public class QuestUtil { public static CardList getComputerStartingCards(final QuestEvent qe) { final CardList list = new CardList(); - if (qe.getEventType().equals(QuestEventType.CHALLENGE)) { + if (qe.getEventType() == CHALLENGE) { final List extras = ((QuestChallenge) qe).getAIExtraCards(); for (final String s : extras) { @@ -116,7 +113,7 @@ public class QuestUtil { public static CardList getHumanStartingCards(final QuestAssets qa, final QuestEvent qe) { final CardList list = QuestUtil.getHumanStartingCards(qa); - if (qe.getEventType().equals(QuestEventType.CHALLENGE)) { + if (qe.getEventType() == CHALLENGE) { final List extras = ((QuestChallenge) qe).getHumanExtraCards(); for (final String s : extras) { diff --git a/src/main/java/forge/view/match/QuestWinLoseHandler.java b/src/main/java/forge/view/match/QuestWinLoseHandler.java index b3419166ef9..3e07b6ee64a 100644 --- a/src/main/java/forge/view/match/QuestWinLoseHandler.java +++ b/src/main/java/forge/view/match/QuestWinLoseHandler.java @@ -1,706 +1,694 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Forge Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.view.match; - -import java.awt.Color; -import java.awt.Dimension; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.BorderFactory; -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.SwingConstants; - -import net.slightlymagic.braids.util.UtilFunctions; -import forge.AllZone; -import forge.CardList; -import forge.Constant; -import forge.Constant.Zone; -import forge.Player; -import forge.Singletons; -import forge.control.FControl; -import forge.control.match.ControlWinLose; -import forge.game.GameEndReason; -import forge.game.GameFormat; -import forge.game.GameLossReason; -import forge.game.GameNew; -import forge.game.GamePlayerRating; -import forge.game.GameSummary; -import forge.gui.GuiUtils; -import forge.gui.ListChooser; -import forge.gui.OverlayUtils; -import forge.gui.home.quest.CSubmenuChallenges; -import forge.gui.home.quest.CSubmenuDuels; -import forge.gui.toolbox.FSkin; -import forge.item.CardPrinted; -import forge.model.FMatchState; -import forge.properties.ForgePreferences.FPref; -import forge.quest.QuestChallenge; -import forge.quest.QuestController; -import forge.quest.QuestEvent; -import forge.quest.QuestUtil; -import forge.quest.QuestEvent.QuestEventType; -import forge.quest.data.QuestAssets; -import forge.quest.data.QuestMode; -import forge.quest.data.QuestPreferences.QPref; -import forge.quest.data.item.QuestItemType; -import forge.util.MyRandom; - -/** - *

- * QuestWinLoseHandler. - *

- * Processes win/lose presentation for Quest events. This presentation is - * displayed by WinLoseFrame. Components to be added to pnlCustom in - * WinLoseFrame should use MigLayout. - * - */ -public class QuestWinLoseHandler extends ControlWinLose { - private final transient boolean wonMatch; - private final transient ViewWinLose view; - private transient ImageIcon icoTemp; - private transient JLabel lblTemp1; - private transient JLabel lblTemp2; - private final transient boolean isAnte; - - /** String constraint parameters for title blocks and cardviewer blocks. */ - private static final String CONSTRAINTS_TITLE = "w 95%!, gap 0 0 20px 10px"; - private static final String CONSTRAINTS_TEXT = "w 95%!,, h 180px!, gap 0 0 0 20px"; - private static final String CONSTRAINTS_CARDS = "w 95%!, h 330px!, gap 0 0 0 20px"; - - private final transient FMatchState matchState; - private final transient QuestController qData; - private final transient QuestEvent qEvent; - - /** - * Instantiates a new quest win lose handler. - * - * @param view0 ViewWinLose object - */ - public QuestWinLoseHandler(final ViewWinLose view0) { - super(view0); - this.view = view0; - matchState = Singletons.getModel().getMatchState(); - qData = AllZone.getQuest(); - qEvent = qData.getCurrentEvent(); - this.wonMatch = matchState.isMatchWonBy(AllZone.getHumanPlayer().getName()); - this.isAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE); - } - - /** - *

- * startNextRound. - *

- * Either continues or restarts a current game. - * - */ - @Override - public final void startNextRound() { - Singletons.getModel().savePrefs(); - OverlayUtils.hideOverlay(); - Singletons.getModel().getQuestPreferences().save(); - - QuestAssets qa = qData.getAssets(); - if (qData.getMode() == QuestMode.Fantasy) { - int extraLife = 0; - - if (qEvent.getEventType().equals(QuestEventType.CHALLENGE)) { - if (qa.hasItem(QuestItemType.ZEPPELIN)) { - extraLife = 3; - } - } - - final CardList humanList = QuestUtil.getHumanStartingCards(qa, qEvent); - final CardList computerList = QuestUtil.getComputerStartingCards(qEvent); - - final int humanLife = qa.getLife(qData.getMode()) + extraLife; - int computerLife = 20; - if (qEvent.getEventType().equals("challenge")) { - computerLife = ((QuestChallenge) qEvent).getAILife(); - } - - GameNew.newGame(Constant.Runtime.HUMAN_DECK[0], Constant.Runtime.COMPUTER_DECK[0], - humanList, computerList, humanLife, computerLife, qEvent.getIconFilename()); - } else { - super.startNextRound(); - } - } - - /** - *

- * populateCustomPanel. - *

- * Checks conditions of win and fires various reward display methods - * accordingly. - * - * @return true, if successful - */ - @Override - public final boolean populateCustomPanel() { - this.getView().getBtnRestart().setVisible(false); - qData.getCards().resetNewList(); - - //do per-game actions - if (matchState.hasWonLastGame(AllZone.getHumanPlayer().getName())) { - if (isAnte) { - final CardList antes = AllZone.getComputerPlayer().getCardsIn(Zone.Ante); - final List antesPrinted = Singletons.getModel().getMatchState().addAnteWon(antes); - this.anteWon(antesPrinted); - - } - } else { - if (isAnte) { - final CardList antes = AllZone.getHumanPlayer().getCardsIn(Zone.Ante); - final List antesPrinted = Singletons.getModel().getMatchState().addAnteLost(antes); - for (final CardPrinted ante : antesPrinted) { - //the last param here (should) determine if this is added to the Card Shop - AllZone.getQuest().getCards().sellCard(ante, 0, false); - } - this.anteLost(antesPrinted); - } - } - - if (!matchState.isMatchOver()) { - this.getView().getBtnQuit().setText("Quit (15 Credits)"); - return isAnte; - } else { - this.getView().getBtnContinue().setVisible(false); - if (this.wonMatch) { - this.getView().getBtnQuit().setText("Great!"); - } else { - this.getView().getBtnQuit().setText("OK"); - } - } - - // Win case - if (this.wonMatch) { - // Standard event reward credits - this.awardEventCredits(); - - // Challenge reward credits - if (qEvent.getEventType().equals(QuestEventType.CHALLENGE)) { - this.awardChallengeWin(); - } - - // Random rare given at 50% chance (65% with luck upgrade) - if (this.getLuckyCoinResult()) { - this.awardRandomRare("You've won a random rare."); - } - - // Random rare for winning against a very hard deck - if (qData.getAchievements().getDifficulty() == 4) { - this.awardRandomRare("You've won a random rare for winning against a very hard deck."); - } - - // Award jackpot every 80 games won (currently 10 rares) - final int wins = qData.getAchievements().getWin(); - if ((wins > 0) && ((wins % 80) == 0)) { - this.awardJackpot(); - } - } - // Lose case - else { - this.penalizeLoss(); - } - - // Win or lose, still a chance to win a booster, frequency set in - // preferences - final int outcome = this.wonMatch ? qData.getAchievements().getWin() : qData.getAchievements().getLost(); - if ((outcome % Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.WINS_BOOSTER, qData.getAchievements().getDifficulty())) == 0) { - this.awardBooster(); - } - - // Add any antes won this match (regardless of Match Win/Lose to Card Pool - // Note: Antes lost have already been remove from decks. - Singletons.getModel().getMatchState().addAnteWonToCardPool(); - - return true; - } - - /** - *

- * anteLost. - *

- * Displays cards lost to ante this game. - * - */ - private void anteLost(final List antesLost) { - // Generate Swing components and attach. - this.lblTemp1 = new TitleLabel("Ante Lost: You lost the following cards in Ante:"); - - this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); - this.getView().getPnlCustom().add( - new QuestWinLoseCardViewer(antesLost), QuestWinLoseHandler.CONSTRAINTS_CARDS); - } - - /** - *

- * anteWon. - *

- * Displays cards won in ante this game (which will be added to your Card Pool). - * - */ - private void anteWon(final List antesWon) { - final StringBuilder str = new StringBuilder(); - str.append("Ante Won: These cards will be available in your card pool after this match."); - // Generate Swing components and attach. - this.lblTemp1 = new TitleLabel(str.toString()); - - this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); - this.getView().getPnlCustom().add( - new QuestWinLoseCardViewer(antesWon), QuestWinLoseHandler.CONSTRAINTS_CARDS); - } - - /** - *

- * actionOnQuit. - *

- * When "quit" button is pressed, this method adjusts quest data as - * appropriate and saves. - * - */ - @Override - public final void actionOnQuit() { - final int x = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.PENALTY_LOSS); - - // Record win/loss in quest data - if (this.wonMatch) { - qData.getAchievements().addWin(); - } else { - qData.getAchievements().addLost(); - qData.getAssets().subtractCredits(x); - } - - qData.getCards().clearShopList(); - - if (!((QuestChallenge) qEvent).isRepeatable()) { - qData.getAchievements().addCompletedChallenge(((QuestChallenge) qEvent).getId()); - } - - if (qData.getAvailableChallenges() != null) { - qData.clearAvailableChallenges(); - } - - matchState.reset(); - CSubmenuDuels.SINGLETON_INSTANCE.update(); - CSubmenuChallenges.SINGLETON_INSTANCE.update(); - - qData.setCurrentEvent(null); - qData.save(); - Singletons.getModel().getQuestPreferences().save(); - Singletons.getModel().savePrefs(); - - Singletons.getControl().changeState(FControl.HOME_SCREEN); - - OverlayUtils.hideOverlay(); - } - - /** - *

- * awardEventCredits. - *

- * Generates and displays standard rewards for gameplay and skill level. - * - */ - private void awardEventCredits() { - // TODO use q.qdPrefs to write bonus credits in prefs file - final StringBuilder sb = new StringBuilder(""); - - int credTotal = 0; - int credBase = 0; - int credGameplay = 0; - int credUndefeated = 0; - int credEstates = 0; - - // Basic win bonus - final int base = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_BASE); - double multiplier = 1; - - String diff = qEvent.getDifficulty(); - diff = diff.substring(0, 1).toUpperCase() + diff.substring(1); - - if (diff.equalsIgnoreCase("medium")) { - multiplier = 1.5; - } else if (diff.equalsIgnoreCase("hard")) { - multiplier = 2; - } else if (diff.equalsIgnoreCase("very hard")) { - multiplier = 2.5; - } else if (diff.equalsIgnoreCase("expert")) { - multiplier = 3; - } - - credBase += (int) ((base * multiplier) - + (Double.parseDouble(Singletons.getModel().getQuestPreferences().getPreference(QPref.REWARDS_WINS_MULTIPLIER)) - * qData.getAchievements().getWin())); - - sb.append(diff + " opponent: " + credBase + " credits.
"); - // Gameplay bonuses (for each game win) - boolean hasNeverLost = true; - final Player computer = AllZone.getComputerPlayer(); - for (final GameSummary game : matchState.getGamesPlayed()) { - if (game.isWinner(computer.getName())) { - hasNeverLost = false; - continue; // no rewards for losing a game - } - // Alternate win - final GamePlayerRating aiRating = game.getPlayerRating(computer.getName()); - final GamePlayerRating humanRating = game.getPlayerRating(AllZone.getHumanPlayer().getName()); - final GameLossReason whyAiLost = aiRating.getLossReason(); - final int altReward = this.getCreditsRewardForAltWin(whyAiLost); - - if (altReward > 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; - case SpellEffect: - winConditionName = aiRating.getLossSpellName(); - break; - default: - break; - } - } - - credGameplay += 50; - sb.append(String.format("Alternate win condition: %s! " + "Bonus: %d credits.
", - winConditionName, 50)); - } - // Mulligan to zero - final int cntCardsHumanStartedWith = humanRating.getOpeningHandSize(); - final int mulliganReward = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_MULLIGAN0); - - if (0 == cntCardsHumanStartedWith) { - credGameplay += mulliganReward; - sb.append(String - .format("Mulliganed to zero and still won! " + "Bonus: %d credits.
", mulliganReward)); - } - - // Early turn bonus - final int winTurn = game.getTurnGameEnded(); - final int turnCredits = this.getCreditsRewardForWinByTurn(winTurn); - - if (winTurn == 0) { - throw new UnsupportedOperationException("QuestWinLoseHandler > " + "turn calculation error: Zero turn win"); - } 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) { - credGameplay += turnCredits; - sb.append(String.format(" Bonus: %d credits.
", turnCredits)); - } - } // End for(game) - - // Undefeated bonus - if (hasNeverLost) { - credUndefeated += Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_UNDEFEATED); - final int reward = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_UNDEFEATED); - sb.append(String.format("You have not lost once! " + "Bonus: %d credits.
", reward)); - } - - // Estates bonus - credTotal = credBase + credGameplay + credUndefeated; - double estateValue = 0; - switch (qData.getAssets().getItemLevel(QuestItemType.ESTATES)) { - case 1: - estateValue = .1; - break; - - case 2: - estateValue = .15; - break; - - case 3: - estateValue = .2; - break; - - default: - break; - } - if (estateValue > 0) { - credEstates = (int) (estateValue * credTotal); - sb.append("Estates bonus: ").append((int) (100 * estateValue)).append("%.
"); - credTotal += credEstates; - } - - // Final output - String congrats = "

"; - if (credTotal < 100) { - congrats += "You've earned"; - } else if (credTotal < 250) { - congrats += "Could be worse: "; - } else if (credTotal < 500) { - congrats += "A respectable"; - } else if (credTotal < 750) { - congrats += "An impressive"; - } else { - congrats += "Spectacular match!"; - } - - sb.append(String.format("%s %d credits in total.

", congrats, credTotal)); - sb.append(""); - qData.getAssets().addCredits(credTotal); - - // Generate Swing components and attach. - this.icoTemp = GuiUtils.getResizedIcon(FSkin.getIcon(FSkin.QuestIcons.ICO_GOLD), 0.5); - - this.lblTemp1 = new TitleLabel("Gameplay Results"); - - this.lblTemp2 = new JLabel(sb.toString()); - this.lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); - this.lblTemp2.setFont(FSkin.getFont(14)); - this.lblTemp2.setForeground(Color.white); - this.lblTemp2.setIcon(this.icoTemp); - this.lblTemp2.setIconTextGap(50); - - this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); - this.getView().getPnlCustom().add(this.lblTemp2, QuestWinLoseHandler.CONSTRAINTS_TEXT); - } - - /** - *

- * awardRandomRare. - *

- * Generates and displays a random rare win case. - * - */ - private void awardRandomRare(final String message) { - final CardPrinted c = qData.getCards().addRandomRare(); - final List cardsWon = new ArrayList(); - cardsWon.add(c); - - // Generate Swing components and attach. - this.lblTemp1 = new TitleLabel(message); - - final QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); - - this.view.getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); - this.view.getPnlCustom().add(cv, QuestWinLoseHandler.CONSTRAINTS_CARDS); - } - - /** - *

- * awardJackpot. - *

- * Generates and displays jackpot win case. - * - */ - private void awardJackpot() { - final List cardsWon = qData.getCards().addRandomRare(10); - - // Generate Swing components and attach. - this.lblTemp1 = new TitleLabel("You just won 10 random rares!"); - final QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); - - this.view.getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); - this.view.getPnlCustom().add(cv, QuestWinLoseHandler.CONSTRAINTS_CARDS); - } - - /** - *

- * awardBooster. - *

- * Generates and displays booster pack win case. - * - */ - private void awardBooster() { - final GameFormat[] formats = UtilFunctions.iteratorToArray(Singletons.getModel().getFormats().iterator(), new GameFormat[]{}); - final ListChooser ch = new ListChooser("Choose bonus booster format", 1, formats); - - String prefferedFormat = Singletons.getModel().getQuestPreferences().getPreference(QPref.BOOSTER_FORMAT); - int index = 0; - for (int i = 0; i < formats.length; i++) { - if (formats[i].toString().equals(prefferedFormat)) { - index = i; - break; - } - } - - ch.show(index); - - final GameFormat selected = ch.getSelectedValue(); - Singletons.getModel().getQuestPreferences().setPreference(QPref.BOOSTER_FORMAT, selected.toString()); - - final List cardsWon = qData.getCards().addCards(selected.getFilterPrinted()); - - // Generate Swing components and attach. - this.lblTemp1 = new TitleLabel("Bonus booster pack from the \"" + selected.getName() + "\" format!"); - final QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); - - this.view.getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); - this.view.getPnlCustom().add(cv, QuestWinLoseHandler.CONSTRAINTS_CARDS); - } - - /** - *

- * awardChallengeWin. - *

- * Generates and displays win case for challenge event. - * - */ - private void awardChallengeWin() { - // This method should perhaps be called addChallengesWon() since it's actually - // used for "wins before next challenge" - qData.getAchievements().addChallengesPlayed(); - - final List cardsWon = ((QuestChallenge) qEvent).getCardRewardList(); - final long questRewardCredits = ((QuestChallenge) qEvent).getCreditsReward(); - - final StringBuilder sb = new StringBuilder(); - sb.append("Challenge completed.

"); - sb.append("Challenge bounty: " + questRewardCredits + " credits."); - - qData.getAssets().addCredits(questRewardCredits); - - // Generate Swing components and attach. - this.icoTemp = GuiUtils.getResizedIcon(FSkin.getIcon(FSkin.QuestIcons.ICO_BOX), 0.5); - this.lblTemp1 = new TitleLabel("Challenge Rewards for \"" + ((QuestChallenge) qEvent).getTitle() - + "\""); - - this.lblTemp2 = new JLabel(sb.toString()); - this.lblTemp2.setFont(FSkin.getFont(14)); - this.lblTemp2.setForeground(Color.white); - this.lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); - this.lblTemp2.setIconTextGap(50); - this.lblTemp2.setIcon(this.icoTemp); - - this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); - this.getView().getPnlCustom().add(this.lblTemp2, QuestWinLoseHandler.CONSTRAINTS_TEXT); - - if (cardsWon != null) { - final QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); - this.getView().getPnlCustom().add(cv, QuestWinLoseHandler.CONSTRAINTS_CARDS); - qData.getCards().addAllCards(cardsWon); - } - } - - private void penalizeLoss() { - final int x = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.PENALTY_LOSS); - this.icoTemp = GuiUtils.getResizedIcon(FSkin.getIcon(FSkin.QuestIcons.ICO_HEART), 0.5); - - this.lblTemp1 = new TitleLabel("Gameplay Results"); - - this.lblTemp2 = new JLabel("You lose! You have lost " + x + " credits."); - this.lblTemp2.setFont(FSkin.getFont(14)); - this.lblTemp2.setForeground(Color.white); - this.lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); - this.lblTemp2.setIconTextGap(50); - this.lblTemp2.setIcon(this.icoTemp); - - this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); - this.getView().getPnlCustom().add(this.lblTemp2, QuestWinLoseHandler.CONSTRAINTS_TEXT); - } - - /** - *

- * getLuckyCoinResult. - *

- * A chance check, for rewards like random rares. - * - * @return boolean - */ - private boolean getLuckyCoinResult() { - final boolean hasCoin = qData.getAssets().getItemLevel(QuestItemType.LUCKY_COIN) >= 1; - - return MyRandom.getRandom().nextFloat() <= (hasCoin ? 0.65f : 0.5f); - } - - /** - *

- * getCreditsRewardForAltWin. - *

- * Retrieves credits for win under special conditions. - * - * @param GameLossReason - * why AI lost - * @return int - */ - private int getCreditsRewardForAltWin(final GameLossReason whyAiLost) { - switch (whyAiLost) { - case LifeReachedZero: - return 0; // nothing special here, ordinary kill - case Milled: - return Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_MILLED); - case Poisoned: - return Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_POISON); - case DidNotLoseYet: // Felidar, Helix Pinnacle, etc. - return Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_UNDEFEATED); - case SpellEffect: // Door to Nothingness, etc. - return Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_UNDEFEATED); - default: - return 0; - } - } - - /** - *

- * getCreditsRewardForWinByTurn. - *

- * Retrieves credits for win on or under turn count. - * - * @param int turn count - * @return int credits won - */ - private int getCreditsRewardForWinByTurn(final int iTurn) { - int credits; - - if (iTurn == 1) { - credits = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_TURN1); - } else if (iTurn <= 5) { - credits = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_TURN5); - } else if (iTurn <= 10) { - credits = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_TURN10); - } else if (iTurn <= 15) { - credits = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_TURN15); - } else { - credits = 0; - } - - return credits; - } - - /** - * JLabel header between reward sections. - * - */ - @SuppressWarnings("serial") - private class TitleLabel extends JLabel { - TitleLabel(final String msg) { - super(msg); - this.setFont(FSkin.getFont(16)); - this.setPreferredSize(new Dimension(200, 40)); - this.setHorizontalAlignment(SwingConstants.CENTER); - this.setForeground(Color.white); - this.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.white)); - } - } -} +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Forge Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.view.match; + +import forge.*; +import forge.Constant.Zone; +import forge.control.FControl; +import forge.control.match.ControlWinLose; +import forge.game.*; +import forge.gui.GuiUtils; +import forge.gui.ListChooser; +import forge.gui.OverlayUtils; +import forge.gui.home.quest.CSubmenuChallenges; +import forge.gui.home.quest.CSubmenuDuels; +import forge.gui.toolbox.FSkin; +import forge.item.CardPrinted; +import forge.model.FMatchState; +import forge.properties.ForgePreferences.FPref; +import forge.quest.QuestChallenge; +import forge.quest.QuestController; +import forge.quest.QuestEvent; +import forge.quest.QuestUtil; +import forge.quest.data.QuestAssets; +import forge.quest.data.QuestMode; +import forge.quest.data.QuestPreferences.QPref; +import forge.quest.data.item.QuestItemType; +import forge.util.MyRandom; +import net.slightlymagic.braids.util.UtilFunctions; + +import javax.swing.*; +import java.awt.Color; +import java.awt.Dimension; +import java.util.ArrayList; +import java.util.List; + +import static forge.quest.QuestEvent.QuestEventType.CHALLENGE; + +/** + *

+ * QuestWinLoseHandler. + *

+ * Processes win/lose presentation for Quest events. This presentation is + * displayed by WinLoseFrame. Components to be added to pnlCustom in + * WinLoseFrame should use MigLayout. + * + */ +public class QuestWinLoseHandler extends ControlWinLose { + private final transient boolean wonMatch; + private final transient ViewWinLose view; + private transient ImageIcon icoTemp; + private transient JLabel lblTemp1; + private transient JLabel lblTemp2; + private final transient boolean isAnte; + + /** String constraint parameters for title blocks and cardviewer blocks. */ + private static final String CONSTRAINTS_TITLE = "w 95%!, gap 0 0 20px 10px"; + private static final String CONSTRAINTS_TEXT = "w 95%!,, h 180px!, gap 0 0 0 20px"; + private static final String CONSTRAINTS_CARDS = "w 95%!, h 330px!, gap 0 0 0 20px"; + + private final transient FMatchState matchState; + private final transient QuestController qData; + private final transient QuestEvent qEvent; + + /** + * Instantiates a new quest win lose handler. + * + * @param view0 ViewWinLose object + */ + public QuestWinLoseHandler(final ViewWinLose view0) { + super(view0); + this.view = view0; + matchState = Singletons.getModel().getMatchState(); + qData = AllZone.getQuest(); + qEvent = qData.getCurrentEvent(); + this.wonMatch = matchState.isMatchWonBy(AllZone.getHumanPlayer().getName()); + this.isAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE); + } + + /** + *

+ * startNextRound. + *

+ * Either continues or restarts a current game. + * + */ + @Override + public final void startNextRound() { + Singletons.getModel().savePrefs(); + OverlayUtils.hideOverlay(); + Singletons.getModel().getQuestPreferences().save(); + + QuestAssets qa = qData.getAssets(); + if (qData.getMode() == QuestMode.Fantasy) { + int extraLife = 0; + + if (qEvent.getEventType() == CHALLENGE) { + if (qa.hasItem(QuestItemType.ZEPPELIN)) { + extraLife = 3; + } + } + + final CardList humanList = QuestUtil.getHumanStartingCards(qa, qEvent); + final CardList computerList = QuestUtil.getComputerStartingCards(qEvent); + + final int humanLife = qa.getLife(qData.getMode()) + extraLife; + int computerLife = 20; + if (qEvent.getEventType() == CHALLENGE) { + computerLife = ((QuestChallenge) qEvent).getAILife(); + } + + GameNew.newGame(Constant.Runtime.HUMAN_DECK[0], Constant.Runtime.COMPUTER_DECK[0], + humanList, computerList, humanLife, computerLife, qEvent.getIconFilename()); + } else { + super.startNextRound(); + } + } + + /** + *

+ * populateCustomPanel. + *

+ * Checks conditions of win and fires various reward display methods + * accordingly. + * + * @return true, if successful + */ + @Override + public final boolean populateCustomPanel() { + this.getView().getBtnRestart().setVisible(false); + qData.getCards().resetNewList(); + + //do per-game actions + if (matchState.hasWonLastGame(AllZone.getHumanPlayer().getName())) { + if (isAnte) { + final CardList antes = AllZone.getComputerPlayer().getCardsIn(Zone.Ante); + final List antesPrinted = Singletons.getModel().getMatchState().addAnteWon(antes); + this.anteWon(antesPrinted); + + } + } else { + if (isAnte) { + final CardList antes = AllZone.getHumanPlayer().getCardsIn(Zone.Ante); + final List antesPrinted = Singletons.getModel().getMatchState().addAnteLost(antes); + for (final CardPrinted ante : antesPrinted) { + //the last param here (should) determine if this is added to the Card Shop + AllZone.getQuest().getCards().sellCard(ante, 0, false); + } + this.anteLost(antesPrinted); + } + } + + if (!matchState.isMatchOver()) { + this.getView().getBtnQuit().setText("Quit (15 Credits)"); + return isAnte; + } else { + this.getView().getBtnContinue().setVisible(false); + if (this.wonMatch) { + this.getView().getBtnQuit().setText("Great!"); + } else { + this.getView().getBtnQuit().setText("OK"); + } + } + + // Win case + if (this.wonMatch) { + // Standard event reward credits + this.awardEventCredits(); + + // Challenge reward credits + if (qEvent.getEventType() == CHALLENGE) { + this.awardChallengeWin(); + } + + // Random rare given at 50% chance (65% with luck upgrade) + if (this.getLuckyCoinResult()) { + this.awardRandomRare("You've won a random rare."); + } + + // Random rare for winning against a very hard deck + if (qData.getAchievements().getDifficulty() == 4) { + this.awardRandomRare("You've won a random rare for winning against a very hard deck."); + } + + // Award jackpot every 80 games won (currently 10 rares) + final int wins = qData.getAchievements().getWin(); + if ((wins > 0) && ((wins % 80) == 0)) { + this.awardJackpot(); + } + } + // Lose case + else { + this.penalizeLoss(); + } + + // Win or lose, still a chance to win a booster, frequency set in + // preferences + final int outcome = this.wonMatch ? qData.getAchievements().getWin() : qData.getAchievements().getLost(); + if ((outcome % Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.WINS_BOOSTER, qData.getAchievements().getDifficulty())) == 0) { + this.awardBooster(); + } + + // Add any antes won this match (regardless of Match Win/Lose to Card Pool + // Note: Antes lost have already been remove from decks. + Singletons.getModel().getMatchState().addAnteWonToCardPool(); + + return true; + } + + /** + *

+ * anteLost. + *

+ * Displays cards lost to ante this game. + * + */ + private void anteLost(final List antesLost) { + // Generate Swing components and attach. + this.lblTemp1 = new TitleLabel("Ante Lost: You lost the following cards in Ante:"); + + this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); + this.getView().getPnlCustom().add( + new QuestWinLoseCardViewer(antesLost), QuestWinLoseHandler.CONSTRAINTS_CARDS); + } + + /** + *

+ * anteWon. + *

+ * Displays cards won in ante this game (which will be added to your Card Pool). + * + */ + private void anteWon(final List antesWon) { + final StringBuilder str = new StringBuilder(); + str.append("Ante Won: These cards will be available in your card pool after this match."); + // Generate Swing components and attach. + this.lblTemp1 = new TitleLabel(str.toString()); + + this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); + this.getView().getPnlCustom().add( + new QuestWinLoseCardViewer(antesWon), QuestWinLoseHandler.CONSTRAINTS_CARDS); + } + + /** + *

+ * actionOnQuit. + *

+ * When "quit" button is pressed, this method adjusts quest data as + * appropriate and saves. + * + */ + @Override + public final void actionOnQuit() { + final int x = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.PENALTY_LOSS); + + // Record win/loss in quest data + if (this.wonMatch) { + qData.getAchievements().addWin(); + } else { + qData.getAchievements().addLost(); + qData.getAssets().subtractCredits(x); + } + + qData.getCards().clearShopList(); + + if (qEvent.getEventType() == CHALLENGE && !((QuestChallenge) qEvent).isRepeatable()) { + qData.getAchievements().addCompletedChallenge(((QuestChallenge) qEvent).getId()); + } + + if (qData.getAvailableChallenges() != null) { + qData.clearAvailableChallenges(); + } + + matchState.reset(); + CSubmenuDuels.SINGLETON_INSTANCE.update(); + CSubmenuChallenges.SINGLETON_INSTANCE.update(); + + qData.setCurrentEvent(null); + qData.save(); + Singletons.getModel().getQuestPreferences().save(); + Singletons.getModel().savePrefs(); + + Singletons.getControl().changeState(FControl.HOME_SCREEN); + + OverlayUtils.hideOverlay(); + } + + /** + *

+ * awardEventCredits. + *

+ * Generates and displays standard rewards for gameplay and skill level. + * + */ + private void awardEventCredits() { + // TODO use q.qdPrefs to write bonus credits in prefs file + final StringBuilder sb = new StringBuilder(""); + + int credTotal = 0; + int credBase = 0; + int credGameplay = 0; + int credUndefeated = 0; + int credEstates = 0; + + // Basic win bonus + final int base = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_BASE); + double multiplier = 1; + + String diff = qEvent.getDifficulty(); + diff = diff.substring(0, 1).toUpperCase() + diff.substring(1); + + if (diff.equalsIgnoreCase("medium")) { + multiplier = 1.5; + } else if (diff.equalsIgnoreCase("hard")) { + multiplier = 2; + } else if (diff.equalsIgnoreCase("very hard")) { + multiplier = 2.5; + } else if (diff.equalsIgnoreCase("expert")) { + multiplier = 3; + } + + credBase += (int) ((base * multiplier) + + (Double.parseDouble(Singletons.getModel().getQuestPreferences().getPreference(QPref.REWARDS_WINS_MULTIPLIER)) + * qData.getAchievements().getWin())); + + sb.append(diff + " opponent: " + credBase + " credits.
"); + // Gameplay bonuses (for each game win) + boolean hasNeverLost = true; + final Player computer = AllZone.getComputerPlayer(); + for (final GameSummary game : matchState.getGamesPlayed()) { + if (game.isWinner(computer.getName())) { + hasNeverLost = false; + continue; // no rewards for losing a game + } + // Alternate win + final GamePlayerRating aiRating = game.getPlayerRating(computer.getName()); + final GamePlayerRating humanRating = game.getPlayerRating(AllZone.getHumanPlayer().getName()); + final GameLossReason whyAiLost = aiRating.getLossReason(); + final int altReward = this.getCreditsRewardForAltWin(whyAiLost); + + if (altReward > 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; + case SpellEffect: + winConditionName = aiRating.getLossSpellName(); + break; + default: + break; + } + } + + credGameplay += 50; + sb.append(String.format("Alternate win condition: %s! " + "Bonus: %d credits.
", + winConditionName, 50)); + } + // Mulligan to zero + final int cntCardsHumanStartedWith = humanRating.getOpeningHandSize(); + final int mulliganReward = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_MULLIGAN0); + + if (0 == cntCardsHumanStartedWith) { + credGameplay += mulliganReward; + sb.append(String + .format("Mulliganed to zero and still won! " + "Bonus: %d credits.
", mulliganReward)); + } + + // Early turn bonus + final int winTurn = game.getTurnGameEnded(); + final int turnCredits = this.getCreditsRewardForWinByTurn(winTurn); + + if (winTurn == 0) { + throw new UnsupportedOperationException("QuestWinLoseHandler > " + "turn calculation error: Zero turn win"); + } 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) { + credGameplay += turnCredits; + sb.append(String.format(" Bonus: %d credits.
", turnCredits)); + } + } // End for(game) + + // Undefeated bonus + if (hasNeverLost) { + credUndefeated += Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_UNDEFEATED); + final int reward = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_UNDEFEATED); + sb.append(String.format("You have not lost once! " + "Bonus: %d credits.
", reward)); + } + + // Estates bonus + credTotal = credBase + credGameplay + credUndefeated; + double estateValue = 0; + switch (qData.getAssets().getItemLevel(QuestItemType.ESTATES)) { + case 1: + estateValue = .1; + break; + + case 2: + estateValue = .15; + break; + + case 3: + estateValue = .2; + break; + + default: + break; + } + if (estateValue > 0) { + credEstates = (int) (estateValue * credTotal); + sb.append("Estates bonus: ").append((int) (100 * estateValue)).append("%.
"); + credTotal += credEstates; + } + + // Final output + String congrats = "

"; + if (credTotal < 100) { + congrats += "You've earned"; + } else if (credTotal < 250) { + congrats += "Could be worse: "; + } else if (credTotal < 500) { + congrats += "A respectable"; + } else if (credTotal < 750) { + congrats += "An impressive"; + } else { + congrats += "Spectacular match!"; + } + + sb.append(String.format("%s %d credits in total.

", congrats, credTotal)); + sb.append(""); + qData.getAssets().addCredits(credTotal); + + // Generate Swing components and attach. + this.icoTemp = GuiUtils.getResizedIcon(FSkin.getIcon(FSkin.QuestIcons.ICO_GOLD), 0.5); + + this.lblTemp1 = new TitleLabel("Gameplay Results"); + + this.lblTemp2 = new JLabel(sb.toString()); + this.lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); + this.lblTemp2.setFont(FSkin.getFont(14)); + this.lblTemp2.setForeground(Color.white); + this.lblTemp2.setIcon(this.icoTemp); + this.lblTemp2.setIconTextGap(50); + + this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); + this.getView().getPnlCustom().add(this.lblTemp2, QuestWinLoseHandler.CONSTRAINTS_TEXT); + } + + /** + *

+ * awardRandomRare. + *

+ * Generates and displays a random rare win case. + * + */ + private void awardRandomRare(final String message) { + final CardPrinted c = qData.getCards().addRandomRare(); + final List cardsWon = new ArrayList(); + cardsWon.add(c); + + // Generate Swing components and attach. + this.lblTemp1 = new TitleLabel(message); + + final QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); + + this.view.getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); + this.view.getPnlCustom().add(cv, QuestWinLoseHandler.CONSTRAINTS_CARDS); + } + + /** + *

+ * awardJackpot. + *

+ * Generates and displays jackpot win case. + * + */ + private void awardJackpot() { + final List cardsWon = qData.getCards().addRandomRare(10); + + // Generate Swing components and attach. + this.lblTemp1 = new TitleLabel("You just won 10 random rares!"); + final QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); + + this.view.getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); + this.view.getPnlCustom().add(cv, QuestWinLoseHandler.CONSTRAINTS_CARDS); + } + + /** + *

+ * awardBooster. + *

+ * Generates and displays booster pack win case. + * + */ + private void awardBooster() { + final GameFormat[] formats = UtilFunctions.iteratorToArray(Singletons.getModel().getFormats().iterator(), new GameFormat[]{}); + final ListChooser ch = new ListChooser("Choose bonus booster format", 1, formats); + + String prefferedFormat = Singletons.getModel().getQuestPreferences().getPreference(QPref.BOOSTER_FORMAT); + int index = 0; + for (int i = 0; i < formats.length; i++) { + if (formats[i].toString().equals(prefferedFormat)) { + index = i; + break; + } + } + + ch.show(index); + + final GameFormat selected = ch.getSelectedValue(); + Singletons.getModel().getQuestPreferences().setPreference(QPref.BOOSTER_FORMAT, selected.toString()); + + final List cardsWon = qData.getCards().addCards(selected.getFilterPrinted()); + + // Generate Swing components and attach. + this.lblTemp1 = new TitleLabel("Bonus booster pack from the \"" + selected.getName() + "\" format!"); + final QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); + + this.view.getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); + this.view.getPnlCustom().add(cv, QuestWinLoseHandler.CONSTRAINTS_CARDS); + } + + /** + *

+ * awardChallengeWin. + *

+ * Generates and displays win case for challenge event. + * + */ + private void awardChallengeWin() { + // This method should perhaps be called addChallengesWon() since it's actually + // used for "wins before next challenge" + qData.getAchievements().addChallengesPlayed(); + + final List cardsWon = ((QuestChallenge) qEvent).getCardRewardList(); + final long questRewardCredits = ((QuestChallenge) qEvent).getCreditsReward(); + + final StringBuilder sb = new StringBuilder(); + sb.append("Challenge completed.

"); + sb.append("Challenge bounty: " + questRewardCredits + " credits."); + + qData.getAssets().addCredits(questRewardCredits); + + // Generate Swing components and attach. + this.icoTemp = GuiUtils.getResizedIcon(FSkin.getIcon(FSkin.QuestIcons.ICO_BOX), 0.5); + this.lblTemp1 = new TitleLabel("Challenge Rewards for \"" + ((QuestChallenge) qEvent).getTitle() + + "\""); + + this.lblTemp2 = new JLabel(sb.toString()); + this.lblTemp2.setFont(FSkin.getFont(14)); + this.lblTemp2.setForeground(Color.white); + this.lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); + this.lblTemp2.setIconTextGap(50); + this.lblTemp2.setIcon(this.icoTemp); + + this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); + this.getView().getPnlCustom().add(this.lblTemp2, QuestWinLoseHandler.CONSTRAINTS_TEXT); + + if (cardsWon != null) { + final QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); + this.getView().getPnlCustom().add(cv, QuestWinLoseHandler.CONSTRAINTS_CARDS); + qData.getCards().addAllCards(cardsWon); + } + } + + private void penalizeLoss() { + final int x = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.PENALTY_LOSS); + this.icoTemp = GuiUtils.getResizedIcon(FSkin.getIcon(FSkin.QuestIcons.ICO_HEART), 0.5); + + this.lblTemp1 = new TitleLabel("Gameplay Results"); + + this.lblTemp2 = new JLabel("You lose! You have lost " + x + " credits."); + this.lblTemp2.setFont(FSkin.getFont(14)); + this.lblTemp2.setForeground(Color.white); + this.lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); + this.lblTemp2.setIconTextGap(50); + this.lblTemp2.setIcon(this.icoTemp); + + this.getView().getPnlCustom().add(this.lblTemp1, QuestWinLoseHandler.CONSTRAINTS_TITLE); + this.getView().getPnlCustom().add(this.lblTemp2, QuestWinLoseHandler.CONSTRAINTS_TEXT); + } + + /** + *

+ * getLuckyCoinResult. + *

+ * A chance check, for rewards like random rares. + * + * @return boolean + */ + private boolean getLuckyCoinResult() { + final boolean hasCoin = qData.getAssets().getItemLevel(QuestItemType.LUCKY_COIN) >= 1; + + return MyRandom.getRandom().nextFloat() <= (hasCoin ? 0.65f : 0.5f); + } + + /** + *

+ * getCreditsRewardForAltWin. + *

+ * Retrieves credits for win under special conditions. + * + * @param GameLossReason + * why AI lost + * @return int + */ + private int getCreditsRewardForAltWin(final GameLossReason whyAiLost) { + switch (whyAiLost) { + case LifeReachedZero: + return 0; // nothing special here, ordinary kill + case Milled: + return Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_MILLED); + case Poisoned: + return Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_POISON); + case DidNotLoseYet: // Felidar, Helix Pinnacle, etc. + return Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_UNDEFEATED); + case SpellEffect: // Door to Nothingness, etc. + return Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_UNDEFEATED); + default: + return 0; + } + } + + /** + *

+ * getCreditsRewardForWinByTurn. + *

+ * Retrieves credits for win on or under turn count. + * + * @param int turn count + * @return int credits won + */ + private int getCreditsRewardForWinByTurn(final int iTurn) { + int credits; + + if (iTurn == 1) { + credits = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_TURN1); + } else if (iTurn <= 5) { + credits = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_TURN5); + } else if (iTurn <= 10) { + credits = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_TURN10); + } else if (iTurn <= 15) { + credits = Singletons.getModel().getQuestPreferences().getPreferenceInt(QPref.REWARDS_TURN15); + } else { + credits = 0; + } + + return credits; + } + + /** + * JLabel header between reward sections. + * + */ + @SuppressWarnings("serial") + private class TitleLabel extends JLabel { + TitleLabel(final String msg) { + super(msg); + this.setFont(FSkin.getFont(16)); + this.setPreferredSize(new Dimension(200, 40)); + this.setHorizontalAlignment(SwingConstants.CENTER); + this.setForeground(Color.white); + this.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.white)); + } + } +}