diff --git a/.gitattributes b/.gitattributes index bb3e3887384..b1b0cbb5f5e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10240,6 +10240,8 @@ src/main/java/forge/quest/gui/QuestAbstractPanel.java svneol=native#text/plain src/main/java/forge/quest/gui/QuestFrame.java svneol=native#text/plain src/main/java/forge/quest/gui/QuestMainPanel.java -text src/main/java/forge/quest/gui/QuestOptions.java svneol=native#text/plain +src/main/java/forge/quest/gui/QuestWinLoseCardViewer.java -text +src/main/java/forge/quest/gui/QuestWinLoseHandler.java -text src/main/java/forge/quest/gui/bazaar/QuestBazaarItem.java svneol=native#text/plain src/main/java/forge/quest/gui/bazaar/QuestBazaarPanel.java svneol=native#text/plain src/main/java/forge/quest/gui/bazaar/QuestBazaarStall.java svneol=native#text/plain @@ -10263,6 +10265,8 @@ src/main/java/forge/view/swing/OldGuiNewGame.java svneol=native#text/plain src/main/java/forge/view/swing/SplashFrame.java -text src/main/java/forge/view/swing/SplashProgressComponent.java -text src/main/java/forge/view/swing/SplashProgressModel.java -text +src/main/java/forge/view/swing/WinLoseFrame.java -text +src/main/java/forge/view/swing/WinLoseModeHandler.java -text src/main/java/forge/view/swing/package-info.java svneol=native#text/plain src/main/java/net/slightlymagic/braids/LICENSE.txt svneol=native#text/plain src/main/java/net/slightlymagic/braids/util/ClumsyRunnable.java svneol=native#text/plain diff --git a/src/main/java/forge/GameAction.java b/src/main/java/forge/GameAction.java index 6e8b6e46dd3..d977ef81ba3 100644 --- a/src/main/java/forge/GameAction.java +++ b/src/main/java/forge/GameAction.java @@ -29,8 +29,10 @@ import forge.gui.input.Input_PayManaCost_Ability; import forge.item.CardPrinted; import forge.properties.ForgeProps; import forge.properties.NewConstants.LANG.GameAction.GAMEACTION_TEXT; +import forge.quest.gui.QuestWinLoseHandler; import forge.quest.gui.main.QuestChallenge; import forge.quest.gui.main.QuestEvent; +import forge.view.swing.WinLoseFrame; import java.util.ArrayList; import java.util.Arrays; @@ -655,13 +657,27 @@ public class GameAction { AllZone.getDisplay().savePrefs(); frame.setEnabled(false); //frame.dispose(); - Gui_WinLose gwl = new Gui_WinLose(AllZone.getMatchState(), AllZone.getQuestData(), AllZone.getQuestEvent()); + + //Gui_WinLose gwl = new Gui_WinLose(AllZone.getMatchState(), AllZone.getQuestData(), AllZone.getQuestChallenge()); + + // New WinLoseFrame below. Old Gui_WinLose above. + // Old code should still work if any problems with new. Doublestrike 02-10-11 + WinLoseFrame gwl; + + if(AllZone.getQuestData() != null) { + gwl = new WinLoseFrame(new QuestWinLoseHandler()); + } + else { + gwl = new WinLoseFrame(); + } + //gwl.setAlwaysOnTop(true); gwl.toFront(); canShowWinLose = false; return; } + //do this twice, sometimes creatures/permanents will survive when they shouldn't for (int q = 0; q < 9; q++) { diff --git a/src/main/java/forge/gui/GuiUtils.java b/src/main/java/forge/gui/GuiUtils.java index f4abc159e84..eb8cccc3d41 100644 --- a/src/main/java/forge/gui/GuiUtils.java +++ b/src/main/java/forge/gui/GuiUtils.java @@ -113,18 +113,48 @@ public final class GuiUtils { /** *

getIconFromFile.

