// handle a Start message. We set a lock when someone clicks Start // to prevent race conditions. func handleStart(table channels.Realm, user string, wc WebolithCommunicator, sender channels.SocketMessageSender) { log.Println("[DEBUG] In handleStart....") sendFail := func(errorCode string) { sender.BroadcastMessage(table, FailMT, errorCode) } // XXX: Set a lock for this table on start. st := gameStates.getState(table) st.Lock() defer st.Unlock() if st.options == nil { // XXX: This should always be really quick but maybe once in a // while it'll fail; should prompt user to try again log.Println("[ERROR] Settings for this table do not yet exist!") sendFail(FailureSettingsDoNotExist) return } users.wantsToPlay(table, user) if !users.allowStart(table) { log.Println("[DEBUG] Start not yet allowed.") sendFail(FailureNotAllowed) return } if st.going != GameDone { log.Println("[DEBUG] This game is going or about to start.") sendFail(FailureGameGoing) return } st.going = GameInitializing wordList := getWordList(wc, st.options.WordListID) if wordList == nil { log.Println("[ERROR] Got nil word list, error!") sendFail(FailureNullWordList) return } st.setList(wordList) qToSend := st.nextQuestionSet(st.options.QuestionsToPull) // Turn the raw alphagrams into full question objects. fullQResponse, err := getFullQInfo(wc, qToSend, wordList.Lexicon) if err != nil { log.Println("[ERROR] Error getting full Q response!", err) sendFail(FailureQuestionInfo) return } log.Println("[DEBUG] Got full Q response:", string(fullQResponse)) countdown := time.NewTimer(time.Second * time.Duration(CountdownTime)) st.setCountdownTimer(countdown) st.going = GameCountingDown sender.BroadcastMessage(table, CountdownMT, strconv.Itoa(CountdownTime)) // Countdown before starting game. // We should not accept guesses until the game has started. go handleGameTimer(table, countdown, string(fullQResponse), sender) log.Println("[DEBUG] Leaving start, mutex should unlock.") }
func handleGuess(data string, table channels.Realm, user string, sender channels.SocketMessageSender) { if gameStates.getGameGoing(table) != GameStarted { log.Println("[DEBUG] Got a guess when game had not started.") return } answer := gameStates.guess(data, table, user) if answer == nil { return } // Otherwise, broadcast correct guess and score! msg, err := json.Marshal(answer) if err != nil { log.Println("[ERROR] Marshalling answer", answer, err) } sender.BroadcastMessage(table, ScoreMT, string(msg)) }
func handleGameTimer(table channels.Realm, countdown *time.Timer, questionsToSend string, sender channels.SocketMessageSender) { <-countdown.C log.Println("[DEBUG] Finished counting down! About to send qs...") st := gameStates.getState(table) st.Lock() defer st.Unlock() st.going = GameStarted sender.BroadcastMessage(table, QuestionsMT, questionsToSend) sender.BroadcastMessage(table, TimerMT, strconv.Itoa(st.options.TimerSecs)) // Start another nested goroutine here for game over. This looks // messy, but it seems easy enough to do. gameOver := time.NewTimer(time.Second * time.Duration(st.options.TimerSecs)) st.setGameTimer(gameOver) go func() { <-gameOver.C log.Println("[DEBUG] This game is over!") st := gameStates.getState(table) st.Lock() defer st.Unlock() st.going = GameDone sender.BroadcastMessage(table, GameOverMT, "") }() }