package handlers import ( "fmt" "gralias/llmapi" "gralias/models" "html/template" "net/http" "strings" ) func HandleShowCreateForm(w http.ResponseWriter, r *http.Request) { show := true tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } if err := tmpl.ExecuteTemplate(w, "createform", show); err != nil { log.Error("failed to execute createform template", "error", err) } } func HandleHideCreateForm(w http.ResponseWriter, r *http.Request) { show := false tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } if err := tmpl.ExecuteTemplate(w, "createform", show); err != nil { log.Error("failed to execute createform template", "error", err) } } func HandleShowColor(w http.ResponseWriter, r *http.Request) { word := r.URL.Query().Get("word") ctx := r.Context() tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } fi, err := getFullInfoByCtx(ctx) if err != nil { abortWithError(w, err.Error()) return } if err := validateMove(fi, models.UserRoleGuesser); err != nil { abortWithError(w, err.Error()) return } color, exists := fi.Room.WCMap[word] log.Debug("got show-color request", "word", word, "color", color) if !exists { abortWithError(w, "word is not found") return } cardword := models.WordCard{ Word: word, Color: color, Revealed: true, } fi.Room.RevealSpecificWord(word) fi.Room.UpdateCounter() action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: string(color), Action: models.ActionTypeGuess, Word: word, } fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) // if opened card is of color of opp team, change turn oppositeColor := fi.Room.GetOppositeTeamColor() fi.Room.OpenedThisTurn++ if fi.Room.ThisTurnLimit > 0 { if fi.Room.ThisTurnLimit >= fi.Room.OpenedThisTurn { // end turn fi.Room.TeamTurn = oppositeColor fi.Room.MimeDone = false fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 } } switch string(color) { case "black": // game over fi.Room.IsRunning = false fi.Room.IsOver = true fi.Room.TeamWon = oppositeColor action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: models.WordColorBlack, Action: models.ActionTypeGameOver, } fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) case "white", string(oppositeColor): // end turn fi.Room.TeamTurn = oppositeColor fi.Room.MimeDone = false fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 // check if no cards left => game over if fi.Room.BlueCounter == 0 { // blue won fi.Room.IsRunning = false fi.Room.IsOver = true fi.Room.TeamWon = "blue" action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: models.WordColorBlue, Action: models.ActionTypeGameOver, } fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) } if fi.Room.RedCounter == 0 { // red won fi.Room.IsRunning = false fi.Room.IsOver = true fi.Room.TeamWon = "red" action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: models.WordColorRed, Action: models.ActionTypeGameOver, } fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) } } if err := saveFullInfo(fi); err != nil { abortWithError(w, err.Error()) return } // get mime bot for opp team and notify it notifyBotIfNeeded(fi) notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") if err := tmpl.ExecuteTemplate(w, "cardword", cardword); err != nil { log.Error("failed to execute cardword template", "error", err) } } func HandleMarkCard(w http.ResponseWriter, r *http.Request) { word := r.URL.Query().Get("word") ctx := r.Context() tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } fi, err := getFullInfoByCtx(ctx) if err != nil { abortWithError(w, err.Error()) return } if err := validateMove(fi, models.UserRoleGuesser); err != nil { abortWithError(w, err.Error()) return } color, exists := fi.Room.WCMap[word] log.Debug("got show-color request", "word", word, "color", color) if !exists { abortWithError(w, "word is not found") return } // check if card already was revealed for i, card := range fi.Room.Cards { if !strings.EqualFold(card.Word, word) { continue } if card.Revealed { abortWithError(w, "cannot mark already revealed") return } fi.Room.Cards[i].Mark = append(card.Mark, models.CardMark{ Username: fi.State.Username, Active: true, }) } cardword := models.WordCard{ Word: word, Color: color, Revealed: false, } fi.Room.RevealSpecificWord(word) fi.Room.UpdateCounter() action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: string(color), Action: models.ActionTypeGuess, Word: word, } fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) // if opened card is of color of opp team, change turn oppositeColor := fi.Room.GetOppositeTeamColor() fi.Room.OpenedThisTurn++ if fi.Room.ThisTurnLimit > 0 { if fi.Room.ThisTurnLimit >= fi.Room.OpenedThisTurn { // end turn fi.Room.TeamTurn = oppositeColor fi.Room.MimeDone = false fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 } } switch string(color) { case "black": // game over fi.Room.IsRunning = false fi.Room.IsOver = true fi.Room.TeamWon = oppositeColor action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: models.WordColorBlack, Action: models.ActionTypeGameOver, } fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) case "white", string(oppositeColor): // end turn fi.Room.TeamTurn = oppositeColor fi.Room.MimeDone = false fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 // check if no cards left => game over if fi.Room.BlueCounter == 0 { // blue won fi.Room.IsRunning = false fi.Room.IsOver = true fi.Room.TeamWon = "blue" action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: models.WordColorBlue, Action: models.ActionTypeGameOver, } fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) } if fi.Room.RedCounter == 0 { // red won fi.Room.IsRunning = false fi.Room.IsOver = true fi.Room.TeamWon = "red" action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: models.WordColorRed, Action: models.ActionTypeGameOver, } fi.Room.OpenedThisTurn = 0 fi.Room.ThisTurnLimit = 0 fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) } } if err := saveFullInfo(fi); err != nil { abortWithError(w, err.Error()) return } // get mime bot for opp team and notify it notifyBotIfNeeded(fi) notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") if err := tmpl.ExecuteTemplate(w, "cardword", cardword); err != nil { log.Error("failed to execute cardword template", "error", err) } } func HandleActionHistory(w http.ResponseWriter, r *http.Request) { fi, err := getFullInfoByCtx(r.Context()) if err != nil { abortWithError(w, err.Error()) return } tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } if err := tmpl.ExecuteTemplate(w, "actionhistory", fi.Room.ActionHistory); err != nil { log.Error("failed to execute actionhistory template", "error", err) } } func HandleAddBot(w http.ResponseWriter, r *http.Request) { // get team; // get role; make up a name team := r.URL.Query().Get("team") role := r.URL.Query().Get("role") log.Debug("got add-bot request", "team", team, "role", role) fi, err := getFullInfoByCtx(r.Context()) if err != nil { abortWithError(w, err.Error()) return } botname := fmt.Sprintf("bot_%d", len(llmapi.SignalChanMap)+1) // what if many rooms? _, err = llmapi.NewBot(role, team, botname, fi.Room.ID, cfg, false) if err != nil { abortWithError(w, err.Error()) return } // go bot.StartBot() notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") } func HandleRemoveBot(w http.ResponseWriter, r *http.Request) { botName := r.URL.Query().Get("bot") log.Debug("got remove-bot request", "bot_name", botName) fi, err := getFullInfoByCtx(r.Context()) if err != nil { abortWithError(w, err.Error()) return } if err := llmapi.RemoveBot(botName, fi.Room); err != nil { abortWithError(w, err.Error()) return } notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") }