diff --git a/client/src/main/java/help/FundamentalsGlossary.java b/client/src/main/java/help/FundamentalsGlossary.java deleted file mode 100644 index 883a8a6..0000000 --- a/client/src/main/java/help/FundamentalsGlossary.java +++ /dev/null @@ -1,67 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; -import util.Registry; - -@SuppressWarnings("serial") -public class FundamentalsGlossary extends HelpPanel - implements Registry -{ - private String panelName = "FundamentalsGlossary"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneOne}; - - public FundamentalsGlossary() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners("perfect", "challenge"); - setNodeName("Glossary"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setBounds(21, 54, 429, 282); - add(paneOne); - title.setText("Glossary"); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setBounds(21, 25, 159, 30); - add(title); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } - - @Override - public void refresh() - { - boolean blindUnlocked = rewards.getBoolean(REWARDS_BOOLEAN_BLIND, false); - - String glossaryText = "\r\n\r\n"; - - paneOne.setText(glossaryText); - } -} \ No newline at end of file diff --git a/client/src/main/java/help/FundamentalsTheDeck.java b/client/src/main/java/help/FundamentalsTheDeck.java deleted file mode 100644 index c24733c..0000000 --- a/client/src/main/java/help/FundamentalsTheDeck.java +++ /dev/null @@ -1,200 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JLabel; -import javax.swing.JTextPane; -import javax.swing.SwingConstants; - -import screen.ScreenCache; -import util.CardsUtil; -import util.Debug; -import util.EntropyColour; -import util.Registry; - -@SuppressWarnings("serial") -public class FundamentalsTheDeck extends HelpPanel - implements Registry -{ - private String clubString = "clubs (\u2663)"; - private String diamondString = "diamonds (\u2666)"; - private String moonString = null; - - private String panelName = "FundamentalsTheDeck"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneOne}; - - private final JLabel clubLabel = new JLabel("\u2663"); - private final JLabel diamondLabel = new JLabel("\u2666"); - private final JLabel heartLabel = new JLabel("\u2665"); - private final JLabel moonLabel = new JLabel(CardsUtil.MOONS_SYMBOL); - private final JLabel spadeLabel = new JLabel("\u2660"); - private final JLabel starLabel = new JLabel(CardsUtil.STARS_SYMBOL); - private final JLabel label_3 = new JLabel("<"); - private final JLabel label_4 = new JLabel("<"); - private final JLabel label_5 = new JLabel("<"); - private final JLabel rightmostLabel = new JLabel("<"); - private final JLabel leftmostLabel = new JLabel("<"); - - public FundamentalsTheDeck() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners("bidding"); - setNodeName("The Deck"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setBounds(21, 54, 429, 310); - add(paneOne); - title.setText("The Deck"); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setEditable(false); - title.setBounds(21, 25, 165, 30); - add(title); - clubLabel.setHorizontalAlignment(SwingConstants.CENTER); - clubLabel.setFont(new Font("Segoe UI Symbol", Font.PLAIN, 40)); - clubLabel.setBounds(80, 360, 65, 60); - add(clubLabel); - label_4.setHorizontalAlignment(SwingConstants.CENTER); - label_4.setFont(new Font("Arial", Font.PLAIN, 40)); - label_4.setBounds(120, 360, 65, 60); - add(label_4); - diamondLabel.setHorizontalAlignment(SwingConstants.CENTER); - diamondLabel.setForeground(Color.RED); - diamondLabel.setFont(new Font("Segoe UI Symbol", Font.PLAIN, 40)); - diamondLabel.setBounds(160, 360, 65, 60); - add(diamondLabel); - label_3.setHorizontalAlignment(SwingConstants.CENTER); - label_3.setFont(new Font("Arial", Font.PLAIN, 40)); - label_3.setBounds(200, 360, 65, 60); - add(label_3); - heartLabel.setHorizontalAlignment(SwingConstants.CENTER); - heartLabel.setForeground(Color.RED); - heartLabel.setFont(new Font("Segoe UI Symbol", Font.PLAIN, 40)); - heartLabel.setBounds(240, 360, 65, 60); - add(heartLabel); - moonLabel.setHorizontalAlignment(SwingConstants.CENTER); - moonLabel.setForeground(EntropyColour.COLOUR_SUIT_PURPLE); - moonLabel.setFont(new Font("Segoe UI Symbol", Font.PLAIN, 32)); - moonLabel.setBounds(240, 360, 65, 60); - add(moonLabel); - label_5.setHorizontalAlignment(SwingConstants.CENTER); - label_5.setFont(new Font("Arial", Font.PLAIN, 40)); - label_5.setBounds(280, 360, 65, 60); - add(label_5); - spadeLabel.setHorizontalAlignment(SwingConstants.CENTER); - spadeLabel.setFont(new Font("Segoe UI Symbol", Font.PLAIN, 40)); - spadeLabel.setBounds(320, 360, 65, 60); - add(spadeLabel); - rightmostLabel.setHorizontalAlignment(SwingConstants.CENTER); - rightmostLabel.setFont(new Font("Arial", Font.PLAIN, 40)); - rightmostLabel.setBounds(360, 360, 65, 60); - add(rightmostLabel); - leftmostLabel.setHorizontalAlignment(SwingConstants.CENTER); - leftmostLabel.setFont(new Font("Arial", Font.PLAIN, 40)); - leftmostLabel.setBounds(40, 360, 65, 60); - add(leftmostLabel); - starLabel.setHorizontalAlignment(SwingConstants.CENTER); - starLabel.setFont(new Font("Segoe UI Symbol", Font.PLAIN, 40)); - starLabel.setBounds(400, 360, 65, 60); - starLabel.setForeground(EntropyColour.COLOUR_SUIT_GOLD); - add(starLabel); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } - - private void setPaneOneText(boolean moonsAndStars) - { - String paneOneText = "For the standard game, a normal deck of 52 cards is used. This deck is made up of four suits: " - + clubString + ", " + diamondString + ", hearts (\u2665) and spades (\u2660), " - + "each of 13 cards. "; - - if (moonsAndStars) - { - paneOneText += "Two optional suits, " + moonString + " and stars "; - paneOneText += "(" + CardsUtil.STARS_SYMBOL + ") can also be added to the deck."; - } - - paneOneText += "The 13 cards in each suit are the 13 ranks of cards: ace (A), two (2), three (3), four (4), " - + "five (5), six (6), seven (7), eight (8), nine (9), ten (T), jack (J), queen (Q) and king (K). " - + "\r\n

\r\nWhen playing Entropy and its variants, the focus is on the suit as that\u2019s what is used during the bidding. " - + "Each card is worth one of its own suit, irrespective of rank. For example, the five of hearts (5\u2665) " - + "is worth one heart. However, aces are special cards. Not only are they worth one of their own suit, but they are also worth an extra one of all the suits. " - + "This means that the ace of spades (A\u2660) is worth one club, one diamond, one heart and two spades (one for being a spade and one for being an ace)." - + "\r\n

\r\nTo define whether one bid is higher than another, the suits are also ordered as follows:\r\n"; - - paneOne.setText(paneOneText); - } - - @Override - public void fireAppearancePreferencesChange() - { - boolean fourColours = ScreenCache.getHelpDialog().fourColours; - String clubsColour = fourColours?"green":"black"; - String diamondsColour = fourColours?"blue":"red"; - String moonsColour = fourColours?"purple":"CC9900"; - - clubString = "clubs (\u2663)"; - diamondString = "diamonds (\u2666)"; - moonString = "moons (" + CardsUtil.MOONS_SYMBOL + ")"; - - boolean moonsAndStars = rewards.getBoolean(REWARDS_BOOLEAN_EXTRA_SUITS, false); - setPaneOneText(moonsAndStars); - - if (fourColours) - { - clubLabel.setForeground(new Color(0, 128, 0)); - diamondLabel.setForeground(Color.BLUE); - moonLabel.setForeground(EntropyColour.COLOUR_SUIT_PURPLE); - } - else - { - clubLabel.setForeground(Color.black); - diamondLabel.setForeground(new Color(255, 0, 0)); - moonLabel.setForeground(EntropyColour.COLOUR_SUIT_GOLD); - } - } - - private void refreshSuitRankingVisibility() - { - boolean moonsAndStars = rewards.getBoolean(REWARDS_BOOLEAN_EXTRA_SUITS, false); - - if (moonsAndStars) - { - moonLabel.setVisible(true); - starLabel.setVisible(true); - rightmostLabel.setVisible(true); - leftmostLabel.setVisible(true); - clubLabel.setBounds(0, 360, 65, 60); - diamondLabel.setBounds(80, 360, 65, 60); - heartLabel.setBounds(160, 360, 65, 60); - } - else - { - moonLabel.setVisible(false); - starLabel.setVisible(false); - rightmostLabel.setVisible(false); - leftmostLabel.setVisible(false); - clubLabel.setBounds(80, 360, 65, 60); - diamondLabel.setBounds(160, 360, 65, 60); - heartLabel.setBounds(240, 360, 65, 60); - } - } - - @Override - public void refresh() - { - fireAppearancePreferencesChange(); - refreshSuitRankingVisibility(); - } -} \ No newline at end of file diff --git a/client/src/main/java/help/HelpPanel.java b/client/src/main/java/help/HelpPanel.java deleted file mode 100644 index a91d631..0000000 --- a/client/src/main/java/help/HelpPanel.java +++ /dev/null @@ -1,396 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Point; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionAdapter; - -import javax.swing.JPanel; -import javax.swing.JTextPane; -import javax.swing.text.DefaultHighlighter; -import javax.swing.text.Highlighter; -import javax.swing.text.Highlighter.HighlightPainter; - -import screen.HelpDialog; -import screen.ScreenCache; -import util.Debug; - -@SuppressWarnings("serial") -/** - * Object representing a 'page' of the help dialog. - */ -public class HelpPanel extends JPanel -{ - private String panelName = null; - private String nodeName = null; - private JTextPane[] textFields = null; - - public HelpPanel() - { - - } - - public boolean contains(String searchStr) - { - if (textFields == null) - { - Debug.stackTrace("NULL textFields for panel " + panelName); - return false; - } - int length = textFields.length; - - String searchStrLowerCase = searchStr.toLowerCase(); - - for (int i=0; i 1) - { - int i = 1; - String characterToTheLeft = text.substring(position-i-1, position-i); - - while (isLetter(characterToTheLeft)) - { - try - { - word = characterToTheLeft + word; - i++; - characterToTheLeft = text.substring(position-i-1, position-i); - } - catch (IndexOutOfBoundsException e) - { - characterToTheLeft = ""; - } - } - } - - if (position < length) - { - int i = 1; - String characterToTheRight = text.substring(position+i-1, position+i); - - while (isLetter(characterToTheRight)) - { - try - { - word += characterToTheRight; - i++; - characterToTheRight = text.substring(position+i-1, position+i); - } - catch (IndexOutOfBoundsException e) - { - characterToTheRight = ""; - } - } - } - - return word.toLowerCase(); - } - - private boolean isLetter(String letter) - { - return letter.matches("^[a-zA-Z]+$"); - } - - private void navigateToPageBasedOnKeyWord(String keyWord) - { - Debug.append("Navigated for word " + keyWord, true); - HelpDialog helpDialog = ScreenCache.getHelpDialog(); - - if (keyWord.startsWith("bidd")) - { - if (panelName.contains("Entropy")) - { - helpDialog.setSelectionForWord("RulesEntropyBidding"); - } - else if (panelName.contains("Vectropy")) - { - helpDialog.setSelectionForWord("RulesVectropyBidding"); - } - } - else if (keyWord.startsWith("chall")) - { - if (panelName.contains("Entropy")) - { - helpDialog.setSelectionForWord("RulesEntropyChallenging"); - } - else if (panelName.contains("Vectropy")) - { - helpDialog.setSelectionForWord("RulesVectropyChallenging"); - } - } - else if (keyWord.equals("order")) - { - helpDialog.setSelectionForWord("FundamentalsTheDeck"); - } - else if (keyWord.equals("perfect")) - { - helpDialog.setSelectionForWord("FundamentalsGlossary"); - } - } - - private String getDocumentText(JTextPane pane) - { - try - { - int length = pane.getDocument().getLength(); - String documentText = pane.getDocument().getText(0, length); - return documentText; - } - catch (Throwable e) - { - Debug.stackTrace(e); - return null; - } - } - - private boolean isKeyWord(String word, String[] wordsToExclude) - { - int size = wordsToExclude.length; - for (int i=0; iYou can report any issues you may find through the 'Bug Report' feature, located under the 'Help' menu. Please include as much information as you can about what you were doing when you encountered the problem. \r\n

\r\nSending the bug report will also send logs that will help me to investigate, however these are lost when you exit the application so please send the bug report before doing so. In more severe circumstances the logs will get emailed automatically, so if you see the following error message you don't need to send a bug report yourself:"); - paneIntro.setBounds(21, 408, 429, 190); - add(paneIntro); - - JLabel lblNewLabel = new JLabel(""); - lblNewLabel.setIcon(new ImageIcon(MiscBugReport.class.getResource("/help/bugReport.png"))); - lblNewLabel.setBounds(70, 66, 320, 321); - add(lblNewLabel); - - JLabel label = new JLabel(""); - label.setIcon(new ImageIcon(MiscBugReport.class.getResource("/help/bugError.png"))); - label.setBounds(35, 610, 379, 105); - add(label); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/MiscCheatCodes.java b/client/src/main/java/help/MiscCheatCodes.java deleted file mode 100644 index 575a4eb..0000000 --- a/client/src/main/java/help/MiscCheatCodes.java +++ /dev/null @@ -1,58 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -public class MiscCheatCodes extends HelpPanel -{ - private String panelName = "MiscCheatCodes"; - private JTextPane title = new JTextPane(); - private JTextPane paneIntro = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneIntro, paneOne}; - - private static String cheatsText = "- showmethecards: Turn all hands face-up!

" - + "- maxbids: Lists the amount of each suit present in the current game.

" - + "- perfectbid: Gives you the perfect bid for the current round. Returns the same value as maxbids if playing in Vectropy mode.

" - + "- rainingjokers: Randomly turns 1-5 of the cards in play into jokers.

" - + "- bluescreenofdeath: Unlocks the hidden 'Blue Screen of Death' achievement (pfft, like you've not already got it).

" - + "- simulator: Opens the Entropy Simulator. This was used during development to pit strategies against one another so that we could test enhancements and rank them."; - - public MiscCheatCodes() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners(""); - setNodeName("Cheat Codes"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setText(cheatsText); - paneOne.setBounds(21, 156, 429, 317); - add(paneOne); - title.setText("Cheat Codes"); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setEditable(false); - title.setBounds(21, 25, 192, 30); - add(title); - paneIntro.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneIntro.setContentType("text/html"); - paneIntro.setText("Congratulations on reaching 50 achievements! Here are some cheats you can enter whilst playing the game, which I originally created to make testing easier. Whilst in the main window, press CTRL+; to bring up the command bar, then enter any of the following commands:"); - paneIntro.setBounds(21, 54, 429, 91); - add(paneIntro); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/MiscClearingSaveData.java b/client/src/main/java/help/MiscClearingSaveData.java deleted file mode 100644 index 10f378c..0000000 --- a/client/src/main/java/help/MiscClearingSaveData.java +++ /dev/null @@ -1,58 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -@SuppressWarnings("serial") -public class MiscClearingSaveData extends HelpPanel -{ - private String panelName = "MiscClearingSaveData"; - private JTextPane title = new JTextPane(); - private JTextPane paneIntro = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneIntro, paneOne}; - - public MiscClearingSaveData() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners(""); - setNodeName("Clearing Data"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setText("\r\n- Statistics Only: This will clear anything that appears under your statistics such as time played and total games won. Clearing this will preserve any achievements you have already earned, but any progress made towards locked achievements (e.g. those for amount of time played) will be lost.\r\n

\r\n- Achievements and Statistics: This will again clear your statistics, but will this time also remove any achievements you have already earned.\r\n

\r\n- My Replays / Imported Replays: These options will attempt to delete the replay files in your Personal / Imported folders. Note that it is not possible to recover these once they have been deleted, so be certain that you want to do this before proceeding.\r\n"); - paneOne.setBounds(21, 360, 429, 279); - add(paneOne); - title.setText("Clearing Saved Data"); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setEditable(false); - title.setBounds(21, 25, 192, 30); - add(title); - JLabel lblNewLabel = new JLabel(""); - lblNewLabel.setIcon(new ImageIcon(MiscClearingSaveData.class.getResource("/help/clearData.png"))); - lblNewLabel.setBounds(120, 114, 230, 230); - add(lblNewLabel); - paneIntro.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneIntro.setContentType("text/html"); - paneIntro.setText("Options to clear saved data can be found under File > Clear Data. This will bring up the following dialog: "); - paneIntro.setBounds(21, 54, 429, 50); - add(paneIntro); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/RulesEntropyBidding.java b/client/src/main/java/help/RulesEntropyBidding.java deleted file mode 100644 index ac81eda..0000000 --- a/client/src/main/java/help/RulesEntropyBidding.java +++ /dev/null @@ -1,61 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -@SuppressWarnings("serial") -public class RulesEntropyBidding extends HelpPanel -{ - private String panelName = "RulesEntropyBidding"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane subtitle = new JTextPane(); - private JTextPane paneTwo = new JTextPane(); - private JTextPane[] textFields = {title, paneOne, subtitle, paneTwo}; - - public RulesEntropyBidding() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners("bidding"); - setNodeName("Bidding"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setText("A round starts with the first person to play bidding. At the start of a new game, the round is started by a player chosen at random. In each subsequent round the loser of the previous round starts, unless losing the last round caused them to go out. In this case, the person to the left of the losing player starts the next round.\r\n

\r\nEach bid must be a suit and a number, for example \"2 Spades\". Each subsequent bid must be higher than the last, including adhering to the suit order. Bidding continues clockwise round the players. At any point a player may opt to challenge the current bid rather than making a higher bid of their own."); - paneOne.setBounds(21, 54, 429, 220); - paneOne.setEditable(false); - add(paneOne); - paneTwo.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneTwo.setContentType("text/html"); - paneTwo.setText("A bid is higher than another if the number is higher or if the number is equal and the suit is higher. For example, \"3 Hearts\" is higher than \"2 Hearts\", as 3 is greater than 2. \"3 Hearts\" is lower than \"3 Spades\" because spades is a higher suit than hearts. "); - paneTwo.setBounds(21, 313, 429, 100); - paneTwo.setEditable(false); - add(paneTwo); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setText("Bidding"); - title.setBounds(21, 25, 159, 30); - title.setEditable(false); - add(title); - subtitle.setText("Bid Hierarchy"); - subtitle.setForeground(EntropyColour.COLOUR_HELP_TITLE); - subtitle.setFont(new Font("Tahoma", Font.BOLD, 18)); - subtitle.setBounds(21, 284, 159, 30); - subtitle.setEditable(false); - add(subtitle); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/RulesEntropyChallenging.java b/client/src/main/java/help/RulesEntropyChallenging.java deleted file mode 100644 index 3c4abf8..0000000 --- a/client/src/main/java/help/RulesEntropyChallenging.java +++ /dev/null @@ -1,46 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -@SuppressWarnings("serial") -public class RulesEntropyChallenging extends HelpPanel -{ - private String panelName = "RulesEntropyChallenging"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneOne}; - - public RulesEntropyChallenging() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners("challeng"); - setNodeName("Challenging"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setText("Any player whose turn it is to bid can choose to challenge instead. This means that the player does not believe that there are as many cards of the suit as bid by the previous player. When a player challenges, all cards are revealed on the table and counted. The challenge is then evaluated.\r\n

\r\nIf a challenge is successful, the player who made the last bid loses the round, whereas if it is unsuccessful the player who challenged is the one to lose. Whether or not a challenge is successful is determined by how many of the suit were actually present \u2013 it is successful if there were fewer than the number bid and unsuccessful otherwise. \r\n

\r\nFor example if Tom bids five hearts and Alex challenges him, that means Alex thinks there are fewer than five hearts in all the players cards. The cards are turned over and counted. In fact there were six hearts, so Alex lost the challenge and loses a card for the next round."); - paneOne.setBounds(21, 54, 429, 353); - add(paneOne); - title.setText("Challenging"); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setEditable(false); - title.setBounds(21, 25, 216, 30); - add(title); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/RulesEntropyIntroduction.java b/client/src/main/java/help/RulesEntropyIntroduction.java deleted file mode 100644 index 944790e..0000000 --- a/client/src/main/java/help/RulesEntropyIntroduction.java +++ /dev/null @@ -1,45 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -@SuppressWarnings("serial") -public class RulesEntropyIntroduction extends HelpPanel -{ - private String panelName = "RulesEntropyIntroduction"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneOne}; - - public RulesEntropyIntroduction() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners(""); - setNodeName("Introduction"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setText("Entropy is a bidding game for 2-4 players, played with one or more decks of cards. The players are dealt hands of up to 5 cards and play proceeds clockwise, with each player bidding higher than those before until someone challenges and the cards are revealed. \r\n

\r\nThe loser of the challenge loses one card for the next round. Rounds continue until only one player has cards left, at which point they are declared the winner."); - paneOne.setBounds(21, 54, 418, 158); - add(paneOne); - title.setText("Introduction"); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setBounds(21, 25, 159, 30); - add(title); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/RulesIllegal.java b/client/src/main/java/help/RulesIllegal.java deleted file mode 100644 index 1d34584..0000000 --- a/client/src/main/java/help/RulesIllegal.java +++ /dev/null @@ -1,47 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -@SuppressWarnings("serial") -public class RulesIllegal extends HelpPanel -{ - private String panelName = "RulesIllegal"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneOne}; - - public RulesIllegal() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners("bid"); - setNodeName("Illegal!"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setText("The 'Illegal' option provides an alternative to bidding higher or challenging when facing a bid. If a player declares 'Illegal', they claim that the bid they were faced with was perfect. If they are right the opponent loses a card for the next round, else they lose a card - regardless of whether the bid they were faced with was an overbid or an underbid."); - paneOne.setBounds(21, 54, 429, 220); - paneOne.setEditable(false); - add(paneOne); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setText("Illegal!"); - title.setBounds(21, 25, 159, 30); - title.setEditable(false); - add(title); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/RulesVectropyBidding.java b/client/src/main/java/help/RulesVectropyBidding.java deleted file mode 100644 index 755fd91..0000000 --- a/client/src/main/java/help/RulesVectropyBidding.java +++ /dev/null @@ -1,104 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import screen.ScreenCache; -import util.Debug; -import util.EntropyColour; -import util.Registry; - -@SuppressWarnings("serial") -public class RulesVectropyBidding extends HelpPanel - implements Registry -{ - private String panelName = "RulesVectropyBidding"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane subtitle = new JTextPane(); - private JTextPane paneTwo = new JTextPane(); - private JTextPane[] textFields = {title, paneOne, subtitle, paneTwo}; - - private String clubsColour = "black"; - private String diamondsColour = "red"; - - public RulesVectropyBidding() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners("bidding"); - setNodeName("Bidding"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setBounds(21, 54, 429, 230); - paneOne.setEditable(false); - add(paneOne); - paneTwo.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneTwo.setContentType("text/html"); - paneTwo.setText("A bid is higher than another if the sum of its elements is higher, with the added restriction that each bid must include at least as many of each individual suit as the one before it. For example, if faced with a bid of (0, 0, 0, 2):\r\n\r\n"); - paneTwo.setFont(new Font("Tahoma", Font.PLAIN, 14)); - paneTwo.setBounds(21, 320, 429, 156); - paneTwo.setEditable(false); - add(paneTwo); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setText("Bidding"); - title.setBounds(21, 25, 159, 30); - title.setEditable(false); - add(title); - subtitle.setText("Bid Hierarchy"); - subtitle.setForeground(EntropyColour.COLOUR_HELP_TITLE); - subtitle.setFont(new Font("Tahoma", Font.BOLD, 18)); - subtitle.setBounds(21, 290, 159, 30); - subtitle.setEditable(false); - add(subtitle); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } - - @Override - public void fireAppearancePreferencesChange() - { - boolean fourColours = ScreenCache.getHelpDialog().fourColours; - clubsColour = fourColours?"green":"black"; - diamondsColour = fourColours?"blue":"red"; - } - - @Override - public void refresh() - { - setPaneOneText(); - } - - private void setPaneOneText() - { - boolean extraSuits = rewards.getBoolean(REWARDS_BOOLEAN_EXTRA_SUITS, false); - - String text = "A round starts with the first person to play bidding. At the start of a new game, "; - text += "the round is started by a player chosen at random. In each subsequent round the loser of the previous "; - text += "round starts, unless losing the last round caused them to go out. In this case, the person to the left "; - text += "of the losing player starts the next round.\r\n

\r\nEach bid is an ordered vector of four numbers. "; - text += "These numbers represent the amount that is being bid for each suit from lowest to highest - "; - text += "(\u2663, \u2666, "; - text += "\u2665, \u2660). "; - - if (extraSuits) - { - text += "This vector naturally extends if additional suits are in play. "; - } - - text += "Each subsequent bid must be higher than the last. Bidding continues clockwise round the players. "; - text += "At any point a player may opt to challenge the current bid rather than making a higher bid of their own.\r\n\r\n\r\n"; - - paneOne.setText(text); - } -} \ No newline at end of file diff --git a/client/src/main/java/help/RulesVectropyChallenging.java b/client/src/main/java/help/RulesVectropyChallenging.java deleted file mode 100644 index cc7c05d..0000000 --- a/client/src/main/java/help/RulesVectropyChallenging.java +++ /dev/null @@ -1,46 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -@SuppressWarnings("serial") -public class RulesVectropyChallenging extends HelpPanel -{ - private String panelName = "RulesVectropyChallenging"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneOne}; - - public RulesVectropyChallenging() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners("challeng"); - setNodeName("Challenging"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setText("Any player whose turn it is to bid can choose to challenge instead. This means that the player does not believe that there are as many cards of one or more of the suits bid by the previous player. When a player challenges, all cards are revealed on the table and counted. The challenge is then evaluated.\r\n

\r\nIf a challenge is successful, the player who made the last bid loses the round, whereas if it is unsuccessful the player who challenged is the one to lose. Whether or not a challenge is successful is determined by how many of the four suits were actually present \u2013 it is successful if there were fewer of any of the suits bid, and unsuccessful otherwise.\r\n

\r\nFor example, in a game with 3 clubs, 4 diamonds, 2 hearts and 2 spades, challenging a bid of (3, 2, 1, 0) would be unsuccessful as there were at least as many cards as bid in all four suits. A bid of (3, 3, 0, 3), however, contains more spades than are present, so challenging this would be successful."); - paneOne.setBounds(21, 54, 429, 353); - add(paneOne); - title.setText("Challenging"); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setEditable(false); - title.setBounds(21, 25, 216, 30); - add(title); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/RulesVectropyIntroduction.java b/client/src/main/java/help/RulesVectropyIntroduction.java deleted file mode 100644 index 7f7ca53..0000000 --- a/client/src/main/java/help/RulesVectropyIntroduction.java +++ /dev/null @@ -1,45 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -@SuppressWarnings("serial") -public class RulesVectropyIntroduction extends HelpPanel -{ - private String panelName = "RulesVectropyIntroduction"; - private JTextPane title = new JTextPane(); - private JTextPane paneOne = new JTextPane(); - private JTextPane[] textFields = {title, paneOne}; - - public RulesVectropyIntroduction() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners(""); - setNodeName("Introduction"); - setLayout(null); - paneOne.setFont(new Font("SansSerif", Font.PLAIN, 14)); - paneOne.setContentType("text/html"); - paneOne.setText("Vectropy is a variant of Entropy where the bidding requires players to bid in all four suits at once. As before, the players are dealt hands of up to 5 cards and play proceeds clockwise, with each player bidding higher than those before until someone challenges and the cards are revealed. \r\n

\r\nThe loser of the challenge loses one card for the next round. Rounds continue until only one player has cards left, at which point they are declared the winner."); - paneOne.setBounds(21, 54, 418, 158); - add(paneOne); - title.setText("Introduction"); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setBounds(21, 25, 159, 30); - add(title); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/ToolsGameplaySettings.java b/client/src/main/java/help/ToolsGameplaySettings.java deleted file mode 100644 index fa13d4a..0000000 --- a/client/src/main/java/help/ToolsGameplaySettings.java +++ /dev/null @@ -1,160 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; - -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; -import util.Registry; - -public class ToolsGameplaySettings extends HelpPanel - implements Registry -{ - private String panelName = "ToolsGameplaySettings"; - private JTextPane title = new JTextPane(); - private final JLabel bulletThree = new JLabel(""); - private final JLabel bulletFour = new JLabel(""); - private final JLabel playBlindImage = new JLabel(""); - private final JTextPane txtpnOneTitle = new JTextPane(); - private final JTextPane txtpnOneExplanation = new JTextPane(); - private final JTextPane txtpnTwoTitle = new JTextPane(); - private final JTextPane txtpnTwoExplanation = new JTextPane(); - private final JTextPane txtpnThreeTitle = new JTextPane(); - private final JTextPane txtpnThreeExplanation = new JTextPane(); - private final JTextPane txtpnTickbox = new JTextPane(); - private final JTextPane txtpnFourTitle = new JTextPane(); - private final JTextPane txtpnIfThisIs = new JTextPane(); - private final JTextPane txtpnHandicap_1 = new JTextPane(); - private final JTextPane txtpnWithThisTicked_1 = new JTextPane(); - private JTextPane[] textFields = {title, txtpnOneTitle, txtpnOneExplanation, txtpnTwoTitle, txtpnTwoExplanation, txtpnThreeTitle, txtpnThreeExplanation, - txtpnTickbox, txtpnFourTitle, txtpnIfThisIs, txtpnHandicap_1, txtpnWithThisTicked_1}; - - private final JPanel blindPanel = new JPanel(); - private final JPanel panel = new JPanel(); - private final JLabel label = new JLabel(""); - - - public ToolsGameplaySettings() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners(""); - setNodeName("Gameplay Settings"); - setLayout(null); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setText("Preferences: Gameplay"); - title.setBounds(21, 25, 259, 30); - add(title); - JLabel bulletOne = new JLabel(""); - bulletOne.setIcon(new ImageIcon(ToolsGameplaySettings.class.getResource("/help/numberOne.png"))); - bulletOne.setBounds(24, 78, 25, 25); - add(bulletOne); - JLabel bulletTwo = new JLabel(""); - bulletTwo.setIcon(new ImageIcon(ToolsGameplaySettings.class.getResource("/help/numberTwo.png"))); - bulletTwo.setBounds(24, 130, 25, 25); - add(bulletTwo); - txtpnOneTitle.setFont(new Font("Tahoma", Font.BOLD, 12)); - txtpnOneTitle.setText("Starting Cards"); - txtpnOneTitle.setBounds(54, 132, 118, 20); - add(txtpnOneTitle); - txtpnOneExplanation.setFont(new Font("Tahoma", Font.PLAIN, 12)); - txtpnOneExplanation.setText("A simple slider to set how many cards are dealt to each player at the start of a new game."); - txtpnOneExplanation.setBounds(54, 156, 390, 36); - add(txtpnOneExplanation); - txtpnTwoTitle.setText("Game Mode"); - txtpnTwoTitle.setFont(new Font("Tahoma", Font.BOLD, 12)); - txtpnTwoTitle.setBounds(54, 80, 118, 20); - add(txtpnTwoTitle); - txtpnTwoExplanation.setText("Toggle between the different game modes you have unlocked."); - txtpnTwoExplanation.setFont(new Font("Tahoma", Font.PLAIN, 12)); - txtpnTwoExplanation.setBounds(54, 104, 390, 25); - add(txtpnTwoExplanation); - JPanel jokerPanel = new JPanel(); - jokerPanel.setBackground(Color.WHITE); - jokerPanel.setBounds(21, 206, 423, 128); - add(jokerPanel); - jokerPanel.setLayout(null); - bulletThree.setBounds(3, 4, 25, 25); - jokerPanel.add(bulletThree); - bulletThree.setIcon(new ImageIcon(ToolsGameplaySettings.class.getResource("/help/numberThree.png"))); - txtpnThreeTitle.setBounds(33, 6, 118, 20); - jokerPanel.add(txtpnThreeTitle); - txtpnThreeTitle.setText("Joker Settings"); - txtpnThreeTitle.setFont(new Font("Tahoma", Font.BOLD, 12)); - txtpnThreeExplanation.setBounds(33, 30, 390, 19); - jokerPanel.add(txtpnThreeExplanation); - txtpnThreeExplanation.setText("Settings to vary how many jokers are included in the deck:"); - txtpnThreeExplanation.setFont(new Font("Tahoma", Font.PLAIN, 12)); - txtpnTickbox.setContentType("text/html"); - txtpnTickbox.setText("- Tickbox: Whether jokers are included or not.
\r\n- Quantity: How many jokers to add, between 1 and 4.
\r\n- Value: The worth of each joker, between 2 and 4. Jokers will be worth this many of every suit.
"); - txtpnTickbox.setBounds(33, 60, 380, 68); - jokerPanel.add(txtpnTickbox); - panel.setBounds(21, 342, 423, 104); - add(panel); - panel.setLayout(null); - panel.setBackground(Color.WHITE); - label.setIcon(new ImageIcon(ToolsGameplaySettings.class.getResource("/help/numberFour.png"))); - label.setBounds(3, 4, 25, 25); - panel.add(label); - txtpnHandicap_1.setText("Handicap"); - txtpnHandicap_1.setFont(new Font("Tahoma", Font.BOLD, 12)); - txtpnHandicap_1.setBounds(33, 6, 118, 20); - panel.add(txtpnHandicap_1); - txtpnWithThisTicked_1.setText("With this ticked, you will be dealt less cards than your opponents at the start of a new game. The number represents how many cards less you will be dealt - so the higher the number, the larger your disadvantage will be. "); - txtpnWithThisTicked_1.setFont(new Font("Tahoma", Font.PLAIN, 12)); - txtpnWithThisTicked_1.setBounds(33, 30, 390, 66); - panel.add(txtpnWithThisTicked_1); - blindPanel.setLayout(null); - blindPanel.setBackground(Color.WHITE); - blindPanel.setBounds(21, 460, 423, 296); - add(blindPanel); - bulletFour.setBounds(3, 4, 25, 25); - blindPanel.add(bulletFour); - bulletFour.setIcon(new ImageIcon(ToolsGameplaySettings.class.getResource("/help/numberFive.png"))); - txtpnFourTitle.setFont(new Font("Tahoma", Font.BOLD, 12)); - txtpnFourTitle.setBounds(33, 6, 217, 20); - blindPanel.add(txtpnFourTitle); - txtpnIfThisIs.setOpaque(false); - txtpnIfThisIs.setFont(new Font("Tahoma", Font.PLAIN, 12)); - txtpnIfThisIs.setBounds(33, 37, 380, 66); - blindPanel.add(txtpnIfThisIs); - playBlindImage.setIcon(new ImageIcon(ToolsGameplaySettings.class.getResource("/help/playingBlind_backBlue.png"))); - playBlindImage.setBounds(128, 114, 199, 157); - blindPanel.add(playBlindImage); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } - - @Override - public void refresh() - { - boolean unlockedBlind = rewards.getBoolean(REWARDS_BOOLEAN_BLIND, false); - blindPanel.setVisible(unlockedBlind); - - if (unlockedBlind) - { - setPreferredSize(new Dimension(455, 750)); - txtpnFourTitle.setText("Blind Play"); - txtpnIfThisIs.setText("If this is ticked, your cards will be dealt face-down at the start of every round. \r\nYou will still be able to view your cards at any time by pressing the eye symbol below them:"); - } - else - { - setPreferredSize(new Dimension(455, 450)); - txtpnFourTitle.setText(""); - txtpnIfThisIs.setText(""); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/help/ToolsReplayViewer.java b/client/src/main/java/help/ToolsReplayViewer.java deleted file mode 100644 index e6b69f5..0000000 --- a/client/src/main/java/help/ToolsReplayViewer.java +++ /dev/null @@ -1,150 +0,0 @@ -package help; - -import java.awt.Color; -import java.awt.Font; - -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextPane; - -import util.Debug; -import util.EntropyColour; - -@SuppressWarnings("serial") -public class ToolsReplayViewer extends HelpPanel -{ - private String panelName = "ToolsReplayViewer"; - - private final JTextPane title = new JTextPane(); - private final JLabel lblReplayTable = new JLabel(""); - private final JTextPane txtpnIntroduction = new JTextPane(); - private final JTextPane txtpnSavingReplays1 = new JTextPane(); - private final JTextPane titleSavingReplays = new JTextPane(); - private final JTextPane txtpnSavingReplays2 = new JTextPane(); - private final JLabel lblSaveReplaysOption = new JLabel(""); - private final JTextPane titleUsingTheReplayViewer = new JTextPane(); - private final JTextPane txtpnUsingTheReplayViewer1 = new JTextPane(); - private final JTextPane txtpnUsingTheReplayViewer2 = new JTextPane(); - private final JTextPane titleFilteringAndOrdering = new JTextPane(); - private final JTextPane txtpnFilteringAndOrdering1 = new JTextPane(); - private final JTextPane txtpnFilteringAndOrdering2 = new JTextPane(); - private final JTextPane titleImportingExporting = new JTextPane(); - private final JTextPane txtpnImportingExporting = new JTextPane(); - - private JTextPane[] textFields = {title, txtpnIntroduction, titleSavingReplays, txtpnSavingReplays1, txtpnSavingReplays2, titleUsingTheReplayViewer, - txtpnUsingTheReplayViewer1, txtpnUsingTheReplayViewer2, titleFilteringAndOrdering, txtpnFilteringAndOrdering1, - txtpnFilteringAndOrdering2, titleImportingExporting, txtpnImportingExporting}; - - private final JPanel panel_2 = new JPanel(); - - public ToolsReplayViewer() - { - try - { - setBackground(Color.WHITE); - setPanelName(panelName); - setTextFields(textFields); - addMouseListeners(""); - setNodeName("Replay Viewer"); - setLayout(null); - title.setForeground(EntropyColour.COLOUR_HELP_TITLE); - title.setFont(new Font("Tahoma", Font.BOLD, 18)); - title.setText("The Replay Viewer"); - title.setBounds(21, 25, 188, 30); - add(title); - txtpnIntroduction.setContentType("text/html"); - txtpnIntroduction.setFont(new Font("SansSerif", Font.PLAIN, 14)); - txtpnIntroduction.setText("The Replay Viewer provides a useful interface for you to watch back all your past games of Entropy. Replays are shown in a colour-coded table, with filter options to make it easy to locate a specific game."); - txtpnIntroduction.setBounds(21, 54, 429, 66); - add(txtpnIntroduction); - txtpnSavingReplays1.setFont(new Font("SansSerif", Font.PLAIN, 14)); - txtpnSavingReplays1.setContentType("text/html"); - txtpnSavingReplays1.setText("To use the Replay Viewer, you will first need to turn on the setting to save replays. You will find this under the 'Miscellaneous' tab in Preferences:"); - txtpnSavingReplays1.setBounds(21, 157, 423, 66); - add(txtpnSavingReplays1); - titleSavingReplays.setText("Saving Replays"); - titleSavingReplays.setForeground(EntropyColour.COLOUR_HELP_TITLE); - titleSavingReplays.setFont(new Font("Tahoma", Font.BOLD, 18)); - titleSavingReplays.setBounds(21, 128, 188, 30); - add(titleSavingReplays); - txtpnSavingReplays2.setFont(new Font("SansSerif", Font.PLAIN, 14)); - txtpnSavingReplays2.setContentType("text/html"); - txtpnSavingReplays2.setText("You will need to tick this option and choose a place for the replays to be saved. This will create a new folder called 'Replays', with sub-folders 'Personal' (for your own replays) and 'Imported' (see Importing & Exporting Replays, lower down).\r\n

\r\nNote: If you change your mind about this location at any point, you can change it without losing any data. You will be given the option to move all of the replay files over to the new location so all of your existing replays will be preserved."); - txtpnSavingReplays2.setBounds(21, 291, 423, 177); - add(txtpnSavingReplays2); - lblSaveReplaysOption.setIcon(new ImageIcon(ToolsReplayViewer.class.getResource("/help/replayViewerSettings.png"))); - lblSaveReplaysOption.setBounds(62, 234, 309, 38); - add(lblSaveReplaysOption); - JPanel panel = new JPanel(); - panel.setBackground(Color.WHITE); - panel.setBounds(11, 480, 494, 461); - add(panel); - panel.setLayout(null); - titleUsingTheReplayViewer.setText("Using the Replay Viewer"); - titleUsingTheReplayViewer.setForeground(EntropyColour.COLOUR_HELP_TITLE); - titleUsingTheReplayViewer.setFont(new Font("Tahoma", Font.BOLD, 18)); - titleUsingTheReplayViewer.setBounds(10, 11, 262, 30); - panel.add(titleUsingTheReplayViewer); - txtpnUsingTheReplayViewer1.setFont(new Font("SansSerif", Font.PLAIN, 14)); - txtpnUsingTheReplayViewer1.setContentType("text/html"); - txtpnUsingTheReplayViewer1.setText("Once you have saved some replays, you will see a table like the following:"); - txtpnUsingTheReplayViewer1.setBounds(10, 40, 423, 44); - panel.add(txtpnUsingTheReplayViewer1); - lblReplayTable.setBounds(10, 95, 428, 264); - panel.add(lblReplayTable); - lblReplayTable.setIcon(new ImageIcon(ToolsReplayViewer.class.getResource("/help/replayViewerTable.png"))); - txtpnUsingTheReplayViewer2.setFont(new Font("SansSerif", Font.PLAIN, 14)); - txtpnUsingTheReplayViewer2.setContentType("text/html"); - txtpnUsingTheReplayViewer2.setText("Double-clicking on a row will show that replay. You can also select a row and press the enter key.\r\n
You can also delete one or more replays by selecting the row(s) and pressing the delete key."); - txtpnUsingTheReplayViewer2.setBounds(10, 370, 423, 84); - panel.add(txtpnUsingTheReplayViewer2); - JPanel panel_1 = new JPanel(); - panel_1.setLayout(null); - panel_1.setBackground(Color.WHITE); - panel_1.setBounds(11, 940, 494, 554); - add(panel_1); - titleFilteringAndOrdering.setText("Filtering and Sorting Replays"); - titleFilteringAndOrdering.setForeground(EntropyColour.COLOUR_HELP_TITLE); - titleFilteringAndOrdering.setFont(new Font("Tahoma", Font.BOLD, 18)); - titleFilteringAndOrdering.setBounds(10, 11, 280, 30); - panel_1.add(titleFilteringAndOrdering); - txtpnFilteringAndOrdering1.setFont(new Font("SansSerif", Font.PLAIN, 14)); - txtpnFilteringAndOrdering1.setContentType("text/html"); - txtpnFilteringAndOrdering1.setText("Many filter options are available on the left hand side to help you narrow down the selection (you need to click refresh for them to take effect). The first set of options is as follows:"); - txtpnFilteringAndOrdering1.setBounds(10, 40, 423, 63); - panel_1.add(txtpnFilteringAndOrdering1); - txtpnFilteringAndOrdering2.setFont(new Font("SansSerif", Font.PLAIN, 14)); - txtpnFilteringAndOrdering2.setContentType("text/html"); - txtpnFilteringAndOrdering2.setText("A 'complete' game is one where a winner was determined, and an 'incomplete' game is one which was ended prematurely. Complete games show as opaque in the table, whereas incomplete games will have a washed out effect.\r\n

\r\nWins are displayed in green, losses are displayed in red. An unknown result occurs when a game is ended before the player has been knocked out. These are displayed in grey. The remaining filter options should be self-explanatory. \r\n

\r\nTo sort the table, click on the title of the column you want to sort by:"); - txtpnFilteringAndOrdering2.setBounds(10, 173, 423, 220); - panel_1.add(txtpnFilteringAndOrdering2); - JLabel label = new JLabel(""); - label.setIcon(new ImageIcon(ToolsReplayViewer.class.getResource("/help/replayViewerFilters.png"))); - label.setBounds(50, 114, 338, 48); - panel_1.add(label); - JLabel lblNewLabel = new JLabel(""); - lblNewLabel.setIcon(new ImageIcon(ToolsReplayViewer.class.getResource("/help/replayViewerOrdering.png"))); - lblNewLabel.setBounds(15, 400, 412, 143); - panel_1.add(lblNewLabel); - panel_2.setLayout(null); - panel_2.setBackground(Color.WHITE); - panel_2.setBounds(11, 1500, 442, 317); - add(panel_2); - titleImportingExporting.setText("Importing & Exporting Replays"); - titleImportingExporting.setForeground(EntropyColour.COLOUR_HELP_TITLE); - titleImportingExporting.setFont(new Font("Tahoma", Font.BOLD, 18)); - titleImportingExporting.setBounds(10, 11, 299, 30); - panel_2.add(titleImportingExporting); - txtpnImportingExporting.setFont(new Font("SansSerif", Font.PLAIN, 14)); - txtpnImportingExporting.setContentType("text/html"); - txtpnImportingExporting.setText("Replays are divided into 'Personal' and 'Imported' categories. The Personal category corresponds to the replays you have recorded yourself, whilst the Imported category provides you with a way to view the replays of other people. \r\n

\r\nExporting: If you have a replay you want to show to someone else, you will first need to export it. To do this, select the row in your replay table and click the 'Export' button. This will allow you to choose a name for the file and save it somewhere on your PC.\r\n

\r\nImporting: Once you have a file to import, go to the 'Imported' tab of the Replay Viewer, find the file and click 'Import'. You shouldn't try to move it manually into the 'Imported' folder as this will skip the conversion process and so the file won't be readable."); - txtpnImportingExporting.setBounds(10, 40, 423, 280); - panel_2.add(txtpnImportingExporting); - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } -} \ No newline at end of file diff --git a/client/src/main/java/screen/HelpDialog.java b/client/src/main/java/screen/HelpDialog.java deleted file mode 100644 index ae4a0e9..0000000 --- a/client/src/main/java/screen/HelpDialog.java +++ /dev/null @@ -1,458 +0,0 @@ -package screen; -import help.FundamentalsGlossary; -import help.FundamentalsTheDeck; -import help.HelpPanel; -import help.MiscBugReport; -import help.MiscCheatCodes; -import help.MiscClearingSaveData; -import help.RulesEntropyBidding; -import help.RulesEntropyChallenging; -import help.RulesEntropyIntroduction; -import help.RulesIllegal; -import help.RulesVectropyBidding; -import help.RulesVectropyChallenging; -import help.RulesVectropyIntroduction; -import help.ToolsGameplaySettings; -import help.ToolsReplayViewer; - -import java.awt.Dimension; -import java.awt.Font; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; -import java.util.Enumeration; -import java.util.Timer; -import java.util.TimerTask; - -import javax.swing.BorderFactory; -import javax.swing.ImageIcon; -import javax.swing.JFormattedTextField; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTree; -import javax.swing.ScrollPaneConstants; -import javax.swing.SwingConstants; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; -import javax.swing.tree.TreeSelectionModel; - -import util.AchievementsUtil; -import util.Debug; -import util.Registry; - -@SuppressWarnings("serial") -public class HelpDialog extends JFrame - implements TreeSelectionListener, - WindowListener, - Registry -{ - private HelpPanel fundamentalsTheDeck = new FundamentalsTheDeck(); - private HelpPanel fundamentalsGlossary = new FundamentalsGlossary(); - private HelpPanel rulesEntropyIntroduction = new RulesEntropyIntroduction(); - private HelpPanel rulesEntropyBidding = new RulesEntropyBidding(); - private HelpPanel rulesEntropyChallenging = new RulesEntropyChallenging(); - private HelpPanel rulesVectropyIntroduction = new RulesVectropyIntroduction(); - private HelpPanel rulesVectropyBidding = new RulesVectropyBidding(); - private HelpPanel rulesVectropyChallenging = new RulesVectropyChallenging(); - private HelpPanel rulesIllegal = new RulesIllegal(); - private HelpPanel toolsGameplaySettings = new ToolsGameplaySettings(); - private HelpPanel toolsReplayViewer = new ToolsReplayViewer(); - private HelpPanel miscBugReport = new MiscBugReport(); - private HelpPanel miscClearingSaveData = new MiscClearingSaveData(); - private HelpPanel miscCheatCodes = new MiscCheatCodes(); - - private DefaultMutableTreeNode nodeToHighlightAfterSearch = null; - private DefaultMutableTreeNode currentNode = new DefaultMutableTreeNode(); - - private Timer bookwormTimer = null; - private long startTime = -1; - - public boolean fourColours = false; - public String backs = ""; - - public HelpDialog() - { - setTitle("Help"); - setSize(750, 550); - setResizable(false); - setIconImage(new ImageIcon(AchievementsDialog.class.getResource("/icons/help.png")).getImage()); - getContentPane().setLayout(null); - JPanel leftPane = new JPanel(); - leftPane.setBorder(null); - leftPane.setBounds(0, 0, 250, 522); - getContentPane().add(leftPane); - leftPane.setLayout(null); - searchBox.setBounds(62, 11, 178, 20); - leftPane.add(searchBox); - searchBox.setColumns(10); - lblSearch.setBounds(10, 14, 46, 14); - leftPane.add(lblSearch); - JPanel selectionTreePanel = new JPanel(); - selectionTreePanel.setBorder(null); - selectionTreePanel.setBounds(0, 40, 250, 482); - leftPane.add(selectionTreePanel); - selectionTreePanel.setLayout(null); - treePane.setBounds(10, 0, 240, 471); - selectionTreePanel.add(treePane); - tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - tree.addTreeSelectionListener(this); - treePane.setViewportView(tree); - JPanel rightPane = new JPanel(); - rightPane.setBorder(null); - rightPane.setBounds(250, 0, 494, 522); - getContentPane().add(rightPane); - rightPane.setLayout(null); - helpPane.setBounds(10, 11, 474, 500); - rightPane.add(helpPane); - helpPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - helpPane.setViewportView(new JPanel()); - helpPane.getVerticalScrollBar().setUnitIncrement(16); - noSearchResults.setVerticalAlignment(SwingConstants.TOP); - noSearchResults.setHorizontalAlignment(SwingConstants.CENTER); - noSearchResults.setFont(new Font("Tahoma", Font.ITALIC, 12)); - noSearchResults.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - - searchBox.getDocument().addDocumentListener(new DocumentListener() - { - @Override - public void changedUpdate(DocumentEvent e) - { - refreshNodes(searchBox.getText()); - } - @Override - public void removeUpdate(DocumentEvent e) - { - refreshNodes(searchBox.getText()); - } - @Override - public void insertUpdate(DocumentEvent e) - { - refreshNodes(searchBox.getText()); - } - }); - - addWindowListener(this); - } - - private JFormattedTextField searchBox = new JFormattedTextField(); - private JLabel lblSearch = new JLabel("Search:"); - private DefaultMutableTreeNode root = new DefaultMutableTreeNode("Index"); - private JTree tree = new JTree(root); - private JScrollPane helpPane = new JScrollPane(); - private JScrollPane treePane = new JScrollPane(); - private JLabel noSearchResults = new JLabel("There are no results to display."); - - public void initVariables() - { - fireAppearancePreferencesChange(); - - createNodes(); - toolsReplayViewer.setPreferredSize(new Dimension(455, 1830)); - miscClearingSaveData.setPreferredSize(new Dimension(455, 660)); - miscBugReport.setPreferredSize(new Dimension(455, 720)); - - startTime = System.currentTimeMillis(); - startTimer(); - } - - private void startTimer() - { - if (!achievements.getBoolean(ACHIEVEMENTS_BOOLEAN_BOOKWORM, false)) - { - bookwormTimer = new Timer("BookwormTimer"); - - TimerTask task = new AchievementsUtil.UnlockAchievementTask(ACHIEVEMENTS_BOOLEAN_BOOKWORM); - long time = Math.max(60000*5 - achievements.getLong(ACHIEVEMENTS_LONG_BOOKWORM_TIME, 0), 0); - bookwormTimer.schedule(task, time); - } - } - - private void createNodes() - { - populateFundamentals(""); - populateGameRules(""); - populateTools(""); - populateMisc(""); - - for (int i = 0; i < tree.getRowCount(); i++) { - tree.expandRow(i); - } - - tree.setRootVisible(false); - } - - public void refreshNodes(String searchStr) - { - try - { - nodeToHighlightAfterSearch = null; - root = new DefaultMutableTreeNode("Index"); - - populateFundamentals(searchStr); - populateGameRules(searchStr); - populateTools(searchStr); - populateMisc(searchStr); - - tree = new JTree(root); - tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - tree.addTreeSelectionListener(this); - - int count = tree.getRowCount(); - - if (count == 1) - { - treePane.setViewportView(noSearchResults); - helpPane.setViewportView(new JPanel()); - } - else - { - for (int i = 0; i < tree.getRowCount(); i++) - { - tree.expandRow(i); - } - - DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); - TreeNode[] nodePath = model.getPathToRoot(nodeToHighlightAfterSearch); - tree.setSelectionPath(new TreePath(nodePath)); - tree.setRootVisible(false); - treePane.setViewportView(tree); - } - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } - - private void populateFundamentals(String searchStr) - { - DefaultMutableTreeNode fundamentals = new DefaultMutableTreeNode("Fundamentals"); - - addNodeBasedOnString(fundamentals, fundamentalsTheDeck, searchStr); - addNodeBasedOnString(fundamentals, fundamentalsGlossary, searchStr); - - if (!fundamentals.isLeaf()) - { - root.add(fundamentals); - } - } - - private void populateGameRules(String searchStr) - { - DefaultMutableTreeNode gameRules = new DefaultMutableTreeNode("Game Rules"); - - DefaultMutableTreeNode entropyRules = new DefaultMutableTreeNode("Entropy"); - addNodeBasedOnString(entropyRules, rulesEntropyIntroduction, searchStr); - addNodeBasedOnString(entropyRules, rulesEntropyBidding, searchStr); - addNodeBasedOnString(entropyRules, rulesEntropyChallenging, searchStr); - - if (!entropyRules.isLeaf()) - { - gameRules.add(entropyRules); - } - - if (rewards.getBoolean(REWARDS_BOOLEAN_VECTROPY, false)) - { - DefaultMutableTreeNode vectropyRules = new DefaultMutableTreeNode("Vectropy"); - addNodeBasedOnString(vectropyRules, rulesVectropyIntroduction, searchStr); - addNodeBasedOnString(vectropyRules, rulesVectropyBidding, searchStr); - addNodeBasedOnString(vectropyRules, rulesVectropyChallenging, searchStr); - - if (!vectropyRules.isLeaf()) - { - gameRules.add(vectropyRules); - } - } - - if (rewards.getBoolean(REWARDS_BOOLEAN_ILLEGAL, false)) - { - addNodeBasedOnString(gameRules, rulesIllegal, searchStr); - } - - if (!gameRules.isLeaf()) - { - root.add(gameRules); - } - } - - private void populateTools(String searchStr) - { - DefaultMutableTreeNode preferences = new DefaultMutableTreeNode("Tools"); - - addNodeBasedOnString(preferences, toolsGameplaySettings, searchStr); - addNodeBasedOnString(preferences, toolsReplayViewer, searchStr); - - if (!preferences.isLeaf()) - { - root.add(preferences); - } - } - - private void populateMisc(String searchStr) - { - DefaultMutableTreeNode misc = new DefaultMutableTreeNode("Miscellaneous"); - - addNodeBasedOnString(misc, miscBugReport, searchStr); - addNodeBasedOnString(misc, miscClearingSaveData, searchStr); - - if (rewards.getBoolean(REWARDS_BOOLEAN_CHEATS, false)) - { - addNodeBasedOnString(misc, miscCheatCodes, searchStr); - } - - if (!misc.isLeaf()) - { - root.add(misc); - } - } - - private void addNodeBasedOnString(DefaultMutableTreeNode parent, HelpPanel node, String searchStr) - { - if (node.contains(searchStr)) - { - node.refresh(); - node.highlight(searchStr); - DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(node); - parent.add(childNode); - - String childStr = childNode.toString(); - String currentStr = currentNode.toString(); - - if (childStr.equals(currentStr)) - { - nodeToHighlightAfterSearch = childNode; - } - else if (nodeToHighlightAfterSearch == null) - { - nodeToHighlightAfterSearch = childNode; - } - } - } - - @Override - public void valueChanged(TreeSelectionEvent e) - { - try - { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent(); - currentNode = node; - - if (node == null) - { - return; - } - - Object nodeInfo = node.getUserObject(); - if (node.isLeaf()) - { - HelpPanel page = (HelpPanel)nodeInfo; - - if (page == null) - { - Debug.append("Page was null for node " + node, true); - return; - } - - helpPane.setViewport(null); - helpPane.setViewportView((HelpPanel)nodeInfo); - helpPane.createVerticalScrollBar(); - } - else - { - helpPane.setViewportView(new JPanel()); - } - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } - - @SuppressWarnings("unchecked") - public void setSelectionForWord() { - setSelectionForWord(null); - } - - @SuppressWarnings("unchecked") - public void setSelectionForWord(String word) - { - searchBox.setText(""); - refreshNodes(""); - Enumeration children = root.children(); - setSelectionForWordRecursively(children, word); - } - - @SuppressWarnings("unchecked") - private void setSelectionForWordRecursively(Enumeration nodes, String word) - { - while (nodes.hasMoreElements()) - { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)nodes.nextElement(); - if (node.isLeaf()) - { - HelpPanel panel = (HelpPanel)node.getUserObject(); - String panelName = panel.getPanelName(); - if (panelName.equals(word)) - { - DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); - TreeNode[] nodePath = model.getPathToRoot(node); - tree.setSelectionPath(new TreePath(nodePath)); - break; - } - } - else - { - Enumeration children = node.children(); - setSelectionForWordRecursively(children, word); - } - } - } - - public void fireAppearancePreferencesChange() - { - try - { - backs = prefs.get(PREFERENCES_STRING_CARD_BACKS, Registry.BACK_CODE_CLASSIC_BLUE); - fourColours = prefs.get(PREFERENCES_STRING_NUMBER_OF_COLOURS, Registry.TWO_COLOURS).equals(Registry.FOUR_COLOURS); - - if (isVisible()) - { - fundamentalsTheDeck.fireAppearancePreferencesChange(); - rulesVectropyBidding.fireAppearancePreferencesChange(); - } - } - catch (Throwable t) - { - Debug.stackTrace(t); - } - } - - @Override - public void windowActivated(WindowEvent arg0) {} - @Override - public void windowClosed(WindowEvent arg0) {} - @Override - public void windowClosing(WindowEvent arg0) - { - long timeSpentOnDialog = System.currentTimeMillis() - startTime; - long currentBookwormTime = achievements.getLong(ACHIEVEMENTS_LONG_BOOKWORM_TIME, 0); - achievements.putLong(ACHIEVEMENTS_LONG_BOOKWORM_TIME, currentBookwormTime + timeSpentOnDialog); - - bookwormTimer.cancel(); - } - @Override - public void windowDeactivated(WindowEvent arg0) {} - @Override - public void windowDeiconified(WindowEvent arg0) {} - @Override - public void windowIconified(WindowEvent arg0) {} - @Override - public void windowOpened(WindowEvent arg0) {} -} \ No newline at end of file diff --git a/client/src/main/kotlin/help/FundamentalsGlossary.kt b/client/src/main/kotlin/help/FundamentalsGlossary.kt new file mode 100644 index 0000000..e199d1d --- /dev/null +++ b/client/src/main/kotlin/help/FundamentalsGlossary.kt @@ -0,0 +1,55 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour +import util.Registry + +class FundamentalsGlossary : HelpPanel(), Registry { + override val nodeName = "Glossary" + + private val title = JTextPane() + private val paneOne = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.setBounds(21, 54, 429, 282) + add(paneOne) + title.text = "Glossary" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.setBounds(21, 25, 159, 30) + add(title) + + finaliseComponents() + } + + override fun searchTermsToExclude() = listOf("perfect", "challenge") + + override fun refresh() { + val blindUnlocked = Registry.rewards.getBoolean(Registry.REWARDS_BOOLEAN_BLIND, false) + + var glossaryText = "\r\n
    \r\n" + + if (blindUnlocked) { + glossaryText += + "
  • Blind: Playing blind means not looking at your cards.
  • \r\n" + } + + glossaryText += + "
  • Handicap: Starting a game with fewer cards than your opponents.
  • \r\n" + glossaryText += + "
  • Minbid: The minimum possible bid at a given moment, which varies for different variants of Entropy.
  • \r\n" + glossaryText += + "
  • Overbid: A bid which will lose to a challenge - the exact definition will vary for different variants of Entropy.
  • \r\n" + glossaryText += + "
  • Perfect Bid: The highest possible bid for a particular round. For achievements, this counts only if the numeric value is 5 or higher.
  • \r\n" + glossaryText += "
\r\n" + + paneOne.text = glossaryText + } +} diff --git a/client/src/main/kotlin/help/FundamentalsTheDeck.kt b/client/src/main/kotlin/help/FundamentalsTheDeck.kt new file mode 100644 index 0000000..285e141 --- /dev/null +++ b/client/src/main/kotlin/help/FundamentalsTheDeck.kt @@ -0,0 +1,186 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JLabel +import javax.swing.JTextPane +import javax.swing.SwingConstants +import util.CardsUtil +import util.EntropyColour +import util.Registry + +class FundamentalsTheDeck : HelpPanel(), Registry { + override val nodeName = "The Deck" + + private var clubString = "clubs (\u2663)" + private var diamondString = "diamonds (\u2666)" + private var moonString: String? = null + + private val title = JTextPane() + private val paneOne = JTextPane() + + private val clubLabel = JLabel("\u2663") + private val diamondLabel = JLabel("\u2666") + private val heartLabel = JLabel("\u2665") + private val moonLabel = JLabel(CardsUtil.MOONS_SYMBOL) + private val spadeLabel = JLabel("\u2660") + private val starLabel = JLabel(CardsUtil.STARS_SYMBOL) + private val label_3 = JLabel("<") + private val label_4 = JLabel("<") + private val label_5 = JLabel("<") + private val rightmostLabel = JLabel("<") + private val leftmostLabel = JLabel("<") + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.setBounds(21, 54, 429, 310) + add(paneOne) + title.text = "The Deck" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.setBounds(21, 25, 165, 30) + add(title) + clubLabel.horizontalAlignment = SwingConstants.CENTER + clubLabel.font = Font("Segoe UI Symbol", Font.PLAIN, 40) + clubLabel.setBounds(80, 360, 65, 60) + add(clubLabel) + label_4.horizontalAlignment = SwingConstants.CENTER + label_4.font = Font("Arial", Font.PLAIN, 40) + label_4.setBounds(120, 360, 65, 60) + add(label_4) + diamondLabel.horizontalAlignment = SwingConstants.CENTER + diamondLabel.foreground = Color.RED + diamondLabel.font = Font("Segoe UI Symbol", Font.PLAIN, 40) + diamondLabel.setBounds(160, 360, 65, 60) + add(diamondLabel) + label_3.horizontalAlignment = SwingConstants.CENTER + label_3.font = Font("Arial", Font.PLAIN, 40) + label_3.setBounds(200, 360, 65, 60) + add(label_3) + heartLabel.horizontalAlignment = SwingConstants.CENTER + heartLabel.foreground = Color.RED + heartLabel.font = Font("Segoe UI Symbol", Font.PLAIN, 40) + heartLabel.setBounds(240, 360, 65, 60) + add(heartLabel) + moonLabel.horizontalAlignment = SwingConstants.CENTER + moonLabel.foreground = EntropyColour.COLOUR_SUIT_PURPLE + moonLabel.font = Font("Segoe UI Symbol", Font.PLAIN, 32) + moonLabel.setBounds(240, 360, 65, 60) + add(moonLabel) + label_5.horizontalAlignment = SwingConstants.CENTER + label_5.font = Font("Arial", Font.PLAIN, 40) + label_5.setBounds(280, 360, 65, 60) + add(label_5) + spadeLabel.horizontalAlignment = SwingConstants.CENTER + spadeLabel.font = Font("Segoe UI Symbol", Font.PLAIN, 40) + spadeLabel.setBounds(320, 360, 65, 60) + add(spadeLabel) + rightmostLabel.horizontalAlignment = SwingConstants.CENTER + rightmostLabel.font = Font("Arial", Font.PLAIN, 40) + rightmostLabel.setBounds(360, 360, 65, 60) + add(rightmostLabel) + leftmostLabel.horizontalAlignment = SwingConstants.CENTER + leftmostLabel.font = Font("Arial", Font.PLAIN, 40) + leftmostLabel.setBounds(40, 360, 65, 60) + add(leftmostLabel) + starLabel.horizontalAlignment = SwingConstants.CENTER + starLabel.font = Font("Segoe UI Symbol", Font.PLAIN, 40) + starLabel.setBounds(400, 360, 65, 60) + starLabel.foreground = EntropyColour.COLOUR_SUIT_GOLD + add(starLabel) + + finaliseComponents() + } + + override fun searchTermsToExclude() = listOf("bidding") + + private fun setPaneOneText(moonsAndStars: Boolean) { + var paneOneText = + ("For the standard game, a normal deck of 52 cards is used. This deck is made up of four suits: " + + clubString + + ", " + + diamondString + + ", hearts (\u2665) and spades (\u2660), " + + "each of 13 cards. ") + + if (moonsAndStars) { + paneOneText += "Two optional suits, $moonString and stars " + paneOneText += + "(" + + CardsUtil.STARS_SYMBOL + + ") can also be added to the deck." + } + + paneOneText += + """ + The 13 cards in each suit are the 13 ranks of cards: ace (A), two (2), three (3), four (4), five (5), six (6), seven (7), eight (8), nine (9), ten (T), jack (J), queen (Q) and king (K). +

+ When playing Entropy and its variants, the focus is on the suit as that’s what is used during the bidding. Each card is worth one of its own suit, irrespective of rank. For example, the five of hearts (5) is worth one heart. However, aces are special cards. Not only are they worth one of their own suit, but they are also worth an extra one of all the suits. This means that the ace of spades (A♠) is worth one club, one diamond, one heart and two spades (one for being a spade and one for being an ace). +

+ To define whether one bid is higher than another, the suits are also ordered as follows: + + """ + .trimIndent() + + paneOne.text = paneOneText + } + + fun fireAppearancePreferencesChange() { + val fourColours = useFourColours() + val clubsColour = if (fourColours) "green" else "black" + val diamondsColour = if (fourColours) "blue" else "red" + val moonsColour = if (fourColours) "purple" else "CC9900" + + clubString = "clubs (\u2663)" + diamondString = "diamonds (\u2666)" + moonString = + "moons (" + + CardsUtil.MOONS_SYMBOL + + ")" + + val moonsAndStars = Registry.rewards.getBoolean(Registry.REWARDS_BOOLEAN_EXTRA_SUITS, false) + setPaneOneText(moonsAndStars) + + if (fourColours) { + clubLabel.foreground = Color(0, 128, 0) + diamondLabel.foreground = Color.BLUE + moonLabel.foreground = EntropyColour.COLOUR_SUIT_PURPLE + } else { + clubLabel.foreground = Color.black + diamondLabel.foreground = Color(255, 0, 0) + moonLabel.foreground = EntropyColour.COLOUR_SUIT_GOLD + } + } + + private fun refreshSuitRankingVisibility() { + val moonsAndStars = Registry.rewards.getBoolean(Registry.REWARDS_BOOLEAN_EXTRA_SUITS, false) + + if (moonsAndStars) { + moonLabel.isVisible = true + starLabel.isVisible = true + rightmostLabel.isVisible = true + leftmostLabel.isVisible = true + clubLabel.setBounds(0, 360, 65, 60) + diamondLabel.setBounds(80, 360, 65, 60) + heartLabel.setBounds(160, 360, 65, 60) + } else { + moonLabel.isVisible = false + starLabel.isVisible = false + rightmostLabel.isVisible = false + leftmostLabel.isVisible = false + clubLabel.setBounds(80, 360, 65, 60) + diamondLabel.setBounds(160, 360, 65, 60) + heartLabel.setBounds(240, 360, 65, 60) + } + } + + override fun refresh() { + fireAppearancePreferencesChange() + refreshSuitRankingVisibility() + } +} diff --git a/client/src/main/kotlin/help/HelpPanel.kt b/client/src/main/kotlin/help/HelpPanel.kt new file mode 100644 index 0000000..19ab4ab --- /dev/null +++ b/client/src/main/kotlin/help/HelpPanel.kt @@ -0,0 +1,231 @@ +package help + +import java.awt.Color +import java.awt.Cursor +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import java.awt.event.MouseMotionAdapter +import java.util.* +import javax.swing.JPanel +import javax.swing.JTextPane +import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter +import javax.swing.text.Highlighter +import screen.ScreenCache +import util.Registry +import utils.InjectedThings.logger +import utils.getAllChildComponentsForType + +/** Object representing a 'page' of the help dialog. */ +abstract class HelpPanel : JPanel() { + abstract val nodeName: String + + protected open fun searchTermsToExclude(): List { + return emptyList() + } + + protected fun finaliseComponents() { + addMouseListeners(searchTermsToExclude()) + setTextFieldsReadOnly() + } + + private fun getTextFields() = getAllChildComponentsForType(JTextPane::class.java) + + fun contains(searchStr: String): Boolean { + val searchStrLowerCase = searchStr.lowercase(Locale.getDefault()) + + for (fieldToCheck in getTextFields()) { + val fieldLength = fieldToCheck.document.length + val fieldText = fieldToCheck.document.getText(0, fieldLength) + val fieldTextLowerCase = fieldText.lowercase(Locale.getDefault()) + + if (fieldTextLowerCase.contains(searchStrLowerCase)) { + return true + } + } + + return false + } + + fun highlight(searchStr: String) { + val termLength = searchStr.length + + val hlp: Highlighter.HighlightPainter = DefaultHighlightPainter(Color.YELLOW) + + for (pane in getTextFields()) { + val highlighter = pane.highlighter + val paneLength = pane.document.length + + try { + highlighter.removeAllHighlights() + val paneText = getDocumentText(pane) + + for (i in 0..paneLength - termLength) { + val potentialSearchStr = paneText.substring(i, i + termLength) + + if ( + potentialSearchStr.equals(searchStr, ignoreCase = true) && + searchStr.isNotEmpty() + ) { + highlighter.addHighlight(i, i + termLength, hlp) + } + } + } catch (e: Throwable) { + logger.error("highlightError", "Error highlighting pane", e) + } + } + } + + private fun setTextFieldsReadOnly() { + for (pane in getTextFields()) { + pane.isEditable = false + } + } + + private fun addMouseListeners(wordsToExclude: List) { + for (pane in getTextFields()) { + pane.addMouseListener( + object : MouseAdapter() { + override fun mouseClicked(arg0: MouseEvent) { + val text = getDocumentText(pane) + val pt = arg0.point + val pos = pane.viewToModel(pt) + + val word = getWordFromPosition(text, pos) + + if (isKeyWord(word, wordsToExclude)) { + navigateToPageBasedOnKeyWord(word) + } + } + + override fun mouseEntered(arg0: MouseEvent) { + mouseHovered(pane, arg0, wordsToExclude) + } + } + ) + + pane.addMouseMotionListener( + object : MouseMotionAdapter() { + override fun mouseMoved(arg0: MouseEvent) { + mouseHovered(pane, arg0, wordsToExclude) + } + } + ) + } + } + + private fun mouseHovered(pane: JTextPane, arg0: MouseEvent, wordsToExclude: List) { + val text = getDocumentText(pane) + val pt = arg0.point + val pos = pane.viewToModel(pt) + + val word = getWordFromPosition(text, pos) + + cursor = + if (isKeyWord(word, wordsToExclude)) { + Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) + } else { + Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR) + } + } + + private fun getWordFromPosition(text: String, position: Int): String { + if (position < 1) { + return "" + } + + val character = text.substring(position - 1, position) + + if (!isLetter(character)) { + return "" + } + + var word = character + + if (position > 1) { + var i = 1 + var characterToTheLeft = text.substring(position - i - 1, position - i) + + while (isLetter(characterToTheLeft)) { + try { + word = characterToTheLeft + word + i++ + characterToTheLeft = text.substring(position - i - 1, position - i) + } catch (e: IndexOutOfBoundsException) { + characterToTheLeft = "" + } + } + } + + if (position < text.length) { + var i = 1 + var characterToTheRight = text.substring(position + i - 1, position + i) + + while (isLetter(characterToTheRight)) { + try { + word += characterToTheRight + i++ + characterToTheRight = text.substring(position + i - 1, position + i) + } catch (e: IndexOutOfBoundsException) { + characterToTheRight = "" + } + } + } + + return word.lowercase(Locale.getDefault()) + } + + private fun isLetter(letter: String): Boolean { + return letter.matches("^[a-zA-Z]+$".toRegex()) + } + + private fun navigateToPageBasedOnKeyWord(keyWord: String) { + logger.info("navigatedForWord", "Navigated for word $keyWord") + val helpDialog = ScreenCache.getHelpDialog() + + if (keyWord.startsWith("bidd")) { + if (javaClass.simpleName.contains("Entropy")) { + helpDialog.selectPane() + } else if (javaClass.simpleName.contains("Vectropy")) { + helpDialog.selectPane() + } + } else if (keyWord.startsWith("chall")) { + if (javaClass.simpleName.contains("Entropy")) { + helpDialog.selectPane() + } else if (javaClass.simpleName.contains("Vectropy")) { + helpDialog.selectPane() + } + } else if (keyWord == "order") { + helpDialog.selectPane() + } else if (keyWord == "perfect") { + helpDialog.selectPane() + } + } + + private fun getDocumentText(pane: JTextPane): String { + val length = pane.document.length + return pane.document.getText(0, length) + } + + private fun isKeyWord(word: String, wordsToExclude: List): Boolean { + for (wordToExclude in wordsToExclude) { + if (word.startsWith(wordToExclude) && wordToExclude.isNotEmpty()) { + return false + } + } + + return word == "bidding" || + word.startsWith("challeng") || + word == "order" || + word == "perfect" + } + + override fun toString() = nodeName + + protected fun useFourColours() = + Registry.prefs[Registry.PREFERENCES_STRING_NUMBER_OF_COLOURS, Registry.TWO_COLOURS] == + Registry.FOUR_COLOURS + + open fun refresh() { + // to be overridden by any pages that have dynamic content + } +} diff --git a/client/src/main/kotlin/help/MiscBugReport.kt b/client/src/main/kotlin/help/MiscBugReport.kt new file mode 100644 index 0000000..20a4c35 --- /dev/null +++ b/client/src/main/kotlin/help/MiscBugReport.kt @@ -0,0 +1,44 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.ImageIcon +import javax.swing.JLabel +import javax.swing.JTextPane +import util.EntropyColour + +class MiscBugReport : HelpPanel() { + override val nodeName = "Bug Report" + + private val title = JTextPane() + private val paneIntro = JTextPane() + + init { + background = Color.WHITE + layout = null + title.text = "Bug Report" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.isEditable = false + title.setBounds(21, 25, 192, 30) + add(title) + paneIntro.font = Font("SansSerif", Font.PLAIN, 14) + paneIntro.contentType = "text/html" + paneIntro.text = + "You can report any issues you may find through the 'Bug Report' feature, located under the 'Help' menu. Please include as much information as you can about what you were doing when you encountered the problem. \r\n

\r\nSending the bug report will also send logs that will help me to investigate, however these are lost when you exit the application so please send the bug report before doing so. In more severe circumstances the logs will get emailed automatically, so if you see the following error message you don't need to send a bug report yourself:" + paneIntro.setBounds(21, 408, 429, 190) + add(paneIntro) + + val lblNewLabel = JLabel("") + lblNewLabel.icon = ImageIcon(MiscBugReport::class.java.getResource("/help/bugReport.png")) + lblNewLabel.setBounds(70, 66, 320, 321) + add(lblNewLabel) + + val label = JLabel("") + label.icon = ImageIcon(MiscBugReport::class.java.getResource("/help/bugError.png")) + label.setBounds(35, 610, 379, 105) + add(label) + + finaliseComponents() + } +} diff --git a/client/src/main/kotlin/help/MiscCheatCodes.kt b/client/src/main/kotlin/help/MiscCheatCodes.kt new file mode 100644 index 0000000..ff47fc6 --- /dev/null +++ b/client/src/main/kotlin/help/MiscCheatCodes.kt @@ -0,0 +1,45 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour + +class MiscCheatCodes : HelpPanel() { + override val nodeName = "Cheat Codes" + + private val title = JTextPane() + private val paneIntro = JTextPane() + private val paneOne = JTextPane() + + private val cheatsText = + ("- showmethecards: Turn all hands face-up!

" + + "- maxbids: Lists the amount of each suit present in the current game.

" + + "- perfectbid: Gives you the perfect bid for the current round. Returns the same value as maxbids if playing in Vectropy mode.

" + + "- rainingjokers: Randomly turns 1-5 of the cards in play into jokers.

" + + "- bluescreenofdeath: Unlocks the hidden 'Blue Screen of Death' achievement (pfft, like you've not already got it).

" + + "- simulator: Opens the Entropy Simulator. This was used during development to pit strategies against one another so that we could test enhancements and rank them.") + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = cheatsText + paneOne.setBounds(21, 156, 429, 317) + add(paneOne) + title.text = "Cheat Codes" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.setBounds(21, 25, 192, 30) + add(title) + paneIntro.font = Font("SansSerif", Font.PLAIN, 14) + paneIntro.contentType = "text/html" + paneIntro.text = + "Congratulations on reaching 50 achievements! Here are some cheats you can enter whilst playing the game, which I originally created to make testing easier. Whilst in the main window, press CTRL+; to bring up the command bar, then enter any of the following commands:" + paneIntro.setBounds(21, 54, 429, 91) + add(paneIntro) + + finaliseComponents() + } +} diff --git a/client/src/main/kotlin/help/MiscClearingSaveData.kt b/client/src/main/kotlin/help/MiscClearingSaveData.kt new file mode 100644 index 0000000..290b1c7 --- /dev/null +++ b/client/src/main/kotlin/help/MiscClearingSaveData.kt @@ -0,0 +1,45 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.ImageIcon +import javax.swing.JLabel +import javax.swing.JTextPane +import util.EntropyColour + +class MiscClearingSaveData : HelpPanel() { + override val nodeName = "Clearing Data" + + private val title = JTextPane() + private val paneIntro = JTextPane() + private val paneOne = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = + "\r\n- Statistics Only: This will clear anything that appears under your statistics such as time played and total games won. Clearing this will preserve any achievements you have already earned, but any progress made towards locked achievements (e.g. those for amount of time played) will be lost.\r\n

\r\n- Achievements and Statistics: This will again clear your statistics, but will this time also remove any achievements you have already earned.\r\n

\r\n- My Replays / Imported Replays: These options will attempt to delete the replay files in your Personal / Imported folders. Note that it is not possible to recover these once they have been deleted, so be certain that you want to do this before proceeding.\r\n" + paneOne.setBounds(21, 360, 429, 279) + add(paneOne) + title.text = "Clearing Saved Data" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.setBounds(21, 25, 192, 30) + add(title) + val lblNewLabel = JLabel("") + lblNewLabel.icon = + ImageIcon(MiscClearingSaveData::class.java.getResource("/help/clearData.png")) + lblNewLabel.setBounds(120, 114, 230, 230) + add(lblNewLabel) + paneIntro.font = Font("SansSerif", Font.PLAIN, 14) + paneIntro.contentType = "text/html" + paneIntro.text = + "Options to clear saved data can be found under File > Clear Data. This will bring up the following dialog: " + paneIntro.setBounds(21, 54, 429, 50) + add(paneIntro) + + finaliseComponents() + } +} diff --git a/client/src/main/kotlin/help/RulesEntropyBidding.kt b/client/src/main/kotlin/help/RulesEntropyBidding.kt new file mode 100644 index 0000000..ae94131 --- /dev/null +++ b/client/src/main/kotlin/help/RulesEntropyBidding.kt @@ -0,0 +1,46 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour + +class RulesEntropyBidding : HelpPanel() { + override val nodeName = "Bidding" + + private val title = JTextPane() + private val paneOne = JTextPane() + private val subtitle = JTextPane() + private val paneTwo = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = + "A round starts with the first person to play bidding. At the start of a new game, the round is started by a player chosen at random. In each subsequent round the loser of the previous round starts, unless losing the last round caused them to go out. In this case, the person to the left of the losing player starts the next round.\r\n

\r\nEach bid must be a suit and a number, for example \"2 Spades\". Each subsequent bid must be higher than the last, including adhering to the suit order. Bidding continues clockwise round the players. At any point a player may opt to challenge the current bid rather than making a higher bid of their own." + paneOne.setBounds(21, 54, 429, 220) + add(paneOne) + paneTwo.font = Font("SansSerif", Font.PLAIN, 14) + paneTwo.contentType = "text/html" + paneTwo.text = + "A bid is higher than another if the number is higher or if the number is equal and the suit is higher. For example, \"3 Hearts\" is higher than \"2 Hearts\", as 3 is greater than 2. \"3 Hearts\" is lower than \"3 Spades\" because spades is a higher suit than hearts. " + paneTwo.setBounds(21, 313, 429, 100) + add(paneTwo) + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.text = "Bidding" + title.setBounds(21, 25, 159, 30) + add(title) + subtitle.text = "Bid Hierarchy" + subtitle.foreground = EntropyColour.COLOUR_HELP_TITLE + subtitle.font = Font("Tahoma", Font.BOLD, 18) + subtitle.setBounds(21, 284, 159, 30) + add(subtitle) + + finaliseComponents() + } + + override fun searchTermsToExclude() = listOf("bidding") +} diff --git a/client/src/main/kotlin/help/RulesEntropyChallenging.kt b/client/src/main/kotlin/help/RulesEntropyChallenging.kt new file mode 100644 index 0000000..47b0749 --- /dev/null +++ b/client/src/main/kotlin/help/RulesEntropyChallenging.kt @@ -0,0 +1,33 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour + +class RulesEntropyChallenging : HelpPanel() { + override val nodeName = "Challenging" + + private val title = JTextPane() + private val paneOne = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = + "Any player whose turn it is to bid can choose to challenge instead. This means that the player does not believe that there are as many cards of the suit as bid by the previous player. When a player challenges, all cards are revealed on the table and counted. The challenge is then evaluated.\r\n

\r\nIf a challenge is successful, the player who made the last bid loses the round, whereas if it is unsuccessful the player who challenged is the one to lose. Whether or not a challenge is successful is determined by how many of the suit were actually present – it is successful if there were fewer than the number bid and unsuccessful otherwise. \r\n

\r\nFor example if Tom bids five hearts and Alex challenges him, that means Alex thinks there are fewer than five hearts in all the players cards. The cards are turned over and counted. In fact there were six hearts, so Alex lost the challenge and loses a card for the next round." + paneOne.setBounds(21, 54, 429, 353) + add(paneOne) + title.text = "Challenging" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.setBounds(21, 25, 216, 30) + add(title) + + finaliseComponents() + } + + override fun searchTermsToExclude() = listOf("challeng") +} diff --git a/client/src/main/kotlin/help/RulesEntropyIntroduction.kt b/client/src/main/kotlin/help/RulesEntropyIntroduction.kt new file mode 100644 index 0000000..77539a5 --- /dev/null +++ b/client/src/main/kotlin/help/RulesEntropyIntroduction.kt @@ -0,0 +1,31 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour + +class RulesEntropyIntroduction : HelpPanel() { + override val nodeName = "Introduction" + + private val title = JTextPane() + private val paneOne = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = + "Entropy is a bidding game for 2-4 players, played with one or more decks of cards. The players are dealt hands of up to 5 cards and play proceeds clockwise, with each player bidding higher than those before until someone challenges and the cards are revealed. \r\n

\r\nThe loser of the challenge loses one card for the next round. Rounds continue until only one player has cards left, at which point they are declared the winner." + paneOne.setBounds(21, 54, 418, 158) + add(paneOne) + title.text = "Introduction" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.setBounds(21, 25, 159, 30) + add(title) + + finaliseComponents() + } +} diff --git a/client/src/main/kotlin/help/RulesIllegal.kt b/client/src/main/kotlin/help/RulesIllegal.kt new file mode 100644 index 0000000..dee0000 --- /dev/null +++ b/client/src/main/kotlin/help/RulesIllegal.kt @@ -0,0 +1,33 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour + +class RulesIllegal : HelpPanel() { + override val nodeName = "Illegal!" + + private val title = JTextPane() + private val paneOne = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = + "The 'Illegal' option provides an alternative to bidding higher or challenging when facing a bid. If a player declares 'Illegal', they claim that the bid they were faced with was perfect. If they are right the opponent loses a card for the next round, else they lose a card - regardless of whether the bid they were faced with was an overbid or an underbid." + paneOne.setBounds(21, 54, 429, 220) + add(paneOne) + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.text = "Illegal!" + title.setBounds(21, 25, 159, 30) + add(title) + + finaliseComponents() + } + + override fun searchTermsToExclude() = listOf("bid") +} diff --git a/client/src/main/kotlin/help/RulesVectropyBidding.kt b/client/src/main/kotlin/help/RulesVectropyBidding.kt new file mode 100644 index 0000000..181dca7 --- /dev/null +++ b/client/src/main/kotlin/help/RulesVectropyBidding.kt @@ -0,0 +1,88 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour +import util.Registry + +class RulesVectropyBidding : HelpPanel(), Registry { + override val nodeName = "Bidding" + + private val title = JTextPane() + private val paneOne = JTextPane() + private val subtitle = JTextPane() + private val paneTwo = JTextPane() + + private var clubsColour = "black" + private var diamondsColour = "red" + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.setBounds(21, 54, 429, 230) + add(paneOne) + paneTwo.font = Font("SansSerif", Font.PLAIN, 14) + paneTwo.contentType = "text/html" + paneTwo.text = + "A bid is higher than another if the sum of its elements is higher, with the added restriction that each bid must include at least as many of each individual suit as the one before it. For example, if faced with a bid of (0, 0, 0, 2):\r\n\r\n
    \r\n
  • (1, 0, 0, 2) is a valid higher bid because it includes (0, 0, 0, 2).
  • \r\n
  • (5, 5, 5, 0) is a higher bid, but this is not legal because it contains fewer spades than the bid before it.
" + paneTwo.font = Font("Tahoma", Font.PLAIN, 14) + paneTwo.setBounds(21, 320, 429, 156) + add(paneTwo) + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.text = "Bidding" + title.setBounds(21, 25, 159, 30) + add(title) + subtitle.text = "Bid Hierarchy" + subtitle.foreground = EntropyColour.COLOUR_HELP_TITLE + subtitle.font = Font("Tahoma", Font.BOLD, 18) + subtitle.setBounds(21, 290, 159, 30) + add(subtitle) + + finaliseComponents() + } + + override fun searchTermsToExclude() = listOf("bidding") + + fun fireAppearancePreferencesChange() { + val fourColours = useFourColours() + clubsColour = if (fourColours) "green" else "black" + diamondsColour = if (fourColours) "blue" else "red" + } + + override fun refresh() { + setPaneOneText() + } + + private fun setPaneOneText() { + val extraSuits = Registry.rewards.getBoolean(Registry.REWARDS_BOOLEAN_EXTRA_SUITS, false) + + var text = + "A round starts with the first person to play bidding. At the start of a new game, " + text += + "the round is started by a player chosen at random. In each subsequent round the loser of the previous " + text += + "round starts, unless losing the last round caused them to go out. In this case, the person to the left " + text += + "of the losing player starts the next round.\r\n

\r\nEach bid is an ordered vector of four numbers. " + text += + "These numbers represent the amount that is being bid for each suit from lowest to highest - " + text += + "(\u2663, \u2666, " + text += "\u2665, \u2660). " + + if (extraSuits) { + text += "This vector naturally extends if additional suits are in play. " + } + + text += + "Each subsequent bid must be higher than the last. Bidding continues clockwise round the players. " + text += + "At any point a player may opt to challenge the current bid rather than making a higher bid of their own.\r\n\r\n\r\n" + + paneOne.text = text + } +} diff --git a/client/src/main/kotlin/help/RulesVectropyChallenging.kt b/client/src/main/kotlin/help/RulesVectropyChallenging.kt new file mode 100644 index 0000000..0cd92fc --- /dev/null +++ b/client/src/main/kotlin/help/RulesVectropyChallenging.kt @@ -0,0 +1,33 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour + +class RulesVectropyChallenging : HelpPanel() { + override val nodeName = "Challenging" + + private val title = JTextPane() + private val paneOne = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = + "Any player whose turn it is to bid can choose to challenge instead. This means that the player does not believe that there are as many cards of one or more of the suits bid by the previous player. When a player challenges, all cards are revealed on the table and counted. The challenge is then evaluated.\r\n

\r\nIf a challenge is successful, the player who made the last bid loses the round, whereas if it is unsuccessful the player who challenged is the one to lose. Whether or not a challenge is successful is determined by how many of the four suits were actually present \u2013 it is successful if there were fewer of any of the suits bid, and unsuccessful otherwise.\r\n

\r\nFor example, in a game with 3 clubs, 4 diamonds, 2 hearts and 2 spades, challenging a bid of (3, 2, 1, 0) would be unsuccessful as there were at least as many cards as bid in all four suits. A bid of (3, 3, 0, 3), however, contains more spades than are present, so challenging this would be successful." + paneOne.setBounds(21, 54, 429, 353) + add(paneOne) + title.text = "Challenging" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.setBounds(21, 25, 216, 30) + add(title) + + finaliseComponents() + } + + override fun searchTermsToExclude() = listOf("challeng") +} diff --git a/client/src/main/kotlin/help/RulesVectropyIntroduction.kt b/client/src/main/kotlin/help/RulesVectropyIntroduction.kt new file mode 100644 index 0000000..0e37f11 --- /dev/null +++ b/client/src/main/kotlin/help/RulesVectropyIntroduction.kt @@ -0,0 +1,31 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import util.EntropyColour + +class RulesVectropyIntroduction : HelpPanel() { + override val nodeName = "Introduction" + + private val title = JTextPane() + private val paneOne = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = + "Vectropy is a variant of Entropy where the bidding requires players to bid in all four suits at once. As before, the players are dealt hands of up to 5 cards and play proceeds clockwise, with each player bidding higher than those before until someone challenges and the cards are revealed. \r\n

\r\nThe loser of the challenge loses one card for the next round. Rounds continue until only one player has cards left, at which point they are declared the winner." + paneOne.setBounds(21, 54, 418, 158) + add(paneOne) + title.text = "Introduction" + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.setBounds(21, 25, 159, 30) + add(title) + + finaliseComponents() + } +} diff --git a/client/src/main/kotlin/help/ToolsGameplaySettings.kt b/client/src/main/kotlin/help/ToolsGameplaySettings.kt new file mode 100644 index 0000000..da087b1 --- /dev/null +++ b/client/src/main/kotlin/help/ToolsGameplaySettings.kt @@ -0,0 +1,149 @@ +package help + +import java.awt.Color +import java.awt.Dimension +import java.awt.Font +import javax.swing.ImageIcon +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.JTextPane +import util.EntropyColour +import util.Registry + +class ToolsGameplaySettings : HelpPanel(), Registry { + override val nodeName = "Gameplay Settings" + + private val title = JTextPane() + private val bulletThree = JLabel("") + private val bulletFour = JLabel("") + private val playBlindImage = JLabel("") + private val txtpnOneTitle = JTextPane() + private val txtpnOneExplanation = JTextPane() + private val txtpnTwoTitle = JTextPane() + private val txtpnTwoExplanation = JTextPane() + private val txtpnThreeTitle = JTextPane() + private val txtpnThreeExplanation = JTextPane() + private val txtpnTickbox = JTextPane() + private val txtpnFourTitle = JTextPane() + private val txtpnIfThisIs = JTextPane() + private val txtpnHandicap_1 = JTextPane() + private val txtpnWithThisTicked_1 = JTextPane() + private val blindPanel = JPanel() + private val panel = JPanel() + private val label = JLabel("") + + init { + background = Color.WHITE + layout = null + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.text = "Preferences: Gameplay" + title.setBounds(21, 25, 259, 30) + add(title) + val bulletOne = JLabel("") + bulletOne.icon = + ImageIcon(ToolsGameplaySettings::class.java.getResource("/help/numberOne.png")) + bulletOne.setBounds(24, 78, 25, 25) + add(bulletOne) + val bulletTwo = JLabel("") + bulletTwo.icon = + ImageIcon(ToolsGameplaySettings::class.java.getResource("/help/numberTwo.png")) + bulletTwo.setBounds(24, 130, 25, 25) + add(bulletTwo) + txtpnOneTitle.font = Font("Tahoma", Font.BOLD, 12) + txtpnOneTitle.text = "Starting Cards" + txtpnOneTitle.setBounds(54, 132, 118, 20) + add(txtpnOneTitle) + txtpnOneExplanation.font = Font("Tahoma", Font.PLAIN, 12) + txtpnOneExplanation.text = + "A simple slider to set how many cards are dealt to each player at the start of a new game." + txtpnOneExplanation.setBounds(54, 156, 390, 36) + add(txtpnOneExplanation) + txtpnTwoTitle.text = "Game Mode" + txtpnTwoTitle.font = Font("Tahoma", Font.BOLD, 12) + txtpnTwoTitle.setBounds(54, 80, 118, 20) + add(txtpnTwoTitle) + txtpnTwoExplanation.text = "Toggle between the different game modes you have unlocked." + txtpnTwoExplanation.font = Font("Tahoma", Font.PLAIN, 12) + txtpnTwoExplanation.setBounds(54, 104, 390, 25) + add(txtpnTwoExplanation) + val jokerPanel = JPanel() + jokerPanel.background = Color.WHITE + jokerPanel.setBounds(21, 206, 423, 128) + add(jokerPanel) + jokerPanel.layout = null + bulletThree.setBounds(3, 4, 25, 25) + jokerPanel.add(bulletThree) + bulletThree.icon = + ImageIcon(ToolsGameplaySettings::class.java.getResource("/help/numberThree.png")) + txtpnThreeTitle.setBounds(33, 6, 118, 20) + jokerPanel.add(txtpnThreeTitle) + txtpnThreeTitle.text = "Joker Settings" + txtpnThreeTitle.font = Font("Tahoma", Font.BOLD, 12) + txtpnThreeExplanation.setBounds(33, 30, 390, 19) + jokerPanel.add(txtpnThreeExplanation) + txtpnThreeExplanation.text = "Settings to vary how many jokers are included in the deck:" + txtpnThreeExplanation.font = Font("Tahoma", Font.PLAIN, 12) + txtpnTickbox.contentType = "text/html" + txtpnTickbox.text = + "- Tickbox: Whether jokers are included or not.
\r\n- Quantity: How many jokers to add, between 1 and 4.
\r\n- Value: The worth of each joker, between 2 and 4. Jokers will be worth this many of every suit.
" + txtpnTickbox.setBounds(33, 60, 380, 68) + jokerPanel.add(txtpnTickbox) + panel.setBounds(21, 342, 423, 104) + add(panel) + panel.layout = null + panel.background = Color.WHITE + label.icon = + ImageIcon(ToolsGameplaySettings::class.java.getResource("/help/numberFour.png")) + label.setBounds(3, 4, 25, 25) + panel.add(label) + txtpnHandicap_1.text = "Handicap" + txtpnHandicap_1.font = Font("Tahoma", Font.BOLD, 12) + txtpnHandicap_1.setBounds(33, 6, 118, 20) + panel.add(txtpnHandicap_1) + txtpnWithThisTicked_1.text = + "With this ticked, you will be dealt less cards than your opponents at the start of a new game. The number represents how many cards less you will be dealt - so the higher the number, the larger your disadvantage will be. " + txtpnWithThisTicked_1.font = Font("Tahoma", Font.PLAIN, 12) + txtpnWithThisTicked_1.setBounds(33, 30, 390, 66) + panel.add(txtpnWithThisTicked_1) + blindPanel.layout = null + blindPanel.background = Color.WHITE + blindPanel.setBounds(21, 460, 423, 296) + add(blindPanel) + bulletFour.setBounds(3, 4, 25, 25) + blindPanel.add(bulletFour) + bulletFour.icon = + ImageIcon(ToolsGameplaySettings::class.java.getResource("/help/numberFive.png")) + txtpnFourTitle.font = Font("Tahoma", Font.BOLD, 12) + txtpnFourTitle.setBounds(33, 6, 217, 20) + blindPanel.add(txtpnFourTitle) + txtpnIfThisIs.isOpaque = false + txtpnIfThisIs.font = Font("Tahoma", Font.PLAIN, 12) + txtpnIfThisIs.setBounds(33, 37, 380, 66) + blindPanel.add(txtpnIfThisIs) + playBlindImage.icon = + ImageIcon( + ToolsGameplaySettings::class.java.getResource("/help/playingBlind_backBlue.png") + ) + playBlindImage.setBounds(128, 114, 199, 157) + blindPanel.add(playBlindImage) + + finaliseComponents() + } + + override fun refresh() { + val unlockedBlind = Registry.rewards.getBoolean(Registry.REWARDS_BOOLEAN_BLIND, false) + blindPanel.isVisible = unlockedBlind + + if (unlockedBlind) { + preferredSize = Dimension(455, 750) + txtpnFourTitle.text = "Blind Play" + txtpnIfThisIs.text = + "If this is ticked, your cards will be dealt face-down at the start of every round. \r\nYou will still be able to view your cards at any time by pressing the eye symbol below them:" + } else { + preferredSize = Dimension(455, 450) + txtpnFourTitle.text = "" + txtpnIfThisIs.text = "" + } + } +} diff --git a/client/src/main/kotlin/help/ToolsReplayViewer.kt b/client/src/main/kotlin/help/ToolsReplayViewer.kt new file mode 100644 index 0000000..ec4bef7 --- /dev/null +++ b/client/src/main/kotlin/help/ToolsReplayViewer.kt @@ -0,0 +1,142 @@ +package help + +import java.awt.Color +import java.awt.Font +import javax.swing.ImageIcon +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.JTextPane +import util.EntropyColour + +class ToolsReplayViewer : HelpPanel() { + override val nodeName = "Replay Viewer" + + private val title = JTextPane() + private val lblReplayTable = JLabel("") + private val txtpnIntroduction = JTextPane() + private val txtpnSavingReplays1 = JTextPane() + private val titleSavingReplays = JTextPane() + private val txtpnSavingReplays2 = JTextPane() + private val lblSaveReplaysOption = JLabel("") + private val titleUsingTheReplayViewer = JTextPane() + private val txtpnUsingTheReplayViewer1 = JTextPane() + private val txtpnUsingTheReplayViewer2 = JTextPane() + private val titleFilteringAndOrdering = JTextPane() + private val txtpnFilteringAndOrdering1 = JTextPane() + private val txtpnFilteringAndOrdering2 = JTextPane() + private val titleImportingExporting = JTextPane() + private val txtpnImportingExporting = JTextPane() + private val panel_2 = JPanel() + + init { + background = Color.WHITE + layout = null + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.text = "The Replay Viewer" + title.setBounds(21, 25, 188, 30) + add(title) + txtpnIntroduction.contentType = "text/html" + txtpnIntroduction.font = Font("SansSerif", Font.PLAIN, 14) + txtpnIntroduction.text = + "The Replay Viewer provides a useful interface for you to watch back all your past games of Entropy. Replays are shown in a colour-coded table, with filter options to make it easy to locate a specific game." + txtpnIntroduction.setBounds(21, 54, 429, 66) + add(txtpnIntroduction) + txtpnSavingReplays1.font = Font("SansSerif", Font.PLAIN, 14) + txtpnSavingReplays1.contentType = "text/html" + txtpnSavingReplays1.text = + "To use the Replay Viewer, you will first need to turn on the setting to save replays. You will find this under the 'Miscellaneous' tab in Preferences:" + txtpnSavingReplays1.setBounds(21, 157, 423, 66) + add(txtpnSavingReplays1) + titleSavingReplays.text = "Saving Replays" + titleSavingReplays.foreground = EntropyColour.COLOUR_HELP_TITLE + titleSavingReplays.font = Font("Tahoma", Font.BOLD, 18) + titleSavingReplays.setBounds(21, 128, 188, 30) + add(titleSavingReplays) + txtpnSavingReplays2.font = Font("SansSerif", Font.PLAIN, 14) + txtpnSavingReplays2.contentType = "text/html" + txtpnSavingReplays2.text = + "You will need to tick this option and choose a place for the replays to be saved. This will create a new folder called 'Replays', with sub-folders 'Personal' (for your own replays) and 'Imported' (see Importing & Exporting Replays, lower down).\r\n

\r\nNote: If you change your mind about this location at any point, you can change it without losing any data. You will be given the option to move all of the replay files over to the new location so all of your existing replays will be preserved." + txtpnSavingReplays2.setBounds(21, 291, 423, 177) + add(txtpnSavingReplays2) + lblSaveReplaysOption.icon = + ImageIcon(ToolsReplayViewer::class.java.getResource("/help/replayViewerSettings.png")) + lblSaveReplaysOption.setBounds(62, 234, 309, 38) + add(lblSaveReplaysOption) + val panel = JPanel() + panel.background = Color.WHITE + panel.setBounds(11, 480, 494, 461) + add(panel) + panel.layout = null + titleUsingTheReplayViewer.text = "Using the Replay Viewer" + titleUsingTheReplayViewer.foreground = EntropyColour.COLOUR_HELP_TITLE + titleUsingTheReplayViewer.font = Font("Tahoma", Font.BOLD, 18) + titleUsingTheReplayViewer.setBounds(10, 11, 262, 30) + panel.add(titleUsingTheReplayViewer) + txtpnUsingTheReplayViewer1.font = Font("SansSerif", Font.PLAIN, 14) + txtpnUsingTheReplayViewer1.contentType = "text/html" + txtpnUsingTheReplayViewer1.text = + "Once you have saved some replays, you will see a table like the following:" + txtpnUsingTheReplayViewer1.setBounds(10, 40, 423, 44) + panel.add(txtpnUsingTheReplayViewer1) + lblReplayTable.setBounds(10, 95, 428, 264) + panel.add(lblReplayTable) + lblReplayTable.icon = + ImageIcon(ToolsReplayViewer::class.java.getResource("/help/replayViewerTable.png")) + txtpnUsingTheReplayViewer2.font = Font("SansSerif", Font.PLAIN, 14) + txtpnUsingTheReplayViewer2.contentType = "text/html" + txtpnUsingTheReplayViewer2.text = + "Double-clicking on a row will show that replay. You can also select a row and press the enter key.\r\n
You can also delete one or more replays by selecting the row(s) and pressing the delete key." + txtpnUsingTheReplayViewer2.setBounds(10, 370, 423, 84) + panel.add(txtpnUsingTheReplayViewer2) + val panel_1 = JPanel() + panel_1.layout = null + panel_1.background = Color.WHITE + panel_1.setBounds(11, 940, 494, 554) + add(panel_1) + titleFilteringAndOrdering.text = "Filtering and Sorting Replays" + titleFilteringAndOrdering.foreground = EntropyColour.COLOUR_HELP_TITLE + titleFilteringAndOrdering.font = Font("Tahoma", Font.BOLD, 18) + titleFilteringAndOrdering.setBounds(10, 11, 280, 30) + panel_1.add(titleFilteringAndOrdering) + txtpnFilteringAndOrdering1.font = Font("SansSerif", Font.PLAIN, 14) + txtpnFilteringAndOrdering1.contentType = "text/html" + txtpnFilteringAndOrdering1.text = + "Many filter options are available on the left hand side to help you narrow down the selection (you need to click refresh for them to take effect). The first set of options is as follows:" + txtpnFilteringAndOrdering1.setBounds(10, 40, 423, 63) + panel_1.add(txtpnFilteringAndOrdering1) + txtpnFilteringAndOrdering2.font = Font("SansSerif", Font.PLAIN, 14) + txtpnFilteringAndOrdering2.contentType = "text/html" + txtpnFilteringAndOrdering2.text = + "A 'complete' game is one where a winner was determined, and an 'incomplete' game is one which was ended prematurely. Complete games show as opaque in the table, whereas incomplete games will have a washed out effect.\r\n

\r\nWins are displayed in green, losses are displayed in red. An unknown result occurs when a game is ended before the player has been knocked out. These are displayed in grey. The remaining filter options should be self-explanatory. \r\n

\r\nTo sort the table, click on the title of the column you want to sort by:" + txtpnFilteringAndOrdering2.setBounds(10, 173, 423, 220) + panel_1.add(txtpnFilteringAndOrdering2) + val label = JLabel("") + label.icon = + ImageIcon(ToolsReplayViewer::class.java.getResource("/help/replayViewerFilters.png")) + label.setBounds(50, 114, 338, 48) + panel_1.add(label) + val lblNewLabel = JLabel("") + lblNewLabel.icon = + ImageIcon(ToolsReplayViewer::class.java.getResource("/help/replayViewerOrdering.png")) + lblNewLabel.setBounds(15, 400, 412, 143) + panel_1.add(lblNewLabel) + panel_2.layout = null + panel_2.background = Color.WHITE + panel_2.setBounds(11, 1500, 442, 317) + add(panel_2) + titleImportingExporting.text = "Importing & Exporting Replays" + titleImportingExporting.foreground = EntropyColour.COLOUR_HELP_TITLE + titleImportingExporting.font = Font("Tahoma", Font.BOLD, 18) + titleImportingExporting.setBounds(10, 11, 299, 30) + panel_2.add(titleImportingExporting) + txtpnImportingExporting.font = Font("SansSerif", Font.PLAIN, 14) + txtpnImportingExporting.contentType = "text/html" + txtpnImportingExporting.text = + "Replays are divided into 'Personal' and 'Imported' categories. The Personal category corresponds to the replays you have recorded yourself, whilst the Imported category provides you with a way to view the replays of other people. \r\n

\r\nExporting: If you have a replay you want to show to someone else, you will first need to export it. To do this, select the row in your replay table and click the 'Export' button. This will allow you to choose a name for the file and save it somewhere on your PC.\r\n

\r\nImporting: Once you have a file to import, go to the 'Imported' tab of the Replay Viewer, find the file and click 'Import'. You shouldn't try to move it manually into the 'Imported' folder as this will skip the conversion process and so the file won't be readable." + txtpnImportingExporting.setBounds(10, 40, 423, 280) + panel_2.add(txtpnImportingExporting) + + finaliseComponents() + } +} diff --git a/client/src/main/kotlin/screen/HelpDialog.kt b/client/src/main/kotlin/screen/HelpDialog.kt new file mode 100644 index 0000000..ca9811e --- /dev/null +++ b/client/src/main/kotlin/screen/HelpDialog.kt @@ -0,0 +1,388 @@ +package screen + +import help.FundamentalsGlossary +import help.FundamentalsTheDeck +import help.HelpPanel +import help.MiscBugReport +import help.MiscCheatCodes +import help.MiscClearingSaveData +import help.RulesEntropyBidding +import help.RulesEntropyChallenging +import help.RulesEntropyIntroduction +import help.RulesIllegal +import help.RulesVectropyBidding +import help.RulesVectropyChallenging +import help.RulesVectropyIntroduction +import help.ToolsGameplaySettings +import help.ToolsReplayViewer +import java.awt.Dimension +import java.awt.Font +import java.awt.event.WindowEvent +import java.awt.event.WindowListener +import java.util.* +import javax.swing.BorderFactory +import javax.swing.ImageIcon +import javax.swing.JFormattedTextField +import javax.swing.JFrame +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.JScrollPane +import javax.swing.JTree +import javax.swing.ScrollPaneConstants +import javax.swing.SwingConstants +import javax.swing.event.DocumentEvent +import javax.swing.event.DocumentListener +import javax.swing.event.TreeSelectionEvent +import javax.swing.event.TreeSelectionListener +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.DefaultTreeModel +import javax.swing.tree.TreeNode +import javax.swing.tree.TreePath +import javax.swing.tree.TreeSelectionModel +import kotlin.math.max +import util.AchievementsUtil.UnlockAchievementTask +import util.Registry +import utils.InjectedThings.logger + +class HelpDialog : JFrame(), TreeSelectionListener, WindowListener, Registry { + private val fundamentalsTheDeck = FundamentalsTheDeck() + private val fundamentalsGlossary = FundamentalsGlossary() + private val rulesEntropyIntroduction = RulesEntropyIntroduction() + private val rulesEntropyBidding = RulesEntropyBidding() + private val rulesEntropyChallenging = RulesEntropyChallenging() + private val rulesVectropyIntroduction = RulesVectropyIntroduction() + private val rulesVectropyBidding = RulesVectropyBidding() + private val rulesVectropyChallenging = RulesVectropyChallenging() + private val rulesIllegal = RulesIllegal() + private val toolsGameplaySettings = ToolsGameplaySettings() + private val toolsReplayViewer = ToolsReplayViewer() + private val miscBugReport = MiscBugReport() + private val miscClearingSaveData = MiscClearingSaveData() + private val miscCheatCodes = MiscCheatCodes() + + private var nodeToHighlightAfterSearch: DefaultMutableTreeNode? = null + private var currentNode: DefaultMutableTreeNode? = DefaultMutableTreeNode() + + private var bookwormTimer: Timer? = null + private var startTime: Long = -1 + + private val searchBox = JFormattedTextField() + private var root = DefaultMutableTreeNode("Index") + private var tree = JTree(root) + private val helpPane = JScrollPane() + private val treePane = JScrollPane() + private val noSearchResults = JLabel("There are no results to display.") + + init { + title = "Help" + setSize(750, 550) + isResizable = false + iconImage = ImageIcon(AchievementsDialog::class.java.getResource("/icons/help.png")).image + contentPane.layout = null + val leftPane = JPanel() + leftPane.border = null + leftPane.setBounds(0, 0, 250, 522) + contentPane.add(leftPane) + leftPane.layout = null + searchBox.setBounds(62, 11, 178, 20) + leftPane.add(searchBox) + searchBox.columns = 10 + val lblSearch = JLabel("Search:") + lblSearch.setBounds(10, 14, 46, 14) + leftPane.add(lblSearch) + val selectionTreePanel = JPanel() + selectionTreePanel.border = null + selectionTreePanel.setBounds(0, 40, 250, 482) + leftPane.add(selectionTreePanel) + selectionTreePanel.layout = null + treePane.setBounds(10, 0, 240, 471) + selectionTreePanel.add(treePane) + tree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION + tree.addTreeSelectionListener(this) + treePane.setViewportView(tree) + val rightPane = JPanel() + rightPane.border = null + rightPane.setBounds(250, 0, 494, 522) + contentPane.add(rightPane) + rightPane.layout = null + helpPane.setBounds(10, 11, 474, 500) + rightPane.add(helpPane) + helpPane.horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER + helpPane.setViewportView(JPanel()) + helpPane.verticalScrollBar.unitIncrement = 16 + noSearchResults.verticalAlignment = SwingConstants.TOP + noSearchResults.horizontalAlignment = SwingConstants.CENTER + noSearchResults.font = Font("Tahoma", Font.ITALIC, 12) + noSearchResults.border = BorderFactory.createEmptyBorder(10, 10, 10, 10) + + searchBox.document.addDocumentListener( + object : DocumentListener { + override fun changedUpdate(e: DocumentEvent) { + refreshNodes(searchBox.text) + } + + override fun removeUpdate(e: DocumentEvent) { + refreshNodes(searchBox.text) + } + + override fun insertUpdate(e: DocumentEvent) { + refreshNodes(searchBox.text) + } + } + ) + + addWindowListener(this) + } + + fun initVariables() { + fireAppearancePreferencesChange() + + createNodes() + toolsReplayViewer.preferredSize = Dimension(455, 1830) + miscClearingSaveData.preferredSize = Dimension(455, 660) + miscBugReport.preferredSize = Dimension(455, 720) + + startTime = System.currentTimeMillis() + startTimer() + } + + private fun startTimer() { + if (!Registry.achievements.getBoolean(Registry.ACHIEVEMENTS_BOOLEAN_BOOKWORM, false)) { + bookwormTimer = Timer("BookwormTimer") + + val task: TimerTask = UnlockAchievementTask(Registry.ACHIEVEMENTS_BOOLEAN_BOOKWORM) + val time = + max( + (60000 * 5 - + Registry.achievements.getLong( + Registry.ACHIEVEMENTS_LONG_BOOKWORM_TIME, + 0 + )) + .toDouble(), + 0.0 + ) + .toLong() + bookwormTimer!!.schedule(task, time) + } + } + + private fun createNodes() { + populateFundamentals("") + populateGameRules("") + populateTools("") + populateMisc("") + + for (i in 0 ..< tree.rowCount) { + tree.expandRow(i) + } + + tree.isRootVisible = false + } + + fun refreshNodes(searchStr: String) { + nodeToHighlightAfterSearch = null + root = DefaultMutableTreeNode("Index") + + populateFundamentals(searchStr) + populateGameRules(searchStr) + populateTools(searchStr) + populateMisc(searchStr) + + tree = JTree(root) + tree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION + tree.addTreeSelectionListener(this) + + if (root.childCount == 0) { + treePane.setViewportView(noSearchResults) + helpPane.setViewportView(JPanel()) + } else { + for (i in 0 ..< 50) { + tree.expandRow(i) + } + + val model = tree.model as DefaultTreeModel + val nodePath = model.getPathToRoot(nodeToHighlightAfterSearch) + tree.selectionPath = TreePath(nodePath) + tree.isRootVisible = false + treePane.setViewportView(tree) + } + } + + private fun populateFundamentals(searchStr: String) { + val fundamentals = DefaultMutableTreeNode("Fundamentals") + + addNodeBasedOnString(fundamentals, fundamentalsTheDeck, searchStr) + addNodeBasedOnString(fundamentals, fundamentalsGlossary, searchStr) + + if (!fundamentals.isLeaf) { + root.add(fundamentals) + } + } + + private fun populateGameRules(searchStr: String) { + val gameRules = DefaultMutableTreeNode("Game Rules") + + val entropyRules = DefaultMutableTreeNode("Entropy") + addNodeBasedOnString(entropyRules, rulesEntropyIntroduction, searchStr) + addNodeBasedOnString(entropyRules, rulesEntropyBidding, searchStr) + addNodeBasedOnString(entropyRules, rulesEntropyChallenging, searchStr) + + if (!entropyRules.isLeaf) { + gameRules.add(entropyRules) + } + + if (Registry.rewards.getBoolean(Registry.REWARDS_BOOLEAN_VECTROPY, false)) { + val vectropyRules = DefaultMutableTreeNode("Vectropy") + addNodeBasedOnString(vectropyRules, rulesVectropyIntroduction, searchStr) + addNodeBasedOnString(vectropyRules, rulesVectropyBidding, searchStr) + addNodeBasedOnString(vectropyRules, rulesVectropyChallenging, searchStr) + + if (!vectropyRules.isLeaf) { + gameRules.add(vectropyRules) + } + } + + if (Registry.rewards.getBoolean(Registry.REWARDS_BOOLEAN_ILLEGAL, false)) { + addNodeBasedOnString(gameRules, rulesIllegal, searchStr) + } + + if (!gameRules.isLeaf) { + root.add(gameRules) + } + } + + private fun populateTools(searchStr: String) { + val preferences = DefaultMutableTreeNode("Tools") + + addNodeBasedOnString(preferences, toolsGameplaySettings, searchStr) + addNodeBasedOnString(preferences, toolsReplayViewer, searchStr) + + if (!preferences.isLeaf) { + root.add(preferences) + } + } + + private fun populateMisc(searchStr: String) { + val misc = DefaultMutableTreeNode("Miscellaneous") + + addNodeBasedOnString(misc, miscBugReport, searchStr) + addNodeBasedOnString(misc, miscClearingSaveData, searchStr) + + if (Registry.rewards.getBoolean(Registry.REWARDS_BOOLEAN_CHEATS, false)) { + addNodeBasedOnString(misc, miscCheatCodes, searchStr) + } + + if (!misc.isLeaf) { + root.add(misc) + } + } + + private fun addNodeBasedOnString( + parent: DefaultMutableTreeNode, + node: HelpPanel, + searchStr: String + ) { + if (node.contains(searchStr)) { + node.refresh() + node.highlight(searchStr) + val childNode = DefaultMutableTreeNode(node) + parent.add(childNode) + + val childStr = childNode.toString() + val currentStr = currentNode.toString() + + if (childStr == currentStr) { + nodeToHighlightAfterSearch = childNode + } else if (nodeToHighlightAfterSearch == null) { + nodeToHighlightAfterSearch = childNode + } + } + } + + override fun valueChanged(e: TreeSelectionEvent) { + val node = tree.lastSelectedPathComponent as? DefaultMutableTreeNode + currentNode = node + + if (node == null) { + return + } + + val nodeInfo = node.userObject + if (node.isLeaf) { + val page = nodeInfo as? HelpPanel + + if (page == null) { + logger.info("nullHelpPage", "Page was null for node $node") + return + } + + helpPane.viewport = null + helpPane.setViewportView(nodeInfo) + helpPane.createVerticalScrollBar() + } else { + helpPane.setViewportView(JPanel()) + } + } + + inline fun selectPane() { + selectPane(T::class.java) + } + + fun selectPane(clazz: Class) { + searchBox.text = "" + refreshNodes("") + val children = root.children() + selectPaneRecursively(children, clazz) + } + + private fun selectPaneRecursively( + nodes: Enumeration, + clazz: Class + ) { + while (nodes.hasMoreElements()) { + val node = nodes.nextElement() as DefaultMutableTreeNode + if (node.isLeaf) { + if (node.userObject.javaClass == clazz) { + val model = tree.model as DefaultTreeModel + val nodePath = model.getPathToRoot(node) + tree.selectionPath = TreePath(nodePath) + break + } + } else { + val children = node.children() + selectPaneRecursively(children, clazz) + } + } + } + + fun fireAppearancePreferencesChange() { + if (isVisible) { + fundamentalsTheDeck.fireAppearancePreferencesChange() + rulesVectropyBidding.fireAppearancePreferencesChange() + } + } + + override fun windowActivated(arg0: WindowEvent) {} + + override fun windowClosed(arg0: WindowEvent) {} + + override fun windowClosing(arg0: WindowEvent) { + val timeSpentOnDialog = System.currentTimeMillis() - startTime + val currentBookwormTime = + Registry.achievements.getLong(Registry.ACHIEVEMENTS_LONG_BOOKWORM_TIME, 0) + Registry.achievements.putLong( + Registry.ACHIEVEMENTS_LONG_BOOKWORM_TIME, + currentBookwormTime + timeSpentOnDialog + ) + + bookwormTimer?.cancel() + } + + override fun windowDeactivated(arg0: WindowEvent) {} + + override fun windowDeiconified(arg0: WindowEvent) {} + + override fun windowIconified(arg0: WindowEvent) {} + + override fun windowOpened(arg0: WindowEvent) {} +} diff --git a/client/src/test/kotlin/help/AbstractHelpPanelTest.kt b/client/src/test/kotlin/help/AbstractHelpPanelTest.kt new file mode 100644 index 0000000..1029b78 --- /dev/null +++ b/client/src/test/kotlin/help/AbstractHelpPanelTest.kt @@ -0,0 +1,18 @@ +package help + +import io.kotest.matchers.shouldBe +import javax.swing.JTextPane +import main.kotlin.testCore.AbstractTest +import org.junit.jupiter.api.Test +import utils.getAllChildComponentsForType + +abstract class AbstractHelpPanelTest : AbstractTest() { + abstract fun factory(): T + + @Test + fun `All text panes should be read-only`() { + val pane = factory() + val textPanes = pane.getAllChildComponentsForType() + textPanes.forEach { it.isEditable shouldBe false } + } +} diff --git a/client/src/test/kotlin/help/FundamentalsGlossaryTest.kt b/client/src/test/kotlin/help/FundamentalsGlossaryTest.kt new file mode 100644 index 0000000..ccfe537 --- /dev/null +++ b/client/src/test/kotlin/help/FundamentalsGlossaryTest.kt @@ -0,0 +1,5 @@ +package help + +class FundamentalsGlossaryTest : AbstractHelpPanelTest() { + override fun factory() = FundamentalsGlossary() +} diff --git a/client/src/test/kotlin/help/FundamentalsTheDeckTest.kt b/client/src/test/kotlin/help/FundamentalsTheDeckTest.kt new file mode 100644 index 0000000..4d99fb4 --- /dev/null +++ b/client/src/test/kotlin/help/FundamentalsTheDeckTest.kt @@ -0,0 +1,5 @@ +package help + +class FundamentalsTheDeckTest : AbstractHelpPanelTest() { + override fun factory() = FundamentalsTheDeck() +} diff --git a/client/src/test/kotlin/help/HelpPanelTest.kt b/client/src/test/kotlin/help/HelpPanelTest.kt new file mode 100644 index 0000000..6c0a379 --- /dev/null +++ b/client/src/test/kotlin/help/HelpPanelTest.kt @@ -0,0 +1,47 @@ +package help + +import io.kotest.matchers.shouldBe +import java.awt.Color +import java.awt.Font +import javax.swing.JTextPane +import main.kotlin.testCore.AbstractTest +import org.junit.jupiter.api.Test +import util.EntropyColour + +class HelpPanelTest : AbstractTest() { + @Test + fun `should report whether text is contained`() { + val panel = FakeHelpPanel() + + panel.contains("first") shouldBe true + panel.contains("second") shouldBe true + panel.contains("third") shouldBe false + } +} + +class FakeHelpPanel : HelpPanel() { + override val nodeName = "Fake Panel" + + private val title = JTextPane() + private val paneOne = JTextPane() + private val paneTwo = JTextPane() + + init { + background = Color.WHITE + layout = null + paneOne.font = Font("SansSerif", Font.PLAIN, 14) + paneOne.contentType = "text/html" + paneOne.text = "First panel." + paneOne.setBounds(21, 54, 429, 220) + add(paneOne) + paneTwo.text = "Second panel." + add(paneTwo) + title.foreground = EntropyColour.COLOUR_HELP_TITLE + title.font = Font("Tahoma", Font.BOLD, 18) + title.text = "Fake Panel" + title.setBounds(21, 25, 159, 30) + add(title) + + finaliseComponents() + } +} diff --git a/client/src/test/kotlin/help/MiscBugReportTest.kt b/client/src/test/kotlin/help/MiscBugReportTest.kt new file mode 100644 index 0000000..271893f --- /dev/null +++ b/client/src/test/kotlin/help/MiscBugReportTest.kt @@ -0,0 +1,5 @@ +package help + +class MiscBugReportTest : AbstractHelpPanelTest() { + override fun factory() = MiscBugReport() +} diff --git a/client/src/test/kotlin/help/MiscCheatCodesTest.kt b/client/src/test/kotlin/help/MiscCheatCodesTest.kt new file mode 100644 index 0000000..6e067d1 --- /dev/null +++ b/client/src/test/kotlin/help/MiscCheatCodesTest.kt @@ -0,0 +1,5 @@ +package help + +class MiscCheatCodesTest : AbstractHelpPanelTest() { + override fun factory() = MiscCheatCodes() +} diff --git a/client/src/test/kotlin/help/MiscClearingSaveDataTest.kt b/client/src/test/kotlin/help/MiscClearingSaveDataTest.kt new file mode 100644 index 0000000..4ed1a8e --- /dev/null +++ b/client/src/test/kotlin/help/MiscClearingSaveDataTest.kt @@ -0,0 +1,5 @@ +package help + +class MiscClearingSaveDataTest : AbstractHelpPanelTest() { + override fun factory() = MiscClearingSaveData() +} diff --git a/client/src/test/kotlin/help/RulesEntropyBiddingTest.kt b/client/src/test/kotlin/help/RulesEntropyBiddingTest.kt new file mode 100644 index 0000000..d7ed8c0 --- /dev/null +++ b/client/src/test/kotlin/help/RulesEntropyBiddingTest.kt @@ -0,0 +1,5 @@ +package help + +class RulesEntropyBiddingTest : AbstractHelpPanelTest() { + override fun factory() = RulesEntropyBidding() +} diff --git a/client/src/test/kotlin/help/RulesEntropyChallengingTest.kt b/client/src/test/kotlin/help/RulesEntropyChallengingTest.kt new file mode 100644 index 0000000..8fa5ecf --- /dev/null +++ b/client/src/test/kotlin/help/RulesEntropyChallengingTest.kt @@ -0,0 +1,5 @@ +package help + +class RulesEntropyChallengingTest : AbstractHelpPanelTest() { + override fun factory() = RulesEntropyChallenging() +} diff --git a/client/src/test/kotlin/help/RulesEntropyIntroductionTest.kt b/client/src/test/kotlin/help/RulesEntropyIntroductionTest.kt new file mode 100644 index 0000000..7af6a87 --- /dev/null +++ b/client/src/test/kotlin/help/RulesEntropyIntroductionTest.kt @@ -0,0 +1,5 @@ +package help + +class RulesEntropyIntroductionTest : AbstractHelpPanelTest() { + override fun factory() = RulesEntropyIntroduction() +} diff --git a/client/src/test/kotlin/help/RulesIllegalTest.kt b/client/src/test/kotlin/help/RulesIllegalTest.kt new file mode 100644 index 0000000..9dab0a2 --- /dev/null +++ b/client/src/test/kotlin/help/RulesIllegalTest.kt @@ -0,0 +1,5 @@ +package help + +class RulesIllegalTest : AbstractHelpPanelTest() { + override fun factory() = RulesIllegal() +} diff --git a/client/src/test/kotlin/help/RulesVectropyBiddingTest.kt b/client/src/test/kotlin/help/RulesVectropyBiddingTest.kt new file mode 100644 index 0000000..c3d407c --- /dev/null +++ b/client/src/test/kotlin/help/RulesVectropyBiddingTest.kt @@ -0,0 +1,5 @@ +package help + +class RulesVectropyBiddingTest : AbstractHelpPanelTest() { + override fun factory() = RulesVectropyBidding() +} diff --git a/client/src/test/kotlin/help/RulesVectropyChallengingTest.kt b/client/src/test/kotlin/help/RulesVectropyChallengingTest.kt new file mode 100644 index 0000000..2866f0c --- /dev/null +++ b/client/src/test/kotlin/help/RulesVectropyChallengingTest.kt @@ -0,0 +1,5 @@ +package help + +class RulesVectropyChallengingTest : AbstractHelpPanelTest() { + override fun factory() = RulesVectropyChallenging() +} diff --git a/client/src/test/kotlin/help/RulesVectropyIntroductionTest.kt b/client/src/test/kotlin/help/RulesVectropyIntroductionTest.kt new file mode 100644 index 0000000..a48727d --- /dev/null +++ b/client/src/test/kotlin/help/RulesVectropyIntroductionTest.kt @@ -0,0 +1,5 @@ +package help + +class RulesVectropyIntroductionTest : AbstractHelpPanelTest() { + override fun factory() = RulesVectropyIntroduction() +} diff --git a/client/src/test/kotlin/help/ToolsGameplaySettingsTest.kt b/client/src/test/kotlin/help/ToolsGameplaySettingsTest.kt new file mode 100644 index 0000000..e183b50 --- /dev/null +++ b/client/src/test/kotlin/help/ToolsGameplaySettingsTest.kt @@ -0,0 +1,5 @@ +package help + +class ToolsGameplaySettingsTest : AbstractHelpPanelTest() { + override fun factory() = ToolsGameplaySettings() +} diff --git a/client/src/test/kotlin/help/ToolsReplayViewerTest.kt b/client/src/test/kotlin/help/ToolsReplayViewerTest.kt new file mode 100644 index 0000000..e4fe680 --- /dev/null +++ b/client/src/test/kotlin/help/ToolsReplayViewerTest.kt @@ -0,0 +1,5 @@ +package help + +class ToolsReplayViewerTest : AbstractHelpPanelTest() { + override fun factory() = ToolsReplayViewer() +} diff --git a/core/src/main/kotlin/utils/SwingUtils.kt b/core/src/main/kotlin/utils/SwingUtils.kt new file mode 100644 index 0000000..7d0ef7c --- /dev/null +++ b/core/src/main/kotlin/utils/SwingUtils.kt @@ -0,0 +1,34 @@ +package utils + +import java.awt.Component +import java.awt.Container + +/** + * Recurses through all child components, returning an ArrayList of all children of the appropriate + * type + */ +inline fun Container.getAllChildComponentsForType() = + getAllChildComponentsForType(T::class.java) + +fun Container.getAllChildComponentsForType(clazz: Class): List { + val ret = mutableListOf() + + val components = components + addComponents(ret, components, clazz) + + return ret +} + +@Suppress("UNCHECKED_CAST") +fun addComponents(ret: MutableList, components: Array, desiredClazz: Class) { + for (comp in components) { + if (desiredClazz.isInstance(comp)) { + ret.add(comp as T) + } + + if (comp is Container) { + val subComponents = comp.components + addComponents(ret, subComponents, desiredClazz) + } + } +} diff --git a/core/src/test/kotlin/logging/LoggingConsoleTest.kt b/core/src/test/kotlin/logging/LoggingConsoleTest.kt index a612886..305b582 100644 --- a/core/src/test/kotlin/logging/LoggingConsoleTest.kt +++ b/core/src/test/kotlin/logging/LoggingConsoleTest.kt @@ -10,9 +10,9 @@ import java.awt.Color import javax.swing.JLabel import javax.swing.text.StyleConstants import main.kotlin.testCore.AbstractTest -import main.kotlin.testCore.getAllChildComponentsForType import main.kotlin.testCore.makeLogRecord import org.junit.jupiter.api.Test +import utils.getAllChildComponentsForType class LoggingConsoleTest : AbstractTest() { @Test @@ -133,9 +133,4 @@ class LoggingConsoleTest : AbstractTest() { val style = doc.getCharacterElement(position) return StyleConstants.getForeground(style.attributes) } - - private fun LoggingConsole.getBackgroundColour(): Color { - val style = doc.getCharacterElement(0) - return StyleConstants.getBackground(style.attributes) - } } diff --git a/test-core/src/main/kotlin/testCore/TestUtils.kt b/test-core/src/main/kotlin/testCore/TestUtils.kt index e628a9c..929fd8a 100644 --- a/test-core/src/main/kotlin/testCore/TestUtils.kt +++ b/test-core/src/main/kotlin/testCore/TestUtils.kt @@ -4,8 +4,6 @@ import com.github.alyssaburlton.swingtest.findAll import com.github.alyssaburlton.swingtest.findWindow import com.github.alyssaburlton.swingtest.flushEdt import io.kotest.matchers.maps.shouldContainExactly -import java.awt.Component -import java.awt.Container import java.time.Instant import javax.swing.JDialog import javax.swing.JLabel @@ -26,33 +24,6 @@ fun makeLogRecord( keyValuePairs: Map = mapOf() ) = LogRecord(timestamp, severity, loggingCode, message, errorObject, keyValuePairs) -/** - * Recurses through all child components, returning an ArrayList of all children of the appropriate - * type - */ -inline fun Container.getAllChildComponentsForType(): List { - val ret = mutableListOf() - - val components = components - addComponents(ret, components, T::class.java) - - return ret -} - -@Suppress("UNCHECKED_CAST") -fun addComponents(ret: MutableList, components: Array, desiredClazz: Class) { - for (comp in components) { - if (desiredClazz.isInstance(comp)) { - ret.add(comp as T) - } - - if (comp is Container) { - val subComponents = comp.components - addComponents(ret, subComponents, desiredClazz) - } - } -} - fun getInfoDialog() = getOptionPaneDialog("Information") fun getQuestionDialog() = getOptionPaneDialog("Question")