* - * @param iconName a {@link java.lang.String} object. + * @param filename a {@link java.lang.String} object. * @return a {@link javax.swing.ImageIcon} object. */ - public static ImageIcon getIconFromFile(final String iconName) { + public static ImageIcon getIconFromFile(final String filename) { File base = ForgeProps.getFile(NewConstants.IMAGE_ICON); - File file = new File(base, iconName); - if (iconName.equals("") || !file.exists()) { + File file = new File(base, filename); + if (filename.equals("") || !file.exists()) { return null; } else { return new ImageIcon(file.toString()); } } + + /** + *

getResizedIcon.

+ * + * @param {@link java.lang.String} filename. + * @param {@link java.lang.Double} scale + * @return {@link javax.swing.ImageIcon} object + */ + public static ImageIcon getResizedIcon(final String filename, double scale) { + ImageIcon icon = getIconFromFile(filename); + + int w = (int) (icon.getIconWidth()*scale); + int h = (int) (icon.getIconHeight()*scale); + + return new ImageIcon(icon.getImage().getScaledInstance(w, h, Image.SCALE_SMOOTH)); + } + + /** + *

getResizedIcon.

+ * + * @param {@link javax.swing.ImageIcon} object + * @param {@link java.lang.Double} scale + * @return {@link javax.swing.ImageIcon} object + */ + public static ImageIcon getResizedIcon(final ImageIcon icon, double scale) { + int w = (int) (icon.getIconWidth()*scale); + int h = (int) (icon.getIconHeight()*scale); + + return new ImageIcon(icon.getImage().getScaledInstance(w, h, Image.SCALE_SMOOTH)); + } /** *

getResizedIcon.

diff --git a/src/main/java/forge/properties/NewConstants.java b/src/main/java/forge/properties/NewConstants.java index 3169ce54322..b13e951d78e 100644 --- a/src/main/java/forge/properties/NewConstants.java +++ b/src/main/java/forge/properties/NewConstants.java @@ -461,6 +461,20 @@ public interface NewConstants { } } + public static interface WinLoseFrame { + public static interface WINLOSETEXT { + String WON = "%s/WinLose/won"; + String LOST = "%s/WinLose/lost"; + String WIN = "%s/WinLose/win"; + String LOSE = "%s/WinLose/lose"; + String CONTINUE = "%s/WinLose/continue"; + String RESTART = "%s/WinLose/restart"; + String QUIT = "%s/WinLose/quit"; + } + } + // end + + // Doublestrike 02-10-11 - this is soon to be deprecated. public static interface Gui_WinLose { public static interface WINLOSE_TEXT { String WON = "%s/WinLose/won"; diff --git a/src/main/java/forge/quest/gui/QuestWinLoseCardViewer.java b/src/main/java/forge/quest/gui/QuestWinLoseCardViewer.java new file mode 100644 index 00000000000..30c44a49301 --- /dev/null +++ b/src/main/java/forge/quest/gui/QuestWinLoseCardViewer.java @@ -0,0 +1,86 @@ +package forge.quest.gui; + + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import forge.AllZone; +import forge.Card; +import forge.CardUtil; +import forge.gui.game.CardDetailPanel; +import forge.gui.game.CardPicturePanel; +import forge.item.CardPrinted; + +import java.util.List; + +import static java.util.Collections.unmodifiableList; + +/** + * A simple JPanel that shows three columns: card list, pic, and description.. + * + * @author Forge + * @version $Id: ListChooser.java 9708 2011-08-09 19:34:12Z jendave $ + */ +@SuppressWarnings("serial") +public class QuestWinLoseCardViewer extends JPanel { + + //Data and number of choices for the list + private List list; + + //initialized before; listeners may be added to it + private JList jList; + private CardDetailPanel detail; + private CardPicturePanel picture; + + public QuestWinLoseCardViewer(List list) { + this.list = unmodifiableList(list); + jList = new JList(new ChooserListModel()); + detail = new CardDetailPanel(null); + picture = new CardPicturePanel(null); + + this.add(new JScrollPane(jList)); + this.add(picture); + this.add(detail); + this.setLayout( new java.awt.GridLayout(1, 3, 6, 0) ); + + // selection is here + jList.getSelectionModel().addListSelectionListener(new SelListener()); + jList.setSelectedIndex(0); + } + + private class ChooserListModel extends AbstractListModel { + + private static final long serialVersionUID = 3871965346333840556L; + + public int getSize() { return list.size(); } + public Object getElementAt(int index) { return list.get(index); } + } + + + private class SelListener implements ListSelectionListener { + private Card[] cache = null; + + public void valueChanged(final ListSelectionEvent e) { + int row = jList.getSelectedIndex(); + // (String) jList.getSelectedValue(); + if (row >= 0 && row < list.size()) { + CardPrinted cp = list.get(row); + ensureCacheHas(row, cp); + detail.setCard(cache[row]); + picture.setCard(cp); + } + } + + private void ensureCacheHas(int row, CardPrinted cp) { + if (cache == null) { cache = new Card[list.size()]; } + if (null == cache[row]) { + Card card = AllZone.getCardFactory().getCard(cp.getName(), null); + card.setCurSetCode(cp.getSet()); + card.setImageFilename(CardUtil.buildFilename(card)); + cache[row] = card; + } + } + } + +} diff --git a/src/main/java/forge/quest/gui/QuestWinLoseHandler.java b/src/main/java/forge/quest/gui/QuestWinLoseHandler.java new file mode 100644 index 00000000000..e88db564b9d --- /dev/null +++ b/src/main/java/forge/quest/gui/QuestWinLoseHandler.java @@ -0,0 +1,541 @@ +package forge.quest.gui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +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 forge.AllZone; +import forge.CardList; +import forge.Constant; +import forge.MyRandom; +import forge.Player; +import forge.SetUtils; +import forge.game.GameEndReason; +import forge.game.GameFormat; +import forge.game.GameLossReason; +import forge.game.GamePlayerRating; +import forge.game.GameSummary; +import forge.gui.GuiUtils; +import forge.item.CardPrinted; +import forge.quest.data.QuestData; +import forge.quest.data.QuestMatchState; +import forge.quest.data.QuestPreferences; +import forge.quest.gui.QuestWinLoseCardViewer; +import forge.quest.gui.main.QuestEvent; +import forge.quest.gui.main.QuestChallenge; +import forge.view.swing.WinLoseModeHandler; + +/**

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 WinLoseModeHandler { + private boolean wonMatch; + private ImageIcon icoTemp; + private JLabel lblTemp1; + private JLabel lblTemp2; + int spacer = 50; + + private class CommonObjects { + public QuestMatchState qMatchState; + public QuestData qData; + public QuestEvent qEvent; + } + + private CommonObjects model; + + public QuestWinLoseHandler() { + super(); + model = new CommonObjects(); + model.qMatchState = AllZone.getMatchState(); + model.qData = AllZone.getQuestData(); + model.qEvent = AllZone.getQuestEvent(); + wonMatch = model.qMatchState.isMatchWonBy(AllZone.getHumanPlayer().getName()); + } + + /** + *

startNextRound.

+ * Either continues or restarts a current game. + * + * @param e a {@link java.awt.event.ActionEvent} object. + */ + @Override + public void startNextRound() { + + if(model.qEvent.getEventType().equals("challenge")) { + int extraLife = 0; + + if (model.qData.getInventory().hasItem("Zeppelin")) { + extraLife += 3; + } + + // Found this commented out - is it still necessary? Doublestrike 01-10-11 + //AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0], + //humanList, computerList, humanLife, computerLife); + + CardList humanList = forge.quest.data.QuestUtil.getHumanStartingCards(model.qData,model.qEvent); + CardList computerList = forge.quest.data.QuestUtil.getComputerStartingCards(model.qData,model.qEvent); + int humanLife = model.qData.getLife() + extraLife; + int computerLife = 20; + + computerLife = ((QuestChallenge)model.qEvent).getAILife(); + + AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0], + humanList, computerList, humanLife, computerLife, model.qEvent); + } + + super.startNextRound(); + } + + /** + *

populateCustomPanel.

+ * Checks conditions of win and fires various reward display methods accordingly. + * + * @param boolean indicating if custom panel has contents. + */ + @Override + public boolean populateCustomPanel() { + view.btnRestart.setVisible(false); + + if(!model.qMatchState.isMatchOver()) { + view.btnQuit.setText("Surrender (15 Credits)"); + return false; + } + + // Win case + if(wonMatch) { + // Standard event reward credits + awardEventCredits(); + + // Challenge reward credits + if(model.qEvent.getEventType().equals("challenge")) { + awardChallengeWin(); + } + + // Random rare given at 50% chance (65% with luck upgrade) + if (getLuckyCoinResult()) { + awardRandomRare("You've won a random rare."); + } + + // Random rare for winning against a very hard deck + if(model.qData.getDifficultyIndex() == 4) { + awardRandomRare("You've won a random rare for winning against a very hard deck."); + } + + // Award jackpot every 80 games won (currently 10 rares) + int wins = model.qData.getWin(); + if (wins > 0 && wins % 80 == 0) { + awardJackpot(); + } + } + // Lose case + else { + penalizeLoss(); + } + + // Win or lose, still a chance to win a booster, frequency set in preferences + int cntOutcomes = wonMatch ? model.qData.getWin() : model.qData.getLost(); + if (cntOutcomes % QuestPreferences.getWinsForBooster(model.qData.getDifficultyIndex()) == 0) { + awardBooster(); + } + + return true; + } + + /** + *

actionOnQuit.

+ * When "quit" button is pressed, this method adjusts quest data as appropriate and saves. + * + */ + @Override + public void actionOnQuit() { + // Record win/loss in quest data + if (model.qMatchState.isMatchWonBy(AllZone.getHumanPlayer().getName())) { + model.qData.addWin(); + } else { + model.qData.addLost(); + model.qData.subtractCredits(15); + } + + //System.out.println("model.qData cardpoolsize:" + AllZone.getQuestData().getCardpool().size()); + model.qData.getCards().clearShopList(); + + if (model.qData.getAvailableChallenges() != null) { + model.qData.clearAvailableChallenges(); + } + + model.qData.getCards().resetNewList(); + + model.qMatchState.reset(); + AllZone.setQuestEvent(null); + + model.qData.saveData(); + + new QuestFrame(); + } + + /** + *

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 + StringBuilder sb = new StringBuilder(""); + + int credTotal = 0; + int credBase = 0; + int credGameplay = 0; + int credUndefeated = 0; + int credEstates = 0; + + // Basic win bonus + int base = QuestPreferences.getMatchRewardBase(); + double multiplier = 1; + + String diff = AllZone.getQuestEvent().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 + + (QuestPreferences.getMatchRewardTotalWins() * model.qData.getWin())); + + sb.append(diff + " opponent: " + credBase + " credits.
"); + + // Gameplay bonuses (for each game win) + boolean hasNeverLost = true; + + Player computer = AllZone.getComputerPlayer(); + for (GameSummary game : model.qMatchState.getGamesPlayed()) { + + if (game.isWinner(computer.getName())) { + hasNeverLost = false; + continue; // no rewards for losing a game + } + + // Alternate win + GamePlayerRating aiRating = game.getPlayerRating(computer.getName()); + GamePlayerRating humanRating = game.getPlayerRating(AllZone.getHumanPlayer().getName()); + GameLossReason whyAiLost = aiRating.getLossReason(); + int altReward = 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 + int cntCardsHumanStartedWith = humanRating.getOpeningHandSize(); + int mulliganReward = QuestPreferences.getMatchMullToZero(); + + if (0 == cntCardsHumanStartedWith) { + credGameplay += mulliganReward; + sb.append(String.format("Mulliganed to zero and still won! " + + "Bonus: %d credits.
", mulliganReward)); + } + + // Early turn bonus + int winTurn = game.getTurnGameEnded(); + int turnCredits = getCreditsRewardForWinByTurn(winTurn); + + if (winTurn == 0) { System.err.println("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 += QuestPreferences.getMatchRewardNoLosses(); + int reward = QuestPreferences.getMatchRewardNoLosses(); + sb.append(String.format("You have not lost once! " + + "Bonus: %d credits.
", reward)); + } + + // Estates bonus + credTotal = credBase + credGameplay + credUndefeated; + switch(model.qData.getInventory().getItemLevel("Estates")) { + case 1: + credEstates = (int)0.1*credTotal; + sb.append("Estates bonus: 10%.
"); + break; + + case 2: + credEstates = (int)0.15*credTotal; + sb.append("Estates bonus: 15%.
"); + break; + + case 3: + credEstates = (int)0.2*credTotal; + sb.append("Estates bonus: 20%.
"); + break; + + default: break; + } + 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(""); + + // Generate Swing components and attach. + icoTemp = GuiUtils.getResizedIcon("GoldIcon.png",0.5); + + lblTemp1 = new TitleLabel("Gameplay Results"); + + lblTemp2 = new JLabel(sb.toString()); + lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); + lblTemp2.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblTemp2.setForeground(Color.white); + lblTemp2.setIcon(icoTemp); + lblTemp2.setIconTextGap(50); + + + view.pnlCustom.add(lblTemp1,"align center, width 95%!"); + view.pnlCustom.add(lblTemp2,"align center, width 95%!, gaptop 10"); + } + + /** + *

awardRandomRare.

+ * Generates and displays a random rare win case. + * + */ + private void awardRandomRare(String message) { + CardPrinted c = model.qData.getCards().addRandomRare(); + List cardsWon = new ArrayList(); + cardsWon.add(c); + + // Generate Swing components and attach. + lblTemp1 = new TitleLabel(message); + + QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); + + view.pnlCustom.add(lblTemp1,"align center, width 95%!, " + + "gaptop " + spacer + ", gapbottom 10"); + view.pnlCustom.add(cv,"align center, width 95%!"); + } + + /** + *

awardJackpot.

+ * Generates and displays jackpot win case. + * + */ + private void awardJackpot() { + List cardsWon = model.qData.getCards().addRandomRare(10); + + // Generate Swing components and attach. + lblTemp1 = new TitleLabel("You just won 10 random rares!"); + QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); + + view.pnlCustom.add(lblTemp1,"align center, width 95%!, " + + "gaptop " + spacer + ", gapbottom 10"); + view.pnlCustom.add(cv,"align center, width 95%!"); + } + + /** + *

awardBooster.

+ * Generates and displays booster pack win case. + * + */ + private void awardBooster() { + List sets = SetUtils.getFormats(); + int rand = (int)(Math.floor(Math.random()*(sets.size()))); + GameFormat selected = sets.get(rand); + List cardsWon = model.qData.getCards().addCards(selected.getFilterPrinted()); + + // Generate Swing components and attach. + lblTemp1 = new TitleLabel("Bonus booster pack from the \""+selected.getName()+"\" set!"); + QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); + + view.pnlCustom.add(lblTemp1,"align center, width 95%!, " + + "gaptop " + spacer + ", gapbottom 10"); + view.pnlCustom.add(cv,"align center, width 95%!"); + } + + /** + *

awardChallengeWin.

+ * Generates and displays win case for challenge event. + * + */ + private void awardChallengeWin() { + if(!((QuestChallenge)model.qEvent).getRepeatable()) { + model.qData.addCompletedChallenge(((QuestChallenge)model.qEvent).getId()); + } + + // Note: challenge only registers as "played" if it's won. + // This doesn't seem right, but it's easy to fix. Doublestrike 01-10-11 + model.qData.addChallengesPlayed(); + + List cardsWon = ((QuestChallenge)model.qEvent).getCardRewardList(); + long questRewardCredits = ((QuestChallenge)model.qEvent).getCreditsReward(); + + StringBuilder sb = new StringBuilder(); + sb.append("Challenge completed.

"); + sb.append("Challenge bounty: " + questRewardCredits + " credits."); + + model.qData.addCredits(questRewardCredits); + + // Generate Swing components and attach. + icoTemp = GuiUtils.getResizedIcon("BoxIcon.png",0.5); + lblTemp1 = new TitleLabel("Challenge Rewards for \"" + + ((QuestChallenge)model.qEvent).getTitle() + "\""); + + lblTemp2 = new JLabel(sb.toString()); + lblTemp2.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblTemp2.setForeground(Color.white); + lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); + lblTemp2.setIconTextGap(50); + lblTemp2.setIcon(icoTemp); + + view.pnlCustom.add(lblTemp1,"align center, width 95%!, " + + "gaptop " + spacer); + view.pnlCustom.add(lblTemp2,"align center, width 95%!, height 80!, gapbottom 10"); + + if (cardsWon != null) { + QuestWinLoseCardViewer cv = new QuestWinLoseCardViewer(cardsWon); + view.pnlCustom.add(cv,"align center, width 95%!"); + model.qData.getCards().addAllCards(cardsWon); + } + } + + private void penalizeLoss() { + icoTemp = GuiUtils.getResizedIcon("HeartIcon.png",0.5); + + lblTemp1 = new TitleLabel("Gameplay Results"); + + lblTemp2 = new JLabel("You lose! You have lost 15 credits."); + lblTemp2.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblTemp2.setForeground(Color.white); + lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); + lblTemp2.setIconTextGap(50); + lblTemp2.setIcon(icoTemp); + + view.pnlCustom.add(lblTemp1,"align center, width 95%!"); + view.pnlCustom.add(lblTemp2,"align center, width 95%!, height 80!"); + } + + /** + *

getLuckyCoinResult.

+ * A chance check, for rewards like random rares. + * + * @return boolean + */ + private boolean getLuckyCoinResult() { + boolean hasCoin = model.qData.getInventory().getItemLevel("Lucky Coin") >= 1; + + return MyRandom.random.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 QuestPreferences.getMatchRewardMilledWinBonus(); + case Poisoned: return QuestPreferences.getMatchRewardPoisonWinBonus(); + case DidNotLoseYet: return QuestPreferences.getMatchRewardAltWinBonus(); // Felidar, Helix Pinnacle, etc. + case SpellEffect: return QuestPreferences.getMatchRewardAltWinBonus(); // Door to Nothingness, etc. + 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 = 0; + + if (iTurn == 1) { + credits = QuestPreferences.getMatchRewardWinFirst(); + } + else if (iTurn <= 5) { + credits = QuestPreferences.getMatchRewardWinByFifth(); + } + else if (iTurn <= 10) { + credits = QuestPreferences.getMatchRewardWinByTen(); + } + else if (iTurn <= 15) { + credits = QuestPreferences.getMatchRewardWinByFifteen(); + } + + return credits; + } + + @SuppressWarnings("serial") + private class TitleLabel extends JLabel { + TitleLabel(String msg) { + super(msg); + this.setFont(new Font("Tahoma", Font.ITALIC, 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)); + } + } + +} \ No newline at end of file diff --git a/src/main/java/forge/view/swing/WinLoseFrame.java b/src/main/java/forge/view/swing/WinLoseFrame.java new file mode 100644 index 00000000000..d16da0220c3 --- /dev/null +++ b/src/main/java/forge/view/swing/WinLoseFrame.java @@ -0,0 +1,249 @@ +package forge.view.swing; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingConstants; + +import forge.AllZone; +import forge.Phase; +import forge.Player; +import forge.properties.ForgeProps; +import forge.properties.NewConstants.LANG.WinLoseFrame.WINLOSETEXT; +import forge.quest.data.QuestMatchState; + +import net.miginfocom.swing.MigLayout; + +/**

WinLoseFrame.

+ * Core display for win/lose UI shown after completing a game. + * Uses handlers to customize central panel for various game modes. + * + */ +@SuppressWarnings("serial") +public class WinLoseFrame extends JFrame { + + private QuestMatchState matchState; + private WinLoseModeHandler modeHandler; + + public JButton btnContinue; + public JButton btnQuit; + public JButton btnRestart; + + public JLabel lblTitle; + public JLabel lblStats; + + public JPanel pnlCustom; + + /** + *

WinLoseFrame.

+ * Starts win/lose UI with default display. + * + */ + public WinLoseFrame() { + this(new WinLoseModeHandler()); + } + + /** + *

WinLoseFrame.

+ * Starts the standard win/lose UI with custom display + * for different game modes (quest, puzzle, etc.) + * + * @param mh {@link forge.view.swing.WinLoseModeHandler} + */ + public WinLoseFrame(WinLoseModeHandler mh) { + super(); + + // modeHandler handles the unique display for different game modes. + modeHandler = mh; + modeHandler.setView(this); + matchState = AllZone.getMatchState(); + Container contentPane = this.getContentPane(); + contentPane.setLayout(new MigLayout("wrap, fill")); + contentPane.setBackground(new Color(16,28,50)); + + int HEAD_HEIGHT = 100; + int FOOT_HEIGHT = 150; + int FRAME_WIDTH_SMALL = 300; + int FRAME_WIDTH_BIG = 600; + + // Head panel + JPanel pnlHead = new JPanel(new MigLayout("wrap, fill")); + pnlHead.setOpaque(false); + this.add(pnlHead,"width " + FRAME_WIDTH_SMALL + "!, align center"); + + lblTitle = new JLabel("WinLoseFrame > lblTitle is broken."); + lblTitle.setForeground(Color.white); + lblTitle.setHorizontalAlignment(SwingConstants.CENTER); + lblTitle.setFont(new Font("Tahoma", Font.PLAIN, 26)); + + lblStats = new JLabel("WinLoseFrame > lblStats is broken."); + lblStats.setForeground(Color.white); + lblStats.setHorizontalAlignment(SwingConstants.CENTER); + lblStats.setFont(new Font("Tahoma", Font.ITALIC, 21)); + + pnlHead.add(lblTitle, "growx"); + pnlHead.add(lblStats, "growx"); + + // Custom display panel in center; populated later by mode handler. + JScrollPane scroller = new JScrollPane(); + pnlCustom = new JPanel(new MigLayout("wrap, fillx")); + pnlCustom.setBackground(new Color(111,87,59)); + pnlCustom.setForeground(Color.white); + this.add(scroller); + scroller.getViewport().add(pnlCustom); + + // Foot panel + JPanel pnlFoot = new JPanel(new MigLayout("wrap, fill, hidemode 3")); + pnlFoot.setOpaque(false); + this.add(pnlFoot,"width " + FRAME_WIDTH_SMALL + "!, align center"); + + this.btnContinue = new WinLoseButton("Continue"); + this.btnRestart = new WinLoseButton("Restart"); + this.btnQuit = new WinLoseButton("Quit"); + + pnlFoot.add(btnContinue,"height 30!, gap 0 0 5 5, align center"); + pnlFoot.add(btnRestart,"height 30!, gap 0 0 5 5, align center"); + pnlFoot.add(btnQuit,"height 30!, gap 0 0 5 5, align center"); + + // Button actions + btnQuit.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(final ActionEvent e) { btnQuit_actionPerformed(e); } + }); + + btnContinue.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(final ActionEvent e) { btnContinue_actionPerformed(e); } + }); + + btnRestart.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(final ActionEvent e) { btnRestart_actionPerformed(e); } + }); + + // End game and set state of "continue" button + Phase.setGameBegins(0); + + if (matchState.isMatchOver()) { + btnContinue.setEnabled(false); + btnQuit.grabFocus(); + } + + // Show Wins and Loses + Player human = AllZone.getHumanPlayer(); + int humanWins = matchState.countGamesWonBy(human.getName()); + int humanLosses = matchState.getGamesPlayedCount() - humanWins; + + lblStats.setText(ForgeProps.getLocalized(WINLOSETEXT.WON) + humanWins + + ForgeProps.getLocalized(WINLOSETEXT.LOST) + humanLosses); + + // Show "You Won" or "You Lost" + if (matchState.hasWonLastGame(human.getName())) { + lblTitle.setText(ForgeProps.getLocalized(WINLOSETEXT.WIN)); + } else { + lblTitle.setText(ForgeProps.getLocalized(WINLOSETEXT.LOSE)); + } + + // Populate custom panel, if necessary. + boolean hasStuff = modeHandler.populateCustomPanel(); + if(!hasStuff) { scroller.setVisible(false); } + + // Size and show frame + Dimension screen = this.getToolkit().getScreenSize(); + Rectangle bounds = this.getBounds(); + + if(hasStuff) { + bounds.height = screen.height - 150; + scroller.setPreferredSize(new Dimension(FRAME_WIDTH_BIG, + screen.height - HEAD_HEIGHT - FOOT_HEIGHT)); + bounds.width = FRAME_WIDTH_BIG; + bounds.x = (screen.width - FRAME_WIDTH_BIG)/2; + bounds.y = (screen.height - bounds.height)/2; + } + else { + bounds.height = HEAD_HEIGHT + FOOT_HEIGHT; + bounds.width = FRAME_WIDTH_SMALL; + bounds.x = (screen.width - FRAME_WIDTH_SMALL)/2; + bounds.y = (screen.height - bounds.height)/2; + } + + this.setBounds(bounds); + this.setDefaultCloseOperation(EXIT_ON_CLOSE); + this.setUndecorated(true); + this.setVisible(true); + } + + /** + *

continueButton_actionPerformed.

+ * + * @param e a {@link java.awt.event.ActionEvent} object. + */ + final void btnContinue_actionPerformed(ActionEvent e) { + closeWinLoseFrame(); + AllZone.getDisplay().setVisible(true); + modeHandler.startNextRound(); + } + + /** + *

restartButton_actionPerformed.

+ * + * @param e a {@link java.awt.event.ActionEvent} object. + */ + final void btnRestart_actionPerformed(ActionEvent e) { + closeWinLoseFrame(); + AllZone.getDisplay().setVisible(true); + matchState.reset(); + modeHandler.startNextRound(); + } + + /** + *

btnQuit_actionPerformed.

+ * + * @param e a {@link java.awt.event.ActionEvent} object. + */ + final void btnQuit_actionPerformed(ActionEvent e) { + closeWinLoseFrame(); + matchState.reset(); + modeHandler.actionOnQuit(); + + // clear Image caches, so the program doesn't get slower and slower + // not needed with soft values - will shrink as needed + // ImageUtil.rotatedCache.clear(); + // ImageCache.cache.clear(); + } + + /** + *

closeWinLoseFrame.

+ * Disposes WinLoseFrame UI. + * + * @return {@link javax.swing.JFrame} display frame + */ + final JFrame closeWinLoseFrame() { + // issue 147 - keep battlefield up following win/loss + JFrame frame = (JFrame) AllZone.getDisplay(); + frame.dispose(); + frame.setEnabled(true); + this.dispose(); + return frame; + } + + /** + *

WinLoseButton.

+ * Private button class to standardize buttons. + * + */ + private class WinLoseButton extends JButton { + WinLoseButton(String msg) { + super(msg); + this.setFont(new Font("Tahoma", Font.PLAIN, 14)); + this.setOpaque(false); + this.setPreferredSize(new Dimension(125,30)); + } + } +} diff --git a/src/main/java/forge/view/swing/WinLoseModeHandler.java b/src/main/java/forge/view/swing/WinLoseModeHandler.java new file mode 100644 index 00000000000..90fb55edfba --- /dev/null +++ b/src/main/java/forge/view/swing/WinLoseModeHandler.java @@ -0,0 +1,85 @@ +package forge.view.swing; + +import forge.AllZone; +import forge.Constant; + +/** + *

WinLoseModeHandler.

+ * + * Superclass of custom mode handling for win/lose UI. Can add swing components + * to custom center panel. Custom mode handling for quest, puzzle, etc. + * should extend this class. + * + */ +public class WinLoseModeHandler { + + protected WinLoseFrame view; + + /** + *

actionOnQuit.

+ * Action performed when "continue" button is pressed in default win/lose UI. + * + */ + public void actionOnContinue() { + + } + + /** + *

actionOnQuit.

+ * Action performed when "quit" button is pressed in default win/lose UI. + * + */ + public void actionOnQuit() { + if (System.getenv("NG2") != null) { + if (System.getenv("NG2").equalsIgnoreCase("true")) { + String argz[] = {}; + Gui_HomeScreen.main(argz); + } else { + new OldGuiNewGame(); + } + } else { + new OldGuiNewGame(); + } + } + + /** + *

actionOnRestart.

+ * Action performed when "restart" button is pressed in default win/lose UI. + * + */ + public void actionOnRestart() { + + } + + /** + *

startNextRound.

+ * Either continues or restarts a current game. May be overridden + * for use with other game modes. + * + * @param e a {@link java.awt.event.ActionEvent} object. + */ + public void startNextRound() { + AllZone.getGameAction().newGame(Constant.Runtime.HumanDeck[0], Constant.Runtime.ComputerDeck[0]); + } + + /** + *

populateCustomPanel.

+ * May be overridden as required by various mode handlers to show + * custom information in center panel. Default configuration is empty. + * + * @param boolean indicating if custom panel has contents. + */ + public boolean populateCustomPanel() { + return false; + } + + /** + *

setView.

+ * Links win/lose swing frame to mode handler, mostly to allow + * direct manipulation of custom center panel. + * + */ + public void setView(WinLoseFrame wlh) { + view = wlh; + } +}