void Start () {
		CurveStateRenderer renderer = new CurveStateRenderer();
        AudioEngine auEngine = new AudioEngine(0, Settings.game_name, Settings.menu_sounds, Settings.game_sounds);

        List<Actor> actors = new List<Actor>();
        actors.Add(new CurveActor("pointer", "Prefabs/Curve/Ball", new Vector3(initial_x, initial_y, 90f), false, null));

        List<WorldObject> environment = new List<WorldObject>();
        environment.Add(new CurveStaticObject("Prefabs/Curve/Ball", Vector3.zero, false));
        environment.Add(new CurveStaticObject("Prefabs/Curve/MainCamera", Vector3.zero, false));
        environment.Add(new CurveStaticObject("Prefabs/Curve/Light", Vector3.zero, false));
        environment.Add(new CanvasObject("Prefabs/Curve/LeapLogo", true, Vector3.zero, false));
        environment.Add(new CurveStaticObject("Prefabs/Curve/Divider", new Vector3(0, 0, 100f), false));
		
		List<Player> players = new List<Player>();
		players.Add(new Player("player0", "player0"));

        CurveRuleset rules = new CurveRuleset();
		rules.Add(new CurveRule("initialization", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
			AudioClip auClip = auEngine.getSoundForMenu("tutorial_1");
			CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/AudioSource", auClip);
			state.environment.Add(tso);
			state.blockingSound = tso;
            state.timestamp = 11;
            for (int j = 0; j < 14; j++) {
                state.expectedValues[j] = 6;
            }
			return false;
		}));

        rules.Add(new CurveRule("frame", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            if (state.replaying || state.repeating) {
                if (state.delay <= 0) {
                    state.delay = 0.6f;
                    if (state.replaying) {
                        float x = initial_rx + state.index * offset_x;
                        float y = initial_y + state.expectedValues[state.index] * offset_y;
                        engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/VisibleGameAudio", auEngine.getSoundForPlayer("note", new Vector3(state.index, state.expectedValues[state.index], 0)), new Vector3(x, y, 90)));
                    } else {
                        if (state.values[state.index] != -1) {
                            float x = initial_x + state.index * offset_x;
                            float y = initial_y + state.values[state.index] * offset_y;
                            engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/VisibleGameAudio", auEngine.getSoundForPlayer("note", new Vector3(state.index, state.values[state.index], 0)), new Vector3(x, y, 90)));
                        } else {
                            engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/VisibleGameAudio", auEngine.getSoundForPlayer("air")));
                        }
                    }
                    state.index++;
                    if (state.index == max) {
                        if ((state.timestamp == 17 && state.replaying)
                            || (state.timestamp == 19 && state.replaying)
                            || (state.timestamp == 20 && state.repeating)
                            || (state.timestamp == 22 && state.replaying)
                            || (state.timestamp == 23 && state.replaying)) {
                            state.timestamp += 41;
                            if (state.timestamp == 60) {
                                state.values[0] = 12;
                            }
                        }
                        state.index = 0;
                        state.repeating = false;
                        state.replaying = false;
                        state.delay = 0;
                    }
                } else {
                    state.delay -= Time.deltaTime;
                }
            }
            return false;
        }));

        rules.Add(new CurveRule("action", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            if (eve.payload.Equals("escape")) {
                Application.LoadLevel(Settings.previousMenu);
                return false;
            }
            return true;
        }));

        rules.Add(new CurveRule("soundOver", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            int id = int.Parse(eve.payload);
            if (state.blockingSound != null && id == state.blockingSound.clip.GetInstanceID()) {
                state.environment.Remove(state.blockingSound);
                state.blockingSound = null;
                CurveSoundObject tso;
                switch (state.timestamp) {
                    case 11:
                        tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("note", new Vector3(7, 0, 0)));
                        state.blockingSound = tso;
                        state.environment.Add(tso);
                        state.timestamp = 52;
                        return false;
                    case 12:
                        tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("note", new Vector3(7, 1, 0)));
                        state.blockingSound = tso;
                        state.environment.Add(tso);
                        state.timestamp = 53;
                        return false;
                    case 13:
                        tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("note", new Vector3(7, 13, 0)));
                        state.blockingSound = tso;
                        state.environment.Add(tso);
                        state.timestamp = 54;
                        return false;
                    case 14:
                        state.replaying = true;
                        state.timestamp = 55;
                        return false;
                    case 115:
                        tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForMenu("tutorial_5b"));
                        state.blockingSound = tso;
                        state.environment.Add(tso);
                        state.timestamp = 15;
                        return false;
                    case 116:
                        tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForMenu("tutorial_6"));
                        state.blockingSound = tso;
                        state.environment.Add(tso);
                        state.timestamp = 57;
                        max = 3;
                        return false;
                    case 118:
                        tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForMenu("tutorial_8b"));
                        state.blockingSound = tso;
                        state.environment.Add(tso);
                        state.timestamp = 18;
                        return false;
                    case 22:
                        max = 14;
                        for (int i = 0; i < 14; i++) {
                            state.expectedValues[i] = i / 3;
                        }
                        state.replaying = true;
                        return false;
                    case 23:
                        state.replaying = true;
                        for (int i = 0; i < 14; i++) {
                            state.expectedValues[i] = 13 - i;
                        }
                        return false;
                    case 24:
                        state.timestamp = 10;
                        return false;
                    default:
                        if (state.timestamp > 50) {
                            state.timestamp = state.timestamp - 50;
                            tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForMenu("tutorial_" + state.timestamp));
                            state.blockingSound = tso;
                            state.environment.Add(tso);
                            state.timestamp += 10;
                        }
                        return false;
                }
            } else {
                WorldObject toRemove = null;
                foreach (WorldObject go in state.environment) {
                    if (go is CurveSoundObject && (go as CurveSoundObject).clip.GetInstanceID() == id) {
                        toRemove = go;
                        break;
                    }
                }
                if (toRemove != null) {
                    state.environment.Remove(toRemove);
                }
                if (state.timestamp == 55
                    || state.timestamp == 58
                    || state.timestamp == 60
                    || state.timestamp == 61
                    || state.timestamp == 63
                    || state.timestamp == 64
                    || state.timestamp == 65) {
                    state.timestamp -= 50;
                    CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForMenu("tutorial_" + state.timestamp));
                    state.blockingSound = tso;
                    state.environment.Add(tso);
                    state.timestamp += 10;
                }
            }
            return false;
        }));

        rules.Add(new CurveRule("ALL", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            return !eve.initiator.StartsWith("player") || (eve.initiator.Equals("player" + state.curPlayer) && state.blockingSound == null);
        }));

        rules.Add(new CurveRule("action", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            if (state.repeating || state.replaying || state.blockingSound != null) {
                return true;
            }
            switch (eve.payload) {
                case "any":
                    if (state.timestamp == 10) {
                        (state.result as CurveGameResult).status = CurveGameResult.GameStatus.Over;
                        return false;
                    }
                    return true;
                case "replay":
                    state.replaying = true;
                    state.index = 0;
                    return false;
                case "repeat":
                    state.repeating = true;
                    state.index = 0;
                    return false;
                case "enter":
                    foreach (Actor actor in state.actors) {
                        Vector3 position = actor.position - new Vector3(initial_x, initial_y, 0f);
                        int x = (int)(position.x / offset_x);
                        int y = (int)(position.y / offset_y);
                        if (state.values[x] == state.expectedValues[x]) {
                            if (state.timestamp == 18) {
                                CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("boundary", new Vector3(0, 1, 0)));
                                state.environment.Add(tso);
                                state.blockingSound = tso;
                                state.timestamp = 118;
                            } else {
                                engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("boundary", new Vector3(0, 1, 0)), Vector3.zero));
                            }
                        } else {
                            if (state.timestamp == 15) {
                                CurveSoundObject tso;
                                state.values[x] = y;
                                if (state.values[x] == state.expectedValues[x]) {
                                    tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("correct"));
                                    state.environment.Add(tso);
                                    state.blockingSound = tso;
                                    state.timestamp = 116;
                                } else {
                                    tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("note", new Vector3(x, y, 0)));
                                    state.environment.Add(tso);
                                    state.blockingSound = tso;
                                    state.timestamp = 115;
                                }
                            } else {
                                state.values[x] = y;
                                if (state.values[x] == state.expectedValues[x]) {
                                    if (state.timestamp == 18 && state.values[1] == state.expectedValues[1] && state.values[2] == state.expectedValues[2]) {
                                        CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("correct"));
                                        state.environment.Add(tso);
                                        state.blockingSound = tso;
                                        state.timestamp = 59;
                                    } else if (state.timestamp == 21 && state.values[0] == state.expectedValues[0]) {
                                        CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("correct"));
                                        state.environment.Add(tso);
                                        state.blockingSound = tso;
                                        state.timestamp = 62;
                                    } else {
                                        engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("correct")));
                                    }
                                } else {
                                    engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("note", new Vector3(x, y, 0)), Vector3.zero));
                                }
                            }
                        }
                    }
                    return false;
            }
            return true;
        }));

        rules.Add(new CurveRule("move", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            if (state.repeating || state.replaying) {
                return false;
            }
            int dx = 0;
            int dy = 0;
            switch (eve.payload) {
                case "left":
                    dx = -1;
                    break;
                case "right":
                    dx = 1;
                    break;
                case "up":
                    dy = 1;
                    break;
                case "down":
                    dy = -1;
                    break;
                default:
                    return false;
            }
            foreach (Actor actor in state.actors) {
                Vector3 position = actor.position - new Vector3(initial_x, initial_y, 0f);
                int x = (int)(position.x / offset_x) + dx;
                int y = (int)(position.y / offset_y) + dy;
                if (x <= -1 || x >= max || y <= -1 || y >= 14) {
                    return false;
                }
                actor.position = new Vector3(offset_x * x + initial_x, offset_y * y + initial_y, actor.position.z);
                engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("note", new Vector3(x, y, 0))));
            }
            return false;
        }));
		
		gameObject.AddComponent<CurveGameEngine>();
		gameObject.AddComponent<CurveUserInterface>();
		gameObject.GetComponent<CurveGameEngine>().initialize(rules, actors, environment, players, renderer);
		gameObject.GetComponent<CurveUserInterface>().initialize(gameObject.GetComponent<CurveGameEngine>());
		gameObject.GetComponent<CurveGameEngine>().postEvent(new GameEvent("", "initialization", "unity"));
	}
	void Start () {
        CurveStateRenderer renderer = new CurveStateRenderer();
        AudioEngine auEngine = new AudioEngine(0, Settings.game_name, Settings.menu_sounds, Settings.game_sounds);

        List<Actor> actors = new List<Actor>();
        actors.Add(new CurveActor("pointer", "Prefabs/Curve/Ball", new Vector3(initial_x, initial_y, 90f), false, null));

        List<WorldObject> environment = new List<WorldObject>();
        environment.Add(new CurveStaticObject("Prefabs/Curve/Ball", Vector3.zero, false));
        environment.Add(new CurveStaticObject("Prefabs/Curve/MainCamera",    Vector3.zero, false));
        environment.Add(new CurveStaticObject("Prefabs/Curve/Light", Vector3.zero, false));
        environment.Add(new CanvasObject("Prefabs/Curve/LeapLogo", true, Vector3.zero, false));
        environment.Add(new CurveStaticObject("Prefabs/Curve/Divider", new Vector3(0, 0, 100f), false));
        TextCanvasObject gui = new TextCanvasObject("Prefabs/Curve/GUI_Element", true, "Time Left: " + Settings.time * 60, new Vector3(0, 0, 0), false);
        environment.Add(gui);

        List<Player> players = new List<Player>();
        players.Add(new Player("player0", "player0"));

        CurveRuleset rules = new CurveRuleset();
        rules.Add(new CurveRule("initialization", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            AudioClip auClip = auEngine.getSoundForMenu("new_game_intro");
            CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/AudioSource", auClip);
            state.environment.Add(tso);
            state.blockingSound = tso;
            state.timestamp = 0;
            state.level = Settings.level;
            state.time_left = Settings.time * 60;
            for (int j = 0; j < 14; j++) {
                switch (state.level) {
                    case 0:
                        state.expectedValues[j] = 6;
                        break;
                    case 1:
                        state.expectedValues[j] = j;
                        break;
                    case 2:
                        state.expectedValues[j] = (int)(13f - j);
                        break;
                    case 3:
                        state.expectedValues[j] = (int)(j * j / 13f);
                        break;
                    case 4:
                        state.expectedValues[j] = (int)(Mathf.Sqrt(14.5f * j));
                        break;
                    case 5:
                        state.expectedValues[j] = (int) Mathf.Round((Mathf.Sin(j * 3.14159f / 4f) + 1f) * 6f);
                        break;
                    case 6:
                        state.expectedValues[j] = (int)(13f / (j + 1));
                        break;
                }
                state.values[j] = -1;
            }
            return false;
        }));

        rules.Add(new CurveRule("frame", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            if (state.timestamp == 2 && !state.repeating && !state.replaying) {
                state.time_left -= Time.deltaTime;
                gui.text = "Time Left: " + (int)state.time_left;
                if (state.time_left <= 0) {
                    state.timestamp = 9;
                    AudioClip auClip = auEngine.getSoundForMenu("new_game_loss");
                    CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/AudioSource", auClip);
                    state.environment.Add(tso);
                    state.blockingSound = tso;
                }
            } else if (state.timestamp == 2) {
                if (state.delay <= 0) {
                    state.delay = 0.6f;
                    if (state.replaying) {
                        float x = initial_rx + state.index * offset_x;
                        float y = initial_y + state.expectedValues[state.index] * offset_y;
                        engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/VisibleGameAudio", auEngine.getSoundForPlayer("note", new Vector3(state.index, state.expectedValues[state.index], 0)), new Vector3(x, y, 90)));
                    } else {
                        if (state.values[state.index] != -1) {
                            float x = initial_x + state.index * offset_x;
                            float y = initial_y + state.values[state.index] * offset_y;
                            engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/VisibleGameAudio", auEngine.getSoundForPlayer("note", new Vector3(state.index, state.values[state.index], 0)), new Vector3(x, y, 90)));
                        } else {
                            engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/VisibleGameAudio", auEngine.getSoundForPlayer("air")));
                        }
                    }
                    state.index++;
                    if (state.index == 14) {
                        state.index = 0;
                        state.repeating = false;
                        state.replaying = false;
                        state.delay = 0;
                    }
                } else {
                    state.delay -= Time.deltaTime;
                }
            }
            return false;
        }));

        rules.Add(new CurveRule("action", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            if (eve.payload.Equals("escape")) {
                Application.LoadLevel(Settings.previousMenu);
                return false;
            }
            return true;
        }));

        rules.Add(new CurveRule("soundOver", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            int id = int.Parse(eve.payload);
            if (state.blockingSound != null && id == state.blockingSound.clip.GetInstanceID()) {
                state.environment.Remove(state.blockingSound);
                state.blockingSound = null;
                if (state.timestamp == 0) {
                    state.timestamp = 2;
                    state.replaying = true;
                }
                if (state.timestamp == 9) {
                    state.timestamp = 10;
                }
            } else {
                WorldObject toRemove = null;
                foreach (WorldObject go in state.environment) {
                    if (go is CurveSoundObject && (go as CurveSoundObject).clip.GetInstanceID() == id) {
                        toRemove = go;
                        break;
                    }
                }
                if (toRemove != null) {
                    state.environment.Remove(toRemove);
                }
            }
            return false;
        }));

        rules.Add(new CurveRule("ALL", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            return !eve.initiator.StartsWith("player") || (eve.initiator.Equals("player" + state.curPlayer) && state.blockingSound == null);
        }));

        rules.Add(new CurveRule("action", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            if (state.repeating || state.replaying || state.blockingSound != null) {
                return true;
            }
            switch (eve.payload) {
                case "any":
                    if (state.timestamp == 10) {
                        (state.result as CurveGameResult).status = CurveGameResult.GameStatus.Over;
                        return false;
                    }
                    return true;
                case "replay":
                    state.replaying = true;
                    state.index = 0;
                    return false;
                case "repeat":
                    state.repeating = true;
                    state.index = 0;
                    return false;
                case "enter":
                    if (state.timestamp == 1 || state.timestamp >= 9) {
                        return false;
                    }
                    foreach (Actor actor in state.actors) {
                        Vector3 position = actor.position - new Vector3(initial_x, initial_y, 0f);
                        int x = (int)(position.x / offset_x);
                        int y = (int)(position.y / offset_y);
                        if (state.values[x] == state.expectedValues[x]) {
                            engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("boundary", new Vector3(0, 1, 0)), Vector3.zero));
                        } else {
                            state.values[x] = y;
                            if (state.values[x] == state.expectedValues[x]) {
                                engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("correct"), Vector3.zero));
                            } else {
                                engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("note", new Vector3(x, y, 0)), Vector3.zero));
                            }
                        }
                    }
                    int i;
                    for (i = 0; i < 14; i++) {
                        if (state.values[i] != state.expectedValues[i]) {
                            break;
                        }
                    }
                    if (i == 14) {
                        state.timestamp = 9;
                        engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("claps_1"), Vector3.zero));
                        AudioClip auClip = auEngine.getSoundForMenu("new_game_win");
                        CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/AudioSource", auClip);
                        state.environment.Add(tso);
                        state.blockingSound = tso;
                    }
                    return false;
            }
            return true;
        }));

        rules.Add(new CurveRule("move", (CurveGameState state, GameEvent eve, CurveGameEngine engine) => {
            if (state.repeating || state.replaying) {
                return false;
            }
            int dx = 0;
            int dy = 0;
            switch (eve.payload) {
                case "left":
                    dx = -1;
                    break;
                case "right":
                    dx = 1;
                    break;
                case "up":
                    dy = 1;
                    break;
                case "down":
                    dy = -1;
                    break;
                default:
                    return false;
            }
            foreach (Actor actor in state.actors) {
                Vector3 position = actor.position - new Vector3(initial_x, initial_y, 0f);
                int x = (int)(position.x / offset_x) + dx;
                int y = (int)(position.y / offset_y) + dy;
                if (x <= -1 || x >= 14 || y <= -1 || y >= 14) {
                    return false;
                }
                actor.position = new Vector3(offset_x * x + initial_x, offset_y * y + initial_y, actor.position.z);
                engine.state.environment.Add(new CurveSoundObject("Prefabs/Curve/GameAudio", auEngine.getSoundForPlayer("note", new Vector3(x, y, 0))));
            }
            return false;
        }));

        gameObject.AddComponent<CurveGameEngine>();
        gameObject.AddComponent<CurveUserInterface>();
        gameObject.GetComponent<CurveGameEngine>().initialize(rules, actors, environment, players, renderer);
        gameObject.GetComponent<CurveUserInterface>().initialize(gameObject.GetComponent<CurveGameEngine>());
        gameObject.GetComponent<CurveGameEngine>().postEvent(new GameEvent("", "initialization", "unity"));
	}
    void Start() {
        CurveStateRenderer renderer = new CurveStateRenderer();
        AudioEngine auEngine = new AudioEngine(0, Settings.game_name, Settings.menu_sounds, Settings.game_sounds);

        List<WorldObject> environment = new List<WorldObject>();
        environment.Add(movingCamera);
        environment.Add(new CurveStaticObject("Prefabs/Curve/Light_Default", new Vector3(0, 10, 0), false));
        environment.Add(new CanvasObject("Prefabs/Curve/Logos", true, new Vector3(10000, 0, 0), false));
        environment.Add(new CurveMenuItem("Prefabs/Curve/ButtonSelected", "5 λεπτά", "newGame", "5", auEngine.getSoundForMenu("new_game_remaining_time_5"), new Vector3(0, 0, -offset_y), false, true));
        environment.Add(new CurveMenuItem("Prefabs/Curve/ButtonDefault", "4 λεπτά", "newGame", "4", auEngine.getSoundForMenu("new_game_remaining_time_4"), new Vector3(0, 0, 0), false, false));
        environment.Add(new CurveMenuItem("Prefabs/Curve/ButtonDefault", "3 λεπτά", "newGame", "3", auEngine.getSoundForMenu("new_game_remaining_time_3"), new Vector3(0, 0, offset_y), false));
        environment.Add(new CurveMenuItem("Prefabs/Curve/ButtonDefault", "2 λεπτά", "newGame", "2", auEngine.getSoundForMenu("new_game_remaining_time_2"), new Vector3(0, 0, 2 * offset_y), false));
        environment.Add(new CurveMenuItem("Prefabs/Curve/ButtonDefault", "1 λεπτό", "newGame", "1", auEngine.getSoundForMenu("new_game_remaining_time_1"), new Vector3(0, 0, 3 * offset_y), false));
        environment.Add(new CurveMenuItem("Prefabs/Curve/ButtonDefault", "Πίσω", "curveSelectionMenu", "back", auEngine.getSoundForMenu("back"), new Vector3(0, 0, 4 * offset_y), false));

        CurveRuleset rules = new CurveRuleset();
        rules.Add(new CurveRule("initialization", (CurveMenuState state, GameEvent eve, CurveMenuEngine engine) => {
            AudioClip audioClip;
            state.timestamp = 0;
            audioClip = auEngine.getSoundForMenu("new_game_select");
            CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/AudioSource", audioClip, Vector3.zero);
            state.environment.Add(tso);
            state.stoppableSounds.Add(tso);
            Settings.previousMenu = "curveSelectionMenu";
            return false;
        }));

        rules.Add(new CurveRule("soundOver", (CurveMenuState state, GameEvent eve, CurveMenuEngine engine) => {
            if (state.timestamp == 0) {
                AudioClip audioClip = auEngine.getSoundForMenu("new_game_remaining_time_5");
                CurveSoundObject tso = new CurveSoundObject("Prefabs/Curve/AudioSource", audioClip, Vector3.zero);
                state.environment.Add(tso);
                state.stoppableSounds.Add(tso);
                state.timestamp = 1;
            }
            return false;
        }));

        rules.Add(new CurveRule("action", (CurveMenuState state, GameEvent eve, CurveMenuEngine engine) => {
            if (eve.payload.Equals("escape")) {
                Application.LoadLevel("curveSelectionMenu");
                return false;
            }
            return true;
        }));

        rules.Add(new CurveRule("action", (CurveMenuState state, GameEvent eve, CurveMenuEngine engine) => {
            if (eve.payload.Equals("enter")) {
                foreach (WorldObject obj in state.environment) {
                    if (obj is CurveMenuItem) {
                        if ((obj as CurveMenuItem).selected) {
                            int mins;
                            if (Int32.TryParse((obj as CurveMenuItem).audioMessageCode, out mins)) {
                                Settings.time = mins;
                            }
                            Application.LoadLevel((obj as CurveMenuItem).target);
                            return false;
                        }
                    }
                }
            }
            return true;
        }));

        rules.Add(new CurveRule("move", (CurveMenuState state, GameEvent eve, CurveMenuEngine engine) => {
            state.timestamp++;
            foreach (CurveSoundObject Curveso in state.stoppableSounds) {
                state.environment.Remove(Curveso);
            }
            state.stoppableSounds.Clear();
            CurveMenuItem previous = null;
            bool change = false;
            AudioClip audioClip;
            CurveSoundObject tso;
            foreach (WorldObject obj in state.environment) {
                if (obj is CurveMenuItem) {
                    CurveMenuItem temp = obj as CurveMenuItem;
                    if (temp.selected) {
                        if (eve.payload == "_up" || eve.payload == "left") {
                            if (previous == null) {
                                audioClip = auEngine.getSoundForPlayer("boundary", Vector3.up);
                                tso = new CurveSoundObject("Prefabs/Curve/AudioSource", audioClip, Vector3.zero);
                                state.environment.Add(tso);
                                state.stoppableSounds.Add(tso);
                                break;
                            }
                            temp.selected = false;
                            temp.prefab = temp.prefab.Replace("Selected", "Default");
                            previous.selected = true;
                            previous.prefab = previous.prefab.Replace("Default", "Selected");
                            tso = new CurveSoundObject("Prefabs/Curve/AudioSource", previous.audioMessage, Vector3.zero);
                            state.environment.Add(tso);
                            state.stoppableSounds.Add(tso);
                            break;
                        } else {
                            change = true;
                        }
                    } else if (change) {
                        temp.selected = true;
                        temp.prefab = temp.prefab.Replace("Default", "Selected");
                        previous.prefab = previous.prefab.Replace("Selected", "Default");
                        previous.selected = false;
                        change = false;
                        tso = new CurveSoundObject("Prefabs/Curve/AudioSource", temp.audioMessage, Vector3.zero);
                        state.environment.Add(tso);
                        state.stoppableSounds.Add(tso);
                        break;
                    }
                    previous = temp;
                }
            }
            if (change) {
                audioClip = auEngine.getSoundForPlayer("boundary", Vector3.down);
                tso = new CurveSoundObject("Prefabs/Curve/AudioSource", audioClip, Vector3.zero);
                state.environment.Add(tso);
                state.stoppableSounds.Add(tso);
            }
            foreach (WorldObject obj in state.environment) {
                if (obj is CurveMenuItem) {
                    CurveMenuItem temp = obj as CurveMenuItem;
                    if (temp.selected) {
                        movingCamera.position = new Vector3(0, 10, Mathf.Clamp(temp.position.z, 6 * offset_y, 0));
                        break;
                    }
                }
            }
            return true;
        }));

        gameObject.AddComponent<CurveMenuEngine>();
        gameObject.AddComponent<CurveMenuUserInterface>();
        gameObject.GetComponent<CurveMenuEngine>().initialize(rules, environment, renderer);
        gameObject.GetComponent<CurveMenuUserInterface>().initialize(gameObject.GetComponent<CurveMenuEngine>());
        gameObject.GetComponent<CurveMenuEngine>().postEvent(new GameEvent("", "initialization", "unity"));
    }
    void Start()
    {
        TennisStateRenderer renderer = new TennisStateRenderer();
        AudioEngine auEngine = new AudioEngine(0, "tennis", Settings.menu_sounds, Settings.game_sounds);

        List<Actor> actors = new List<Actor>();

        List<WorldObject> environment = new List<WorldObject>();
        ball = new TennisMovingObject("Prefabs/Tennis/Ball", new Vector3(0, -1, Settings.size_mod_z * 5.9f), true);
        environment.Add(ball);
        environment.Add(new TennisStaticObject("Prefabs/Tennis/MainCamera", new Vector3(0, 1, (Settings.size_mod_z * -6f) - 5.5f), false));
        environment.Add(new TennisStaticObject("Prefabs/Tennis/Light", new Vector3(0, 0, 0), false));
        environment.Add(new TennisStaticObject("Prefabs/Tennis/Field", new Vector3(0, -7, 0), false));
        environment.Add(new TennisStaticObject("Prefabs/Tennis/Wall", new Vector3(0, -5, Settings.size_mod_z * 6), false));
        environment.Add(new CanvasObject("Prefabs/Tennis/LeapLogo", true, new Vector3(0, 0, 0), false));

        List<Player> players = new List<Player>();
        players.Add(new Player("player0", "player0"));

        TennisRuleset rules = new TennisRuleset();
        rules.Add(new TennisRule("initialization", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            AudioClip auClip = auEngine.getSoundForMenu("tutorial_intro");
            TennisSoundObject tso = new TennisSoundObject("Prefabs/Tennis/AudioSource", auClip);
            state.environment.Add(tso);
            state.blockingSound = tso;
            state.speed = 0;
            state.timestamp = -1;
            state.target = 0;
            return false;
        }));

        rules.Add(new TennisRule("action", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            if (eve.payload.Equals("any")) {
                switch(state.timestamp) {
                case 0:
                    AudioClip auClip = auEngine.getSoundForMenu("tutorial_01");
                    TennisSoundObject tso = new TennisSoundObject("Prefabs/Tennis/AudioSource", auClip);
                    state.environment.Add(tso);
                    state.blockingSound = tso;
                    state.timestamp++;
                    return false;
                case 10:
                    (state.result as TennisGameResult).status = TennisGameResult.GameStatus.Over;
                    return false;
                default:
                    return false;
                }
            }
            return true;
        }));

        rules.Add(new TennisRule("action", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            if (eve.payload.Equals("escape")) {
                Application.LoadLevel("mainMenu");
                return false;
            }
            return true;
        }));

        rules.Add(new TennisRule("soundOver", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            int id = int.Parse(eve.payload);
            if (state.blockingSound != null && id == state.blockingSound.clip.GetInstanceID()) {
                state.environment.Remove(state.blockingSound);
                state.blockingSound = null;
                switch(state.timestamp) {
                case -1:
                    state.timestamp++;
                    break;
                case 44:
                    break;
                case 55:
                    break;
                case 66:
                    break;
                case 77:
                    break;
                case 78:
                    break;
                case 88:
                    break;
                case 89:
                    break;
                case 76:
                    state.timestamp++;
                    break;
                case 6:
                    state.blockingSound = new TennisSoundObject("Prefabs/Tennis/AudioSource", auEngine.getSoundForMenu("tutorial_0" + state.timestamp));
                    state.environment.Add(state.blockingSound);
                    state.timestamp = 76;
                    break;
                case 7:
                    TennisSoundObject stso = new TennisSoundObject("Prefabs/Tennis/AudioSource", auEngine.getSoundForMenu("tutorial_outro"));
                    state.environment.Add(stso);
                    state.blockingSound = stso;
                    state.timestamp = 9;
                    break;
                case 9:
                    state.timestamp = 10;
                    break;
                default:
                    state.timestamp++;
                    state.speed = 1f;
                    break;
                }
            } else {
                WorldObject toRemove = null;
                foreach (WorldObject go in state.environment) {
                    if (go is TennisSoundObject && (go as TennisSoundObject).clip.GetInstanceID() == id) {
                        toRemove = go;
                        break;
                    }
                }
                if (toRemove != null) {
                    state.environment.Remove(toRemove);
                }
            }
            return false;
        }));

        rules.Add(new TennisRule("action", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            if (eve.payload.Equals("pause") && state.blockingSound != null) {
                state.blockingSound.hidden = true;
                return false;
            }
            return true;
        }));

        rules.Add(new TennisRule("action", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            if (eve.payload.Equals("enter") && state.timestamp > 10 && state.blockingSound == null && state.timestamp < 66) {
                state.timestamp /= 11;
                TennisSoundObject ltso = new TennisSoundObject("Prefabs/Tennis/AudioSource", auEngine.getSoundForMenu("tutorial_0" + state.timestamp));
                state.environment.Add(ltso);
                state.blockingSound = ltso;
                state.target = state.timestamp == 4 ? -1 : 0;
                state.timestamp = (state.timestamp + 1) * 11;
                return false;
            }
            return true;
        }));

        rules.Add(new TennisRule("ALL", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            return !eve.initiator.StartsWith("player") || (eve.initiator.Equals("player" + state.curPlayer) && state.blockingSound == null);
        }));

        rules.Add(new TennisRule("position", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            if (state.timestamp < 67) {
                return false;
            }
            if (state.speed == 0f || !positionalMovement) {
                return false;
            }
            switch (state.timestamp) {
                case 67:
                    if (!eve.payload.Equals("right")) {
                        state.timestamp = 66;
                        actors.Clear();
                        AudioClip auClip = auEngine.getSoundForMenu("tutorial_55");
                        state.blockingSound = new TennisSoundObject("Prefabs/Tennis/AudioSource", auClip);
                        state.environment.Add(state.blockingSound);
                        state.speed = 0;
                    }
                    break;
                case 78:
                    if (!eve.payload.Equals("left")) {
                        state.timestamp = 77;
                        actors.Clear();
                        AudioClip auClip = auEngine.getSoundForMenu("tutorial_66");
                        state.blockingSound = new TennisSoundObject("Prefabs/Tennis/AudioSource", auClip);
                        state.environment.Add(state.blockingSound);
                        state.speed = 0;
                    }
                    break;
                case 68:
                    break;
                case 79:
                    break;
                default:
                    return false;
            }
            int dx = 0;
            switch (eve.payload) {
                case "left":
                    dx = -1;
                    break;
                case "right":
                    dx = 1;
                    break;
            }
            foreach (Actor actor in state.actors) {
                Vector3 newPos = new Vector3(offset_x * dx, actor.position.y, actor.position.z);
                if (actor.position == newPos) {
                    return false;
                }
                actor.position = newPos;
                engine.state.environment.Add(new TennisSoundObject("Prefabs/Tennis/GameAudio", auEngine.getSoundForPlayer("just moved", new Vector3(dx, 0, 0)), actor.position));
            }
            return false;
        }));

        rules.Add(new TennisRule("move", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            switch (state.timestamp) {
            case 44:
                if (eve.payload.Equals("right")) {
                    state.speed = 1f;
                }
                break;
            case 55:
                if (eve.payload.Equals("left")) {
                    state.speed = 1f;
                }
                break;
            case 66:
                actors.Add(new TennisActor("racket", "Prefabs/Tennis/Racket", new Vector3(0, -5, Settings.size_mod_z * - 6), false, null));
                if (eve.payload.Equals("right")) {
                    state.target = 1;
                    state.speed = 1f;
                    state.timestamp = 67;
                }
                break;
            case 77:
                actors.Add(new TennisActor("racket", "Prefabs/Tennis/Racket", new Vector3(0, -5, Settings.size_mod_z * -6), false, null));
                if (eve.payload.Equals("left")) {
                    state.target = -1;
                    state.speed = 1f;
                    state.timestamp = 78;
                }
                break;
            default:
                break;
            }
            return false;
        }));

        rules.Add(new TennisRule("hit", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            switch (eve.payload) {
            case "-1":
                ballTarget = -1;
                break;
            case "0":
                ballTarget = 0;
                break;
            case "1":
                ballTarget = 1;
                break;
            }
            return false;
        }));

        rules.Add(new TennisRule("bounce", (TennisGameState state, GameEvent eve, TennisGameEngine engine) => {
            AudioClip auClip;
            Vector3 position = new Vector3(ballTarget * offset_x, ball.position.y, ball.position.z);
            switch (eve.payload) {
            case "racket":
                auClip = auEngine.getSoundForPlayer("player_racket_hit");
                state.timestamp++;
                break;
            case "wall":
                if (state.timestamp == 68 || state.timestamp == 79) {
                    environment.Remove(ball);
                    ball = new TennisMovingObject("Prefabs/Tennis/Ball", new Vector3(0, -1, Settings.size_mod_z * 5.9f), true);
                    environment.Add(ball);
                    state.speed = 0f;
                    if (state.timestamp == 68) {
                        state.blockingSound = new TennisSoundObject("Prefabs/Tennis/AudioSource", auEngine.getSoundForPlayer("opponent_racket_hit"));
                    } else {
                        state.blockingSound = new TennisSoundObject("Prefabs/Tennis/AudioSource", auEngine.getSoundForPlayer("win_" + Random.Range(1, 13)));
                    }
                    environment.Add(state.blockingSound);
                    state.timestamp = (state.timestamp - 2) / 11;
                    return false;
                }
                auClip = auEngine.getSoundForPlayer("opponent_racket_hit");
                break;
            case "floor":
                auClip = auEngine.getSoundForPlayer("floor_hit");
                break;
            case "net":
                auClip = auEngine.getSoundForPlayer("net_pass");
                position.Scale(new Vector3(1f, 1f, 1f));
                break;
            case "boundary":
                environment.Remove(ball);
                ball = new TennisMovingObject("Prefabs/Tennis/Ball", new Vector3(0, -1, Settings.size_mod_z * 5.9f), true);
                environment.Add(ball);
                state.speed = 0f;
                if (state.timestamp < 10) {
                    TennisSoundObject rtso = new TennisSoundObject("Prefabs/Tennis/AudioSource", auEngine.getSoundForMenu("tutorial_0" + state.timestamp));
                    state.environment.Add(rtso);
                    state.blockingSound = rtso;
                    switch(state.timestamp) {
                    case 2:
                        state.target = 0;
                        break;
                    case 3:
                        state.target = 1;
                        state.timestamp = 44;
                        break;
                    case 44:
                        break;
                    case 55:
                        break;
                    case 66:
                        break;
                    default:
                        state.target = -2;
                        break;
                    }
                }
                return false;
            default:
                return false;
            }
            TennisSoundObject tso = new TennisSoundObject("Prefabs/Tennis/GameAudio", auClip, position);
            engine.state.environment.Add(tso);
            return true;
        }));

        gameObject.AddComponent<TennisGameEngine>();
        gameObject.AddComponent<TennisUserInterface>();
        gameObject.GetComponent<TennisGameEngine>().initialize(rules, actors, environment, players, renderer);
        gameObject.GetComponent<TennisUserInterface>().initialize(gameObject.GetComponent<TennisGameEngine>());
        gameObject.GetComponent<TennisGameEngine>().postEvent(new GameEvent("", "initialization", "unity"));
    }
    void Start()
    {
        TennisStateRenderer renderer = new TennisStateRenderer();
        AudioEngine auEngine = new AudioEngine(0, "tennis", Settings.menu_sounds, Settings.game_sounds);

        List<WorldObject> environment = new List<WorldObject>();
        environment.Add(movingCamera);
        environment.Add(new TennisStaticObject("Prefabs/Tennis/Light_Default", new Vector3(0, 10, 0), false));
        environment.Add(new CanvasObject("Prefabs/Tennis/Logos", true, new Vector3(10000, 0, 0), false));
        int i = 0;
        environment.Add(new TennisMenuItem("Prefabs/Tennis/ButtonSelected", Settings.default_soundset, "default", "default_", null, new Vector3(0, 0, -offset_y), false, true));
        foreach (string s in auEngine.getSettingsAudioForMenu()) {
            if (s == "default") {
                continue;
            }
            environment.Add(new TennisMenuItem("Prefabs/Tennis/ButtonDefault", s, s, s + "_", null, new Vector3(0, 0, i++ * offset_y), false, false));
        }

        TennisRuleset rules = new TennisRuleset();
        rules.Add(new TennisRule("initialization", (TennisMenuState state, GameEvent eve, TennisMenuEngine engine) => {
            AudioClip audioClip;
            audioClip = auEngine.getSoundForMenu("voice_selection");
            state.timestamp = 0;
            TennisSoundObject tso = new TennisSoundObject("Prefabs/Tennis/AudioSource", audioClip, Vector3.zero);
            state.environment.Add(tso);
            state.stoppableSounds.Add(tso);
            Settings.previousMenu = "mainMenu";
            return false;
        }));

        rules.Add(new TennisRule("action", (TennisMenuState state, GameEvent eve, TennisMenuEngine engine) => {
            if (eve.payload.Equals("enter")) {
                foreach (WorldObject obj in state.environment) {
                    if (obj is TennisMenuItem) {
                        TennisMenuItem temp = obj as TennisMenuItem;
                        if (temp.selected) {
                            Settings.menu_sounds = temp.target;
                            Settings.game_sounds = temp.target;
                        }
                    }
                }
                Application.LoadLevel("mainMenu");
            }
            return true;
        }));

        rules.Add(new TennisRule("move", (TennisMenuState state, GameEvent eve, TennisMenuEngine engine) => {
            state.timestamp++;
            foreach (TennisSoundObject tennisSo in state.stoppableSounds) {
                state.environment.Remove(tennisSo);
            }
            state.stoppableSounds.Clear();
            TennisMenuItem previous = null;
            bool change = false;
            AudioClip audioClip;
            TennisSoundObject tso;
            foreach (WorldObject obj in state.environment) {
                if (obj is TennisMenuItem) {
                    TennisMenuItem temp = obj as TennisMenuItem;
                    if (temp.selected) {
                        if (eve.payload == "_up" || eve.payload == "left") {
                            if (previous == null) {
                                audioClip = auEngine.getSoundForPlayer("boundary", Vector3.up);
                                tso = new TennisSoundObject("Prefabs/Tennis/AudioSource", audioClip, Vector3.zero);
                                state.environment.Add(tso);
                                state.stoppableSounds.Add(tso);
                                break;
                            }
                            temp.selected = false;
                            temp.prefab = temp.prefab.Replace("Selected", "Default");
                            previous.selected = true;
                            previous.prefab = previous.prefab.Replace("Default", "Selected");
                            tso = new TennisSoundObject("Prefabs/Tennis/AudioSource", auEngine.getSoundForPlayer(previous.audioMessageCode + Random.Range(1, 5)), Vector3.zero);
                            state.environment.Add(tso);
                            state.stoppableSounds.Add(tso);
                            break;
                        } else {
                            change = true;
                        }
                    } else if (change) {
                        temp.selected = true;
                        temp.prefab = temp.prefab.Replace("Default", "Selected");
                        previous.prefab = previous.prefab.Replace("Selected", "Default");
                        previous.selected = false;
                        change = false;
                        tso = new TennisSoundObject("Prefabs/Tennis/AudioSource", auEngine.getSoundForPlayer(temp.audioMessageCode + Random.Range(1, 5)), Vector3.zero);
                        state.environment.Add(tso);
                        state.stoppableSounds.Add(tso);
                        break;
                    }
                    previous = temp;
                }
            }
            if (change) {
                audioClip = auEngine.getSoundForPlayer("boundary", Vector3.down);
                tso = new TennisSoundObject("Prefabs/Tennis/AudioSource", audioClip, Vector3.zero);
                state.environment.Add(tso);
                state.stoppableSounds.Add(tso);
            }
            foreach (WorldObject obj in state.environment) {
                if (obj is TennisMenuItem) {
                    TennisMenuItem temp = obj as TennisMenuItem;
                    if (temp.selected) {
                        movingCamera.position = new Vector3(0, 10, Mathf.Clamp(temp.position.z, 6 * offset_y, 0));
                        break;
                    }
                }
            }
            return true;
        }));

        gameObject.AddComponent<TennisMenuEngine>();
        gameObject.AddComponent<TennisMenuUserInterface>();
        gameObject.GetComponent<TennisMenuEngine>().initialize(rules, environment, renderer);
        gameObject.GetComponent<TennisMenuUserInterface>().initialize(gameObject.GetComponent<TennisMenuEngine>());
        gameObject.GetComponent<TennisMenuEngine>().postEvent(new GameEvent("", "initialization", "unity"));
    }