From 745a2cafff620747d38a9c7f4e28f2dcccd631e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Fri, 1 Jun 2012 03:48:20 +0200 Subject: [PATCH 01/11] adding IRC support. currently with sockets server, will be removed. improved GUI for display of WALL messages and a timer. Need to refactor from gui into TheGame class --- .idea/libraries/jerklib.xml | 9 + crashteststeuerung.iml | 1 + libs/jerklib.jar | Bin 0 -> 81779 bytes src/de/ctdo/crashtest/BuntiClient.java | 3 + src/de/ctdo/crashtest/Communication.java | 73 +++++ .../ctdo/crashtest/CommunicationRunner.java | 76 +++++ src/de/ctdo/crashtest/GuiControl.java | 18 ++ src/de/ctdo/crashtest/LampelClient.java | 2 +- src/de/ctdo/crashtest/Steuerung.java | 5 +- src/de/ctdo/crashtest/SteuerungFrame.java | 272 +++++++++++++++--- src/de/ctdo/crashtest/TheGame.java | 16 ++ 11 files changed, 428 insertions(+), 47 deletions(-) create mode 100644 .idea/libraries/jerklib.xml create mode 100644 libs/jerklib.jar create mode 100644 src/de/ctdo/crashtest/Communication.java create mode 100644 src/de/ctdo/crashtest/CommunicationRunner.java create mode 100644 src/de/ctdo/crashtest/GuiControl.java create mode 100644 src/de/ctdo/crashtest/TheGame.java diff --git a/.idea/libraries/jerklib.xml b/.idea/libraries/jerklib.xml new file mode 100644 index 0000000..2090b94 --- /dev/null +++ b/.idea/libraries/jerklib.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/crashteststeuerung.iml b/crashteststeuerung.iml index 2ab6dea..5b4384e 100644 --- a/crashteststeuerung.iml +++ b/crashteststeuerung.iml @@ -9,6 +9,7 @@ + diff --git a/libs/jerklib.jar b/libs/jerklib.jar new file mode 100644 index 0000000000000000000000000000000000000000..ac29b2909480901ff1e4b1448961f7450cb78d51 GIT binary patch literal 81779 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 z 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 literal 0 HcmV?d00001 diff --git a/src/de/ctdo/crashtest/BuntiClient.java b/src/de/ctdo/crashtest/BuntiClient.java index 33aaf42..e0b75c5 100644 --- a/src/de/ctdo/crashtest/BuntiClient.java +++ b/src/de/ctdo/crashtest/BuntiClient.java @@ -25,6 +25,7 @@ public class BuntiClient { } public void setPar56(int id, int red, int green, int blue) { + if(true) return; try { HttpPost post = new HttpPost(baseAddress + "/control/devices"); post.addHeader("Content-Type", "application/json"); @@ -53,6 +54,8 @@ public class BuntiClient { public void setLampel(boolean red, boolean yellow, boolean green) { + if(true) return; + int value = 0; if( green ) value |= 0x01; diff --git a/src/de/ctdo/crashtest/Communication.java b/src/de/ctdo/crashtest/Communication.java new file mode 100644 index 0000000..5e503a8 --- /dev/null +++ b/src/de/ctdo/crashtest/Communication.java @@ -0,0 +1,73 @@ +package de.ctdo.crashtest; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class Communication implements Runnable { + private final static int LISTEN_PORT = 2342; + private Boolean isStopped = false; + private ServerSocket serverSocket; + private Thread runningThread; + + private ExecutorService threadPool = Executors.newFixedThreadPool(10); + + private GuiControl control; + + public Communication(GuiControl control) { + this.control = control; + } + + + private synchronized boolean isStopped() { + return this.isStopped; + } + + @Override + public void run() { + + synchronized(this){ + this.runningThread = Thread.currentThread(); + } + + openServerSocket(); + + while(!isStopped()){ + Socket clientSocket = null; + try { + clientSocket = this.serverSocket.accept(); + } catch (IOException e) { + if(isStopped()) { + System.out.println("Server Stopped.") ; + return; + } + throw new RuntimeException("Error accepting client connection", e); + } + this.threadPool.execute(new CommunicationRunner(clientSocket, this.control)); + } + + this.threadPool.shutdown(); + System.out.println("Server Stopped.") ; + + } + + + public synchronized void stop() { + this.isStopped = true; + try { + this.serverSocket.close(); + } catch (IOException e) { + throw new RuntimeException("Error closing server", e); + } + } + + private void openServerSocket() { + try { + this.serverSocket = new ServerSocket(LISTEN_PORT); + } catch (IOException e) { + throw new RuntimeException("Cannot open port 8080", e); + } + } +} diff --git a/src/de/ctdo/crashtest/CommunicationRunner.java b/src/de/ctdo/crashtest/CommunicationRunner.java new file mode 100644 index 0000000..e0afb61 --- /dev/null +++ b/src/de/ctdo/crashtest/CommunicationRunner.java @@ -0,0 +1,76 @@ +package de.ctdo.crashtest; + +import java.io.*; +import java.net.Socket; +import java.net.SocketTimeoutException; + +public class CommunicationRunner implements Runnable { + private Socket clientSocket = null; + private GuiControl control; + + public CommunicationRunner(Socket clientSocket, GuiControl control) { + this.clientSocket = clientSocket; + this.control = control; + } + + @Override + public void run() { + try { + clientSocket.setSoTimeout(5000); + InputStream input = clientSocket.getInputStream(); + OutputStream output = clientSocket.getOutputStream(); + long time = System.currentTimeMillis(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + + String line = reader.readLine(); + + System.out.println("got line: " + line); + + runCommand(line); + + output.close(); + input.close(); + System.out.println("Request processed: " + time + clientSocket.getRemoteSocketAddress()); + } catch (SocketTimeoutException e) { + System.out.println("Socket Timeout, closing " + clientSocket.getRemoteSocketAddress()); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + clientSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + private void runCommand(String line) { + + // must contain a ":" + // then split and switch on the command + int pos = line.indexOf(":"); + if(pos > 0) { + String command = line.substring(0, pos).toLowerCase().trim(); + String parameter = line.substring(pos+1, line.length()).trim(); + + if(command.equals("wall")) { + control.setWall(parameter); + } else if(command.equals("timerstart")) { + control.startTimer(Integer.parseInt(parameter)); + } else if(command.equals("timerstop")) { + control.stopTimer(); + } else if(command.equals("timerpause")) { + control.pauseTimer(Boolean.parseBoolean(parameter)); + } else if(command.equals("setextra")) { + control.setExtra(parameter); + } else if(command == "reset") { + control.resetGame(); + } + + + } + + } +} diff --git a/src/de/ctdo/crashtest/GuiControl.java b/src/de/ctdo/crashtest/GuiControl.java new file mode 100644 index 0000000..1a8eb50 --- /dev/null +++ b/src/de/ctdo/crashtest/GuiControl.java @@ -0,0 +1,18 @@ +package de.ctdo.crashtest; + +public interface GuiControl { + + void startTimer(int seconds); + void stopTimer(); // and hide + void pauseTimer(Boolean pause); + + void setWall(String message); + void setExtra(String text); + + int getTimerSeconds(); + int getTimerSecondsLast(); + Boolean getTimerRunning(); + + void resetGame(); + +} diff --git a/src/de/ctdo/crashtest/LampelClient.java b/src/de/ctdo/crashtest/LampelClient.java index 941aa8c..f055d32 100644 --- a/src/de/ctdo/crashtest/LampelClient.java +++ b/src/de/ctdo/crashtest/LampelClient.java @@ -16,7 +16,7 @@ public class LampelClient { try { Socket client = new Socket(LAMPEL_HOST, ECMD_TCP_PORT); - client.setSoTimeout(2000); + client.setSoTimeout(800); DataOutputStream outToServer = new DataOutputStream(client.getOutputStream()); diff --git a/src/de/ctdo/crashtest/Steuerung.java b/src/de/ctdo/crashtest/Steuerung.java index b2c3aa3..67c9517 100644 --- a/src/de/ctdo/crashtest/Steuerung.java +++ b/src/de/ctdo/crashtest/Steuerung.java @@ -1,9 +1,6 @@ package de.ctdo.crashtest; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.CharBuffer; + public class Steuerung { diff --git a/src/de/ctdo/crashtest/SteuerungFrame.java b/src/de/ctdo/crashtest/SteuerungFrame.java index 452ddec..e67932a 100644 --- a/src/de/ctdo/crashtest/SteuerungFrame.java +++ b/src/de/ctdo/crashtest/SteuerungFrame.java @@ -1,62 +1,73 @@ package de.ctdo.crashtest; -import org.bff.javampd.MPD; -import org.bff.javampd.MPDPlayer; +import jerklib.*; +import jerklib.events.IRCEvent; +import jerklib.events.JoinCompleteEvent; +import jerklib.events.listeners.IRCEventListener; +import org.bff.javampd.*; import org.bff.javampd.exception.MPDConnectionException; +import org.bff.javampd.exception.MPDDatabaseException; +import org.bff.javampd.exception.MPDPlayerException; import org.bff.javampd.exception.MPDResponseException; +import org.bff.javampd.objects.MPDSong; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Random; -public class SteuerungFrame extends JFrame implements StateChangeListener { - private JPanel pnlRoot; - private JLabel lblState; +public class SteuerungFrame extends JFrame implements StateChangeListener, GuiControl, IRCEventListener { + private JTextArea textWall; + private JLabel countDown; + private JLabel extraField; + private JPanel lowerPanel; private char lastKey = ' '; private MPD mpd; private MPDPlayer player; + private int timerSeconds = 0; + private int timerSecondsLast = 0; + private int timeSpentTableGame = 0; + private int timeSpentRokets = 0; + private Timer timer; + private Statemachine machine = new Statemachine(); + private BuntiClient bunti = new BuntiClient("bunti.ctdo.de", 8080); + private Communication server; + private ConnectionManager irc; + private Session ircsession; - Statemachine machine = new Statemachine(); - BuntiClient bunti = new BuntiClient("bunti.ctdo.de", 8080); public SteuerungFrame() { - //setType(Type.UTILITY); - setBackground(Color.black); - setBounds(200,200, 400, 200); - - machine.addStateChangedListener(this); - initGui(); - setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); + setBounds(200,200, 400, 200); + //server = new Communication(this); + + irc = new ConnectionManager(new ProfileImpl("crashtest","crashtest", "crashtest2", "crashtest3")); + ircsession = irc.requestConnection("irc.chaostreff-dortmund.de"); + ircsession.addIRCEventListener(this); + + //initTimer(); + + machine.addStateChangedListener(this); machine.reset(); - try { - mpd = new MPD("dampfradio.raum.chaostreff-dortmund.de", 6600); - player = mpd.getMPDPlayer(); + //initMPD(); - } catch (UnknownHostException e) { - e.printStackTrace(); - return; - } catch (MPDConnectionException e) { - e.printStackTrace(); - return; - } - - addKeyListener(new KeyAdapter() { + this.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { lastKey = e.getKeyChar(); - if (lastKey == KeyEvent.VK_F) { + /*if (lastKey == KeyEvent.VK_F) { Random r = new Random(); setLEDs(r.nextInt(255), r.nextInt(255),r.nextInt(255)); - } + } */ if (lastKey == KeyEvent.VK_1) { machine.reset(); @@ -67,12 +78,20 @@ public class SteuerungFrame extends JFrame implements StateChangeListener { updateGui(); } }); - - addWindowStateListener(new WindowAdapter() { + + this.addWindowStateListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + + System.out.print("oihdf"); + } + @Override public void windowClosing(WindowEvent e) { try { - if(mpd != null) mpd.close(); + if (mpd != null) mpd.close(); + + if (server != null) server.stop(); } catch (MPDConnectionException e1) { e1.printStackTrace(); } catch (MPDResponseException e1) { @@ -80,20 +99,70 @@ public class SteuerungFrame extends JFrame implements StateChangeListener { } } }); + + //new Thread(server).start(); + } + + private void initMPD() { + try { + mpd = new MPD("dampfradio.raum.chaostreff-dortmund.de", 6600); + player = mpd.getMPDPlayer(); + + MPDDatabase database = mpd.getMPDDatabase(); + Collection bla = database.findTitle(""); + + } catch (UnknownHostException e) { + e.printStackTrace(); + return; + } catch (MPDConnectionException e) { + e.printStackTrace(); + return; + } catch (MPDDatabaseException e) { + e.printStackTrace(); + } + } + + private void initTimer() { + timer = new Timer(100, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + timerSecondsLast--; + setTimerText(); + + if(timerSecondsLast <= 0) { + timerSecondsLast = 0; + timer.stop(); + } + } + }); + } + + private void setTimerText() { + int mins = timerSecondsLast / 600; + int secs = timerSecondsLast % 600 / 10 ; + int tsecs = timerSecondsLast % 9; + countDown.setText(" " + mins + ":" + secs + "." + tsecs); } @Override public void stateChanged(Statemachine.state newState) { updateGui(); + + if(ircsession != null) { + for(Channel chan: ircsession.getChannels()) { + chan.say("New State: " + newState); + } + } switch (newState) { case IDLE: - setLEDs(0x40,0,0xff); + //setLEDs(0x40,0,0xff); + setLEDs(0,0,0); bunti.setLampel(false,false,false); break; case ENTERED_ROOM: bunti.setLampel(false,false,false); - setLEDs(255,0,100); + setLEDs(20,0,100); // start von Mo Do - Eins, Zwei Polizei @@ -135,8 +204,8 @@ public class SteuerungFrame extends JFrame implements StateChangeListener { setLEDs(0, 255, 0); break; case ROKET_DONE: - - + bunti.setLampel(true,true,true); + setLEDs(255, 196, 0); break; } @@ -151,21 +220,140 @@ public class SteuerungFrame extends JFrame implements StateChangeListener { } private void initGui() { - Container pane = getContentPane(); + textWall = new JTextArea(); + countDown = new JLabel(); + extraField = new JLabel(); + lowerPanel = new JPanel(); - pnlRoot = new JPanel(new FlowLayout()); - lblState = new JLabel("", JLabel.LEFT); - pnlRoot.add(lblState); - pane.add(pnlRoot); + Container container = getContentPane(); + container.setLayout(new BorderLayout()); + container.add(textWall, BorderLayout.NORTH); + container.add(lowerPanel, BorderLayout.SOUTH); + + lowerPanel.setLayout(new BorderLayout()); + lowerPanel.add(countDown, BorderLayout.WEST); + lowerPanel.add(extraField, BorderLayout.EAST); + + Font wallFont = new Font("Arcade Interlaced", Font.PLAIN, 66); + Font lowerFont = new Font("Arcade Interlaced", Font.PLAIN, 80); + Color fontColor = new Color(0x00, 190, 100); + + textWall.setFont(wallFont); + textWall.setForeground(fontColor); + textWall.setBackground(Color.BLACK); + textWall.setText("follow the white rabbit..."); + textWall.setLineWrap(true); + textWall.setWrapStyleWord(true); + textWall.setFocusable(false); + + countDown.setFont(lowerFont); + countDown.setHorizontalAlignment(SwingConstants.LEFT); + countDown.setForeground(fontColor); + //countDown.setBackground(Color.BLACK); + + extraField.setFont(lowerFont); + extraField.setHorizontalAlignment(SwingConstants.RIGHT); + extraField.setForeground(fontColor); + //extraField.setBackground(Color.BLACK); + + lowerPanel.setBackground(Color.BLACK); + container.setBackground(Color.BLACK); + + + + + countDown.setText(" 15:00.0"); + extraField.setText("B "); + updateGui(); } private void updateGui() { - lblState.setText("LastKey: " + lastKey + "
CurrentState: " + + /*lblState.setText("LastKey: " + lastKey + "
CurrentState: " + machine.getCurrentState() + "
ChangeCounter: " + - machine.getStateChangeCounter() + ""); + machine.getStateChangeCounter() + ""); */ + + } + + @Override + public void startTimer(int seconds) { + timerSeconds = seconds*10; + timerSecondsLast = seconds*10; + timer.start(); + } + + @Override + public void stopTimer() { + timer.stop(); + timerSeconds = 0; + timerSecondsLast = 0; + } + + @Override + public void pauseTimer(Boolean pause) { + if(pause) { + timer.stop(); + } else { + timer.start(); + } + } + + @Override + public void setWall(final String message) { + Runnable runnable = new Runnable() { + @Override + public void run() { + textWall.setText(message); + } + }; + + SwingUtilities.invokeLater(runnable); + } + + @Override + public void setExtra(final String text) { + Runnable runnable = new Runnable() { + @Override + public void run() { + extraField.setText(text + " " + lastKey + " "); + } + }; + + SwingUtilities.invokeLater(runnable); + } + + @Override + public int getTimerSeconds() { + return timerSeconds; + } + + @Override + public int getTimerSecondsLast() { + return timerSecondsLast; + } + + @Override + public Boolean getTimerRunning() { + return null; + } + + @Override + public void resetGame() { + + } + + @Override + public void recieveEvent(IRCEvent e) { + + if (e.getType() == IRCEvent.Type.CONNECT_COMPLETE) { + e.getSession().joinChannel("#crashtest"); + + } else if (e.getType() == IRCEvent.Type.JOIN_COMPLETE) { + JoinCompleteEvent jce = (JoinCompleteEvent) e; + jce.getChannel().say("hello master. what's your order?"); + } } } diff --git a/src/de/ctdo/crashtest/TheGame.java b/src/de/ctdo/crashtest/TheGame.java new file mode 100644 index 0000000..dac5ff7 --- /dev/null +++ b/src/de/ctdo/crashtest/TheGame.java @@ -0,0 +1,16 @@ +package de.ctdo.crashtest; + +public class TheGame { + + // hier müssen alle Verbindungen nach Aussen rein + // MPD + // Lampel + // Bunti + // IRC + + // Die GUI muss als Interface bekannt sein + // fuer Updates der GUI und den Keypress Event + + // Logik des Spiels muss hier programmiert werden + +} From cac038325145b4324357577d0a58ceef968e920a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Fri, 1 Jun 2012 17:00:34 +0200 Subject: [PATCH 02/11] more IRC integration refactoring, cleanup logging to irc --- src/de/ctdo/crashtest/BuntiClient.java | 93 ----- src/de/ctdo/crashtest/Communication.java | 73 ---- .../ctdo/crashtest/CommunicationRunner.java | 76 ---- src/de/ctdo/crashtest/GuiControl.java | 18 - src/de/ctdo/crashtest/LampelClient.java | 36 -- src/de/ctdo/crashtest/Statemachine.java | 173 --------- src/de/ctdo/crashtest/Steuerung.java | 15 +- src/de/ctdo/crashtest/SteuerungFrame.java | 359 ------------------ src/de/ctdo/crashtest/TheGame.java | 16 - .../ctdo/crashtest/domotics/BuntiClient.java | 133 +++++++ .../ctdo/crashtest/domotics/IBuntiClient.java | 11 + src/de/ctdo/crashtest/game/IStatemachine.java | 14 + .../{ => game}/StateChangeListener.java | 2 +- src/de/ctdo/crashtest/game/Statemachine.java | 168 ++++++++ src/de/ctdo/crashtest/game/TheGame.java | 249 ++++++++++++ .../ctdo/crashtest/gui/GuiEventListener.java | 14 + src/de/ctdo/crashtest/gui/IGuiControl.java | 17 + src/de/ctdo/crashtest/gui/MainGui.java | 184 +++++++++ src/de/ctdo/crashtest/irc/IIrcClient.java | 10 + .../ctdo/crashtest/irc/IRCEventListener.java | 10 + src/de/ctdo/crashtest/irc/IrcClient.java | 83 ++++ src/de/ctdo/crashtest/log/ILogger.java | 10 + src/de/ctdo/crashtest/log/Logger.java | 34 ++ src/de/ctdo/crashtest/mpd/IMPDController.java | 10 + src/de/ctdo/crashtest/mpd/MPDController.java | 63 +++ 25 files changed, 1025 insertions(+), 846 deletions(-) delete mode 100644 src/de/ctdo/crashtest/BuntiClient.java delete mode 100644 src/de/ctdo/crashtest/Communication.java delete mode 100644 src/de/ctdo/crashtest/CommunicationRunner.java delete mode 100644 src/de/ctdo/crashtest/GuiControl.java delete mode 100644 src/de/ctdo/crashtest/LampelClient.java delete mode 100644 src/de/ctdo/crashtest/Statemachine.java delete mode 100644 src/de/ctdo/crashtest/SteuerungFrame.java delete mode 100644 src/de/ctdo/crashtest/TheGame.java create mode 100644 src/de/ctdo/crashtest/domotics/BuntiClient.java create mode 100644 src/de/ctdo/crashtest/domotics/IBuntiClient.java create mode 100644 src/de/ctdo/crashtest/game/IStatemachine.java rename src/de/ctdo/crashtest/{ => game}/StateChangeListener.java (82%) create mode 100644 src/de/ctdo/crashtest/game/Statemachine.java create mode 100644 src/de/ctdo/crashtest/game/TheGame.java create mode 100644 src/de/ctdo/crashtest/gui/GuiEventListener.java create mode 100644 src/de/ctdo/crashtest/gui/IGuiControl.java create mode 100644 src/de/ctdo/crashtest/gui/MainGui.java create mode 100644 src/de/ctdo/crashtest/irc/IIrcClient.java create mode 100644 src/de/ctdo/crashtest/irc/IRCEventListener.java create mode 100644 src/de/ctdo/crashtest/irc/IrcClient.java create mode 100644 src/de/ctdo/crashtest/log/ILogger.java create mode 100644 src/de/ctdo/crashtest/log/Logger.java create mode 100644 src/de/ctdo/crashtest/mpd/IMPDController.java create mode 100644 src/de/ctdo/crashtest/mpd/MPDController.java diff --git a/src/de/ctdo/crashtest/BuntiClient.java b/src/de/ctdo/crashtest/BuntiClient.java deleted file mode 100644 index e0b75c5..0000000 --- a/src/de/ctdo/crashtest/BuntiClient.java +++ /dev/null @@ -1,93 +0,0 @@ -package de.ctdo.crashtest; - -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.DefaultHttpClient; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -/** - * User: lpless - * Date: 10.05.12 - * Time: 11:03 - */ -public class BuntiClient { - private String baseAddress; - private HttpClient client = new DefaultHttpClient(); - private LampelClient lampel = new LampelClient(); - - public BuntiClient(String server, int port) { - baseAddress = "http://" + server + ":" + port + "/"; - } - - public void setPar56(int id, int red, int green, int blue) { - if(true) return; - try { - HttpPost post = new HttpPost(baseAddress + "/control/devices"); - post.addHeader("Content-Type", "application/json"); - - StringEntity entity = new StringEntity( - "{ \"timeStamp\": 0, \"updates\": [ {\"deviceId\": "+id+", \"options\": { \"red\": "+ - red+", \"green\": "+green+", \"blue\": "+blue+" } } ] }" , - "UTF-8"); - - post.setEntity(entity); - - HttpResponse response = client.execute(post); - System.out.println(response); - - post.abort(); - - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } catch (ClientProtocolException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - - } - - public void setLampel(boolean red, boolean yellow, boolean green) { - - if(true) return; - - int value = 0; - - if( green ) value |= 0x01; - if( yellow ) value |= 0x02; - if( red ) value |= 0x04; - - lampel.sendCommand("io set port 2 " + Integer.toHexString(value)); - - -/* try { - HttpPost post = new HttpPost(baseAddress + "/control/devices"); - post.addHeader("Content-Type", "application/json"); - - StringEntity entity = new StringEntity( - "{ \"timeStamp\": 0, \"updates\": [ {\"deviceId\": 4, \"options\": { \"red\": "+ - red+", \"green\": "+green+", \"yellow\": "+yellow+" } } ] }" , - "UTF-8"); - - post.setEntity(entity); - - HttpResponse response = client.execute(post); - System.out.println(response); - - post.abort(); - - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } catch (ClientProtocolException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - }*/ - } - -} diff --git a/src/de/ctdo/crashtest/Communication.java b/src/de/ctdo/crashtest/Communication.java deleted file mode 100644 index 5e503a8..0000000 --- a/src/de/ctdo/crashtest/Communication.java +++ /dev/null @@ -1,73 +0,0 @@ -package de.ctdo.crashtest; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class Communication implements Runnable { - private final static int LISTEN_PORT = 2342; - private Boolean isStopped = false; - private ServerSocket serverSocket; - private Thread runningThread; - - private ExecutorService threadPool = Executors.newFixedThreadPool(10); - - private GuiControl control; - - public Communication(GuiControl control) { - this.control = control; - } - - - private synchronized boolean isStopped() { - return this.isStopped; - } - - @Override - public void run() { - - synchronized(this){ - this.runningThread = Thread.currentThread(); - } - - openServerSocket(); - - while(!isStopped()){ - Socket clientSocket = null; - try { - clientSocket = this.serverSocket.accept(); - } catch (IOException e) { - if(isStopped()) { - System.out.println("Server Stopped.") ; - return; - } - throw new RuntimeException("Error accepting client connection", e); - } - this.threadPool.execute(new CommunicationRunner(clientSocket, this.control)); - } - - this.threadPool.shutdown(); - System.out.println("Server Stopped.") ; - - } - - - public synchronized void stop() { - this.isStopped = true; - try { - this.serverSocket.close(); - } catch (IOException e) { - throw new RuntimeException("Error closing server", e); - } - } - - private void openServerSocket() { - try { - this.serverSocket = new ServerSocket(LISTEN_PORT); - } catch (IOException e) { - throw new RuntimeException("Cannot open port 8080", e); - } - } -} diff --git a/src/de/ctdo/crashtest/CommunicationRunner.java b/src/de/ctdo/crashtest/CommunicationRunner.java deleted file mode 100644 index e0afb61..0000000 --- a/src/de/ctdo/crashtest/CommunicationRunner.java +++ /dev/null @@ -1,76 +0,0 @@ -package de.ctdo.crashtest; - -import java.io.*; -import java.net.Socket; -import java.net.SocketTimeoutException; - -public class CommunicationRunner implements Runnable { - private Socket clientSocket = null; - private GuiControl control; - - public CommunicationRunner(Socket clientSocket, GuiControl control) { - this.clientSocket = clientSocket; - this.control = control; - } - - @Override - public void run() { - try { - clientSocket.setSoTimeout(5000); - InputStream input = clientSocket.getInputStream(); - OutputStream output = clientSocket.getOutputStream(); - long time = System.currentTimeMillis(); - - BufferedReader reader = new BufferedReader(new InputStreamReader(input)); - - String line = reader.readLine(); - - System.out.println("got line: " + line); - - runCommand(line); - - output.close(); - input.close(); - System.out.println("Request processed: " + time + clientSocket.getRemoteSocketAddress()); - } catch (SocketTimeoutException e) { - System.out.println("Socket Timeout, closing " + clientSocket.getRemoteSocketAddress()); - } catch (IOException e) { - e.printStackTrace(); - } - - try { - clientSocket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - } - - private void runCommand(String line) { - - // must contain a ":" - // then split and switch on the command - int pos = line.indexOf(":"); - if(pos > 0) { - String command = line.substring(0, pos).toLowerCase().trim(); - String parameter = line.substring(pos+1, line.length()).trim(); - - if(command.equals("wall")) { - control.setWall(parameter); - } else if(command.equals("timerstart")) { - control.startTimer(Integer.parseInt(parameter)); - } else if(command.equals("timerstop")) { - control.stopTimer(); - } else if(command.equals("timerpause")) { - control.pauseTimer(Boolean.parseBoolean(parameter)); - } else if(command.equals("setextra")) { - control.setExtra(parameter); - } else if(command == "reset") { - control.resetGame(); - } - - - } - - } -} diff --git a/src/de/ctdo/crashtest/GuiControl.java b/src/de/ctdo/crashtest/GuiControl.java deleted file mode 100644 index 1a8eb50..0000000 --- a/src/de/ctdo/crashtest/GuiControl.java +++ /dev/null @@ -1,18 +0,0 @@ -package de.ctdo.crashtest; - -public interface GuiControl { - - void startTimer(int seconds); - void stopTimer(); // and hide - void pauseTimer(Boolean pause); - - void setWall(String message); - void setExtra(String text); - - int getTimerSeconds(); - int getTimerSecondsLast(); - Boolean getTimerRunning(); - - void resetGame(); - -} diff --git a/src/de/ctdo/crashtest/LampelClient.java b/src/de/ctdo/crashtest/LampelClient.java deleted file mode 100644 index f055d32..0000000 --- a/src/de/ctdo/crashtest/LampelClient.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.ctdo.crashtest; - -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.Socket; - -public class LampelClient { - - private static final int ECMD_TCP_PORT = 2701; - private static final String LAMPEL_HOST = "lampel.ctdo.de"; - - - public void sendCommand(String command) { - - try { - Socket client = new Socket(LAMPEL_HOST, ECMD_TCP_PORT); - client.setSoTimeout(800); - - - DataOutputStream outToServer = new DataOutputStream(client.getOutputStream()); - BufferedReader inFromServer = new BufferedReader(new InputStreamReader(client.getInputStream())); - - - outToServer.writeBytes(command + '\n'); - - String result = inFromServer.readLine(); - - client.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - } -} diff --git a/src/de/ctdo/crashtest/Statemachine.java b/src/de/ctdo/crashtest/Statemachine.java deleted file mode 100644 index ff7137f..0000000 --- a/src/de/ctdo/crashtest/Statemachine.java +++ /dev/null @@ -1,173 +0,0 @@ -package de.ctdo.crashtest; - -import java.util.ArrayList; -import java.util.List; - -public class Statemachine { - private final char BLUE_BUTTON = 'E'; - private final char LIGHT_BARRIER = 'F'; - private final char TABLE_ONE = 'G'; - private final char TABLE_TWO = 'H'; - private final char TABLE_THREE = 'I'; - private final char ROKET_INPUT = 'B'; - private long lastHandleInput = 0; - private final List stateChangeListenerList = new ArrayList(); - private int stateChangeCounter = 0; - - public void addStateChangedListener(StateChangeListener listener) { - stateChangeListenerList.add(listener); - } - - public enum state { - IDLE, - ENTERED_ROOM, - TABLE_GAME_ONE, - TABLE_GAME_TWO, - TABLE_GAME_THREE, - TABLE_GAME_FOUR, - TABLE_GAME_FIVE, - TABLE_GAME_SIX, - TABLE_GAME_SEVEN, - TABLE_FINISH, - ROKET_DONE - } - - private state currentState = state.IDLE; - - - public state getCurrentState() { - return currentState; - } - - public int getStateChangeCounter() { - return stateChangeCounter; - } - - public void reset() { - stateChangeCounter = 0; - currentState = state.IDLE; - onStateChanged(); - } - - public void handleInput(char input) { - if(System.currentTimeMillis() - lastHandleInput < 200 ) return; - - state newState = getNewState(input); - - if( newState != currentState ) { - stateChangeCounter++; - System.out.println("newState = " + newState); - - workForState(newState); - - - currentState = newState; - onStateChanged(); - } - - - lastHandleInput = System.currentTimeMillis(); - } - - private void onStateChanged() { - for(StateChangeListener listener: stateChangeListenerList) { - listener.stateChanged(currentState); - } - } - - private void workForState(state newState) { - switch (newState) { - case IDLE: - break; - case ENTERED_ROOM: - - - break; - case TABLE_GAME_ONE: - break; - case TABLE_GAME_TWO: - break; - case TABLE_GAME_THREE: - break; - case TABLE_GAME_FOUR: - break; - case TABLE_GAME_FIVE: - break; - case TABLE_GAME_SIX: - break; - case TABLE_GAME_SEVEN: - break; - } - } - - private state getNewState(char input) { - state retVal = currentState; - - switch (currentState) { - case IDLE: - if(input == LIGHT_BARRIER) { - retVal = state.ENTERED_ROOM; - } - break; - case ENTERED_ROOM: - if(input == TABLE_ONE) { - retVal = state.TABLE_GAME_ONE; - } - break; - case TABLE_GAME_ONE: - if(input == TABLE_TWO) { - retVal = state.TABLE_GAME_TWO; - } - break; - case TABLE_GAME_TWO: - if(input == TABLE_THREE) { - retVal = state.TABLE_GAME_THREE; - } else if (input == TABLE_ONE) { - retVal = state.TABLE_GAME_ONE; - } - break; - case TABLE_GAME_THREE: - if(input == TABLE_TWO) { - retVal = state.TABLE_GAME_FOUR; - } else if (input == TABLE_ONE) { - retVal = state.TABLE_GAME_ONE; - } - break; - case TABLE_GAME_FOUR: - if(input == TABLE_THREE) { - retVal = state.TABLE_GAME_FIVE; - } else if (input == TABLE_ONE) { - retVal = state.TABLE_GAME_ONE; - } - break; - case TABLE_GAME_FIVE: - if(input == TABLE_ONE) { - retVal = state.TABLE_GAME_SIX; - } else if (input == TABLE_TWO) { - retVal = state.TABLE_GAME_ONE; - } - break; - case TABLE_GAME_SIX: - if(input == TABLE_THREE) { - retVal = state.TABLE_GAME_SEVEN; - } else if (input == TABLE_TWO) { - retVal = state.TABLE_GAME_ONE; - } - break; - case TABLE_GAME_SEVEN: - if(input == BLUE_BUTTON) { - retVal = state.TABLE_FINISH; - } - break; - case TABLE_FINISH: - if(input == ROKET_INPUT) { - retVal = state.ROKET_DONE; - } - - - } - - - return retVal; - } -} diff --git a/src/de/ctdo/crashtest/Steuerung.java b/src/de/ctdo/crashtest/Steuerung.java index 67c9517..960c7a8 100644 --- a/src/de/ctdo/crashtest/Steuerung.java +++ b/src/de/ctdo/crashtest/Steuerung.java @@ -1,16 +1,29 @@ package de.ctdo.crashtest; +import de.ctdo.crashtest.game.TheGame; +import de.ctdo.crashtest.gui.IGuiControl; +import de.ctdo.crashtest.gui.MainGui; public class Steuerung { + private TheGame game; + private IGuiControl gui; + public static void main(String args[]) { - new SteuerungFrame(); + new Steuerung(); } + public Steuerung() { + gui = new MainGui(); + + game = new TheGame(gui); + + + } } diff --git a/src/de/ctdo/crashtest/SteuerungFrame.java b/src/de/ctdo/crashtest/SteuerungFrame.java deleted file mode 100644 index e67932a..0000000 --- a/src/de/ctdo/crashtest/SteuerungFrame.java +++ /dev/null @@ -1,359 +0,0 @@ -package de.ctdo.crashtest; - -import jerklib.*; -import jerklib.events.IRCEvent; -import jerklib.events.JoinCompleteEvent; -import jerklib.events.listeners.IRCEventListener; -import org.bff.javampd.*; -import org.bff.javampd.exception.MPDConnectionException; -import org.bff.javampd.exception.MPDDatabaseException; -import org.bff.javampd.exception.MPDPlayerException; -import org.bff.javampd.exception.MPDResponseException; -import org.bff.javampd.objects.MPDSong; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Random; - -public class SteuerungFrame extends JFrame implements StateChangeListener, GuiControl, IRCEventListener { - private JTextArea textWall; - private JLabel countDown; - private JLabel extraField; - private JPanel lowerPanel; - private char lastKey = ' '; - private MPD mpd; - private MPDPlayer player; - private int timerSeconds = 0; - private int timerSecondsLast = 0; - private int timeSpentTableGame = 0; - private int timeSpentRokets = 0; - - private Timer timer; - private Statemachine machine = new Statemachine(); - private BuntiClient bunti = new BuntiClient("bunti.ctdo.de", 8080); - private Communication server; - private ConnectionManager irc; - private Session ircsession; - - - public SteuerungFrame() { - initGui(); - setDefaultCloseOperation(EXIT_ON_CLOSE); - setVisible(true); - setBounds(200,200, 400, 200); - - //server = new Communication(this); - - irc = new ConnectionManager(new ProfileImpl("crashtest","crashtest", "crashtest2", "crashtest3")); - ircsession = irc.requestConnection("irc.chaostreff-dortmund.de"); - ircsession.addIRCEventListener(this); - - //initTimer(); - - machine.addStateChangedListener(this); - machine.reset(); - - //initMPD(); - - this.addKeyListener(new KeyAdapter() { - @Override - public void keyTyped(KeyEvent e) { - lastKey = e.getKeyChar(); - - /*if (lastKey == KeyEvent.VK_F) { - Random r = new Random(); - setLEDs(r.nextInt(255), r.nextInt(255),r.nextInt(255)); - } */ - - if (lastKey == KeyEvent.VK_1) { - machine.reset(); - } else { - machine.handleInput(e.getKeyChar()); - } - - updateGui(); - } - }); - - this.addWindowStateListener(new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - - System.out.print("oihdf"); - } - - @Override - public void windowClosing(WindowEvent e) { - try { - if (mpd != null) mpd.close(); - - if (server != null) server.stop(); - } catch (MPDConnectionException e1) { - e1.printStackTrace(); - } catch (MPDResponseException e1) { - e1.printStackTrace(); - } - } - }); - - //new Thread(server).start(); - } - - private void initMPD() { - try { - mpd = new MPD("dampfradio.raum.chaostreff-dortmund.de", 6600); - player = mpd.getMPDPlayer(); - - MPDDatabase database = mpd.getMPDDatabase(); - Collection bla = database.findTitle(""); - - } catch (UnknownHostException e) { - e.printStackTrace(); - return; - } catch (MPDConnectionException e) { - e.printStackTrace(); - return; - } catch (MPDDatabaseException e) { - e.printStackTrace(); - } - } - - private void initTimer() { - timer = new Timer(100, new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - timerSecondsLast--; - setTimerText(); - - if(timerSecondsLast <= 0) { - timerSecondsLast = 0; - timer.stop(); - } - } - }); - } - - private void setTimerText() { - int mins = timerSecondsLast / 600; - int secs = timerSecondsLast % 600 / 10 ; - int tsecs = timerSecondsLast % 9; - countDown.setText(" " + mins + ":" + secs + "." + tsecs); - } - - @Override - public void stateChanged(Statemachine.state newState) { - updateGui(); - - if(ircsession != null) { - for(Channel chan: ircsession.getChannels()) { - chan.say("New State: " + newState); - } - } - - switch (newState) { - case IDLE: - //setLEDs(0x40,0,0xff); - setLEDs(0,0,0); - bunti.setLampel(false,false,false); - break; - case ENTERED_ROOM: - bunti.setLampel(false,false,false); - setLEDs(20,0,100); - - // start von Mo Do - Eins, Zwei Polizei - - break; - case TABLE_GAME_ONE: - bunti.setLampel(true,false,false); - setLEDs(255,0,100); - break; - case TABLE_GAME_TWO: - bunti.setLampel(false,true,false); - setLEDs(255,0,100); - break; - case TABLE_GAME_THREE: - bunti.setLampel(false,true,false); - setLEDs(255,35,0); - - - - - break; - case TABLE_GAME_FOUR: - bunti.setLampel(false,true,false); - setLEDs(255,55,0); - break; - case TABLE_GAME_FIVE: - bunti.setLampel(false,true,false); - setLEDs(255,75,0); - break; - case TABLE_GAME_SIX: - bunti.setLampel(false,true,false); - setLEDs(255,100,0); - break; - case TABLE_GAME_SEVEN: - bunti.setLampel(false,false,true); - setLEDs(255,100,0); - break; - case TABLE_FINISH: // und roket muss starten - bunti.setLampel(false,false,true); - setLEDs(0, 255, 0); - break; - case ROKET_DONE: - bunti.setLampel(true,true,true); - setLEDs(255, 196, 0); - break; - } - - } - - - private void setLEDs(int red, int green, int blue) { - bunti.setPar56(0,red,green,blue); - bunti.setPar56(1,red,green,blue); - bunti.setPar56(2,red,green,blue); - bunti.setPar56(3,red,green,blue); - } - - private void initGui() { - textWall = new JTextArea(); - countDown = new JLabel(); - extraField = new JLabel(); - lowerPanel = new JPanel(); - - - Container container = getContentPane(); - container.setLayout(new BorderLayout()); - container.add(textWall, BorderLayout.NORTH); - container.add(lowerPanel, BorderLayout.SOUTH); - - lowerPanel.setLayout(new BorderLayout()); - lowerPanel.add(countDown, BorderLayout.WEST); - lowerPanel.add(extraField, BorderLayout.EAST); - - Font wallFont = new Font("Arcade Interlaced", Font.PLAIN, 66); - Font lowerFont = new Font("Arcade Interlaced", Font.PLAIN, 80); - Color fontColor = new Color(0x00, 190, 100); - - textWall.setFont(wallFont); - textWall.setForeground(fontColor); - textWall.setBackground(Color.BLACK); - textWall.setText("follow the white rabbit..."); - textWall.setLineWrap(true); - textWall.setWrapStyleWord(true); - textWall.setFocusable(false); - - countDown.setFont(lowerFont); - countDown.setHorizontalAlignment(SwingConstants.LEFT); - countDown.setForeground(fontColor); - //countDown.setBackground(Color.BLACK); - - extraField.setFont(lowerFont); - extraField.setHorizontalAlignment(SwingConstants.RIGHT); - extraField.setForeground(fontColor); - //extraField.setBackground(Color.BLACK); - - lowerPanel.setBackground(Color.BLACK); - container.setBackground(Color.BLACK); - - - - - countDown.setText(" 15:00.0"); - extraField.setText("B "); - - - updateGui(); - } - - private void updateGui() { - /*lblState.setText("LastKey: " + lastKey + "
CurrentState: " + - machine.getCurrentState() + "
ChangeCounter: " + - machine.getStateChangeCounter() + ""); */ - - } - - @Override - public void startTimer(int seconds) { - timerSeconds = seconds*10; - timerSecondsLast = seconds*10; - timer.start(); - } - - @Override - public void stopTimer() { - timer.stop(); - timerSeconds = 0; - timerSecondsLast = 0; - } - - @Override - public void pauseTimer(Boolean pause) { - if(pause) { - timer.stop(); - } else { - timer.start(); - } - } - - @Override - public void setWall(final String message) { - Runnable runnable = new Runnable() { - @Override - public void run() { - textWall.setText(message); - } - }; - - SwingUtilities.invokeLater(runnable); - } - - @Override - public void setExtra(final String text) { - Runnable runnable = new Runnable() { - @Override - public void run() { - extraField.setText(text + " " + lastKey + " "); - } - }; - - SwingUtilities.invokeLater(runnable); - } - - @Override - public int getTimerSeconds() { - return timerSeconds; - } - - @Override - public int getTimerSecondsLast() { - return timerSecondsLast; - } - - @Override - public Boolean getTimerRunning() { - return null; - } - - @Override - public void resetGame() { - - } - - @Override - public void recieveEvent(IRCEvent e) { - - if (e.getType() == IRCEvent.Type.CONNECT_COMPLETE) { - e.getSession().joinChannel("#crashtest"); - - } else if (e.getType() == IRCEvent.Type.JOIN_COMPLETE) { - JoinCompleteEvent jce = (JoinCompleteEvent) e; - jce.getChannel().say("hello master. what's your order?"); - } - - } -} diff --git a/src/de/ctdo/crashtest/TheGame.java b/src/de/ctdo/crashtest/TheGame.java deleted file mode 100644 index dac5ff7..0000000 --- a/src/de/ctdo/crashtest/TheGame.java +++ /dev/null @@ -1,16 +0,0 @@ -package de.ctdo.crashtest; - -public class TheGame { - - // hier müssen alle Verbindungen nach Aussen rein - // MPD - // Lampel - // Bunti - // IRC - - // Die GUI muss als Interface bekannt sein - // fuer Updates der GUI und den Keypress Event - - // Logik des Spiels muss hier programmiert werden - -} diff --git a/src/de/ctdo/crashtest/domotics/BuntiClient.java b/src/de/ctdo/crashtest/domotics/BuntiClient.java new file mode 100644 index 0000000..f44bb0c --- /dev/null +++ b/src/de/ctdo/crashtest/domotics/BuntiClient.java @@ -0,0 +1,133 @@ +package de.ctdo.crashtest.domotics; + +import de.ctdo.crashtest.log.Logger; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; + +import java.io.*; +import java.net.Socket; + +public class BuntiClient implements IBuntiClient { + private String baseAddress; + private final HttpClient client = new DefaultHttpClient(); + + public BuntiClient(String server, int port) { + baseAddress = "http://" + server + ":" + port + "/"; + } + + @Override + public void setPar56(final int red, final int green, final int blue) { + + //if(true) return; + + Runnable r = new Runnable() { + @Override + public void run() { + try { + HttpPost post = new HttpPost(baseAddress + "/control/devices"); + post.addHeader("Content-Type", "application/json"); + + StringBuilder jsonString = new StringBuilder(); + + jsonString.append("{ \"timeStamp\": 0, \"updates\": [ "); + + for(int i = 0; i< 4; i++) { + jsonString.append(" {\"deviceId\": "); + jsonString.append(i); + jsonString.append(", \"options\": { \"red\": "); + jsonString.append(red); + jsonString.append(", \"green\": "); + jsonString.append(green); + jsonString.append(", \"blue\": "); + jsonString.append(blue); + jsonString.append(" } } "); + if(i!=3) jsonString.append(","); + } + + jsonString.append("] }"); + + System.out.println("bunti request: " + jsonString.toString()); + + StringEntity entity = new StringEntity( jsonString.toString(), "UTF-8"); + post.setEntity(entity); + + client.execute(post); + post.abort(); + + } catch (UnsupportedEncodingException e) { + Logger.sLog("bunti error: " + e.getMessage()); + } catch (ClientProtocolException e) { + Logger.sLog("bunti error: " + e.getMessage()); + } catch (IOException e) { + Logger.sLog("bunti error: " + e.getMessage()); + } + } + }; + + new Thread(r).start(); + } + + @Override + public void setLampel(final boolean red, final boolean yellow, final boolean green) { + + //if(true) return; + + Runnable r = new Runnable() { + @Override + public void run() { + int value = 0; +// if( green ) value |= 0x01; +// if( yellow ) value |= 0x02; +// if( red ) value |= 0x04; + + try { + Socket client = new Socket("lampel.ctdo.de", 2701); + client.setSoTimeout(800); + + DataOutputStream outToServer = new DataOutputStream(client.getOutputStream()); + BufferedReader inFromServer = new BufferedReader(new InputStreamReader(client.getInputStream())); + + + outToServer.writeBytes("io set port 2 " + Integer.toHexString(value) + '\n'); + + inFromServer.readLine(); + + client.close(); + } catch (IOException e) { + Logger.sLog("cannot send to lampel: " + e.getMessage()); + } + } + }; + + + new Thread(r).start(); + +/* try { + HttpPost post = new HttpPost(baseAddress + "/control/devices"); + post.addHeader("Content-Type", "application/json"); + + StringEntity entity = new StringEntity( + "{ \"timeStamp\": 0, \"updates\": [ {\"deviceId\": 4, \"options\": { \"red\": "+ + red+", \"green\": "+green+", \"yellow\": "+yellow+" } } ] }" , + "UTF-8"); + + post.setEntity(entity); + + HttpResponse response = client.execute(post); + System.out.println(response); + + post.abort(); + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + }*/ + } + +} diff --git a/src/de/ctdo/crashtest/domotics/IBuntiClient.java b/src/de/ctdo/crashtest/domotics/IBuntiClient.java new file mode 100644 index 0000000..bff4f75 --- /dev/null +++ b/src/de/ctdo/crashtest/domotics/IBuntiClient.java @@ -0,0 +1,11 @@ +package de.ctdo.crashtest.domotics; + +/** + * @author: lucas + * @date: 01.06.12 14:25 + */ +public interface IBuntiClient { + void setPar56(final int red, final int green, final int blue); + + void setLampel(final boolean red, final boolean yellow, final boolean green); +} diff --git a/src/de/ctdo/crashtest/game/IStatemachine.java b/src/de/ctdo/crashtest/game/IStatemachine.java new file mode 100644 index 0000000..8dc9c89 --- /dev/null +++ b/src/de/ctdo/crashtest/game/IStatemachine.java @@ -0,0 +1,14 @@ +package de.ctdo.crashtest.game; + +/** + * @author: lucas + * @date: 01.06.12 14:17 + */ +public interface IStatemachine { + void addStateChangedListener(StateChangeListener listener); + void reset(); + Statemachine.state getCurrentState(); + void setNewState(Statemachine.state newState); + int getStateChangeCounter(); + void handleInput(char input); +} diff --git a/src/de/ctdo/crashtest/StateChangeListener.java b/src/de/ctdo/crashtest/game/StateChangeListener.java similarity index 82% rename from src/de/ctdo/crashtest/StateChangeListener.java rename to src/de/ctdo/crashtest/game/StateChangeListener.java index f6c6ad3..5c00ca1 100644 --- a/src/de/ctdo/crashtest/StateChangeListener.java +++ b/src/de/ctdo/crashtest/game/StateChangeListener.java @@ -1,4 +1,4 @@ -package de.ctdo.crashtest; +package de.ctdo.crashtest.game; /** * User: lpless diff --git a/src/de/ctdo/crashtest/game/Statemachine.java b/src/de/ctdo/crashtest/game/Statemachine.java new file mode 100644 index 0000000..7bb32c6 --- /dev/null +++ b/src/de/ctdo/crashtest/game/Statemachine.java @@ -0,0 +1,168 @@ +package de.ctdo.crashtest.game; + +import java.util.ArrayList; +import java.util.List; + +public class Statemachine implements IStatemachine { + public enum state { + IDLE, + ENTERED_ROOM, + TABLE_GAME_ONE, + TABLE_GAME_TWO, + TABLE_GAME_THREE, + TABLE_GAME_FOUR, + TABLE_GAME_FIVE, + TABLE_GAME_SIX, + TABLE_GAME_SEVEN, + TABLE_FINISH, + ROKET_DONE + } + + private final char RESET = '1'; + private final char BLUE_BUTTON = 'E'; + private final char LIGHT_BARRIER = 'F'; + private final char TABLE_ONE = 'G'; + private final char TABLE_TWO = 'H'; + private final char TABLE_THREE = 'I'; + private final char ROKET_INPUT = 'B'; + private final List stateChangeListenerList = new ArrayList(); + + private long lastHandleInput = 0; + private int stateChangeCounter = 0; + private state currentState = state.IDLE; + + @Override + public void addStateChangedListener(StateChangeListener listener) { + stateChangeListenerList.add(listener); + } + + @Override + public state getCurrentState() { + return currentState; + } + + @Override + public void setNewState(state newState) { + currentState = newState; + stateChangeCounter++; + onStateChanged(); + } + + @Override + public int getStateChangeCounter() { + return stateChangeCounter; + } + + @Override + public void reset() { + stateChangeCounter = 0; + currentState = state.IDLE; + onStateChanged(); + } + + @Override + public void handleInput(char input) { + if(System.currentTimeMillis() - lastHandleInput < 200 ) return; + + state newState = getNewState(input); + + if( newState != currentState ) { + stateChangeCounter++; + System.out.println("newState = " + newState); + + currentState = newState; + onStateChanged(); + } + + lastHandleInput = System.currentTimeMillis(); + } + + + /** + * notifies all listeners about the changed state + */ + private void onStateChanged() { + for(StateChangeListener listener: stateChangeListenerList) { + listener.stateChanged(currentState); + } + } + + + /** + * Calculates the new game state from the current state and new input button + * @param input the char from the input + * @return returns the new state + */ + private state getNewState(char input) { + state retVal = currentState; + + if(input == RESET) { + retVal = state.IDLE; + } else { + + switch (currentState) { + case IDLE: + if(input == LIGHT_BARRIER) { + retVal = state.ENTERED_ROOM; + } + break; + case ENTERED_ROOM: + if(input == TABLE_ONE) { + retVal = state.TABLE_GAME_ONE; + } + break; + case TABLE_GAME_ONE: + if(input == TABLE_TWO) { + retVal = state.TABLE_GAME_TWO; + } + break; + case TABLE_GAME_TWO: + if(input == TABLE_THREE) { + retVal = state.TABLE_GAME_THREE; + } else if (input == TABLE_ONE) { + retVal = state.TABLE_GAME_ONE; + } + break; + case TABLE_GAME_THREE: + if(input == TABLE_TWO) { + retVal = state.TABLE_GAME_FOUR; + } else if (input == TABLE_ONE) { + retVal = state.TABLE_GAME_ONE; + } + break; + case TABLE_GAME_FOUR: + if(input == TABLE_THREE) { + retVal = state.TABLE_GAME_FIVE; + } else if (input == TABLE_ONE) { + retVal = state.TABLE_GAME_ONE; + } + break; + case TABLE_GAME_FIVE: + if(input == TABLE_ONE) { + retVal = state.TABLE_GAME_SIX; + } else if (input == TABLE_TWO) { + retVal = state.TABLE_GAME_ONE; + } + break; + case TABLE_GAME_SIX: + if(input == TABLE_THREE) { + retVal = state.TABLE_GAME_SEVEN; + } else if (input == TABLE_TWO) { + retVal = state.TABLE_GAME_ONE; + } + break; + case TABLE_GAME_SEVEN: + if(input == BLUE_BUTTON) { + retVal = state.TABLE_FINISH; + } + break; + case TABLE_FINISH: + if(input == ROKET_INPUT) { + retVal = state.ROKET_DONE; + } + } + } + + return retVal; + } +} diff --git a/src/de/ctdo/crashtest/game/TheGame.java b/src/de/ctdo/crashtest/game/TheGame.java new file mode 100644 index 0000000..d148ec6 --- /dev/null +++ b/src/de/ctdo/crashtest/game/TheGame.java @@ -0,0 +1,249 @@ +package de.ctdo.crashtest.game; + +import de.ctdo.crashtest.domotics.*; +import de.ctdo.crashtest.gui.*; +import de.ctdo.crashtest.irc.*; + +public class TheGame implements StateChangeListener, GuiEventListener, IRCEventListener { + private IGuiControl guiControl; + private IIrcClient ircClient; + private IStatemachine machine; + private IBuntiClient bunti; + + private int timertSeconds = 0; + private int timertSecondsLast = 0; + private int timeSpentTableGame = 0; + private int timeSpentRokets = 0; + + + + public TheGame(IGuiControl guiControl) { + this.guiControl = guiControl; + + this.ircClient = new IrcClient(); + this.machine = new Statemachine(); + this.bunti = new BuntiClient("bunti.ctdo.de", 8080); + + initGame(); + } + + private void initGame() { + guiControl.addListener(this); + ircClient.addListener(this); + machine.addStateChangedListener(this); + + machine.reset(); + } + + + /** + * Event listener for state change events from statemachine + * @param newState the new game state from statemachine + */ + @Override + public void stateChanged(Statemachine.state newState) { + + ircClient.say("New State: " + newState); + + switch (newState) { + case IDLE: + bunti.setPar56(0,0,0); + bunti.setLampel(false,false,false); + guiControl.showCountDown(false); + break; + case ENTERED_ROOM: + bunti.setLampel(false,false,false); + bunti.setPar56(20,0,100); + break; + case TABLE_GAME_ONE: + bunti.setLampel(true,false,false); + guiControl.showCountDown(true); + bunti.setPar56(255,0,100); + break; + case TABLE_GAME_TWO: + bunti.setLampel(false,true,false); + bunti.setPar56(255,0,100); + break; + case TABLE_GAME_THREE: + bunti.setLampel(false,true,false); + bunti.setPar56(255,35,0); + break; + case TABLE_GAME_FOUR: + bunti.setLampel(false,true,false); + bunti.setPar56(255,55,0); + break; + case TABLE_GAME_FIVE: + bunti.setLampel(false,true,false); + bunti.setPar56(255,75,0); + break; + case TABLE_GAME_SIX: + bunti.setLampel(false,true,false); + bunti.setPar56(255,100,0); + break; + case TABLE_GAME_SEVEN: + bunti.setLampel(false,false,true); + bunti.setPar56(255,100,0); + break; + case TABLE_FINISH: // und roket muss starten + bunti.setLampel(false,false,true); + bunti.setPar56(0, 255, 0); + break; + case ROKET_DONE: + bunti.setLampel(true,true,true); + bunti.setPar56(255, 196, 0); + break; + } + + } + + + /** + * Event listener for keyPress events from the GUI + * @param key the pressed key + */ + @Override + public void keyPress(char key) { + machine.handleInput(key); + guiControl.setExtra("btn: " + key); + + } + + /** + * Event lister for window closing event from the GUI + */ + @Override + public void windowClosing() { + + } + + /** + * Event listener for IRC Messages + * @param message the message from the IRC user + */ + @Override + public void handleMessage(final String message) { + if(message.startsWith("help")) { + handleHelpCommand(message); + } else if(message.equals("reset")) { + machine.reset(); + ircClient.say("reset done"); + } else if(message.startsWith("state")) { + handleStateCommand(message); + } else if(message.startsWith("timer")) { + handleTimerCommand(message); + } else if(message.startsWith("score")) { + handleScoreCommand(message); + } else if(message.startsWith("wall")) { + guiControl.setWall(message.substring("wall".length()).trim()); + } else if(message.startsWith("extra")) { + guiControl.setExtra(message.substring("extra".length()).trim()); + } else { + ircClient.say("y u no use valid command?"); + } + } + + private void handleTimerCommand(final String message) { + String params = message.substring("timer".length()).trim().toLowerCase(); + + if(params.startsWith("start")) { + String timeStr = params.substring("start".length()).trim(); + + if(timeStr.length() > 0) { + int time = 0; + + try { + time = Integer.parseInt(timeStr); + + guiControl.showCountDown(true); + ircClient.say("got it, starting with " + time + " seconds"); + } + catch (NumberFormatException e) { + ircClient.say("your number looks a bit odd..."); + } + } else { + ircClient.say("invalid parameter"); + } + } else if(params.startsWith("stop")) { + + guiControl.showCountDown(false); + ircClient.say("timer stopped"); + } else if(params.startsWith("pause")) { + + } else if(params.startsWith("resume")) { + + } + + + } + + private void handleStateCommand(final String message) { + if(message.equals("state")) { + ircClient.say(machine.getCurrentState().name()); + } else { + + String params = message.substring("state".length()).trim().toLowerCase(); + + Boolean ok = false; + for(Statemachine.state st: Statemachine.state.values()) { + String stateName = st.name().toLowerCase(); + if(stateName.equals(params)) { + ok = true; + machine.setNewState(st); + ircClient.say("consider it done, sir!"); + break; + } + } + + if(!ok) ircClient.say("ehm, impossibruu!"); + + } + } + + private void handleScoreCommand(final String message) { + ircClient.say("stateChangeCounter: " + machine.getStateChangeCounter()); + ircClient.say("timerlast: " + timertSecondsLast / 10); + } + + + private void handleHelpCommand(final String message) { + if(message.equals("help")) { + ircClient.say("commands: help, reset, state, timer, wall, extra, score"); + } else if(message.contains("reset")) { + ircClient.say("resets the game to IDLE"); + } else if(message.contains("state")) { + ircClient.say("get or set game state"); + ircClient.say("> state "); + ircClient.say("valid states: "); + + int counter = 0; + StringBuilder sb = new StringBuilder(); + for(Statemachine.state st: Statemachine.state.values()) { + sb.append(st.name()); + sb.append(" "); + if(++counter == 4) { + counter = 0; + ircClient.say(sb.toString()); + sb.setLength(0); + } + } + + if(sb.length() > 0) { + ircClient.say(sb.toString()); + } + } else if(message.contains("timer")) { + ircClient.say("control timer. commands are: start, stop, pause, resume."); + ircClient.say("for start give lenght in seconds as parameter"); + ircClient.say("e.g.: timer start 120"); + } else if(message.contains("wall")) { + ircClient.say("set text message on the screen"); + } else if(message.contains("extra")) { + ircClient.say("set small extra message on the screen"); + } else if(message.contains("score")) { + ircClient.say("i will tell you the current game score"); + } else { + ircClient.say("dafuq?"); + } + + } + +} diff --git a/src/de/ctdo/crashtest/gui/GuiEventListener.java b/src/de/ctdo/crashtest/gui/GuiEventListener.java new file mode 100644 index 0000000..c7bede4 --- /dev/null +++ b/src/de/ctdo/crashtest/gui/GuiEventListener.java @@ -0,0 +1,14 @@ +package de.ctdo.crashtest.gui; + +import java.awt.event.KeyEvent; + +/** + * @author: lucas + * @date: 01.06.12 10:29 + */ +public interface GuiEventListener { + + void keyPress(final char key); + void windowClosing(); + +} diff --git a/src/de/ctdo/crashtest/gui/IGuiControl.java b/src/de/ctdo/crashtest/gui/IGuiControl.java new file mode 100644 index 0000000..6ba4aec --- /dev/null +++ b/src/de/ctdo/crashtest/gui/IGuiControl.java @@ -0,0 +1,17 @@ +package de.ctdo.crashtest.gui; + +/** + * @author: lucas + * @date: 01.06.12 10:13 + */ +public interface IGuiControl { + + void setWall(final String message); + void setExtra(final String text); + void setCountDown(final int tseconds); + void showCountDown(final Boolean show); + + void addListener(final GuiEventListener listener); + + +} diff --git a/src/de/ctdo/crashtest/gui/MainGui.java b/src/de/ctdo/crashtest/gui/MainGui.java new file mode 100644 index 0000000..871417a --- /dev/null +++ b/src/de/ctdo/crashtest/gui/MainGui.java @@ -0,0 +1,184 @@ +package de.ctdo.crashtest.gui; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.util.List; + +public class MainGui extends JFrame implements IGuiControl { + private final JTextArea textWall = new JTextArea(); + private final JLabel countDown = new JLabel(); + private final JLabel extraField = new JLabel(); + private final JPanel lowerPanel = new JPanel(); + + private final List listenerList = new ArrayList(); + + public MainGui() { + initGui(); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setVisible(true); + setBounds(0,0, 1280, 1024); + + addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + char lastKey = e.getKeyChar(); + + for(GuiEventListener listener: listenerList) { + listener.keyPress(lastKey); + } + } + }); + + addWindowStateListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + for(GuiEventListener listener: listenerList) { + listener.windowClosing(); + } + } + }); + } + +// +// +// private void initTimer() { +// timer = new Timer(100, new ActionListener() { +// @Override +// public void actionPerformed(ActionEvent e) { +// timerSecondsLast--; +// setTimerText(); +// +// if(timerSecondsLast <= 0) { +// timerSecondsLast = 0; +// timer.stop(); +// } +// } +// }); +// } +// + private void setCountDownText(final int tseconds) { + int mins = tseconds / 600; + int secs = tseconds % 600 / 10 ; + int tsecs = tseconds % 9; + countDown.setText(" " + mins + ":" + secs + "." + tsecs); + } + + private void initGui() { + Container container = getContentPane(); + container.setLayout(new BorderLayout()); + container.add(textWall, BorderLayout.NORTH); + container.add(lowerPanel, BorderLayout.SOUTH); + + lowerPanel.setLayout(new BorderLayout()); + lowerPanel.add(countDown, BorderLayout.WEST); + lowerPanel.add(extraField, BorderLayout.EAST); + + Font wallFont = new Font("Arcade Interlaced", Font.PLAIN, 66); + Font lowerFont = new Font("Arcade Interlaced", Font.PLAIN, 80); + Color fontColor = new Color(0x00, 190, 100); + + textWall.setFont(wallFont); + textWall.setForeground(fontColor); + textWall.setBackground(Color.BLACK); + textWall.setText("follow the white rabbit..."); + textWall.setLineWrap(true); + textWall.setWrapStyleWord(true); + textWall.setFocusable(false); + + countDown.setFont(lowerFont); + countDown.setHorizontalAlignment(SwingConstants.LEFT); + countDown.setForeground(fontColor); + extraField.setFont(lowerFont); + extraField.setHorizontalAlignment(SwingConstants.RIGHT); + extraField.setForeground(fontColor); + + lowerPanel.setBackground(Color.BLACK); + container.setBackground(Color.BLACK); + + countDown.setText(" 15:00.0"); + extraField.setText(" "); + } + + +// @Override +// public void startTimer(int seconds) { +// timerSeconds = seconds*10; +// timerSecondsLast = seconds*10; +// timer.start(); +// } +// +// @Override +// public void stopTimer() { +// timer.stop(); +// timerSeconds = 0; +// timerSecondsLast = 0; +// } +// +// @Override +// public void pauseTimer(Boolean pause) { +// if(pause) { +// timer.stop(); +// } else { +// timer.start(); +// } +// } + + @Override + public void setWall(final String message) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + textWall.setText(message); + } + }; + + SwingUtilities.invokeLater(runnable); + } + + @Override + public void setExtra(final String text) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + extraField.setText(text + " "); + } + }; + + SwingUtilities.invokeLater(runnable); + } + + @Override + public void setCountDown(final int tseconds) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + setCountDownText(tseconds); + } + }; + + SwingUtilities.invokeLater(runnable); + } + + @Override + public void showCountDown(final Boolean show) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + countDown.setVisible(show); + } + }; + + SwingUtilities.invokeLater(runnable); + + } + + @Override + public void addListener(final GuiEventListener listener) { + listenerList.add(listener); + } + + + +} diff --git a/src/de/ctdo/crashtest/irc/IIrcClient.java b/src/de/ctdo/crashtest/irc/IIrcClient.java new file mode 100644 index 0000000..ac10e1c --- /dev/null +++ b/src/de/ctdo/crashtest/irc/IIrcClient.java @@ -0,0 +1,10 @@ +package de.ctdo.crashtest.irc; + +/** + * @author: lucas + * @date: 01.06.12 10:05 + */ +public interface IIrcClient { + void say(String message); + void addListener(IRCEventListener listenerIRC); +} diff --git a/src/de/ctdo/crashtest/irc/IRCEventListener.java b/src/de/ctdo/crashtest/irc/IRCEventListener.java new file mode 100644 index 0000000..8fc9ad9 --- /dev/null +++ b/src/de/ctdo/crashtest/irc/IRCEventListener.java @@ -0,0 +1,10 @@ +package de.ctdo.crashtest.irc; + +/** + * @author: lucas + * @date: 01.06.12 11:49 + */ +public interface IRCEventListener { + + void handleMessage(final String message); +} diff --git a/src/de/ctdo/crashtest/irc/IrcClient.java b/src/de/ctdo/crashtest/irc/IrcClient.java new file mode 100644 index 0000000..0e1f446 --- /dev/null +++ b/src/de/ctdo/crashtest/irc/IrcClient.java @@ -0,0 +1,83 @@ +package de.ctdo.crashtest.irc; + +import de.ctdo.crashtest.log.ILogger; +import de.ctdo.crashtest.log.Logger; +import jerklib.Channel; +import jerklib.ConnectionManager; +import jerklib.ProfileImpl; +import jerklib.Session; +import jerklib.events.ChannelMsgEvent; +import jerklib.events.ConnectionCompleteEvent; +import jerklib.events.IRCEvent; +import jerklib.events.JoinCompleteEvent; + +import java.util.ArrayList; +import java.util.List; + +/** + * IRC Client wrapper + * simplifies communication with the irc channel + */ +public class IrcClient implements IIrcClient, jerklib.events.listeners.IRCEventListener, ILogger { + private final List listenerListIRC = new ArrayList(); + private final static String CHANNEL = "#crashtest2"; + private Session ircsession; + + public IrcClient() { + ConnectionManager ircConnection = new ConnectionManager(new ProfileImpl("crashtest", "crashtest", + "crashtest2", "crashtest3")); + ircsession = ircConnection.requestConnection("irc.chaostreff-dortmund.de"); + ircsession.addIRCEventListener(this); + } + + @Override + public void recieveEvent(IRCEvent ircEvent) { + + if(ircEvent instanceof ConnectionCompleteEvent) { + ircEvent.getSession().joinChannel(CHANNEL); + } + else if (ircEvent instanceof JoinCompleteEvent) { + JoinCompleteEvent jce = (JoinCompleteEvent) ircEvent; + jce.getChannel().say("hello master. what's your order?"); + + Logger logger = Logger.getInstance(); + logger.addLogger(this); + } + else if(ircEvent instanceof ChannelMsgEvent) { + ChannelMsgEvent cme = (ChannelMsgEvent)ircEvent; + + String message = cme.getMessage(); + final String nick = ircsession.getNick(); + + if(message.contains(nick)) { + message = message.substring(Math.max(nick.length(), message.indexOf(":")+1)); + message = message.trim(); + + System.out.println("irc message: " + message); + + for(IRCEventListener listenerIRC : listenerListIRC) { + listenerIRC.handleMessage(message); + } + } + } + } + + @Override + public void log(String message) { + say("LOG: " + message); + } + + @Override + public void say(String message) { + if(ircsession != null) { + for(Channel chan: ircsession.getChannels()) { + chan.say(message); + } + } + } + + @Override + public void addListener(final IRCEventListener listenerIRC) { + listenerListIRC.add(listenerIRC); + } +} diff --git a/src/de/ctdo/crashtest/log/ILogger.java b/src/de/ctdo/crashtest/log/ILogger.java new file mode 100644 index 0000000..177d06b --- /dev/null +++ b/src/de/ctdo/crashtest/log/ILogger.java @@ -0,0 +1,10 @@ +package de.ctdo.crashtest.log; + +/** + * @author: lucas + * @date: 01.06.12 16:46 + */ +public interface ILogger { + + void log(String message); +} diff --git a/src/de/ctdo/crashtest/log/Logger.java b/src/de/ctdo/crashtest/log/Logger.java new file mode 100644 index 0000000..ddbc511 --- /dev/null +++ b/src/de/ctdo/crashtest/log/Logger.java @@ -0,0 +1,34 @@ +package de.ctdo.crashtest.log; + +import java.util.ArrayList; +import java.util.List; + +public class Logger { + private final static Logger instance = new Logger(); + private final List loggerList = new ArrayList(); + + + public void addLogger(ILogger listener) { + loggerList.add(listener); + } + + private Logger() { + + } + + public static Logger getInstance() { + return instance; + } + + public void log(String message) { + System.out.println("LOG: " + message); + + for(ILogger logger: loggerList) { + logger.log(message); + } + } + + public static void sLog(String message) { + getInstance().log(message); + } +} diff --git a/src/de/ctdo/crashtest/mpd/IMPDController.java b/src/de/ctdo/crashtest/mpd/IMPDController.java new file mode 100644 index 0000000..a40400c --- /dev/null +++ b/src/de/ctdo/crashtest/mpd/IMPDController.java @@ -0,0 +1,10 @@ +package de.ctdo.crashtest.mpd; + +/** + * @author: lucas + * @date: 01.06.12 10:36 + */ +public interface IMPDController { + void playSong(String artist, String title); + void setVolume(int volume); +} diff --git a/src/de/ctdo/crashtest/mpd/MPDController.java b/src/de/ctdo/crashtest/mpd/MPDController.java new file mode 100644 index 0000000..e4592e5 --- /dev/null +++ b/src/de/ctdo/crashtest/mpd/MPDController.java @@ -0,0 +1,63 @@ +package de.ctdo.crashtest.mpd; + +import de.ctdo.crashtest.log.Logger; +import org.bff.javampd.MPD; +import org.bff.javampd.MPDDatabase; +import org.bff.javampd.MPDPlayer; +import org.bff.javampd.exception.MPDConnectionException; +import org.bff.javampd.exception.MPDDatabaseException; +import org.bff.javampd.objects.MPDSong; + +import java.net.UnknownHostException; +import java.util.Collection; + +/** + * @author: lucas + * @date: 01.06.12 10:34 + */ +public class MPDController implements IMPDController { + + private MPD mpd; + private MPDPlayer player; + + public MPDController() { + initMPD(); + + } + + private void initMPD() { + try { + mpd = new MPD("dampfradio.raum.chaostreff-dortmund.de", 6600); + player = mpd.getMPDPlayer(); + + MPDDatabase database = mpd.getMPDDatabase(); + + Collection bla = database.findTitle(""); + + } catch (UnknownHostException e) { + Logger.sLog("MPD error: " + e.getMessage()); + } catch (MPDConnectionException e) { + Logger.sLog("MPD error: " + e.getMessage()); + } catch (MPDDatabaseException e) { + Logger.sLog("MPD error: " + e.getMessage()); + } + } + + + @Override + public void playSong(String artist, String title) { + if(mpd != null && player != null) { + + // MPDSong finden in der DB + // dann abspielen + + } + } + + @Override + public void setVolume(int volume) { + if(mpd != null && player != null) { + + } + } +} From d8cfca913aba763344d6758f5a2a89455745975f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Fri, 1 Jun 2012 17:06:17 +0200 Subject: [PATCH 03/11] cleanup --- src/de/ctdo/crashtest/domotics/BuntiClient.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/de/ctdo/crashtest/domotics/BuntiClient.java b/src/de/ctdo/crashtest/domotics/BuntiClient.java index f44bb0c..c8f1776 100644 --- a/src/de/ctdo/crashtest/domotics/BuntiClient.java +++ b/src/de/ctdo/crashtest/domotics/BuntiClient.java @@ -21,8 +21,6 @@ public class BuntiClient implements IBuntiClient { @Override public void setPar56(final int red, final int green, final int blue) { - //if(true) return; - Runnable r = new Runnable() { @Override public void run() { @@ -49,8 +47,6 @@ public class BuntiClient implements IBuntiClient { jsonString.append("] }"); - System.out.println("bunti request: " + jsonString.toString()); - StringEntity entity = new StringEntity( jsonString.toString(), "UTF-8"); post.setEntity(entity); @@ -73,15 +69,13 @@ public class BuntiClient implements IBuntiClient { @Override public void setLampel(final boolean red, final boolean yellow, final boolean green) { - //if(true) return; - Runnable r = new Runnable() { @Override public void run() { int value = 0; -// if( green ) value |= 0x01; -// if( yellow ) value |= 0x02; -// if( red ) value |= 0x04; + if( green ) value |= 0x01; + if( yellow ) value |= 0x02; + if( red ) value |= 0x04; try { Socket client = new Socket("lampel.ctdo.de", 2701); @@ -97,7 +91,7 @@ public class BuntiClient implements IBuntiClient { client.close(); } catch (IOException e) { - Logger.sLog("cannot send to lampel: " + e.getMessage()); + Logger.sLog("lampel error: " + e.getMessage()); } } }; From fa25912fe80fd0005e1df5664faa213b4543826e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Fri, 1 Jun 2012 17:06:33 +0200 Subject: [PATCH 04/11] cleanup --- src/de/ctdo/crashtest/irc/IrcClient.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/de/ctdo/crashtest/irc/IrcClient.java b/src/de/ctdo/crashtest/irc/IrcClient.java index 0e1f446..c0a14bb 100644 --- a/src/de/ctdo/crashtest/irc/IrcClient.java +++ b/src/de/ctdo/crashtest/irc/IrcClient.java @@ -53,8 +53,6 @@ public class IrcClient implements IIrcClient, jerklib.events.listeners.IRCEventL message = message.substring(Math.max(nick.length(), message.indexOf(":")+1)); message = message.trim(); - System.out.println("irc message: " + message); - for(IRCEventListener listenerIRC : listenerListIRC) { listenerIRC.handleMessage(message); } From 076ae82639d8654e9789d0cc98ba2072d14b199e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Fri, 1 Jun 2012 17:20:32 +0200 Subject: [PATCH 05/11] added test class --- src/de/ctdo/crashtest/TestClass.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/de/ctdo/crashtest/TestClass.java diff --git a/src/de/ctdo/crashtest/TestClass.java b/src/de/ctdo/crashtest/TestClass.java new file mode 100644 index 0000000..29e35cd --- /dev/null +++ b/src/de/ctdo/crashtest/TestClass.java @@ -0,0 +1,21 @@ +package de.ctdo.crashtest; + +import de.ctdo.crashtest.mpd.IMPDController; +import de.ctdo.crashtest.mpd.MPDController; + + + +public class TestClass { + + + + public static void main(String args[]) { + + IMPDController mpdController = new MPDController(); + + + mpdController.playSong("VNV Nation", "Perpetual"); + + } + +} From 1c28a2a38175b10b722a4698e753ee28dcbeec36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Fri, 1 Jun 2012 21:04:35 +0200 Subject: [PATCH 06/11] completed mpd connection --- src/de/ctdo/crashtest/TestClass.java | 12 +- src/de/ctdo/crashtest/game/TheGame.java | 13 ++- src/de/ctdo/crashtest/irc/IrcClient.java | 2 +- src/de/ctdo/crashtest/log/Logger.java | 6 +- src/de/ctdo/crashtest/mpd/IMPDController.java | 4 +- src/de/ctdo/crashtest/mpd/MPDController.java | 105 +++++++++++++++--- 6 files changed, 116 insertions(+), 26 deletions(-) diff --git a/src/de/ctdo/crashtest/TestClass.java b/src/de/ctdo/crashtest/TestClass.java index 29e35cd..3520787 100644 --- a/src/de/ctdo/crashtest/TestClass.java +++ b/src/de/ctdo/crashtest/TestClass.java @@ -9,12 +9,20 @@ public class TestClass { - public static void main(String args[]) { + public static void main(String args[]) throws InterruptedException { IMPDController mpdController = new MPDController(); + mpdController.playSong("VNV Nation", "Nemesis"); + + Thread.sleep(2000); + + mpdController.playSong("Enter Shikari", "Sorry, You're Not A Winner"); + + + Thread.sleep(2000); + mpdController.playSong("Calabria", "Pump It Up (Club Mix)"); - mpdController.playSong("VNV Nation", "Perpetual"); } diff --git a/src/de/ctdo/crashtest/game/TheGame.java b/src/de/ctdo/crashtest/game/TheGame.java index d148ec6..a92f8a0 100644 --- a/src/de/ctdo/crashtest/game/TheGame.java +++ b/src/de/ctdo/crashtest/game/TheGame.java @@ -3,12 +3,15 @@ package de.ctdo.crashtest.game; import de.ctdo.crashtest.domotics.*; import de.ctdo.crashtest.gui.*; import de.ctdo.crashtest.irc.*; +import de.ctdo.crashtest.mpd.IMPDController; +import de.ctdo.crashtest.mpd.MPDController; public class TheGame implements StateChangeListener, GuiEventListener, IRCEventListener { private IGuiControl guiControl; private IIrcClient ircClient; private IStatemachine machine; private IBuntiClient bunti; + private IMPDController mpdController; private int timertSeconds = 0; private int timertSecondsLast = 0; @@ -23,6 +26,7 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL this.ircClient = new IrcClient(); this.machine = new Statemachine(); this.bunti = new BuntiClient("bunti.ctdo.de", 8080); + this.mpdController = new MPDController(); initGame(); } @@ -47,11 +51,13 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL switch (newState) { case IDLE: + mpdController.playSong("VNV Nation", "Nemesis"); bunti.setPar56(0,0,0); bunti.setLampel(false,false,false); guiControl.showCountDown(false); break; case ENTERED_ROOM: + mpdController.playSong("Blümchen", "Herz an Herz"); bunti.setLampel(false,false,false); bunti.setPar56(20,0,100); break; @@ -83,6 +89,9 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL case TABLE_GAME_SEVEN: bunti.setLampel(false,false,true); bunti.setPar56(255,100,0); + mpdController.playSong("K2", "Der berg ruft"); + ircClient.say("table game complete"); + sayScore(); break; case TABLE_FINISH: // und roket muss starten bunti.setLampel(false,false,true); @@ -132,7 +141,7 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL } else if(message.startsWith("timer")) { handleTimerCommand(message); } else if(message.startsWith("score")) { - handleScoreCommand(message); + sayScore(); } else if(message.startsWith("wall")) { guiControl.setWall(message.substring("wall".length()).trim()); } else if(message.startsWith("extra")) { @@ -199,7 +208,7 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL } } - private void handleScoreCommand(final String message) { + private void sayScore() { ircClient.say("stateChangeCounter: " + machine.getStateChangeCounter()); ircClient.say("timerlast: " + timertSecondsLast / 10); } diff --git a/src/de/ctdo/crashtest/irc/IrcClient.java b/src/de/ctdo/crashtest/irc/IrcClient.java index c0a14bb..cb2b5c3 100644 --- a/src/de/ctdo/crashtest/irc/IrcClient.java +++ b/src/de/ctdo/crashtest/irc/IrcClient.java @@ -20,7 +20,7 @@ import java.util.List; */ public class IrcClient implements IIrcClient, jerklib.events.listeners.IRCEventListener, ILogger { private final List listenerListIRC = new ArrayList(); - private final static String CHANNEL = "#crashtest2"; + private final static String CHANNEL = "#crashtest"; private Session ircsession; public IrcClient() { diff --git a/src/de/ctdo/crashtest/log/Logger.java b/src/de/ctdo/crashtest/log/Logger.java index ddbc511..b1f537d 100644 --- a/src/de/ctdo/crashtest/log/Logger.java +++ b/src/de/ctdo/crashtest/log/Logger.java @@ -21,11 +21,15 @@ public class Logger { } public void log(String message) { + System.out.println("LOG: " + message); for(ILogger logger: loggerList) { - logger.log(message); + synchronized (this) { + logger.log(message); + } } + } public static void sLog(String message) { diff --git a/src/de/ctdo/crashtest/mpd/IMPDController.java b/src/de/ctdo/crashtest/mpd/IMPDController.java index a40400c..275b72c 100644 --- a/src/de/ctdo/crashtest/mpd/IMPDController.java +++ b/src/de/ctdo/crashtest/mpd/IMPDController.java @@ -5,6 +5,6 @@ package de.ctdo.crashtest.mpd; * @date: 01.06.12 10:36 */ public interface IMPDController { - void playSong(String artist, String title); - void setVolume(int volume); + void playSong(final String artist, final String title); + void setVolume(final int volume); } diff --git a/src/de/ctdo/crashtest/mpd/MPDController.java b/src/de/ctdo/crashtest/mpd/MPDController.java index e4592e5..588dad4 100644 --- a/src/de/ctdo/crashtest/mpd/MPDController.java +++ b/src/de/ctdo/crashtest/mpd/MPDController.java @@ -1,15 +1,21 @@ package de.ctdo.crashtest.mpd; +import de.ctdo.crashtest.game.TheGame; import de.ctdo.crashtest.log.Logger; import org.bff.javampd.MPD; import org.bff.javampd.MPDDatabase; import org.bff.javampd.MPDPlayer; +import org.bff.javampd.MPDPlaylist; import org.bff.javampd.exception.MPDConnectionException; import org.bff.javampd.exception.MPDDatabaseException; +import org.bff.javampd.exception.MPDPlayerException; +import org.bff.javampd.exception.MPDPlaylistException; import org.bff.javampd.objects.MPDSong; import java.net.UnknownHostException; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * @author: lucas @@ -18,7 +24,6 @@ import java.util.Collection; public class MPDController implements IMPDController { private MPD mpd; - private MPDPlayer player; public MPDController() { initMPD(); @@ -28,36 +33,100 @@ public class MPDController implements IMPDController { private void initMPD() { try { mpd = new MPD("dampfradio.raum.chaostreff-dortmund.de", 6600); - player = mpd.getMPDPlayer(); - - MPDDatabase database = mpd.getMPDDatabase(); - - Collection bla = database.findTitle(""); + } catch (UnknownHostException e) { Logger.sLog("MPD error: " + e.getMessage()); + } catch (MPDConnectionException e) { + Logger.sLog("MPD error: " + e.getMessage()); + } + } + + + @Override + public void playSong(final String artist, final String title) { + if(mpd != null) { + + Runnable r = new Runnable() { + @Override + public void run() { + addToPlayListIfNeeded(artist, title); + + try { + + MPDPlaylist playlist = mpd.getMPDPlaylist(); + + for(MPDSong song: playlist.getSongList()) { + + if(song.getArtist() != null && song.getTitle() != null) { + if(song.getArtist().getName().toLowerCase().equals(artist.toLowerCase()) && + song.getTitle().toLowerCase().equals(title.toLowerCase())) { + + MPDPlayer player = mpd.getMPDPlayer(); + player.stop(); + player.playId(song); + break; + } + } + } + + } catch (MPDConnectionException e) { + Logger.sLog("MPD error: " + e.getMessage()); + } catch (MPDPlayerException e) { + Logger.sLog("MPD error: " + e.getMessage()); + } + } + }; + + new Thread(r).start(); + } + } + + private void addToPlayListIfNeeded(final String artist, final String title) { + MPDDatabase db = mpd.getMPDDatabase(); + MPDPlaylist playlist = mpd.getMPDPlaylist(); + + try { + List tracks = new ArrayList(db.findArtist(artist)); + + for(MPDSong song: tracks) { + if(song.getName() != null && + song.getName().toLowerCase().contains(title.toLowerCase())) { + + if(!playlist.getSongList().contains(song)) { + playlist.addSong(song); + } + break; + } + } + } catch (MPDConnectionException e) { Logger.sLog("MPD error: " + e.getMessage()); } catch (MPDDatabaseException e) { Logger.sLog("MPD error: " + e.getMessage()); + } catch (MPDPlaylistException e) { + Logger.sLog("MPD error: " + e.getMessage()); } } - @Override - public void playSong(String artist, String title) { - if(mpd != null && player != null) { + public void setVolume(final int volume) { + if(mpd != null) { - // MPDSong finden in der DB - // dann abspielen - - } - } - - @Override - public void setVolume(int volume) { - if(mpd != null && player != null) { + Runnable r = new Runnable() { + @Override + public void run() { + try { + mpd.getMPDPlayer().setVolume(volume); + } catch (MPDConnectionException e) { + Logger.sLog("MPD error: " + e.getMessage()); + } catch (MPDPlayerException e) { + Logger.sLog("MPD error: " + e.getMessage()); + } + } + }; + new Thread(r).start(); } } } From 690012182907a2e14d9b7c3fdca1d1565be3ee2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Sun, 3 Jun 2012 15:45:39 +0200 Subject: [PATCH 07/11] some small refactorings. made the hosts configurable --- src/de/ctdo/crashtest/game/TheGame.java | 6 ++--- src/de/ctdo/crashtest/gui/MainGui.java | 6 ++++- src/de/ctdo/crashtest/irc/IrcClient.java | 11 ++++---- src/de/ctdo/crashtest/mpd/MPDController.java | 28 +++++++++----------- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/de/ctdo/crashtest/game/TheGame.java b/src/de/ctdo/crashtest/game/TheGame.java index a92f8a0..b5c06d6 100644 --- a/src/de/ctdo/crashtest/game/TheGame.java +++ b/src/de/ctdo/crashtest/game/TheGame.java @@ -23,10 +23,10 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL public TheGame(IGuiControl guiControl) { this.guiControl = guiControl; - this.ircClient = new IrcClient(); - this.machine = new Statemachine(); + this.ircClient = new IrcClient("crashtest", "#crashtest","irc.ctdo.de"); this.bunti = new BuntiClient("bunti.ctdo.de", 8080); - this.mpdController = new MPDController(); + this.mpdController = new MPDController("dampfradio.raum.ctdo.de"); + this.machine = new Statemachine(); initGame(); } diff --git a/src/de/ctdo/crashtest/gui/MainGui.java b/src/de/ctdo/crashtest/gui/MainGui.java index 871417a..fd69252 100644 --- a/src/de/ctdo/crashtest/gui/MainGui.java +++ b/src/de/ctdo/crashtest/gui/MainGui.java @@ -17,8 +17,10 @@ public class MainGui extends JFrame implements IGuiControl { public MainGui() { initGui(); setDefaultCloseOperation(EXIT_ON_CLOSE); - setVisible(true); + setBounds(0,0, 1280, 1024); + setExtendedState(Frame.MAXIMIZED_BOTH); + setUndecorated(true); addKeyListener(new KeyAdapter() { @Override @@ -39,6 +41,8 @@ public class MainGui extends JFrame implements IGuiControl { } } }); + + setVisible(true); } // diff --git a/src/de/ctdo/crashtest/irc/IrcClient.java b/src/de/ctdo/crashtest/irc/IrcClient.java index cb2b5c3..a399fc6 100644 --- a/src/de/ctdo/crashtest/irc/IrcClient.java +++ b/src/de/ctdo/crashtest/irc/IrcClient.java @@ -22,11 +22,12 @@ public class IrcClient implements IIrcClient, jerklib.events.listeners.IRCEventL private final List listenerListIRC = new ArrayList(); private final static String CHANNEL = "#crashtest"; private Session ircsession; + private final String channel; - public IrcClient() { - ConnectionManager ircConnection = new ConnectionManager(new ProfileImpl("crashtest", "crashtest", - "crashtest2", "crashtest3")); - ircsession = ircConnection.requestConnection("irc.chaostreff-dortmund.de"); + public IrcClient(String nick, String channel, String server) { + this.channel = channel; + ConnectionManager ircConnection = new ConnectionManager(new ProfileImpl(nick,nick, nick+2, nick+3)); + ircsession = ircConnection.requestConnection(server); ircsession.addIRCEventListener(this); } @@ -34,7 +35,7 @@ public class IrcClient implements IIrcClient, jerklib.events.listeners.IRCEventL public void recieveEvent(IRCEvent ircEvent) { if(ircEvent instanceof ConnectionCompleteEvent) { - ircEvent.getSession().joinChannel(CHANNEL); + ircEvent.getSession().joinChannel(channel); } else if (ircEvent instanceof JoinCompleteEvent) { JoinCompleteEvent jce = (JoinCompleteEvent) ircEvent; diff --git a/src/de/ctdo/crashtest/mpd/MPDController.java b/src/de/ctdo/crashtest/mpd/MPDController.java index 588dad4..100675b 100644 --- a/src/de/ctdo/crashtest/mpd/MPDController.java +++ b/src/de/ctdo/crashtest/mpd/MPDController.java @@ -1,6 +1,5 @@ package de.ctdo.crashtest.mpd; -import de.ctdo.crashtest.game.TheGame; import de.ctdo.crashtest.log.Logger; import org.bff.javampd.MPD; import org.bff.javampd.MPDDatabase; @@ -14,27 +13,17 @@ import org.bff.javampd.objects.MPDSong; import java.net.UnknownHostException; import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** - * @author: lucas - * @date: 01.06.12 10:34 + * A MPD abstraction to the org.bff.javampd library */ public class MPDController implements IMPDController { - private MPD mpd; - public MPDController() { - initMPD(); - - } - - private void initMPD() { + public MPDController(String host) { try { - mpd = new MPD("dampfradio.raum.chaostreff-dortmund.de", 6600); - - + mpd = new MPD(host, 6600); } catch (UnknownHostException e) { Logger.sLog("MPD error: " + e.getMessage()); } catch (MPDConnectionException e) { @@ -42,7 +31,12 @@ public class MPDController implements IMPDController { } } - + /** + * Play a song, defined by artist and track title + * Song gets added to current playlist and is played. + * @param artist Artist of the track to play + * @param title Title of the track to play + */ @Override public void playSong(final String artist, final String title) { if(mpd != null) { @@ -109,6 +103,10 @@ public class MPDController implements IMPDController { } } + /** + * Sets the current mpd volume + * @param volume the volume in percent (0-100) + */ @Override public void setVolume(final int volume) { if(mpd != null) { From 06a0fe0b46996f1d62068dd6176b8e8bc17de722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Sun, 3 Jun 2012 17:05:20 +0200 Subject: [PATCH 08/11] changed music --- src/de/ctdo/crashtest/TestClass.java | 10 ---------- src/de/ctdo/crashtest/game/TheGame.java | 19 +++++++++++++++---- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/de/ctdo/crashtest/TestClass.java b/src/de/ctdo/crashtest/TestClass.java index 3520787..878f2bf 100644 --- a/src/de/ctdo/crashtest/TestClass.java +++ b/src/de/ctdo/crashtest/TestClass.java @@ -11,17 +11,7 @@ public class TestClass { public static void main(String args[]) throws InterruptedException { - IMPDController mpdController = new MPDController(); - mpdController.playSong("VNV Nation", "Nemesis"); - - Thread.sleep(2000); - - mpdController.playSong("Enter Shikari", "Sorry, You're Not A Winner"); - - - Thread.sleep(2000); - mpdController.playSong("Calabria", "Pump It Up (Club Mix)"); } diff --git a/src/de/ctdo/crashtest/game/TheGame.java b/src/de/ctdo/crashtest/game/TheGame.java index b5c06d6..7093355 100644 --- a/src/de/ctdo/crashtest/game/TheGame.java +++ b/src/de/ctdo/crashtest/game/TheGame.java @@ -51,17 +51,21 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL switch (newState) { case IDLE: - mpdController.playSong("VNV Nation", "Nemesis"); + mpdController.setVolume(45); + mpdController.playSong("start", "mix"); bunti.setPar56(0,0,0); bunti.setLampel(false,false,false); guiControl.showCountDown(false); break; case ENTERED_ROOM: - mpdController.playSong("Blümchen", "Herz an Herz"); + mpdController.setVolume(70); + mpdController.playSong("Modem", "Dial_In_and_HF Longplay"); bunti.setLampel(false,false,false); bunti.setPar56(20,0,100); break; case TABLE_GAME_ONE: + mpdController.setVolume(70); + mpdController.playSong("K2", "Der Berg Ruft"); bunti.setLampel(true,false,false); guiControl.showCountDown(true); bunti.setPar56(255,0,100); @@ -73,6 +77,8 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL case TABLE_GAME_THREE: bunti.setLampel(false,true,false); bunti.setPar56(255,35,0); + mpdController.setVolume(60); + mpdController.playSong("Mo-Do","9 Eins Zwei Polizei"); break; case TABLE_GAME_FOUR: bunti.setLampel(false,true,false); @@ -85,21 +91,26 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL case TABLE_GAME_SIX: bunti.setLampel(false,true,false); bunti.setPar56(255,100,0); + mpdController.setVolume(60); + mpdController.playSong("Zlatko & Jürgen","Großer Bruder"); break; case TABLE_GAME_SEVEN: bunti.setLampel(false,false,true); bunti.setPar56(255,100,0); - mpdController.playSong("K2", "Der berg ruft"); - ircClient.say("table game complete"); sayScore(); break; case TABLE_FINISH: // und roket muss starten bunti.setLampel(false,false,true); bunti.setPar56(0, 255, 0); + ircClient.say("table game complete, r0kets now"); + mpdController.setVolume(50); + mpdController.playSong("The Underdog Project", "Summer Jam"); break; case ROKET_DONE: bunti.setLampel(true,true,true); bunti.setPar56(255, 196, 0); + mpdController.setVolume(50); + mpdController.playSong("Coldplay", "Amsterdam"); break; } From bb0645491d85b6d1a10069ebbe3db75f80c4c9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Tue, 5 Jun 2012 01:26:47 +0200 Subject: [PATCH 09/11] implemented the timers and cleaned up game code a bit --- src/de/ctdo/crashtest/game/IStatemachine.java | 12 +- src/de/ctdo/crashtest/game/Statemachine.java | 102 ++++++++++++--- ...istener.java => StatemachineListener.java} | 3 +- src/de/ctdo/crashtest/game/TheGame.java | 117 ++++++++++++------ src/de/ctdo/crashtest/gui/MainGui.java | 42 ------- 5 files changed, 173 insertions(+), 103 deletions(-) rename src/de/ctdo/crashtest/game/{StateChangeListener.java => StatemachineListener.java} (64%) diff --git a/src/de/ctdo/crashtest/game/IStatemachine.java b/src/de/ctdo/crashtest/game/IStatemachine.java index 8dc9c89..ceb5f3d 100644 --- a/src/de/ctdo/crashtest/game/IStatemachine.java +++ b/src/de/ctdo/crashtest/game/IStatemachine.java @@ -1,14 +1,16 @@ package de.ctdo.crashtest.game; -/** - * @author: lucas - * @date: 01.06.12 14:17 - */ public interface IStatemachine { - void addStateChangedListener(StateChangeListener listener); + void addListener(StatemachineListener listener); void reset(); Statemachine.state getCurrentState(); void setNewState(Statemachine.state newState); int getStateChangeCounter(); void handleInput(char input); + int getTimerSecondsLast(); + + + void startTimer(int seconds); + void stopTimer(); + void pauseTimer(boolean pause); } diff --git a/src/de/ctdo/crashtest/game/Statemachine.java b/src/de/ctdo/crashtest/game/Statemachine.java index 7bb32c6..d2d72a8 100644 --- a/src/de/ctdo/crashtest/game/Statemachine.java +++ b/src/de/ctdo/crashtest/game/Statemachine.java @@ -1,7 +1,11 @@ package de.ctdo.crashtest.game; +import de.ctdo.crashtest.log.Logger; + import java.util.ArrayList; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; public class Statemachine implements IStatemachine { public enum state { @@ -13,8 +17,8 @@ public class Statemachine implements IStatemachine { TABLE_GAME_FOUR, TABLE_GAME_FIVE, TABLE_GAME_SIX, - TABLE_GAME_SEVEN, - TABLE_FINISH, + TABLE_GAME_DONE, + ROKET_STARTED, ROKET_DONE } @@ -25,15 +29,24 @@ public class Statemachine implements IStatemachine { private final char TABLE_TWO = 'H'; private final char TABLE_THREE = 'I'; private final char ROKET_INPUT = 'B'; - private final List stateChangeListenerList = new ArrayList(); + private final List statemachineListenerList; - private long lastHandleInput = 0; - private int stateChangeCounter = 0; - private state currentState = state.IDLE; + private Timer timer; + + private long lastHandleInput; + private int stateChangeCounter; + private state currentState; + private int timertSecondsLast; + + + public Statemachine() { + currentState = state.IDLE; + statemachineListenerList = new ArrayList(); + } @Override - public void addStateChangedListener(StateChangeListener listener) { - stateChangeListenerList.add(listener); + public void addListener(StatemachineListener listener) { + statemachineListenerList.add(listener); } @Override @@ -57,6 +70,7 @@ public class Statemachine implements IStatemachine { public void reset() { stateChangeCounter = 0; currentState = state.IDLE; + stopTimer(); onStateChanged(); } @@ -68,7 +82,7 @@ public class Statemachine implements IStatemachine { if( newState != currentState ) { stateChangeCounter++; - System.out.println("newState = " + newState); + Logger.sLog("newState = " + newState); currentState = newState; onStateChanged(); @@ -77,16 +91,50 @@ public class Statemachine implements IStatemachine { lastHandleInput = System.currentTimeMillis(); } + @Override + public int getTimerSecondsLast() { + return timertSecondsLast / 10; + } + + @Override + public void startTimer(int seconds) { + Logger.sLog("starting timer"); + timertSecondsLast = seconds*10; + scheduleTimer(); + } + + @Override + public void stopTimer() { + Logger.sLog("stopping timer"); + if(timer != null) timer.cancel(); + timertSecondsLast = 0; + } + + @Override + public void pauseTimer(boolean pause) { + Logger.sLog("pausing timer: " + pause); + if(pause) { + if(timer != null) timer.cancel(); + } else { + scheduleTimer(); + } + } + /** * notifies all listeners about the changed state */ private void onStateChanged() { - for(StateChangeListener listener: stateChangeListenerList) { + for(StatemachineListener listener: statemachineListenerList) { listener.stateChanged(currentState); } } + private void onTimerTick() { + for(StatemachineListener listener: statemachineListenerList) { + listener.timerTick(timertSecondsLast); + } + } /** * Calculates the new game state from the current state and new input button @@ -99,7 +147,7 @@ public class Statemachine implements IStatemachine { if(input == RESET) { retVal = state.IDLE; } else { - + switch (currentState) { case IDLE: if(input == LIGHT_BARRIER) { @@ -146,17 +194,17 @@ public class Statemachine implements IStatemachine { break; case TABLE_GAME_SIX: if(input == TABLE_THREE) { - retVal = state.TABLE_GAME_SEVEN; + retVal = state.TABLE_GAME_DONE; } else if (input == TABLE_TWO) { retVal = state.TABLE_GAME_ONE; } break; - case TABLE_GAME_SEVEN: + case TABLE_GAME_DONE: if(input == BLUE_BUTTON) { - retVal = state.TABLE_FINISH; + retVal = state.ROKET_STARTED; } break; - case TABLE_FINISH: + case ROKET_STARTED: if(input == ROKET_INPUT) { retVal = state.ROKET_DONE; } @@ -165,4 +213,28 @@ public class Statemachine implements IStatemachine { return retVal; } + + + private void scheduleTimer() { + if(timer != null) timer.cancel(); + + timer = new Timer(); + + TimerTask timerTask = new TimerTask() { + @Override + public void run() { + timertSecondsLast--; + + onTimerTick(); + + if(timertSecondsLast <= 0) { + if(timer != null) timer.cancel(); + } + } + }; + timer.scheduleAtFixedRate(timerTask, 100, 100); + } + + + } diff --git a/src/de/ctdo/crashtest/game/StateChangeListener.java b/src/de/ctdo/crashtest/game/StatemachineListener.java similarity index 64% rename from src/de/ctdo/crashtest/game/StateChangeListener.java rename to src/de/ctdo/crashtest/game/StatemachineListener.java index 5c00ca1..bb8e3e4 100644 --- a/src/de/ctdo/crashtest/game/StateChangeListener.java +++ b/src/de/ctdo/crashtest/game/StatemachineListener.java @@ -5,6 +5,7 @@ package de.ctdo.crashtest.game; * Date: 10.05.12 * Time: 13:37 */ -public interface StateChangeListener { +public interface StatemachineListener { void stateChanged(Statemachine.state newState); + void timerTick(int tsecondsLeft); } diff --git a/src/de/ctdo/crashtest/game/TheGame.java b/src/de/ctdo/crashtest/game/TheGame.java index 7093355..13c12e2 100644 --- a/src/de/ctdo/crashtest/game/TheGame.java +++ b/src/de/ctdo/crashtest/game/TheGame.java @@ -6,20 +6,13 @@ import de.ctdo.crashtest.irc.*; import de.ctdo.crashtest.mpd.IMPDController; import de.ctdo.crashtest.mpd.MPDController; -public class TheGame implements StateChangeListener, GuiEventListener, IRCEventListener { +public class TheGame implements StatemachineListener, GuiEventListener, IRCEventListener { private IGuiControl guiControl; private IIrcClient ircClient; private IStatemachine machine; private IBuntiClient bunti; private IMPDController mpdController; - private int timertSeconds = 0; - private int timertSecondsLast = 0; - private int timeSpentTableGame = 0; - private int timeSpentRokets = 0; - - - public TheGame(IGuiControl guiControl) { this.guiControl = guiControl; @@ -34,7 +27,7 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL private void initGame() { guiControl.addListener(this); ircClient.addListener(this); - machine.addStateChangedListener(this); + machine.addListener(this); machine.reset(); } @@ -51,71 +44,111 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL switch (newState) { case IDLE: - mpdController.setVolume(45); + machine.stopTimer(); + mpdController.playSong("start", "mix"); + mpdController.setVolume(45); + bunti.setPar56(0,0,0); bunti.setLampel(false,false,false); + guiControl.showCountDown(false); break; case ENTERED_ROOM: - mpdController.setVolume(70); mpdController.playSong("Modem", "Dial_In_and_HF Longplay"); + mpdController.setVolume(70); + bunti.setLampel(false,false,false); bunti.setPar56(20,0,100); + + guiControl.showCountDown(true); + + machine.startTimer(60*8); break; case TABLE_GAME_ONE: mpdController.setVolume(70); mpdController.playSong("K2", "Der Berg Ruft"); + bunti.setLampel(true,false,false); - guiControl.showCountDown(true); bunti.setPar56(255,0,100); + guiControl.showCountDown(true); break; case TABLE_GAME_TWO: bunti.setLampel(false,true,false); bunti.setPar56(255,0,100); + + guiControl.showCountDown(true); break; case TABLE_GAME_THREE: bunti.setLampel(false,true,false); bunti.setPar56(255,35,0); - mpdController.setVolume(60); - mpdController.playSong("Mo-Do","9 Eins Zwei Polizei"); + + guiControl.showCountDown(true); break; case TABLE_GAME_FOUR: + mpdController.playSong("Mo-Do","9 Eins Zwei Polizei"); + mpdController.setVolume(60); + bunti.setLampel(false,true,false); bunti.setPar56(255,55,0); + + guiControl.showCountDown(true); break; case TABLE_GAME_FIVE: bunti.setLampel(false,true,false); bunti.setPar56(255,75,0); + + guiControl.showCountDown(true); break; case TABLE_GAME_SIX: + mpdController.playSong("Zlatko & Jürgen","Großer Bruder"); + mpdController.setVolume(60); + bunti.setLampel(false,true,false); bunti.setPar56(255,100,0); - mpdController.setVolume(60); - mpdController.playSong("Zlatko & Jürgen","Großer Bruder"); + + guiControl.showCountDown(true); break; - case TABLE_GAME_SEVEN: + case TABLE_GAME_DONE: bunti.setLampel(false,false,true); bunti.setPar56(255,100,0); + + guiControl.showCountDown(true); + machine.pauseTimer(true); sayScore(); break; - case TABLE_FINISH: // und roket muss starten + case ROKET_STARTED: + mpdController.playSong("The Underdog Project", "Summer Jam"); + mpdController.setVolume(50); + bunti.setLampel(false,false,true); bunti.setPar56(0, 255, 0); + ircClient.say("table game complete, r0kets now"); - mpdController.setVolume(50); - mpdController.playSong("The Underdog Project", "Summer Jam"); + + guiControl.showCountDown(true); + machine.startTimer(7*60); break; case ROKET_DONE: + mpdController.playSong("Coldplay", "Amsterdam"); + mpdController.setVolume(50); + bunti.setLampel(true,true,true); bunti.setPar56(255, 196, 0); - mpdController.setVolume(50); - mpdController.playSong("Coldplay", "Amsterdam"); + + guiControl.showCountDown(true); + machine.pauseTimer(true); break; } } + @Override + public void timerTick(int tsecondsLeft) { + guiControl.setCountDown(tsecondsLeft); + if(tsecondsLeft == 0) ircClient.say("timer expired"); + } + /** * Event listener for keyPress events from the GUI @@ -133,7 +166,9 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL */ @Override public void windowClosing() { - + machine.reset(); + bunti.setPar56(0xff,0xff,0xff); + ircClient.say("bye"); } /** @@ -146,7 +181,6 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL handleHelpCommand(message); } else if(message.equals("reset")) { machine.reset(); - ircClient.say("reset done"); } else if(message.startsWith("state")) { handleStateCommand(message); } else if(message.startsWith("timer")) { @@ -169,12 +203,11 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL String timeStr = params.substring("start".length()).trim(); if(timeStr.length() > 0) { - int time = 0; - try { - time = Integer.parseInt(timeStr); + int time = Integer.parseInt(timeStr); guiControl.showCountDown(true); + machine.startTimer(time); ircClient.say("got it, starting with " + time + " seconds"); } catch (NumberFormatException e) { @@ -184,23 +217,20 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL ircClient.say("invalid parameter"); } } else if(params.startsWith("stop")) { - + machine.stopTimer(); guiControl.showCountDown(false); ircClient.say("timer stopped"); } else if(params.startsWith("pause")) { - + machine.pauseTimer(true); } else if(params.startsWith("resume")) { - + machine.pauseTimer(false); } - - } private void handleStateCommand(final String message) { if(message.equals("state")) { ircClient.say(machine.getCurrentState().name()); } else { - String params = message.substring("state".length()).trim().toLowerCase(); Boolean ok = false; @@ -215,16 +245,9 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL } if(!ok) ircClient.say("ehm, impossibruu!"); - } } - private void sayScore() { - ircClient.say("stateChangeCounter: " + machine.getStateChangeCounter()); - ircClient.say("timerlast: " + timertSecondsLast / 10); - } - - private void handleHelpCommand(final String message) { if(message.equals("help")) { ircClient.say("commands: help, reset, state, timer, wall, extra, score"); @@ -266,4 +289,18 @@ public class TheGame implements StateChangeListener, GuiEventListener, IRCEventL } + + private void sayScore() { + ircClient.say("stateChangeCounter: " + machine.getStateChangeCounter()); +// ircClient.say("timerlast: " + machine.getTimerSecondsLast()); + + int seconds = machine.getTimerSecondsLast(); + int mins = seconds / 60; + int secs = seconds % 60; + ircClient.say(" " + mins + ":" + secs + ""); + + } + + + } diff --git a/src/de/ctdo/crashtest/gui/MainGui.java b/src/de/ctdo/crashtest/gui/MainGui.java index fd69252..74ea890 100644 --- a/src/de/ctdo/crashtest/gui/MainGui.java +++ b/src/de/ctdo/crashtest/gui/MainGui.java @@ -45,23 +45,6 @@ public class MainGui extends JFrame implements IGuiControl { setVisible(true); } -// -// -// private void initTimer() { -// timer = new Timer(100, new ActionListener() { -// @Override -// public void actionPerformed(ActionEvent e) { -// timerSecondsLast--; -// setTimerText(); -// -// if(timerSecondsLast <= 0) { -// timerSecondsLast = 0; -// timer.stop(); -// } -// } -// }); -// } -// private void setCountDownText(final int tseconds) { int mins = tseconds / 600; int secs = tseconds % 600 / 10 ; @@ -105,30 +88,6 @@ public class MainGui extends JFrame implements IGuiControl { extraField.setText(" "); } - -// @Override -// public void startTimer(int seconds) { -// timerSeconds = seconds*10; -// timerSecondsLast = seconds*10; -// timer.start(); -// } -// -// @Override -// public void stopTimer() { -// timer.stop(); -// timerSeconds = 0; -// timerSecondsLast = 0; -// } -// -// @Override -// public void pauseTimer(Boolean pause) { -// if(pause) { -// timer.stop(); -// } else { -// timer.start(); -// } -// } - @Override public void setWall(final String message) { final Runnable runnable = new Runnable() { @@ -175,7 +134,6 @@ public class MainGui extends JFrame implements IGuiControl { }; SwingUtilities.invokeLater(runnable); - } @Override From 9456b6305b2ece34b50aaa97e23276771647c150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Tue, 5 Jun 2012 01:58:22 +0200 Subject: [PATCH 10/11] made timer change color when time is up --- src/de/ctdo/crashtest/gui/MainGui.java | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/de/ctdo/crashtest/gui/MainGui.java b/src/de/ctdo/crashtest/gui/MainGui.java index 74ea890..389f000 100644 --- a/src/de/ctdo/crashtest/gui/MainGui.java +++ b/src/de/ctdo/crashtest/gui/MainGui.java @@ -50,6 +50,29 @@ public class MainGui extends JFrame implements IGuiControl { int secs = tseconds % 600 / 10 ; int tsecs = tseconds % 9; countDown.setText(" " + mins + ":" + secs + "." + tsecs); + + if(tseconds < 400) { + double percentile = ((tseconds-100.0)/300.0); + double red = 255.0 - percentile * 255.0; + double green = 255.0 - red; + double blue = percentile * 100.0; + +// System.out.println("red= " + red + " green=" + green + " blue="+blue); + + if(red > 255) red = 255; + if(red < 0) red = 0; + if(green > 255) green = 255; + if(green < 0) green = 0; + if(blue > 255) blue = 255; + if(blue < 0) blue = 0; + + Color fColor = new Color((int)red,(int)green, (int)blue); + countDown.setForeground(fColor); + } + else { + countDown.setForeground(new Color(0x00, 190, 100)); + } + } private void initGui() { From d8e158dc7124387bb2ace1f6bbd26d818c1b5b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ple=C3=9F?= Date: Wed, 6 Jun 2012 00:59:09 +0200 Subject: [PATCH 11/11] fixes for generating correct jar file --- .idea/artifacts/crashteststeuerung_jar.xml | 1 + .idea/libraries/commons_codec_1_41.xml | 16 +++++++++++++++ crashteststeuerung.iml | 1 + .../ctdo/crashtest/domotics/IRelaisboard.java | 7 +++++++ .../ctdo/crashtest/domotics/Relaisboard.java | 12 +++++++++++ src/de/ctdo/crashtest/game/TheGame.java | 20 ++++++++++++------- src/de/ctdo/crashtest/irc/IrcClient.java | 1 - 7 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 .idea/libraries/commons_codec_1_41.xml create mode 100644 src/de/ctdo/crashtest/domotics/IRelaisboard.java create mode 100644 src/de/ctdo/crashtest/domotics/Relaisboard.java diff --git a/.idea/artifacts/crashteststeuerung_jar.xml b/.idea/artifacts/crashteststeuerung_jar.xml index c7465a8..a91aff4 100644 --- a/.idea/artifacts/crashteststeuerung_jar.xml +++ b/.idea/artifacts/crashteststeuerung_jar.xml @@ -13,6 +13,7 @@ + \ No newline at end of file diff --git a/.idea/libraries/commons_codec_1_41.xml b/.idea/libraries/commons_codec_1_41.xml new file mode 100644 index 0000000..227c388 --- /dev/null +++ b/.idea/libraries/commons_codec_1_41.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/crashteststeuerung.iml b/crashteststeuerung.iml index 5b4384e..4e2f0f8 100644 --- a/crashteststeuerung.iml +++ b/crashteststeuerung.iml @@ -10,6 +10,7 @@ + diff --git a/src/de/ctdo/crashtest/domotics/IRelaisboard.java b/src/de/ctdo/crashtest/domotics/IRelaisboard.java new file mode 100644 index 0000000..a4af876 --- /dev/null +++ b/src/de/ctdo/crashtest/domotics/IRelaisboard.java @@ -0,0 +1,7 @@ +package de.ctdo.crashtest.domotics; + +public interface IRelaisboard { + + void setRelais(int relai, boolean state); + +} diff --git a/src/de/ctdo/crashtest/domotics/Relaisboard.java b/src/de/ctdo/crashtest/domotics/Relaisboard.java new file mode 100644 index 0000000..a6391b9 --- /dev/null +++ b/src/de/ctdo/crashtest/domotics/Relaisboard.java @@ -0,0 +1,12 @@ +package de.ctdo.crashtest.domotics; + + + +public class Relaisboard implements IRelaisboard { + + + @Override + public void setRelais(int relai, boolean state) { + + } +} diff --git a/src/de/ctdo/crashtest/game/TheGame.java b/src/de/ctdo/crashtest/game/TheGame.java index 13c12e2..a0f9e54 100644 --- a/src/de/ctdo/crashtest/game/TheGame.java +++ b/src/de/ctdo/crashtest/game/TheGame.java @@ -16,7 +16,7 @@ public class TheGame implements StatemachineListener, GuiEventListener, IRCEvent public TheGame(IGuiControl guiControl) { this.guiControl = guiControl; - this.ircClient = new IrcClient("crashtest", "#crashtest","irc.ctdo.de"); + this.ircClient = new IrcClient("crashtest", "#crashtest","irc.hackint.eu"); this.bunti = new BuntiClient("bunti.ctdo.de", 8080); this.mpdController = new MPDController("dampfradio.raum.ctdo.de"); this.machine = new Statemachine(); @@ -46,8 +46,9 @@ public class TheGame implements StatemachineListener, GuiEventListener, IRCEvent case IDLE: machine.stopTimer(); - mpdController.playSong("start", "mix"); mpdController.setVolume(45); + mpdController.playSong("start", "mix"); + bunti.setPar56(0,0,0); bunti.setLampel(false,false,false); @@ -55,8 +56,9 @@ public class TheGame implements StatemachineListener, GuiEventListener, IRCEvent guiControl.showCountDown(false); break; case ENTERED_ROOM: - mpdController.playSong("Modem", "Dial_In_and_HF Longplay"); mpdController.setVolume(70); + mpdController.playSong("tidirium", "welcome"); + bunti.setLampel(false,false,false); bunti.setPar56(20,0,100); @@ -86,8 +88,9 @@ public class TheGame implements StatemachineListener, GuiEventListener, IRCEvent guiControl.showCountDown(true); break; case TABLE_GAME_FOUR: - mpdController.playSong("Mo-Do","9 Eins Zwei Polizei"); mpdController.setVolume(60); + mpdController.playSong("Mo-Do","9 Eins Zwei Polizei"); + bunti.setLampel(false,true,false); bunti.setPar56(255,55,0); @@ -101,8 +104,9 @@ public class TheGame implements StatemachineListener, GuiEventListener, IRCEvent guiControl.showCountDown(true); break; case TABLE_GAME_SIX: - mpdController.playSong("Zlatko & Jürgen","Großer Bruder"); mpdController.setVolume(60); + mpdController.playSong("Zlatko & Jürgen","Großer Bruder"); + bunti.setLampel(false,true,false); bunti.setPar56(255,100,0); @@ -118,8 +122,9 @@ public class TheGame implements StatemachineListener, GuiEventListener, IRCEvent sayScore(); break; case ROKET_STARTED: - mpdController.playSong("The Underdog Project", "Summer Jam"); mpdController.setVolume(50); + mpdController.playSong("The Underdog Project", "Summer Jam"); + bunti.setLampel(false,false,true); bunti.setPar56(0, 255, 0); @@ -130,8 +135,9 @@ public class TheGame implements StatemachineListener, GuiEventListener, IRCEvent machine.startTimer(7*60); break; case ROKET_DONE: - mpdController.playSong("Coldplay", "Amsterdam"); mpdController.setVolume(50); + mpdController.playSong("Coldplay", "Amsterdam"); + bunti.setLampel(true,true,true); bunti.setPar56(255, 196, 0); diff --git a/src/de/ctdo/crashtest/irc/IrcClient.java b/src/de/ctdo/crashtest/irc/IrcClient.java index a399fc6..7870a37 100644 --- a/src/de/ctdo/crashtest/irc/IrcClient.java +++ b/src/de/ctdo/crashtest/irc/IrcClient.java @@ -20,7 +20,6 @@ import java.util.List; */ public class IrcClient implements IIrcClient, jerklib.events.listeners.IRCEventListener, ILogger { private final List listenerListIRC = new ArrayList(); - private final static String CHANNEL = "#crashtest"; private Session ircsession; private final String channel;