crashtest/src/de/ctdo/crashtest/game/TheGame.java

605 lines
22 KiB
Java

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;
import java.util.Random;
public class TheGame implements StatemachineListener, GuiEventListener, IRCEventListener {
private final IGuiControl guiControl;
private final IIrcClient ircClient;
private final IStatemachine machine;
private final IBuntiClient bunti;
private final IMPDController mpdController;
private final IRelaisboard relaisboard;
private final IExtraSoundControl extraSoundControl;
private int gamerRating = 3;
private Thread discoThread;
private boolean shouldStopDisco;
private boolean gemActivated = false;
private boolean startedHurrySound = false;
private char lastInput;
private boolean sproing;
public TheGame(IGuiControl guiControl1) {
guiControl = guiControl1;
ircClient = new IrcClient("crashtest", "#crashtest","irc.ctdo.de");
bunti = new BuntiClient("bunti.ctdo.de", 8080);
mpdController = new MPDController("dampfradio.raum.ctdo.de");
relaisboard = new Relaisboard("/dev/ttyUSB0");
machine = new Statemachine();
extraSoundControl = new ExtraSoundControl();
guiControl.addListener(this);
ircClient.addListener(this);
machine.addListener(this);
machine.reset();
relaisboard.open();
resetDomotics();
}
/**
* 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 NEUTRAL:
discoStop();
bunti.setPar56(255,255,255);
bunti.setLampel(false,false,false);
machine.stopTimer();
break;
case IDLE:
gamerRating = 3;
mpdController.clearPlaylist();
machine.stopTimer();
startedHurrySound = false;
resetDomotics();
discoStop();
guiControl.setExtra("");
guiControl.setWall("");
guiControl.showCountDown(false);
playRandomStartMix();
//mpdController.setVolume(50);
break;
case ENTERED_ROOM:
relaisboard.setRelais(7, false); // disable light barrier over relais
mpdController.playSong("crashtest", "entered_room");
bunti.setLampel(false,false,false);
bunti.setPar56(20,0,100);
guiControl.setWall("bitte die tuer schliessen. dann kann das spiel beginnen.");
guiControl.showCountDown(true);
machine.startTimer(60*8);
mpdController.setVolume(50);
break;
case TABLE_GAME_WRONG:
extraSoundControl.playJingle("block");
mpdController.playSong("crashtest", "table_game_one");
bunti.setLampel(true,false,false);
sproing = true;
break;
case TABLE_GAME_ONE:
relaisboard.setRelais(6, true); // enable third green circle
extraSoundControl.playJingle("jump");
if(machine.getLastState() != Statemachine.state.TABLE_GAME_WRONG) {
mpdController.playSong("crashtest", "table_game_one");
}
bunti.setLampel(false, true, false);
bunti.setPar56(20,0,100);
guiControl.showCountDown(true);
break;
case TABLE_GAME_TWO:
//mpdController.playSong("crashtest", "table_game_two");
extraSoundControl.playJingle("jump");
bunti.setLampel(false,true,false);
bunti.setPar56(100,0,100);
guiControl.showCountDown(true);
break;
case TABLE_GAME_THREE:
//mpdController.playSong("crashtest", "table_game_three");
extraSoundControl.playJingle("jump");
bunti.setLampel(false,true,false);
bunti.setPar56(255,35,0);
guiControl.showCountDown(true);
break;
case TABLE_GAME_FOUR:
mpdController.playSong("crashtest", "table_game_four");
extraSoundControl.playJingle("jump");
bunti.setLampel(false,true,false);
bunti.setPar56(200,100,0);
guiControl.showCountDown(true);
break;
case TABLE_GAME_FIVE:
//mpdController.playSong("crashtest", "table_game_five");
extraSoundControl.playJingle("jump");
bunti.setLampel(false,true,false);
bunti.setPar56(150,150,0);
guiControl.showCountDown(true);
break;
case TABLE_GAME_SIX:
//mpdController.playSong("crashtest", "table_game_six");
extraSoundControl.playJingle("jump");
bunti.setLampel(false,true,false);
bunti.setPar56(100,200,0);
guiControl.showCountDown(true);
break;
case TABLE_GAME_DONE:
mpdController.playSong("crashtest", "table_game_done");
extraSoundControl.playJingle("jump");
bunti.setLampel(false,false,true);
bunti.setPar56(100,255,0);
guiControl.showCountDown(true);
machine.pauseTimer(true);
// spieler haben 8 Minuten, wenn sie es in weniger als 4 minuten schaffen
// gibts +1, in weniger als 2 minuten gibts +2
if(machine.getTimerSecondsLeft() >= 6*60 ) {
rate(2, "table game faster than 2 minutes");
} else if(machine.getTimerSecondsLeft() > 4*60) {
rate(1, "table game faster than 4 minutes");
}
if(machine.getStateChangeCounter() > 100) {
rate(-1, "more than 100 tries");
}
sayScore();
relaisboard.setRelais(6, false); // disable third green circle
relaisboard.blinkRelais(2, 700); // hint Button
break;
case ROKET_STARTED:
mpdController.playSong("crashtest", "roket_started");
mpdController.addToPlayList("crashtest", "roket_started2");
startedHurrySound = false;
bunti.setLampel(false,true,false);
bunti.setPar56(0, 255, 0);
relaisboard.toggleRelais(0, 300); // r0kets toogle
relaisboard.toggleRelais(3, 10000); // oven
relaisboard.blinkRelaisStop(2); // stop hint button lamp
relaisboard.setRelais(2, false);
guiControl.setWall("Pizza ist fertig!");
guiControl.showCountDown(true);
machine.startTimer(7*60);
break;
case ROKET_DONE:
mpdController.playSong("crashtest", "roket_done");
//mpdController.setVolume(60);
bunti.setLampel(false,false,true);
bunti.setPar56(255, 255, 255);
guiControl.setWall("willkommen im chaostreff dortmund");
guiControl.showCountDown(true);
machine.pauseTimer(true);
// spieler haben 7 Minuten, wenn sie es in weniger als 4 minuten schaffen
// gibts +1, in weniger als 2 minuten gibts +2
if(machine.getTimerSecondsLeft() >= 5*60 ) {
rate(2, "r0kets faster than 2 minutes");
} else if(machine.getTimerSecondsLeft() > 3*60) {
rate(1, "r0kets faster than 4 minutes");
}
sayScore();
discoStart();
break;
}
}
/**
* Event listener for timer ticks from statemachine.
* @param tsecondsLeft the seconds left on the current game
*/
@Override
public void timerTick(int tsecondsLeft) {
guiControl.setCountDown(tsecondsLeft);
if(tsecondsLeft == 0) {
ircClient.say("timer expired");
Statemachine.state state = machine.getCurrentState();
if( state == Statemachine.state.TABLE_GAME_ONE || state == Statemachine.state.TABLE_GAME_TWO ||
state == Statemachine.state.TABLE_GAME_THREE || state == Statemachine.state.TABLE_GAME_FOUR ||
state == Statemachine.state.TABLE_GAME_FIVE || state == Statemachine.state.TABLE_GAME_SIX ||
state == Statemachine.state.TABLE_GAME_WRONG || state == Statemachine.state.ROKET_STARTED ) {
rate(-2, "game not done in time");
guiControl.setWall("die Zeit ist abgelaufen");
sayScore();
mpdController.playSong("crashtest","timeouted");
if(state == Statemachine.state.ROKET_STARTED) {
relaisboard.toggleRelais(0, 300); // r0kets toogle (so there will probably be switched off)
ircClient.say("if ready, use >reset");
} else {
ircClient.say("if ready, set state with >state TABLE_GAME_DONE");
}
/*
if(state != Statemachine.state.ROKET_STARTED) {
ircClient.say("switching to roket started");
machine.setNewState(Statemachine.state.ROKET_STARTED);
} */
}
} else {
if(tsecondsLeft % 600 == 0) {
sayScore();
}
if(tsecondsLeft <= 630 && !startedHurrySound) {
Statemachine.state state = machine.getCurrentState();
if( state != Statemachine.state.TABLE_GAME_DONE &&
state != Statemachine.state.ROKET_DONE ) {
startedHurrySound = true;
mpdController.playSong("crashtest", "hurry");
}
}
}
}
/**
* Event listener for keyPress events from the GUI
* @param key the pressed key
*/
@Override
public void keyPress(char key) {
machine.handleInput(key);
Statemachine.state state = machine.getCurrentState();
if(state == Statemachine.state.ENTERED_ROOM) {
if(key == Statemachine.TABLE_TWO || key == Statemachine.TABLE_THREE) {
if(lastInput != key) {
extraSoundControl.playJingle("block");
}
}
} else if(state == Statemachine.state.TABLE_GAME_WRONG) {
if(key == Statemachine.TABLE_ONE || key == Statemachine.TABLE_TWO || key == Statemachine.TABLE_THREE) {
if(lastInput != key && !sproing) {
extraSoundControl.playJingle("block");
}
sproing = false;
}
}
lastInput = key;
}
/**
* Event lister for window closing event from the GUI
*/
@Override
public void windowClosing() {
discoStop();
resetDomotics();
relaisboard.close();
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) { }
bunti.setPar56(0xff,0xff,0xff);
ircClient.say("bye");
System.exit(0);
}
/**
* 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();
} else if(message.startsWith("state")) {
handleStateCommand(message);
} else if(message.startsWith("timer")) {
handleTimerCommand(message);
} else if(message.startsWith("score")) {
sayScore();
} 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 if(message.startsWith("relais")) {
handleRelaisCommand(message);
} else if(message.startsWith("disco on")) {
discoStart();
} else if(message.startsWith("disco off")) {
discoStop();
} else if(message.startsWith("gem")) {
handleGemCommand();
} else {
ircClient.say("y u no use valid command?");
}
}
private void rate(int rating, String text) {
gamerRating += rating;
ircClient.say("rated: " + rating + " (" + gamerRating + ") " + text);
if(gamerRating > 5) gamerRating = 5;
if(gamerRating < 1) gamerRating = 1;
}
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) {
try {
int time = Integer.parseInt(timeStr);
guiControl.showCountDown(true);
machine.startTimer(time);
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")) {
machine.stopTimer();
guiControl.showCountDown(false);
} else if(params.startsWith("pause")) {
machine.pauseTimer(true);
} else if(params.startsWith("resume")) {
machine.pauseTimer(false);
}
}
private void handleStateCommand(final String message) {
if(message.trim().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()) {
if(st.name().toLowerCase().equals(params)) {
ok = true;
machine.setNewState(st);
break;
}
}
if(!ok) ircClient.say("ehm, impossibruu!");
}
}
// Yes, it makes no sense, but I want have it anyway. For more Spass am Geraet!
private void handleGemCommand() {
if (!gemActivated) {
java.util.Random random = new java.util.Random();
int scry = random.nextInt(100);
if (scry >= 99) {
ircClient.say("Perfect Gem Activated");
} else if (scry >= 90) {
ircClient.say("Moooooooo!");
} else {
ircClient.say("Gem Activated");
}
} else {
ircClient.say("Gem Deactivated");
}
gemActivated = !gemActivated;
}
private void handleRelaisCommand(final String message) {
String params = message.substring("relais".length()).trim().toLowerCase();
if(params.startsWith("lamp on")) {
relaisboard.setRelais(2, true);
} else if(params.startsWith("lamp off")) {
relaisboard.setRelais(2, false);
} else if(params.startsWith("oven on")) {
relaisboard.setRelais(3, true);
} else if(params.startsWith("oven off")) {
relaisboard.setRelais(3, false);
} else if(params.startsWith("rokets")) {
relaisboard.toggleRelais(0, 300);
} else if(params.startsWith("lamp blink")) {
relaisboard.blinkRelais(2, 700);
} else if(params.startsWith("lamp stop")) {
relaisboard.blinkRelaisStop(2);
}
}
private void handleHelpCommand(final String message) {
if(message.equals("help")) {
ircClient.say("commands: help, reset, state, timer, wall, extra, score, relais, disco, gem");
} 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 <NEWSTATE>");
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 if(message.contains("relais")) {
ircClient.say("control the relais board");
ircClient.say("valid commands: lamp on, lamp off, lamp blink, lamp stop, oven on, oven off, rokets");
} else if(message.contains("disco")) {
ircClient.say("party! use: disco {on,off}");
} else if(message.contains("gem")) {
ircClient.say("The chat gem is working as intended.");
} else {
ircClient.say("dafuq?");
}
}
private void sayScore() {
StringBuilder sb = new StringBuilder();
sb.append("st.ch.: ");
sb.append(machine.getStateChangeCounter());
sb.append(" rating: ");
sb.append(gamerRating);
int secondsLeft = machine.getTimerSecondsLeft();
int seconds = machine.getTimerSeconds();
int secondsUsed = seconds - secondsLeft;
int mins = seconds / 60;
int minsUsed = secondsUsed / 60;
int minsLeft = secondsLeft / 60;
sb.append(String.format(" time:%d:%02d u:%d:%02d l:%d:%02d",
mins, seconds % 60, minsUsed, secondsUsed % 60, minsLeft, secondsLeft % 60));
ircClient.say(sb.toString());
}
private void resetDomotics() {
relaisboard.setRelais(7, true); // enable light barrier over relais
relaisboard.setRelais(6, true); // enable third green circle
relaisboard.setRelais(2, false); // disable the lamp
relaisboard.setRelais(3, false); // disable the oven
bunti.setPar56(0, 0, 0);
bunti.setLampel(false, false, false);
}
private void discoStop() {
if(discoThread != null) {
shouldStopDisco = true;
discoThread.interrupt();
try {
discoThread.join(500);
} catch (InterruptedException ignored) { }
}
}
private void discoStart() {
discoStop();
Runnable r = new Runnable() {
@Override
public void run() {
try {
while(true) {
if(shouldStopDisco) return;
bunti.setPar56(0, 255, 0, 0);
bunti.setPar56(1, 0, 255, 0);
bunti.setPar56(2, 0, 255, 0);
bunti.setPar56(3, 255, 0, 0);
bunti.setLampel(true, false, false);
if(shouldStopDisco) return;
Thread.sleep(500);
bunti.setPar56(0, 0, 0, 255);
bunti.setPar56(1, 255, 255, 0);
bunti.setPar56(2, 255, 255, 0);
bunti.setPar56(3, 0, 0, 255);
bunti.setLampel(false, true, false);
if(shouldStopDisco) return;
Thread.sleep(500);
bunti.setPar56(0, 255, 128, 0);
bunti.setPar56(1, 0, 255, 255);
bunti.setPar56(2, 0, 255, 255);
bunti.setPar56(3, 255, 128, 0);
bunti.setLampel(false, false, true);
if(shouldStopDisco) return;
Thread.sleep(500);
bunti.setPar56(0, 0, 255, 255);
bunti.setPar56(1, 0, 255, 0);
bunti.setPar56(2, 0, 255, 0);
bunti.setPar56(3, 0, 255, 255);
bunti.setLampel(true, true, true);
if(shouldStopDisco) return;
Thread.sleep(500);
}
} catch (InterruptedException ignored) { }
}
};
discoThread = new Thread(r);
shouldStopDisco = false;
discoThread.start();
}
private void playRandomStartMix() {
Random r = new Random();
int num = r.nextInt(3)+1;
if(num == 1) {
mpdController.playSong("crashtest", "idle");
} else if(num == 2) {
mpdController.playSong("crashtest", "idle2");
} else if(num == 3) {
mpdController.playSong("crashtest", "idle3");
} else if(num == 4) {
mpdController.playSong("crashtest", "idle4");
}
mpdController.skipRandomStart();
}
}