package client.frame;
import game.dice.Dice;
import game.gamesheet.GameSheet;
import general.statics.function.GUIFunctions;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;
import server.constants.CommandList;
import server.protocol.Message;
import client.Client;
import client.custom.DrawingPanel;
import client.custom.JCustomField;
import client.custom.JCustomPane;
import client.custom.JCustomPanel;
import client.frame.listener.InstructButtonListener;
import client.frame.listener.LeaveButtonListener;
import client.frame.timer.ActTimeCountdown;
import client.frame.timer.JLabelSubscriber;
import client.gui.Constants;
import client.model.GameSheetTableModel;
import client.model.GameSheetTitleTableModel;
/**
* The <code>GameplayFrame</code> class, a descendant of <code>YahtzeeFrame</code>, is the frame class for displaying the
* main gameplay screen of the Yahtzee game. Contains a huge pile of dynamic inputs and controls.
*
* @author Priidu Neemre
*/
public class GameplayFrame extends YahtzeeFrame{
//Constants
private static final long serialVersionUID = 00000001L;
public static final int WINDOW_WIDTH = 900;
public static final int WINDOW_HEIGHT = 600;
public static final int DIE_ROLL_AREA_DIMENSION = 150;
public static final int DIE_SAVE_AREA_HEIGHT = 200;
public static final int DIE_SAVE_AREA_WIDTH = 10;
public static final int SCORETABLE_HEIGHT = 315;
public static final int SCORETABLE_ROW_WIDTH = 80;
public static final int SCORETABLEHEADER_ROW_WIDTH = 160;
public static final int INFO_AREA_HEIGHT = 220;
public static final int INFO_AREA_WIDTH = 500;
public static final int LEADER_AREA_HEIGHT = 250;
public static final int LEADER_AREA_WIDTH = 120;
//GENERAL GUI elements
private JCustomPanel bgPanel;
private DrawingPanel drawingPanel;
//GENERAL MENU GUI elements (lower eastern corner)
private JButton newGameBtn;
private JButton instructionsBtn;
private JButton leaveGameBtn;
private JPanel generalButtonPanel;
private JLabel txt_generalMenu;
private JPanel generalButtonHeadingPanel;
//PLAY MENU GUI elements (upper eastern corner)
private JLabel txt_playMenu;
private JPanel playHeadingPanel;
private JButton rollDiceBtn;
private JLabel txt_rollsLeft;
private JLabel rollsLeftInd;
private JPanel rollPanel;
private JLabel txt_turnTimeLeft;
private JLabelSubscriber turnTimerText;
private JPanel turnTimePanel;
private JButton skipTurnBtn;
private JPanel skipPanel;
//TURN/PLAYERINFO area elements (upper eastern corner)
private JLabel txt_loggedIn;
private JLabel playerNameInd;
private JLabel txt_curRoller;
private JLabel rollerNameInd;
JPanel turnMenuPanel;
//JTABLEes and their table model bases
private GameSheetTableModel gameSheetGUI;
private JTable scoreSheet;
private GameSheetTitleTableModel gameSheetTitles;
private JTable scoreSheetTitles;
private JScrollPane containerPane;
//CHAT/INFO area elements (for displaying in-game chat, server announcements etc.)
private JTextArea logArea;
private JScrollPane logAreaPane;
private JButton btnSayText;
private JTextField sayField;
//LEADERBOARD elements (for displaying the all-time Hall-of-Fame scores)
private JLabel txt_leaderArea;
private JTextArea leaderArea;
private JScrollPane leaderAreaPane;
private JPanel leaderAreaPanel;
//Pointers to crucial business-logic objects
private Dice curGameDice;
private GameSheet gameSheet;
//Pointers to crucial technical objects
private Client client;
public GameplayFrame(Client client){
this.curGameDice = client.getDice();
this.gameSheet = client.getGameSheet();
this.client = client;
buildConfigureJFrame();
buildConfigureMainContainers(curGameDice);
buildConfigureTurnMenu();
buildConfigurePlayMenuGUI(curGameDice);
buildConfigureLeaderboardGUI();
buildConfigureGeneralMenuGUI();
buildConfigureJTable(gameSheet);
buildConfigureLoggingArea();
weldTogetherEasternMenus();
updateGUIIndicators();
this.setVisible(true);
}
/**
* Sets the desired properties for the <code>GameplayFrame</code> itself.
*/
private void buildConfigureJFrame(){
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(350,150);
this.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
this.setTitle(FRAME_DEFAULT_TITLE);
this.setLocationRelativeTo(null); //Align the JFrame to the center of the screen
}
/**
* Instantiates variables and enforces properties in connection with the main containers of the frame.
*/
private void buildConfigureMainContainers(Dice curGameDice){
//Create the contentpane JPanel(bgPanel) of the frame, the root container for all following elements
bgPanel = new JCustomPanel(new BorderLayout(), Constants.MAIN_BACKGROUND_IMAGE_PATH);
bgPanel.setBorder(BorderFactory.createMatteBorder(1,1,1,1,Color.BLACK));
setContentPane(bgPanel);
//Create a panel for animation behaviour (drawingPanel) to display dice rolls etc.
drawingPanel = new DrawingPanel(curGameDice);
drawingPanel.addMouseListener(new ClickDiceListener());
drawingPanel.setOpaque(false);
getContentPane().add(drawingPanel);
}
/**
* Instantiates variables and enforces properties for all the elements of the GUI's "Turn menu" area.
*/
private void buildConfigureTurnMenu(){
txt_loggedIn = new JLabel("Logged in as: ");
txt_loggedIn.setFont(Constants.tahoma_mediumsmall_bold);
txt_loggedIn.setForeground(Color.WHITE);
playerNameInd = new JLabel("TurkWarrior");
playerNameInd.setFont(Constants.tahoma_mediumsmall_bold);
playerNameInd.setForeground(Color.RED);
txt_curRoller = new JLabel("Currently rolling: ");
txt_curRoller.setFont(Constants.tahoma_mediumsmall_bold);
txt_curRoller.setForeground(Color.WHITE);
rollerNameInd = new JLabel("Metsamees123");
rollerNameInd.setFont(Constants.tahoma_mediumsmall_bold);
rollerNameInd.setForeground(Color.RED);
turnMenuPanel = new JCustomPanel(new FlowLayout(FlowLayout.LEFT), Constants.REGULAR_TILE_IMAGE_PATH);
turnMenuPanel.setPreferredSize(new Dimension(120, 78));
turnMenuPanel.setBorder(BorderFactory.createMatteBorder(0, 1, 1, 0, Color.BLACK));
turnMenuPanel.setOpaque(false);
turnMenuPanel.add(txt_loggedIn);
turnMenuPanel.add(playerNameInd);
turnMenuPanel.add(txt_curRoller);
turnMenuPanel.add(rollerNameInd);
}
/**
* Instantiates variables and enforces properties for all the elements of the GUI's "General menu" area.
*/
private void buildConfigureGeneralMenuGUI(){
newGameBtn = new JButton("Join new game");
newGameBtn.setPreferredSize(new Dimension(110, 22));
newGameBtn.addActionListener(new JoinNewListener());
instructionsBtn = new JButton("Instructions");
instructionsBtn.setPreferredSize(new Dimension(110, 22));
instructionsBtn.addActionListener(new InstructButtonListener());
leaveGameBtn = new JButton("Leave game");
leaveGameBtn.setPreferredSize(new Dimension(110, 22));
leaveGameBtn.addActionListener(new LeaveButtonListener(client));
generalButtonPanel = new JCustomPanel(new FlowLayout(FlowLayout.CENTER, 2, 3), Constants.REGULAR_TILE_IMAGE_PATH);
generalButtonPanel.setPreferredSize(new Dimension(120,190));
generalButtonPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.BLACK));
generalButtonPanel.setOpaque(false);
generalButtonPanel.add(newGameBtn);
generalButtonPanel.add(instructionsBtn);
generalButtonPanel.add(leaveGameBtn);
txt_generalMenu = new JLabel("General menu");
txt_generalMenu.setFont(Constants.tahoma_medium_bold);
txt_generalMenu.setForeground(Color.WHITE);
generalButtonHeadingPanel = new JCustomPanel(new FlowLayout(FlowLayout.CENTER, 2, 2), Constants.REGULAR_TILE_IMAGE_PATH);
generalButtonHeadingPanel.setPreferredSize(new Dimension(120,18));
generalButtonHeadingPanel.setOpaque(false);
generalButtonHeadingPanel.add(txt_generalMenu);
}
/**
* Instantiates variables and enforces properties for all the elements of the GUI's "Leaderboard" area.
*/
private void buildConfigureLeaderboardGUI(){
txt_leaderArea = new JLabel("Hall of Fame (top 20)");
txt_leaderArea.setFont(Constants.tahoma_mediumsmall_bold);
txt_leaderArea.setForeground(Color.WHITE);
leaderArea = new JTextArea();
leaderArea.setLineWrap(true);
leaderArea.setFont(Constants.tahoma_small_normal);
leaderArea.setForeground(Color.WHITE);
leaderArea.setEditable(false);
leaderArea.setOpaque(false);
leaderAreaPane = new JCustomPane(leaderArea, Constants.TEXTAREA_TILE_IMAGE_PATH);
leaderAreaPane.setPreferredSize(new Dimension(LEADER_AREA_WIDTH - 3, LEADER_AREA_HEIGHT - 26));
leaderAreaPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
leaderAreaPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
leaderAreaPane.getVerticalScrollBar().addAdjustmentListener(new LeaderboardScrollListener());
leaderAreaPane.setOpaque(false);
leaderAreaPane.getViewport().setOpaque(false);
leaderAreaPanel = new JCustomPanel(new FlowLayout(FlowLayout.CENTER,1,1), Constants.REGULAR_TILE_IMAGE_PATH);
leaderAreaPanel.setPreferredSize(new Dimension(new Dimension(LEADER_AREA_WIDTH, LEADER_AREA_HEIGHT - 6)));
leaderAreaPanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 0, Color.BLACK));
leaderAreaPanel.setOpaque(false);
leaderAreaPanel.add(txt_leaderArea);
leaderAreaPanel.add(leaderAreaPane);
//for(int i = 0; i < 20; i++)leaderArea.append((i+1) + " turkWarrior666 " + (374 - i*3) + "\n"); //DEBUG INFO
}
/**
* Instantiates variables and enforces properties for all the elements of the GUI's "Play menu" area.
*/
private void buildConfigurePlayMenuGUI(Dice curGameDice){
txt_playMenu = new JLabel("Play options");
txt_playMenu.setFont(Constants.tahoma_medium_bold);
txt_playMenu.setForeground(Color.WHITE);
playHeadingPanel = new JCustomPanel(new FlowLayout(FlowLayout.CENTER, 1, 2), Constants.REGULAR_TILE_IMAGE_PATH);
playHeadingPanel.setPreferredSize(new Dimension(119,18));
playHeadingPanel.setOpaque(false);
playHeadingPanel.add(txt_playMenu);
rollDiceBtn = new JButton("Roll");
rollDiceBtn.setPreferredSize(new Dimension(110,22));
rollDiceBtn.addActionListener(new RollActionListener());
txt_rollsLeft = new JLabel("Rolls left: ");
txt_rollsLeft.setBorder(new EmptyBorder(4,0,0,0));
txt_rollsLeft.setFont(Constants.tahoma_mediumsmall_bold);
txt_rollsLeft.setForeground(Color.WHITE);
rollsLeftInd = new JLabel("2");
rollsLeftInd.setBorder(new EmptyBorder(4,0,0,0));
rollsLeftInd.setFont(Constants.tahoma_mediumsmall_bold);
rollsLeftInd.setForeground(Color.RED);
rollPanel = new JCustomPanel(new FlowLayout(FlowLayout.CENTER, 1, 2), Constants.REGULAR_TILE_IMAGE_PATH);
rollPanel.setPreferredSize(new Dimension(119, 45));
rollPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.BLACK));
rollPanel.setOpaque(false);
rollPanel.add(rollDiceBtn);
rollPanel.add(txt_rollsLeft);
rollPanel.add(rollsLeftInd);
txt_turnTimeLeft = new JLabel("Turn time left:");
txt_turnTimeLeft.setFont(Constants.tahoma_mediumsmall_bold);
txt_turnTimeLeft.setForeground(Color.WHITE);
turnTimerText = new JLabelSubscriber("03:00");
turnTimerText.setFont(Constants.tahoma_mediumsmall_bold);
turnTimerText.setForeground(Color.RED);
client.setTurnTimer(new ActTimeCountdown(Client.TURN_TIME_MILLIS, Client.TIMEUNIT_MILLIS, client));
client.getTurnTimer().addSubscriber(turnTimerText);
turnTimePanel = new JCustomPanel(new FlowLayout(FlowLayout.CENTER, 10, 2), Constants.REGULAR_TILE_IMAGE_PATH);
turnTimePanel.setPreferredSize(new Dimension(119, 33));
turnTimePanel.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.BLACK));
turnTimePanel.setOpaque(false);
turnTimePanel.add(txt_turnTimeLeft);
turnTimePanel.add(turnTimerText);
skipTurnBtn = new JButton("Skip turn");
skipTurnBtn.setPreferredSize(new Dimension(110, 22));
skipTurnBtn.addActionListener(new SkipListener());
skipPanel = new JCustomPanel(new FlowLayout(FlowLayout.CENTER, 2, 2), Constants.REGULAR_TILE_IMAGE_PATH);
skipPanel.setPreferredSize(new Dimension(119, 27));
skipPanel.setOpaque(false);
skipPanel.add(skipTurnBtn);
}
/**
* Instantiates variables and enforces properties for all the elements of the GUI's "Gamesheet" area.
*/
private void buildConfigureJTable(GameSheet newSheet){
//Create a JTable for displaying the scores, another JTable as a row header (combination names) and a JScrollPane
//to hold the two
gameSheetGUI = new GameSheetTableModel(newSheet);
scoreSheet = new JTable(gameSheetGUI);
scoreSheet.getTableHeader().setReorderingAllowed(false);
scoreSheet.getTableHeader().setResizingAllowed(false);
GUIFunctions.alignJTableContents(JLabel.CENTER, scoreSheet);
scoreSheet.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
GUIFunctions.setAllJTableColumnWidths(scoreSheet, SCORETABLE_ROW_WIDTH);
scoreSheet.addMouseListener(new ClickGamesheetListener());
gameSheetTitles = new GameSheetTitleTableModel(newSheet);
scoreSheetTitles = new JTable(gameSheetTitles);
scoreSheetTitles.getTableHeader().setReorderingAllowed(false);
scoreSheetTitles.getTableHeader().setResizingAllowed(false);
GUIFunctions.alignJTableContents(JLabel.LEFT, scoreSheetTitles);
scoreSheetTitles.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
GUIFunctions.setAllJTableColumnWidths(scoreSheetTitles, SCORETABLE_ROW_WIDTH*2);
scoreSheetTitles.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
scoreSheetTitles.setPreferredScrollableViewportSize(new Dimension(SCORETABLE_ROW_WIDTH*2,
SCORETABLE_HEIGHT));
containerPane = new JScrollPane(scoreSheet);
containerPane.setRowHeaderView(scoreSheetTitles);
containerPane.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.BLACK));
containerPane.setPreferredSize(new Dimension(newSheet.getNoOfPlayers()*SCORETABLE_ROW_WIDTH
+ SCORETABLEHEADER_ROW_WIDTH + 2, SCORETABLE_HEIGHT));
}
/**
* Instantiates variables and enforces properties for all the elements of the GUI's "Logging area" pane.
*/
private void buildConfigureLoggingArea(){
logArea = new JTextArea();
logArea.setLineWrap(true);
logArea.setWrapStyleWord(true);
logArea.setEditable(false);
logArea.setFont(Constants.tahoma_mediumsmall_normal);
logArea.setForeground(Color.WHITE);
logArea.setOpaque(false);
logAreaPane = new JCustomPane(logArea, Constants.TEXTAREA_TILE_IMAGE_PATH);
logAreaPane.setPreferredSize(new Dimension(INFO_AREA_WIDTH - 6, INFO_AREA_HEIGHT - 25));
logAreaPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
logAreaPane.getVerticalScrollBar().addAdjustmentListener(new LogScrollListener());
logAreaPane.setOpaque(false);
logAreaPane.getViewport().setOpaque(false);
btnSayText = new JButton("Say");
btnSayText.setPreferredSize(new Dimension(50,20));
btnSayText.addActionListener(new SayMessageListener());
sayField = new JCustomField(Constants.TEXTAREA_TILE_IMAGE_PATH);
sayField.setPreferredSize(new Dimension(INFO_AREA_WIDTH-58, 20));
sayField.setFont(Constants.tahoma_mediumsmall_normal);
sayField.setForeground(Color.WHITE);
sayField.setCaretColor(Color.WHITE);
sayField.setOpaque(false);
sayField.addActionListener(new SayMessageListener());
writeToLogArea("[" + new Date() + "]: Welcome to Yahtzee! If you want to say something to your fellow players, feel free to " +
"us the chatbox provided below! We would also like to remind you, that to leave the current game, join a new game or " +
"read the instructions and rules for the game, refer to the button menu on the lower right corner.\n");
//for(int i = 0; i < 100; i++){logArea.append("[" + new Date() + "]: Announcement " + i + "- The quick brown fox jumped over the crying 8-year-old molested by a catholic priest (must \"huumor\").\n");} //DEBUG INFO
}
/**
* Builds up and welds together the entire eastern side of the frame by the use of <code>JPanel</code>'s and <code>
* GridBagLayout</code>. Adds the eastern side to the content pane of the frame.
*/
private void weldTogetherEasternMenus(){
JPanel easternPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JPanel intEasternPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
intEasternPanel.setPreferredSize(new Dimension(500, 570));
intEasternPanel.setOpaque(false);
JPanel upperIntEasternPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
upperIntEasternPanel.setPreferredSize(new Dimension(500, 347));
upperIntEasternPanel.setOpaque(false);
upperIntEasternPanel.add(containerPane);
intEasternPanel.add(upperIntEasternPanel);
JPanel lowerIntEasternPanel = new JCustomPanel(new FlowLayout(FlowLayout.CENTER, 2, 2), Constants.REGULAR_TILE_IMAGE_PATH);
lowerIntEasternPanel.setPreferredSize(new Dimension(INFO_AREA_WIDTH, INFO_AREA_HEIGHT+3));
lowerIntEasternPanel.setBorder(BorderFactory.createMatteBorder(1, 1, 0, 1, Color.BLACK));
lowerIntEasternPanel.setOpaque(false);
lowerIntEasternPanel.add(logAreaPane);
lowerIntEasternPanel.add(sayField);
lowerIntEasternPanel.add(btnSayText);
intEasternPanel.add(lowerIntEasternPanel);
c.fill = GridBagConstraints.VERTICAL;
c.gridx = 0;
c.gridy = 0;
easternPanel.add(intEasternPanel, c);
JPanel extEasternPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
extEasternPanel.setPreferredSize(new Dimension(120,570));
JPanel mostUpperExtEasternPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
mostUpperExtEasternPanel.setPreferredSize(new Dimension(120, 82));
mostUpperExtEasternPanel.setOpaque(false);
mostUpperExtEasternPanel.add(turnMenuPanel);
extEasternPanel.add(mostUpperExtEasternPanel);
JPanel upperExtEasternPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
upperExtEasternPanel.setPreferredSize(new Dimension(120, 125));
upperExtEasternPanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 0, Color.BLACK));
upperExtEasternPanel.setOpaque(false);
upperExtEasternPanel.add(playHeadingPanel);
upperExtEasternPanel.add(rollPanel);
upperExtEasternPanel.add(turnTimePanel);
upperExtEasternPanel.add(skipPanel);
extEasternPanel.add(upperExtEasternPanel);
JPanel midExtEasternPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
midExtEasternPanel.setPreferredSize(new Dimension(LEADER_AREA_WIDTH, LEADER_AREA_HEIGHT));
midExtEasternPanel.setBorder(new EmptyBorder(3, 0, 3, 0));
midExtEasternPanel.setOpaque(false);
midExtEasternPanel.add(leaderAreaPanel);
extEasternPanel.add(midExtEasternPanel);
JPanel lowerExtEasternPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
lowerExtEasternPanel.setPreferredSize(new Dimension(120, 113));
lowerExtEasternPanel.setBorder(BorderFactory.createMatteBorder(1 ,0 ,0 ,0 ,Color.BLACK));
lowerExtEasternPanel.setOpaque(false);
lowerExtEasternPanel.add(generalButtonHeadingPanel);
lowerExtEasternPanel.add(generalButtonPanel);
extEasternPanel.add(lowerExtEasternPanel);
extEasternPanel.setOpaque(false);
c.fill = GridBagConstraints.VERTICAL;
c.gridx = 1;
c.gridy = 0;
easternPanel.add(extEasternPanel, c);
getContentPane().add(easternPanel, BorderLayout.EAST);
easternPanel.setOpaque(false);
}
@Override
public void updateGUIIndicators(){
//General GUI updates
setTitle(FRAME_DEFAULT_TITLE + " - " + client.getClientName());
playerNameInd.setText(client.getClientName());
rollerNameInd.setText(client.getDice().getCurOwner());
rollsLeftInd.setText("" + (Dice.ALLOWED_ROLLS - client.getDice().getTimesRolled()));
leaderArea.setText(client.getLeaderboard().getAsString());
//State-specific updates
switch(client.getState()){
case GAME_IN_PROGRESS:
if(!(client.getDice().getCurOwner().equals(client.getClientName()))){ //Check if current players turn (FALSE)
lockAllInputs();
}else if(client.getDice().getCurOwner().equals(client.getClientName())){ //Check if current players turn (TRUE)
if(client.getDice().getTimesRolled() == Dice.ALLOWED_ROLLS){ //Check if still has free rolls left (FALSE)
rollDiceBtn.setEnabled(false);
skipTurnBtn.setEnabled(true);
scoreSheet.setEnabled(true);
}else{ //Check if still has free rolls left (FALSE)
rollDiceBtn.setEnabled(true);
skipTurnBtn.setEnabled(true);
scoreSheet.setEnabled(true);
}
}
break;
case GAME_FINISHED:
lockAllInputs();
break;
default:
break;
}
this.repaint();
}
/**
* Locks all the player-manipulatable inputs of the frame.
*/
public void lockAllInputs(){
rollDiceBtn.setEnabled(false);
skipTurnBtn.setEnabled(false);
scoreSheet.setEnabled(false);
drawingPanel.setEnabled(false);
}
/**
* Notifies the player about the end of the current game and transitions the client to the <code>GAME_FINISHED</code> state.
* Displays a confirmation dialog asking if the player wants another game: If "Yes" is chosen, the client is reloaded
* with a restart. In any other case, the client is reloaded without a restart.
*/
public void notifyGameFinished(){
ArrayList<String> sortedResults = client.getGameSheet().getSortedResult(client.getClientName());
client.fGameInProgressTOGameFinished();
updateGUIForeign();
int decision = JOptionPane.showConfirmDialog(null,
"Congratulations " + client.getClientName() + "! You earned the "
+ sortedResults.get(2) + ". place with a score of " + sortedResults.get(1) + "!\n"
+ "Would you like to play again?",
"Game finished", JOptionPane.YES_NO_OPTION);
if(decision == JOptionPane.YES_OPTION){
dispose();
client.reloadClient(Client.RELOAD_WITH_RESTART);
}else if(decision == JOptionPane.NO_OPTION){
client.reloadClient(Client.RELOAD_WITHOUT_RESTART);
}
}
/**
* Displays a notification, letting the player know that he/she made it to the Top 20 Hall of Fame.
*/
public void notifyNewHighScore(){
int clientIndex = client.getGameSheet().getClientIndex(client.getClientName());
JOptionPane.showMessageDialog(null, "NEW HIGH SCORE! Congratulations!\nYou, " + client.getClientName() +
", have been added to the Top 20 Hall of Fame with a score of " +
client.getGameSheet().getGameSheetContents().get(clientIndex).get(GameSheet.TOTAL_SUM).getSlotScore() + "!");
}
@Override
public void writeToLogArea(Message msg){
logArea.append(msg.getContents().toString());
}
@Override
public void writeToLogArea(String msg){
logArea.append(msg.toString());
}
//[START]LISTENERS (CONTROLLER)
/**
* The <code>RollActionListener</code> class is an implementation of the <code>ActionListener</code> which if
* instantiated and binded to a control, reacts to an incoming event by:<br />
* a) Checking if its the players turn,<br />
* b) If the player is the <code>curOwner</code> of the dice, broadcasting a "Roll" command via the comm. module
*/
class RollActionListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
if(curGameDice.getCurOwner().equals(client.getClientName())){
client.getConnection().broadcast(CommandList.ROLLCMD);
}
}
}
/**
* The <code>SkipListener</code> class is an implementation of the <code>ActionListener</code> which if
* instantiated and binded to a control, reacts to an incoming event by:<br />
* a) Checking if its the players turn,<br />
* b) If the player is the <code>curOwner</code> of the dice, broadcasting a "Skip" command via the comm. module
*/
class SkipListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
if(curGameDice.getCurOwner().equals(client.getClientName())){
client.getConnection().broadcast(CommandList.SKIPCMD);
lockAllInputs();
}
}
}
/**
* The <code>JoinNewListener</code> class is an implementation of the <code>ActionListener</code> which if
* instantiated and binded to a control, reacts to an incoming event by:<br />
* a) Prompting the player for confirmation on leaving the current game (via a <code>JOptionPane</code>)<br />
* b) If the "Yes" option is chosen, reloading the client with a restart
* (parameter <code>Client.RELOAD_WITH_RESTART</code> used)
*/
class JoinNewListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent arg0) {
int decision = JOptionPane.showConfirmDialog(null,
"Are you sure you want to join a new game (your current process will be lost)?",
"Join a new game", JOptionPane.YES_NO_OPTION);
if(decision == JOptionPane.YES_OPTION){
dispose();
client.reloadClient(Client.RELOAD_WITH_RESTART);
}
}
}
/**
* The <code>ClickDiceListener</code> class is an extension of the <code>MouseAdapter</code> which if
* instantiated and binded to a control, reacts to an incoming event by:<br />
* a) Checking if its the players turn,<br />
* b) If the player is the <code>curOwner</code> of the dice, broadcasting a "ClickDice" command with attached
* X- and Y-coordinates specifying the location of the click (This command is neccessary for pruning potentially
* useful dice from the overall set of dice) via the comm. module
*/
class ClickDiceListener extends MouseAdapter{
@Override
public void mousePressed(MouseEvent e){
if(curGameDice.getCurOwner().equals(client.getClientName())){
client.getConnection().broadcast(CommandList.CLICKDICECMD + CommandList.CMD_DELIM + e.getX() +
CommandList.CMD_DELIM + e.getY());
}else{
writeToLogArea("It is not your turn, " + client.getClientName() + "! Wait for " +
curGameDice.getCurOwner() + "'s turn to end!\n"); //Write to the log area that its not the players' turn
}
}
}
/**
* The <code>ClickGamesheetListener</code> class is an extension of the <code>MouseAdapter</code> which if
* instantiated and binded to a control, reacts to an incoming event by:<br />
* a) Checking if its the players turn,<br />
* b) Checking whether the player clicked on a directly-manipulatable score slot on the <code>JTable</code> (
* for example, the intermediate sum and total sum slots cannot be manipulated directly),<br />
* c) Checking whether the player clicked on a score slots that has not yet been used (hasn't had a score entered
* into it),<br />
* d) If all the previous checks are passed, broadcasting an "Insert" command with an attached player name and row
* index via the comm. module
*/
class ClickGamesheetListener extends MouseAdapter{
@Override
public void mousePressed(MouseEvent e){
//Check if this player is the curOwner of the dice
if(curGameDice.getCurOwner().equals(client.getClientName())){
int rowIndex = scoreSheet.rowAtPoint(e.getPoint());
if(rowIndex == GameSheet.INTERMEDIATE_SUM || rowIndex == GameSheet.TOTAL_SUM || //Check, whether
rowIndex == GameSheet.UPPERSECTION_BONUS){ //the value is being entered into a proper slot
writeToLogArea("You cannot enter your score directly into the \"Uppersection bonus\"," +
" \"Intermediate sum\" or \"Final sum\" cell!\n");
}else{
if(client.getGameSheet().getGameSheetContents().get(client.getGameSheet().getClientIndex(client.getClientName()))
.get(rowIndex).getSlotStatus() == true){
if(getInsertConfirmation(rowIndex) == JOptionPane.YES_OPTION){
client.getConnection().broadcast(CommandList.INSERTCMD + CommandList.CMD_DELIM + client.getClientName()
+ CommandList.CMD_DELIM + rowIndex);
lockAllInputs();
}
}else{
writeToLogArea("You can not enter your score into the \"" + client.getGameSheet().getGameSheetContents().
get(0).get(rowIndex).getCombinationName() + "\" slot, because it has already been used!\n");
}
}
}else{
writeToLogArea("It is not your turn, " + client.getClientName() + "! Wait for " +
curGameDice.getCurOwner() + "'s turn to end!\n"); //Write to the log area that its not the players' turn
}
}
public int getInsertConfirmation(int rowIndex){
int decision = JOptionPane.showConfirmDialog(null, "Are you sure you'd like to enter " +
"your score into slot \"" + client.getGameSheet().getGameSheetContents().get(0).
get(rowIndex).getCombinationName() + "\"?", "Move confirmation", JOptionPane.YES_NO_OPTION);
return decision;
}
}
/**
* The <code>SayMessageListener</code> class is an implementation of the <code>ActionListener</code> which if
* instantiated and binded to a control, reacts to an incoming event by:<br />
* a) Checking whether the chat's text field contains any text,<br />
* b) If the chat's text field does contain text, broadcasting a "Said" message with the text fields' contents
* attached via the comm. module
*/
class SayMessageListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
if(sayField.getText().equals(""))return;
String srcText = sayField.getText(); //Get the contained text from the component
sayField.setText("");
client.getConnection().broadcast(CommandList.SAIDCMD + CommandList.CMD_DELIM + srcText);
}
}
/**
* Neccessary for keeping the log area scrolled to the bottom.
*/
class LogScrollListener implements AdjustmentListener{
@Override
public void adjustmentValueChanged(AdjustmentEvent arg0) {
logArea.select(Integer.MAX_VALUE, 0);
}
}
/**
* Neccessary for keeping the leaderboard aea scrolled to the top.
*/
class LeaderboardScrollListener implements AdjustmentListener{
@Override
public void adjustmentValueChanged(AdjustmentEvent arg0) {
leaderArea.select(0, 0);
}
}
//[END] LISTENERS (CONTROLLER)
}