/**
*
*/
package de.axxeed.animosy.model;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.TreeSet;
import javax.swing.AbstractAction;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import org.apache.log4j.Logger;
import de.axxeed.animosy.ai.MrX;
import de.axxeed.animosy.gui.MapPanel;
import de.axxeed.animosy.gui.OptionsDialog;
import de.axxeed.animosy.gui.PanelRepository;
/**
* Game.java
* Created 10.12.2007 14:08:16
* @author Markus J. Luzius
*
*/
public class Game {
private static Logger log = Logger.getLogger(Game.class);
public static final int NO_GAME = -1;
public static final int MOVE_MRX = 0;
public static final int WIN_MRX = 100;
public static final int WIN_DET = 101;
private static final SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
private GameBoard board = new GameBoard();
private int currentMove = 0;
private int state = NO_GAME;
private int strandedDetectives = 0;
private MrXTracker tracker = null;
private long gameStartTime = 0;
public Game() {
log.debug("Game created...");
}
public GameBoard getBoard() {
return board;
}
public void startGame() {
state = NO_GAME;
OptionsDialog od = new OptionsDialog();
od.setVisible(true);
PanelRepository.get(PanelRepository.HISTORY_ITEM).setEnabled(true);
board.init();
tracker = new MrXTracker();
tracker.setPotentialPosition(board.getMrX().getPosition().getPosition());
currentMove = 1;
log.info("Starting a new game");
gameStartTime = System.currentTimeMillis();
PanelRepository.get(PanelRepository.MAIN_WINDOW).repaint();
state = MOVE_MRX;
try {
new MrX(Class.forName("de.axxeed.animosy.ai.RandomMrX"));
} catch (ClassNotFoundException e) {
log.error("MrX class not found - unable to start a game.");
state = NO_GAME;
}
PanelRepository.get(PanelRepository.MAIN_WINDOW).requestFocus();
}
public int getState() {
return state;
}
public MrXTracker getTracker() {
return tracker;
}
public String getStateText() {
if(state==NO_GAME) {
return "No game";
}
else if(state==MOVE_MRX) {
return "Move MrX";
}
else if(state==WIN_DET) {
return "Detectives win";
}
else if(state==WIN_MRX) {
return "MrX wins";
}
else if(state>NO_GAME && state<WIN_MRX) {
return "Move detective #"+state;
}
return "undefined";
}
public int getCurrentMove() {
return currentMove;
}
public int getActiveDetectiveIndex() {
if(state>0 && state<WIN_MRX) {
return state-1;
}
return -1;
}
public Detective getActiveDetective() {
return board.getDetectives()[getActiveDetectiveIndex()];
}
public void nextDetective() {
int mrXpos = board.getMrX().getPosition().getPosition();
for (int i=0;i<board.getDetectives().length;i++) {
if(mrXpos==board.getDetectives()[i].getPosition().getPosition()) {
state = WIN_DET;
log.info("The detectives win!");
String additionalText = "";
if(currentMove<10) {
additionalText = "only ";
}
if(currentMove>Manager.getOptions().getNumberOfMoves()-8) {
additionalText = "a long ";
}
JOptionPane.showMessageDialog( null, "The detectives have won!\n" +
"You caught him in time on field "+board.getMrX().getPosition().getPosition()+"!\n"+
"It took you "+additionalText+currentMove+" moves. \n\n" +
"Game time: "+getGameTime(),
"Detectives win", JOptionPane.INFORMATION_MESSAGE);
return;
}
}
log.debug(".nextDetective()");
if(isCheckPoint()) {
PanelRepository.get(PanelRepository.TRACKER_ITEM).setEnabled(true);
tracker.reset();
tracker.setPotentialPosition(board.getMrX().getPosition().getPosition());
}
else if(state!=MOVE_MRX) {
tracker.removePotentialPosition(board.getDetectives()[state-1].getPosition().getPosition());
}
state++;
if(state>board.getDetectives().length) {
log.debug("Cleaning move menu...");
cleanMoveMenu();
currentMove++;
if(currentMove>Manager.getOptions().getNumberOfMoves()) {
state = WIN_MRX;
log.info("MrX escaped in time, so he wins!");
PanelRepository.get(PanelRepository.MAIN_WINDOW).repaint();
JOptionPane.showMessageDialog( null, "MrX has won!\nYou didn't catch him in time!\n\nGame time: "+getGameTime(), "MrX wins", JOptionPane.INFORMATION_MESSAGE);
return;
}
state = MOVE_MRX;
}
else {
log.debug("Updating move menu...");
updateMoveMenu();
}
PanelRepository.get(PanelRepository.MAIN_WINDOW).repaint();
}
private void undoMove() {
if(state<=MOVE_MRX+1) return;
int previousDetective = getActiveDetectiveIndex()-1;
board.getDetectives()[previousDetective].undoMove();
state--;
updateMoveMenu();
((MapPanel)PanelRepository.get(PanelRepository.MAP_PANEL)).updatePositions();
PanelRepository.get(PanelRepository.STATUS_PANEL).repaint();
}
public void moveDetective(Move move) {
getActiveDetective().changePosition(BoardModel.getNode(move.getNode()), move.getType());
((MapPanel)PanelRepository.get(PanelRepository.MAP_PANEL)).updatePositions();
if(getActiveDetective().isStranded()) {
strandedDetectives += twoUp(getActiveDetectiveIndex());
log.debug("Stranded detectives="+strandedDetectives);
if(strandedDetectives==(twoUp(Manager.getOptions().getNumberOfDetectives())-1)) {
log.info("All detectives are stranded - MrX wins!");
state = WIN_MRX;
JOptionPane.showMessageDialog( null, "MrX has won!\nAll detectives are unable to move!\n\nGame time: "+getGameTime(), "MrX wins", JOptionPane.INFORMATION_MESSAGE);
return;
}
}
if(getActiveDetective().getPosition().getPosition()==board.getMrX().getPosition().getPosition()) {
state = WIN_DET;
log.info("The detectives win!");
String additionalText = "";
if(currentMove<10) {
additionalText = "only ";
}
if(currentMove>Manager.getOptions().getNumberOfMoves()-8) {
additionalText = "a long ";
}
JOptionPane.showMessageDialog( null, "The detectives have won!\nYou caught him in time on field "+
board.getMrX().getPosition().getPosition()+"!\n" +
"It took you "+additionalText+currentMove+" moves.\n\n" +
"Game time: "+getGameTime(),
"Detectives win", JOptionPane.INFORMATION_MESSAGE);
}
else {
nextDetective();
int maxCount = 0;
while(getActiveDetectiveIndex()>= 0 && getActiveDetective().isStranded() && maxCount<Manager.getOptions().getNumberOfDetectives()*2 && state<WIN_MRX) {
maxCount++;
nextDetective();
}
}
}
public boolean isCheckPoint() {
return isCheckPoint(currentMove);
}
public boolean isCheckPoint(int move) {
if(move==3) {
return true;
}
int level = Manager.getOptions().getLevel();
// log.debug("("+move+"-3)%(3+"+level+")="+(move-3)+"%"+(3+level)+"="+((move-3)%(3+level)));
if((move-3)%(3+level)==0) {
return true;
}
return false;
}
private int twoUp(int up) {
if(up>20) return -1;
if(up==0) return 1;
else return 2*twoUp(up-1);
}
private void updateMoveMenu() {
int activeDet = Manager.getGame().getActiveDetectiveIndex();
JMenu detectiveMenu = (JMenu) PanelRepository.get(PanelRepository.MOVE_MENU);
detectiveMenu.removeAll();
TreeSet<Move> possibleMoves = board.getDetectives()[activeDet].getPossibleMoves();
JMenuItem undo = new JMenuItem("Undo move");
undo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
undoMove();
}
});
undo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
if(state<=MOVE_MRX+1 || state>=WIN_MRX) {
undo.setEnabled(false);
}
detectiveMenu.add( undo );
detectiveMenu.addSeparator();
if(possibleMoves==null || possibleMoves.isEmpty()) {
AbstractAction action = new AbstractAction("Skip turn")
{
private static final long serialVersionUID = 0L;
public void actionPerformed( ActionEvent e ) {
Manager.getGame().nextDetective();
((MapPanel)PanelRepository.get(PanelRepository.MAP_PANEL)).updatePositions();
PanelRepository.get(PanelRepository.STATUS_PANEL).repaint();
}
};
detectiveMenu.add( action );
}
else {
log.debug("Possible moves: "+possibleMoves.size()+" - "+possibleMoves);
Iterator<Move> i = possibleMoves.iterator();
while(i.hasNext()) {
Move m = (Move) i.next();
StringBuilder linkText = new StringBuilder();
linkText.append(m.getNode()).append(" (");
switch(m.getType()) {
case BoardModel.TAXI: linkText.append("TAXI").append(")"); break;
case BoardModel.BUS: linkText.append("BUS").append(")"); break;
case BoardModel.UG: linkText.append("UG").append(")"); break;
case BoardModel.BLACK: break;
case BoardModel.INF: linkText.append("INF").append(")"); break;
default: linkText.append("???").append(")"); break;
}
// detectiveMenu.add( new JMenuItem(linkText.toString()) );
AbstractAction action = new AbstractAction(linkText.toString())
{
private static final long serialVersionUID = -4379938472159497577L;
public void actionPerformed( ActionEvent e ) {
log.debug("Selected move: "+((Move)this.getValue(e.getActionCommand())));
Manager.getGame().moveDetective((Move)this.getValue(e.getActionCommand()));
PanelRepository.get(PanelRepository.STATUS_PANEL).repaint();
}
};
action.putValue(linkText.toString(), m);
action.putValue("Detective", board.getDetectives()[activeDet]);
detectiveMenu.add( action );
}
}
}
private void cleanMoveMenu() {
JMenu detectiveMenu = (JMenu) PanelRepository.get(PanelRepository.MOVE_MENU);
detectiveMenu.removeAll();
JMenuItem item = null;
detectiveMenu.add(item = new JMenuItem("no move available"));
item.setEnabled(false);
}
public String getGameTime() {
if(state>NO_GAME && state<WIN_MRX) {
return sdf.format(new Date(System.currentTimeMillis()-gameStartTime-3600000));
}
return "---";
}
}