/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package monopoly.view;
import external.HTMLColors;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import monopoly.model.events.GameModelEvent;
import monopoly.model.events.GameViewEvent;
import monopoly.model.events.IGameModelListener;
import monopoly.model.events.IGameViewListener;
import monopoly.model.game.GameModel;
import monopoly.model.gamefield.CompanyCell;
import monopoly.model.gamefield.GameFieldCellBase;
import monopoly.model.gamefield.GiftCell;
import monopoly.model.gamefield.PenaltyCell;
import monopoly.model.personality.ILandOwner;
import monopoly.model.personality.Player;
import monopoly.model.resource.ILand;
/**
* Определяет визуальное представление игры "Монополия".
* @author Роман
*/
public class GameView extends JFrame implements IGameModelListener {
private static final long serialVersionUID = 5L;
/**
* Представление игрового поля.
*/
private final GameFieldPanel _fieldPanel;
/**
* Игровая модель.
*/
private GameModel _gameModel;
/**
* Фишки, принимающие участие в игре.
*/
private final List<PlayerChip> _playerChips;
/**
* Булевый флаг, указывающий может ли текущий игрок оплатить ренту.
*/
private boolean _canPlayerPaidRent;
/**
* Булевый флаг, указывающий может ли текущий игрок купить земельный участок.
*/
private boolean _canPlayerBuyLand;
/**
* Булевый флаг, указывающий начать ли новую игру.
*/
private boolean _canNewGame;
/**
* Показать простой диалог-сообшение.
* @param title заголовок.
* @param message сообщение.
*/
private void showSimpleDialogMessage(String title, String message) {
final Dialog infoDialog = new JDialog();
infoDialog.setModal(true);
infoDialog.setTitle(title);
infoDialog.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(5, 5, 5, 5);
c.ipady = 5;
c.ipadx = 5;
c.gridx = 0;
c.gridy = 0;
infoDialog.add(new JLabel(message), c);
JButton bttn = new JButton("OK");
bttn.setAlignmentX(JComponent.CENTER_ALIGNMENT);
bttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
infoDialog.dispose();
}
});
c.fill = GridBagConstraints.NONE;
c.gridy = 2;
c.ipady = 0;
c.ipadx = 0;
infoDialog.add(bttn, c);
infoDialog.pack();
infoDialog.setLocationRelativeTo(this);
infoDialog.setResizable(false);
infoDialog.setVisible(true);
}
/**
* Получить игровую фишку для данного игрока.
* @param p игрок.
* @return фишка.
*/
private PlayerChip getPlayerChip(Player p) {
for (PlayerChip c : _playerChips) {
if (c.player() == p) {
return c;
}
}
return null;
}
/**
* Начать новую игру.
*/
private void startNewGame() {
_canNewGame = false;
final Dialog dialog = new JDialog();
dialog.setModal(true);
dialog.setTitle("Новая игра");
dialog.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(5, 5, 5, 5);
c.gridx = 0;
c.gridy = 0;
dialog.add(new JLabel("Укажите количество игроков, "
+ "принимающих участие в игре."), c);
final JSpinner countSpr = new JSpinner(new SpinnerNumberModel(5, 2, 10, 1));
c.gridy = 1;
dialog.add(countSpr, c);
JButton okbttn = new JButton("OK");
okbttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_canNewGame = true;
GameViewEvent event = new GameViewEvent(this,
(Integer) countSpr.getValue());
fireNewStartedGame(event);
dialog.dispose();
}
});
c.fill = GridBagConstraints.NONE;
c.gridy = 2;
dialog.add(okbttn, c);
dialog.pack();
dialog.setLocationRelativeTo(this);
dialog.setResizable(false);
dialog.setVisible(true);
if (_canNewGame == false) {
setVisible(false);
dispose();
}
}
/**
* Инициализировать игровые фишки.
*/
private void initializePlayerChips() {
_playerChips.clear();
for (Player p : _gameModel.players()) {
PlayerChip chip = new PlayerChip(p);
CellBasePanel cellPanel = _fieldPanel.cellPanel(p.position());
cellPanel.chipsPanel().addChip(chip);
_playerChips.add(chip);
}
}
/**
* Слушатели действий представления игры.
*/
private final List<IGameViewListener> _listeners =
new ArrayList<IGameViewListener>();
/**
* Запустить событие - начать новую игру.
* @param e аргументы события.
*/
protected void fireNewStartedGame(GameViewEvent e) {
for (IGameViewListener listener : _listeners) {
listener.gemeViewNewStartedGame(e);
}
}
/**
* Запустить событие - сделать следующий ход игры.
* @param e аргументы события.
*/
protected void fireMadeNextMove(GameViewEvent e) {
for (IGameViewListener listener : _listeners) {
listener.gameViewMadeNextMove(e);
}
}
/**
* Запустить событие - сделать игроку подарок.
* @param e аргументы события.
*/
protected void fireMadePlayerGift(GameViewEvent e) {
for (IGameViewListener listener : _listeners) {
listener.gameViewMadePlayerGift(e);
}
}
/**
* Запустить событие - оштрафовать игрока.
* @param e аргументы события.
*/
protected void fireMadePlayerPenalty(GameViewEvent e) {
for (IGameViewListener listener : _listeners) {
listener.gameViewMadePlayerPenalty(e);
}
}
/**
* Запустить событие - купить фирму игроку.
* @param e аргументы события.
*/
protected void fireMadePlayerBuyLand(GameViewEvent e) {
for (IGameViewListener listener : _listeners) {
listener.gameViewMadePlayerBuyLand(e);
}
}
/**
* Запустить событие - залатить игроку ренту.
* @param e аргументы события.
*/
protected void fireMadePlayerPayRent(GameViewEvent e) {
for (IGameViewListener listener : _listeners) {
listener.gameViewMadePlayerPayRent(e);
}
}
/**
* Установить видимым или не видимым фрейм.
* @param b флаг.
*/
@Override
public void setVisible(boolean b) {
super.setVisible(b);
if (b) {
startNewGame();
}
}
/**
* Добавить нового слушателя.
* @param listener слушатель.
*/
public void addGameViewListener(IGameViewListener listener) {
_listeners.add(listener);
}
/**
* Удалить указанного слушателя.
* @param listener слушатель.
*/
public void removeGameViewListener(IGameViewListener listener) {
_listeners.remove(listener);
}
/**
* Получить игровую модель.
* @return игровая модель.
*/
public GameModel gameModel() {
return _gameModel;
}
/**
* Задать игровую модель.
* @param model игровая модель.
*/
public void setGameModel(GameModel model) {
_gameModel = model;
_fieldPanel.setGameField(_gameModel.field());
initializePlayerChips();
}
/**
* Задать представление игры.
* @param model модель игры.
*/
public GameView(GameModel model) {
_gameModel = model;
_fieldPanel = new GameFieldPanel(_gameModel.field());
_playerChips = new ArrayList<PlayerChip>();
_fieldPanel.scoreboard().addMouseListener(new MouseListener() {
public void mousePressed(MouseEvent e) {
GameViewEvent event = new GameViewEvent(this);
fireMadeNextMove(event);
}
public void mouseClicked(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
});
initializePlayerChips();
setTitle("Игра \"Монополия\"");
setContentPane(_fieldPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
pack();
}
/**
* Обработчик события - игрок бросил игровые кости.
* @param e аргументы события.
*/
public void gamePlayerDroppedDice(GameModelEvent e) {
_fieldPanel.scoreboard().setScore(e.getScore());
}
/**
* Обработчик события - игрок переместился на игровом поле.
* @param e аргументы события.
*/
public void gamePlayerShiftedOnField(GameModelEvent e) {
PlayerChip c = getPlayerChip(e.getPlayer());
if (c == null) {
return;
}
_fieldPanel.cellPanel(e.getPlayerOldPosition()).chipsPanel().removeChip(c);
_fieldPanel.cellPanel(e.getPlayerNewPosition()).chipsPanel().addChip(c);
}
/**
* Обработчик события - игрок начал выполнять действие.
* Инициирует взаимодействие с пользователем через диалоговое
* окно представления, отображая возможные действие игрока согласно логике
* конкретной ячейке игрового поля.
* @param e аргументы события.
*/
public void gamePlayerStartedDoAction(GameModelEvent e) {
final Player p = e.getPlayer();
GameFieldCellBase cell = p.position();
if (cell instanceof GiftCell) {
GiftCell giftCell = (GiftCell) cell;
int gift = giftCell.currentGift();
showSimpleDialogMessage("ПОДАРОК", "<html>"
+ "Игрок <font color=" + HTMLColors.getName(p.color()) + ">"
+ "\"" + p.name() + "\"</font>" + " остановился на ячейки "
+ "<font color=green>\"ПОДАРОК\"</font>. "
+ "Получите от банка <i>" + gift + "$.</i>"
+ "</html>");
GameViewEvent event = new GameViewEvent(this, p, gift);
fireMadePlayerGift(event);
} else if (cell instanceof PenaltyCell) {
PenaltyCell penaltyCell = (PenaltyCell) cell;
int penalty = penaltyCell.currentPenalty();
showSimpleDialogMessage("ШТРАФ", "<html>"
+ "Игрок <font color=" + HTMLColors.getName(p.color()) + ">"
+ "\"" + p.name() + "\"</font>" + " остановился на ячейки "
+ "<font color=red>\"ШТРАФ\"</font>. "
+ "Вы будете оштрафованы банком на <i>"
+ penalty + "$.</i>"
+ "</html>");
GameViewEvent event = new GameViewEvent(this, p, penalty);
fireMadePlayerPenalty(event);
} else if (cell instanceof CompanyCell) {
final CompanyCell companyCell = (CompanyCell) cell;
if (companyCell.owner() == _gameModel.bank()) {
_canPlayerBuyLand = true;
final Dialog dialog = new JDialog();
dialog.setModal(true);
dialog.setTitle("Фирма \"" + companyCell.name() + "\"");
dialog.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(5, 5, 5, 5);
c.gridx = 0;
c.gridy = 0;
dialog.add(new JLabel("<html>"
+ "Игрок <font color=" + HTMLColors.getName(p.color()) + ">"
+ "\"" + p.name() + "\"</font>" + "остановился на ячейки"
+ " являющейся фирмой <u>\"" + companyCell.name() + "\"</u>"
+ " принадлежащей Банку.<br>"
+ "Желаете приобрести указанную фирму за ее номинальную"
+ " цену <i>" + companyCell.cost() + "$?</i>"
+ "</html>"), c);
JButton ybttn = new JButton("Да");
ybttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_canPlayerBuyLand = false;
GameViewEvent event = new GameViewEvent(this, p,
companyCell, companyCell.cost());
fireMadePlayerBuyLand(event);
dialog.dispose();
}
});
c.fill = GridBagConstraints.VERTICAL;
c.gridy = 1;
dialog.add(ybttn, c);
JButton nbttn = new JButton("Нет");
nbttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
c.gridy = 2;
dialog.add(nbttn, c);
dialog.pack();
dialog.setLocationRelativeTo(this);
dialog.setResizable(false);
dialog.setVisible(true);
if (_canPlayerBuyLand == false) {
showSimpleDialogMessage("Недостаточно денежных средств",
"<html>"
+ "Игроку <font color=" + HTMLColors.getName(p.color())
+ ">\"" + p.name() + "\"</font> не хватило денежных "
+ "средств для покупки фирмы <u>\"" + companyCell.name()
+ "\"</u>.<br>Необходмо: <i>" + companyCell.cost()
+ "$.</i><br>Имеется: <i>" + p.money() + "$.</i>"
+ "</html>");
}
} else if (companyCell.owner() != p) {
final Dialog infoDialog = new JDialog();
infoDialog.setModal(true);
infoDialog.setTitle("Фирма \"" + companyCell.name() + "\"");
infoDialog.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(5, 5, 5, 5);
c.gridx = 0;
c.gridy = 0;
Color color = HTMLColors.black;
final ILandOwner owner = companyCell.owner();
if (owner instanceof Player) {
color = ((Player) owner).color();
}
infoDialog.add(new JLabel("<html>"
+ "Игрок <font color=" + HTMLColors.getName(p.color()) + ">"
+ "\"" + p.name() + "\"</font>" + "остановился на ячейки"
+ " являющейся фирмой <u>\"" + companyCell.name() + "\"</u>"
+ " и принадлежащей игроку <font color="
+ HTMLColors.getName(color) + ">\"" + owner.name()
+ "\"</font>.<br>"
+ "Оплатите арендную плату в размере <i>"
+ companyCell.rent() + "$.</i>"
+ "</html>"), c);
JButton okbttn = new JButton("OK");
okbttn.setAlignmentX(JComponent.CENTER_ALIGNMENT);
okbttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_canPlayerPaidRent = false;
GameViewEvent event = new GameViewEvent(this, p,
companyCell);
fireMadePlayerPayRent(event);
infoDialog.dispose();
}
});
c.fill = GridBagConstraints.NONE;
c.gridy = 1;
infoDialog.add(okbttn, c);
infoDialog.pack();
infoDialog.setLocationRelativeTo(this);
infoDialog.setResizable(false);
infoDialog.setVisible(true);
if (_canPlayerPaidRent == true) {
final Dialog dialog = new JDialog();
dialog.setModal(true);
dialog.setTitle("Игрок \"" + p.name() + "\"");
dialog.setLayout(new GridBagLayout());
c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(5, 5, 5, 5);
final JLabel questionLbl = new JLabel();
final JLabel amountLbl = new JLabel();
final JSpinner amountSpr = new JSpinner();
final JButton ybttn = new JButton("Да");
ybttn.setAlignmentX(JComponent.CENTER_ALIGNMENT);
final JButton nbttn = new JButton("Нет");
nbttn.setAlignmentX(JComponent.CENTER_ALIGNMENT);
c.gridx = 0;
c.gridy = 0;
dialog.add(questionLbl, c);
c.gridx = 0;
c.gridy = 1;
dialog.add(amountLbl, c);
c.gridx = 0;
c.gridy = 2;
dialog.add(amountSpr, c);
c.gridx = 0;
c.gridy = 3;
c.fill = GridBagConstraints.NONE;
dialog.add(ybttn, c);
c.gridx = 0;
c.gridy = 4;
dialog.add(nbttn, c);
questionLbl.setText("<html>"
+ "Желаете попробывать перекупить у игрока <font color="
+ HTMLColors.getName(color) + ">\"" + owner.name()
+ "\"</font> фирму <u>\"" + companyCell.name()
+ "\"</u>?"
+ "</html>");
amountLbl.setText("Предложить сумму ($):");
SpinnerModel sprModel = new SpinnerNumberModel(
companyCell.cost(), companyCell.cost(),
companyCell.cost() * 10, 1000);
amountSpr.setModel(sprModel);
ybttn.setActionCommand("P1");
ybttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
if ("P1".equals(actionCommand)) {
dialog.setTitle("Игрок \"" + owner.name() + "\"");
questionLbl.setText("<html>"
+ "Игрок <font color="
+ HTMLColors.getName(p.color()) + ">\""
+ p.name() + "\"</font> предложил вам "
+ "продать свою фирму <u>\""
+ companyCell.name() + "\"</u>. Вы согласны?"
+ "</html>");
amountLbl.setText("Предложенная сумма ($):");
amountSpr.setEnabled(false);
ybttn.setActionCommand("P2");
dialog.pack();
} else if ("P2".equals(actionCommand)) {
_canPlayerBuyLand = false;
GameViewEvent event = new GameViewEvent(this, p,
companyCell, (Integer) amountSpr.getValue());
fireMadePlayerBuyLand(event);
dialog.dispose();
}
}
});
nbttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_canPlayerBuyLand = true;
dialog.dispose();
}
});
dialog.pack();
dialog.setLocationRelativeTo(this);
dialog.setResizable(false);
dialog.setVisible(true);
if (_canPlayerBuyLand == false) {
showSimpleDialogMessage("Недостаточно денежных средств",
"<html>"
+ "Игроку <font color=" + HTMLColors.getName(p.color())
+ ">\"" + p.name() + "\"</font> не хватило денежных "
+ "средств для покупки фирмы <u>\"" + companyCell.name()
+ "\"</u>.<br>Необходмо: <i>" + companyCell.cost()
+ "$.</i><br>Имеется: <i>" + p.money() + "$.</i>"
+ "</html>");
}
}
}
}
}
/**
* Обработчик события - у игрока была конфискована земельная собственность.
* @param e аргументы события.
*/
public void gamePlayerLandsConfiscated(GameModelEvent e) {
Player p = e.getPlayer();
List<ILand> confiscated = e.getConfiscated();
final Dialog infoDialog = new JDialog();
infoDialog.setModal(true);
infoDialog.setTitle("Конфискация фирм");
infoDialog.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(5, 5, 5, 5);
c.gridx = 0;
c.gridy = 0;
infoDialog.add(new JLabel("<html>"
+ "У игрока <font color=" + HTMLColors.getName(p.color()) + ">"
+ "\"" + p.name() + "\"</font>" + ", в связи с отсутсвием "
+ "денежных средств для уплаты, были конфискованы следующие "
+ "фирмы: "
+ "</html>"), c);
List<String> companyNames = new ArrayList<String>();
for (ILand company : confiscated) {
companyNames.add(company.name());
}
JList list = new JList(companyNames.toArray());
list.setLayoutOrientation(JList.VERTICAL);
list.setVisibleRowCount(0);
JScrollPane scroll = new JScrollPane(list);
scroll.setPreferredSize(new Dimension(100, 100));
c.gridy = 1;
infoDialog.add(scroll, c);
JButton bttn = new JButton("OK");
bttn.setAlignmentX(JComponent.CENTER_ALIGNMENT);
bttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
infoDialog.dispose();
}
});
c.fill = GridBagConstraints.NONE;
c.gridy = 2;
infoDialog.add(bttn, c);
infoDialog.pack();
infoDialog.setLocationRelativeTo(this);
infoDialog.setResizable(false);
infoDialog.setVisible(true);
}
/**
* Обработчик события - игрок закончил игру(банкрот).
* @param e аргументы события.
*/
public void gamePlayerFinishedGame(GameModelEvent e) {
Player p = e.getPlayer();
showSimpleDialogMessage("Банкрот", "<html>"
+ "Игрок <font color=" + HTMLColors.getName(p.color()) + ">"
+ "\"" + p.name() + "\"</font> не имеет денежных средств "
+ "для уплаты и закончил игру."
+ "</html>");
PlayerChip chip = getPlayerChip(p);
_playerChips.remove(chip);
_fieldPanel.removePlayerChip(chip);
_fieldPanel.detailsPanel().repaint();
}
/**
* Обработчик события - игра закончина и выявлен победитель.
* @param e аргументы события.
*/
public void gameFinished(GameModelEvent e) {
Player p = e.getPlayer();
showSimpleDialogMessage("Игра окончена", "<html>"
+ "Игрок <font color=" + HTMLColors.getName(p.color()) + ">"
+ "\"" + p.name() + "\"</font> стал монополистом и победил в игре."
+ "</html>");
final JFrame mainWindow = this;
final Dialog infoDialog = new JDialog();
infoDialog.setModal(true);
infoDialog.setTitle("Новая игра");
infoDialog.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(5, 5, 5, 5);
c.gridx = 0;
c.gridy = 0;
infoDialog.add(new JLabel("Начать новую игру?"), c);
JButton ybttn = new JButton("Да");
ybttn.setAlignmentX(JComponent.CENTER_ALIGNMENT);
ybttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startNewGame();
infoDialog.dispose();
}
});
c.fill = GridBagConstraints.NONE;
c.gridy = 1;
infoDialog.add(ybttn, c);
JButton nbttn = new JButton("Нет");
nbttn.setAlignmentX(JComponent.CENTER_ALIGNMENT);
nbttn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
infoDialog.dispose();
mainWindow.setVisible(false);
mainWindow.dispose();
}
});
c.gridy = 2;
infoDialog.add(nbttn, c);
infoDialog.pack();
infoDialog.setLocationRelativeTo(this);
infoDialog.setResizable(false);
infoDialog.setVisible(true);
}
/**
* Обработчик события - у земельного участка сменился владелец.
* @param e аргументы события.
*/
public void gameLandChangedOwner(GameModelEvent e) {
ILand land = e.getLand();
if (land instanceof CompanyCell) {
CompanyCell company = (CompanyCell) land;
CompanyCellPanel panel =
(CompanyCellPanel) _fieldPanel.cellPanel(company);
panel.repaint();
}
}
/**
* Обработчик события - игрок приобрел земельную собственность.
* @param e аргументы события.
*/
public void gamePlayerBoughtLand(GameModelEvent e) {
_canPlayerBuyLand = true;
_fieldPanel.detailsPanel().repaint();
}
/**
* Обработчик события - игрок уплатил ренту.
* @param e аргументы события.
*/
public void gamePlayerPaidRent(GameModelEvent e) {
_canPlayerPaidRent = true;
_fieldPanel.detailsPanel().repaint();
}
/**
* Обработчик события - игрок получил подарок.
* @param e аргументы события.
*/
public void gamePlayerReceivedGift(GameModelEvent e) {
_fieldPanel.detailsPanel().repaint();
}
/**
* Обработчик события - игрок оштрафован.
* @param e аргументы события.
*/
public void gamePlayerReceivedPenalty(GameModelEvent e) {
_fieldPanel.detailsPanel().repaint();
}
/**
* Обработчик события - игра начата.
* @param e аргументы события.
*/
public void gameStarted(GameModelEvent e) {
setGameModel((GameModel) e.getSource());
}
}