private IEnumerator StopEveryCoroutine()
    {
        yield return(new WaitForSeconds(2.0f));

        _coroutinesToStart.Enqueue(MiscellaneousMessageResponder.FindHoldables());
        _coroutineQueue.StopQueue();
        _coroutineQueue.CancelFutureSubcoroutines();
        _coroutineQueue.StopForcedSolve();
        StopAllCoroutines();
        while (_coroutinesToStart.Count > 0)
        {
            StartCoroutine(_coroutinesToStart.Dequeue());
        }
    }
    private void Start()
    {
        transform.Find("Prefabs").gameObject.SetActive(false);
        bombMessageResponder          = GetComponentInChildren <BombMessageResponder>(true);
        postGameMessageResponder      = GetComponentInChildren <PostGameMessageResponder>(true);
        missionMessageResponder       = GetComponentInChildren <MissionMessageResponder>(true);
        miscellaneousMessageResponder = GetComponentInChildren <MiscellaneousMessageResponder>(true);

        bombMessageResponder.twitchBombHandlePrefab      = GetComponentInChildren <TwitchBombHandle>(true);
        bombMessageResponder.twitchComponentHandlePrefab = GetComponentInChildren <TwitchComponentHandle>(true);
        bombMessageResponder.moduleCamerasPrefab         = GetComponentInChildren <ModuleCameras>(true);

        BombMessageResponder.Instance = bombMessageResponder;

        GameRoom.InitializeSecondaryCamera();
        _gameInfo = GetComponent <KMGameInfo>();
        _gameInfo.OnStateChange += OnStateChange;

        _coroutineQueue = GetComponent <CoroutineQueue>();

        Leaderboard.Instance.LoadDataFromFile();

        ModuleData.LoadDataFromFile();
        ModuleData.WriteDataToFile();

        TwitchPlaySettings.LoadDataFromFile();

        SetupResponder(bombMessageResponder);
        SetupResponder(postGameMessageResponder);
        SetupResponder(missionMessageResponder);
        SetupResponder(miscellaneousMessageResponder);

        bombMessageResponder.parentService = this;

        GameObject infoObject = new GameObject("TwitchPlays_Info");

        infoObject.transform.parent          = gameObject.transform;
        _publicProperties                    = infoObject.AddComponent <TwitchPlaysProperties>();
        _publicProperties.TwitchPlaysService = this;
        if (TwitchPlaySettings.data.SkipModManagerInstructionScreen || IRCConnection.Instance.State == IRCConnectionState.Connected)
        {
            ModManagerManualInstructionScreen.HasShownOnce = true;
        }
    }
    public override IEnumerator BombCommanderTurnBomb(Bomb bomb)
    {
        yield return(false);

        IEnumerator dropAllHoldables = MiscellaneousMessageResponder.DropAllHoldables();

        while (dropAllHoldables.MoveNext())
        {
            yield return(dropAllHoldables.Current);
        }
        IEnumerator rotateCamera;

        switch (_currentWall)
        {
        case CurrentElevatorWall.Right:
            rotateCamera = DoElevatorCameraRotate(_currentWall, CurrentElevatorWall.Back, 1, false, false);
            _currentWall = CurrentElevatorWall.Back;
            break;

        case CurrentElevatorWall.Dropped:
        case CurrentElevatorWall.Back:
            rotateCamera = DoElevatorCameraRotate(_currentWall, CurrentElevatorWall.Left, 1, false, false);
            _currentWall = CurrentElevatorWall.Left;
            break;

        case CurrentElevatorWall.Left:
            rotateCamera = DoElevatorCameraRotate(_currentWall, CurrentElevatorWall.Right, 1, false, false);
            _currentWall = CurrentElevatorWall.Right;
            break;

        default: yield break;
        }
        while (rotateCamera.MoveNext())
        {
            yield return(rotateCamera.Current);
        }
    }
    public override IEnumerator BombCommanderHoldBomb(Bomb bomb, bool frontFace = true)
    {
        yield return(false);

        if (_currentWall != CurrentElevatorWall.Dropped)
        {
            yield break;
        }

        IEnumerator dropAllHoldables = MiscellaneousMessageResponder.DropAllHoldables();

        while (dropAllHoldables.MoveNext())
        {
            yield return(dropAllHoldables.Current);
        }

        IEnumerator holdBomb = DoElevatorCameraRotate(CurrentElevatorWall.Dropped, CurrentElevatorWall.Back, 1, false, false);

        while (holdBomb.MoveNext())
        {
            yield return(holdBomb.Current);
        }
        _currentWall = CurrentElevatorWall.Back;
    }
    public IEnumerator ToggleSetupRoomElevatorSwitch(bool elevatorState)
    {
        ElevatorSwitch elevatorSwitch = null;

        if (SceneManager.Instance.CurrentRoom is SetupRoom setupRoom)
        {
            elevatorSwitch = setupRoom.ElevatorSwitch;
        }

        DebugHelper.Log("Setting Elevator state to {0}", elevatorState);
        if (elevatorSwitch == null)
        {
            IEnumerator ircManager = IRCConnectionManagerHandler.Instance.RespondToCommand("Elevator Switch", elevatorState ? "elevator on" : "elevator off");
            while (ircManager.MoveNext())
            {
                yield return(ircManager.Current);
            }
            yield break;
        }
        else
        {
            IEnumerator dropHoldables = MiscellaneousMessageResponder.DropAllHoldables();
            while (dropHoldables.MoveNext())
            {
                yield return(dropHoldables.Current);
            }
            yield return(new WaitForSeconds(0.25f));
        }
        float duration = 2f;

        GameRoom.ToggleCamera(false);
        yield return(null);

        float     initialTime         = Time.time;
        Vector3   currentWallPosition = new Vector3(0, 0, 0);
        Vector3   currentWallRotation = new Vector3(26.39f, 0, 0);
        Vector3   newWallPosition     = new Vector3(-0.6f, -1f, 0.3f);
        Vector3   newWallRotation     = new Vector3(0, 40, 0);
        Transform camera = GameRoom.SecondaryCamera.transform;

        while ((Time.time - initialTime) < duration)
        {
            float lerp = (Time.time - initialTime) / duration;
            camera.localPosition = new Vector3(Mathf.SmoothStep(currentWallPosition.x, newWallPosition.x, lerp),
                                               Mathf.SmoothStep(currentWallPosition.y, newWallPosition.y, lerp),
                                               Mathf.SmoothStep(currentWallPosition.z, newWallPosition.z, lerp));
            camera.localEulerAngles = new Vector3(Mathf.SmoothStep(currentWallRotation.x, newWallRotation.x, lerp),
                                                  Mathf.SmoothStep(currentWallRotation.y, newWallRotation.y, lerp),
                                                  Mathf.SmoothStep(currentWallRotation.z, newWallRotation.z, lerp));
            yield return(null);
        }
        camera.localPosition    = newWallPosition;
        camera.localEulerAngles = newWallRotation;
        yield return(new WaitForSeconds(0.5f));

        DebugHelper.Log("Elevator Switch Toggled");
        if (elevatorState != elevatorSwitch.On())
        {
            elevatorSwitch.Switch.Toggle();
        }
        else
        {
            ReportState();
        }
        yield return(new WaitForSeconds(0.5f));

        initialTime = Time.time;
        while ((Time.time - initialTime) < duration)
        {
            float lerp = (Time.time - initialTime) / duration;
            camera.localPosition = new Vector3(Mathf.SmoothStep(newWallPosition.x, currentWallPosition.x, lerp),
                                               Mathf.SmoothStep(newWallPosition.y, currentWallPosition.y, lerp),
                                               Mathf.SmoothStep(newWallPosition.z, currentWallPosition.z, lerp));
            camera.localEulerAngles = new Vector3(Mathf.SmoothStep(newWallRotation.x, currentWallRotation.x, lerp),
                                                  Mathf.SmoothStep(newWallRotation.y, currentWallRotation.y, lerp),
                                                  Mathf.SmoothStep(newWallRotation.z, currentWallRotation.z, lerp));
            yield return(null);
        }
        camera.localPosition    = currentWallPosition;
        camera.localEulerAngles = currentWallRotation;
        yield return(null);

        DebugHelper.Log("Finished");
        GameRoom.ToggleCamera(true);
    }
    public override IEnumerator BombCommanderBombEdgework(Bomb bomb, Match edgeworkMatch)
    {
        yield return(false);

        if (edgeworkMatch == null || !edgeworkMatch.Success)
        {
            yield break;
        }

        for (int i = 0; i < edgeworkMatch.Groups.Count; i++)
        {
            DebugHelper.Log($"edgeworkMatch.Groups[{i}].Value = {edgeworkMatch.Groups[i].Value}");
        }

        string edge = edgeworkMatch.Groups[1].Value.ToLowerInvariant().Trim();

        if (string.IsNullOrEmpty(edge))
        {
            edge = "all edges";
        }

        IEnumerator showEdgework = MiscellaneousMessageResponder.DropAllHoldables();

        while (showEdgework.MoveNext())
        {
            yield return(showEdgework.Current);
        }

        CurrentElevatorWall currentWall = _currentWall == CurrentElevatorWall.Dropped ? CurrentElevatorWall.Back : _currentWall;

        if (edge.EqualsAny("all edges", "l", "left"))
        {
            showEdgework = DoElevatorCameraRotate(_currentWall, CurrentElevatorWall.Left, 1, false, true);
            _currentWall = CurrentElevatorWall.Left;
            while (showEdgework.MoveNext())
            {
                yield return(showEdgework.Current);
            }
            yield return(new WaitForSeconds(3));
        }
        if (edge.EqualsAny("all edges", "b", "back"))
        {
            showEdgework = DoElevatorCameraRotate(_currentWall, CurrentElevatorWall.Back, 1, edge == "all edges", true);
            _currentWall = CurrentElevatorWall.Back;
            while (showEdgework.MoveNext())
            {
                yield return(showEdgework.Current);
            }
            yield return(new WaitForSeconds(3));
        }
        if (edge.EqualsAny("all edges", "r", "right"))
        {
            showEdgework = DoElevatorCameraRotate(_currentWall, CurrentElevatorWall.Right, 1, edge == "all edges", true);
            _currentWall = CurrentElevatorWall.Right;
            while (showEdgework.MoveNext())
            {
                yield return(showEdgework.Current);
            }
            yield return(new WaitForSeconds(3));
        }
        showEdgework = DoElevatorCameraRotate(_currentWall, currentWall, 1, true, false);
        _currentWall = currentWall;
        while (showEdgework.MoveNext())
        {
            yield return(showEdgework.Current);
        }
    }