public VMEODTwoPersonJobObjectMazePlugin(VMEODServer server) : base(server)
        {
            GameState = VMEODTwoPersonJobObjectMazePluginStates.Waiting_For_Player;
            Rng       = new Random();

            // listeners
            BinaryHandlers["TSOMaze_Button_Click"] = CharismaButtonClickedHandler;
        }
        public override void Tick()
        {
            if (NextState != VMEODTwoPersonJobObjectMazePluginStates.Invalid)
            {
                var state = NextState;
                NextState = VMEODTwoPersonJobObjectMazePluginStates.Invalid;
                GotoState(state);
            }

            switch (GameState)
            {
            case VMEODTwoPersonJobObjectMazePluginStates.Waiting_For_Player:
            {
                // only send data to charisma player if logic player exists
                if (LogicPlayer != null)
                {
                    if (!LogicPlayerHasInit && MazeGenerated)
                    {
                        SendLogicPlayerData();
                    }
                    if (CharismaPlayer != null)
                    {
                        if (!CharismaPlayerHasInit && MazeGenerated)
                        {
                            SendCharismaPlayerData(true);
                        }

                        // failsafe, since both players are not null
                        EnqueueGotoState(VMEODTwoPersonJobObjectMazePluginStates.Ready);
                    }
                }
                break;
            }

            case VMEODTwoPersonJobObjectMazePluginStates.Ready:
            {
                if (MazeGenerated)
                {
                    if (LogicPlayerHasInit && CharismaPlayerHasInit)
                    {
                        if (CooldownTimer > 0)
                        {
                            if (++Tock >= 30)
                            {
                                CooldownTimer--;
                                Tock = 0;
                                BroadcastSharedEvent("TSOMaze_Update_Timer", BitConverter.GetBytes(CooldownTimer));
                            }
                        }
                        else
                        {
                            EnqueueGotoState(VMEODTwoPersonJobObjectMazePluginStates.Solving);
                        }
                    }
                    else
                    {
                        if (!LogicPlayerHasInit)
                        {
                            SendLogicPlayerData();
                        }
                        else
                        {
                            SendCharismaPlayerData(true);
                        }
                    }
                }
                else
                {
                    // should never happen, very bad things help
                    if (++Tock >= 30)
                    {
                        RoundTimeRemaining--;         // intially 6 seconds for the maze to finish generating and send
                        Tock = 0;
                    }
                    else         // better than they stand waiting forever
                    {
                        Server.Shutdown();
                    }
                }
                break;
            }

            case VMEODTwoPersonJobObjectMazePluginStates.Solving:
            {
                if (RoundTimeRemaining > 0)
                {
                    if (++Tock >= 30)
                    {
                        RoundTimeRemaining--;
                        Tock = 0;
                        BroadcastSharedEvent("TSOMaze_Update_Timer", BitConverter.GetBytes(RoundTimeRemaining));
                    }
                }
                else         // force loss
                {
                    EnqueueGotoState(VMEODTwoPersonJobObjectMazePluginStates.Reacting);
                }
                break;
            }

            case VMEODTwoPersonJobObjectMazePluginStates.Reacting:
            {
                if (RoundTimeRemaining > 0)
                {
                    if (++Tock >= 30)
                    {
                        RoundTimeRemaining--;
                        Tock = 0;
                    }
                }
                else
                {
                    EnqueueGotoState(VMEODTwoPersonJobObjectMazePluginStates.Waiting_For_Player);
                }
                break;
            }
            }
            base.Tick();
        }
        private void GotoState(VMEODTwoPersonJobObjectMazePluginStates state)
        {
            switch (state)
            {
            case VMEODTwoPersonJobObjectMazePluginStates.Waiting_For_Player:
            {
                Reset();         // get a maze
                GameState = state;
                BroadcastSharedEvent("TSOMaze_Show_Waiting", new byte[0]);
                break;
            }

            case VMEODTwoPersonJobObjectMazePluginStates.Ready:
            {
                Tock = 0;
                RoundTimeRemaining = ReactionSeconds;
                GameState          = state;
                break;
            }

            case VMEODTwoPersonJobObjectMazePluginStates.Solving:
            {
                Tock = 0;
                RoundTimeRemaining = RoundSeconds;
                GameState          = state;
                SendCharismaPlayerData(false);         // finally allow input
                break;
            }

            case VMEODTwoPersonJobObjectMazePluginStates.Reacting:
            {
                if (MazeSolved)
                {
                    Controller.SendOBJEvent(new VMEODEvent((short)VMEODTwoPersonObjectMazePluginEvents.Success));
                    BroadcastSharedEvent("TSOMaze_Show_Result", new byte[] { 1 });         // win dialog as UIAlert
                    // send the Logic Player the solution by sending (y,x) coords
                    List <byte> solutionCoords = new List <byte>();
                    // but send the cell color first
                    solutionCoords.Add((byte)ThisRoundOriginColor);
                    for (int index = 0; index < SolutionPath.Count - 1; index++)
                    {
                        solutionCoords.Add((byte)SolutionPath[index].Row);
                        solutionCoords.Add((byte)SolutionPath[index].Column);
                    }
                    if (LogicPlayer != null)
                    {
                        LogicPlayer.Send("TSOMaze_Draw_Solution", solutionCoords.ToArray());
                    }
                }
                else         // failed to solve
                {
                    Controller.SendOBJEvent(new VMEODEvent((short)VMEODTwoPersonObjectMazePluginEvents.Failure));
                    BroadcastSharedEvent("TSOMaze_Show_Result", new byte[] { 0 });         // loss dialog as UIAlert
                }
                Tock = 0;
                RoundTimeRemaining = ReactionSeconds;
                GameState          = state;
                break;
            }
            }
        }
 private void EnqueueGotoState(VMEODTwoPersonJobObjectMazePluginStates newState)
 {
     NextState = newState;
 }