From 2a7fd00f41ac579ba38fa13eccc35eba218197a0 Mon Sep 17 00:00:00 2001 From: Trevor Slocum Date: Mon, 18 Sep 2023 21:23:56 -0700 Subject: [PATCH] Support joining private matches --- app.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++-------- board.go | 13 +++++++-- client.go | 2 ++ go.mod | 2 +- go.sum | 4 +-- 5 files changed, 88 insertions(+), 17 deletions(-) diff --git a/app.go b/app.go index 8b0cb98..ea6a964 100644 --- a/app.go +++ b/app.go @@ -35,6 +35,11 @@ var ( createGamePasswordField *cview.InputField createGameGrid *cview.Grid + joinGameForm *cview.Form + joinGameLabelField *cview.TextView + joinGamePasswordField *cview.InputField + joinGameGrid *cview.Grid + statusWriter *bufferWriter gameWriter *bufferWriter @@ -42,6 +47,10 @@ var ( inputMode bool screenWidth int + showJoinGameDialog bool + joinGameID int + joinGameName string + allGames []bgammon.GameListing autoRefresh = true showCreateGameDialog bool @@ -79,7 +88,7 @@ func logIn(c *Client) { updateFocus() hideCursor() - l(fmt.Sprintf("Connecting to %s...", c.address)) + l("*** Connecting...") go c.Connect() } @@ -115,7 +124,7 @@ func beforeFocus(p cview.Primitive) bool { } if viewScreen == ScreenLobby { - if showCreateGameDialog { + if showCreateGameDialog || showJoinGameDialog { return p != gameList && p != gameBuffer && p != statusBuffer && p != inputField } else if gameInProgress { return p == inputField @@ -141,6 +150,9 @@ func updateFocus() { } else if showCreateGameDialog { createGameForm.SetFocus(0) app.SetFocus(createGameForm) + } else if showJoinGameDialog { + joinGameForm.SetFocus(0) + app.SetFocus(joinGameForm) } else if gameInProgress { app.SetFocus(inputField) } else { @@ -169,6 +181,8 @@ func buildLayout() { if viewScreen == ScreenLobby { if showCreateGameDialog { currentScreen = createGameGrid + } else if showJoinGameDialog { + currentScreen = joinGameGrid } else if gameInProgress { currentScreen = confirmExit } else { @@ -322,6 +336,7 @@ func RunApp(c *Client, b *GameBoard) error { app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { handleCreateGameInput := viewScreen == ScreenLobby && showCreateGameDialog + handleJoinGameInput := viewScreen == ScreenLobby && showJoinGameDialog handleGameInput := viewScreen == ScreenGame && !inputMode && gameInProgress switch event.Key() { @@ -355,6 +370,14 @@ func RunApp(c *Client, b *GameBoard) error { acceptCreateGameDialog() } return nil + } else if handleJoinGameInput { + if app.GetFocus() == joinGameForm.GetButton(0) { + showJoinGameDialog = false + buildLayout() + } else { + board.client.Out <- []byte(fmt.Sprintf("j %d %s", joinGameID, joinGamePasswordField.GetText())) + } + return nil } else if handleGameInput { inputMode = true buildLayout() @@ -362,7 +385,13 @@ func RunApp(c *Client, b *GameBoard) error { } else { selected := gameList.GetCurrentItemIndex() if viewScreen == ScreenLobby && len(allGames) > 0 && selected >= 0 && selected < len(allGames) { - board.client.Out <- []byte(fmt.Sprintf("j %d", allGames[selected].ID)) + if allGames[selected].Password { + showJoinGameDialog = true + joinGameID = allGames[selected].ID + buildLayout() + } else { + board.client.Out <- []byte(fmt.Sprintf("j %d", allGames[selected].ID)) + } } return nil } @@ -372,6 +401,10 @@ func RunApp(c *Client, b *GameBoard) error { showCreateGameDialog = false buildLayout() return nil + } else if showJoinGameDialog { + showJoinGameDialog = false + buildLayout() + return nil } else if !gameInProgress { return nil } @@ -413,11 +446,11 @@ func RunApp(c *Client, b *GameBoard) error { if gameInProgress { switch event.Rune() { case 'r', 'R': - if board.Board.NeedRoll() { + if board.Board.MayRoll() { board.client.Out <- []byte("roll") } case 'k', 'K': - if board.Board.NeedOk() { + if board.Board.MayOK() { board.client.Out <- []byte("ok") } } @@ -459,7 +492,13 @@ func RunApp(c *Client, b *GameBoard) error { } // TODO prompt for password when required entry := allGames[i] - board.client.Out <- []byte(fmt.Sprintf("j %d", entry.ID)) + if entry.Password { + showJoinGameDialog = true + joinGameID = entry.ID + buildLayout() + } else { + board.client.Out <- []byte(fmt.Sprintf("j %d", entry.ID)) + } }) gameListHeader := cview.NewTextView() @@ -487,8 +526,8 @@ func RunApp(c *Client, b *GameBoard) error { }) createGameLabel := cview.NewTextView() - createGameLabel.SetText("[" + colorYellow + "]Create match[-]") createGameLabel.SetDynamicColors(true) + createGameLabel.SetText("[" + colorYellow + "]Create match[-]") publicOption := cview.NewDropDownOption("Public") publicOption.SetSelectedFunc(func(index int, option *cview.DropDownOption) { @@ -527,6 +566,28 @@ func RunApp(c *Client, b *GameBoard) error { createGameGrid.AddItem(cview.NewBox(), 1, 0, 1, 1, 0, 0, true) createGameGrid.AddItem(createGameForm, 1, 1, 1, 1, 0, 0, true) + joinGameLabelField = cview.NewTextView() + joinGameLabelField.SetDynamicColors(true) + joinGameLabelField.SetText("[" + colorYellow + "]Join match: " + cview.Escape(joinGameName) + "[-]") + + joinGameForm = cview.NewForm() + joinGameForm.AddPasswordField("Password", "", 10, '*', nil) + joinGameForm.AddButton("Cancel", func() { + showJoinGameDialog = false + buildLayout() + }) + joinGameForm.AddButton("Join", func() { + board.client.Out <- []byte(fmt.Sprintf("j %d %s", joinGameID, joinGamePasswordField.GetText())) + }) + joinGamePasswordField = joinGameForm.GetFormItem(0).(*cview.InputField) + + joinGameGrid = cview.NewGrid() + joinGameGrid.SetRows(1, -1) + joinGameGrid.SetColumns(1, -1) + joinGameGrid.AddItem(joinGameLabelField, 0, 0, 1, 2, 0, 0, false) + joinGameGrid.AddItem(cview.NewBox(), 1, 0, 1, 1, 0, 0, true) + joinGameGrid.AddItem(joinGameForm, 1, 1, 1, 1, 0, 0, true) + gameListGrid = cview.NewGrid() gameListGrid.SetRows(1, -1, 1) gameListGrid.AddItem(gameListHeader, 0, 0, 1, 1, 0, 0, false) @@ -589,7 +650,7 @@ func UpdateGameList(ev *bgammon.EventList) { } } - if viewScreen == ScreenLobby && !showCreateGameDialog { + if viewScreen == ScreenLobby && !showCreateGameDialog && !showJoinGameDialog { app.Draw() } } @@ -607,11 +668,11 @@ func HandleEvents(c *Client, b *GameBoard) { if ev.Clients == 1 { clientsPlural = "" } - gamesPlural := "s" + matchesPlural := "es" if ev.Games == 1 { - gamesPlural = "" + matchesPlural = "" } - l(fmt.Sprintf("Welcome, %s. There %s currently %d client%s playing %d game%s.", ev.PlayerName, areIs, ev.Clients, clientsPlural, ev.Games, gamesPlural)) + l(fmt.Sprintf("*** Welcome, %s. There %s %d client%s playing %d match%s.", ev.PlayerName, areIs, ev.Clients, clientsPlural, ev.Games, matchesPlural)) case *bgammon.EventHelp: l(fmt.Sprintf("Help: %s", ev.Message)) case *bgammon.EventPing: @@ -632,6 +693,7 @@ func HandleEvents(c *Client, b *GameBoard) { if ev.Player == c.Username { gameInProgress = true showCreateGameDialog = false + showJoinGameDialog = false setScreen(ScreenGame) } else { lg(fmt.Sprintf("%s joined the match.", ev.Player)) diff --git a/board.go b/board.go index d469132..6e37876 100644 --- a/board.go +++ b/board.go @@ -38,10 +38,17 @@ func NewGameBoard(client *Client) *GameBoard { func (b *GameBoard) Update() { b.TextView.SetBytes(b.Board.BoardState(b.Board.PlayerNumber)) - if b.Board.NeedRoll() { + if b.Board.MayRoll() { b.TextView.Write([]byte("\n[" + colorYellow + "][\"btnroll\"][ ROLL ][\"\"][-:-:-][\"dummy\"] [\"\"]")) - } else if b.Board.Turn != 0 && b.Board.Turn == b.Board.PlayerNumber { // Always show OK button when it is the user's turn. - b.TextView.Write([]byte("\n[" + colorYellow + "][\"btnok\"][ OK ][\"\"] [\"btnreset\"][ RESET ][\"\"][-:-:-][\"dummy\"] [\"\"]")) + } else { + b.TextView.Write([]byte("\n[" + colorYellow + "]")) + if b.Board.MayReset() { + b.TextView.Write([]byte("[\"btnreset\"][ RESET ][\"\"] ")) + } + if b.Board.MayOK() { + b.TextView.Write([]byte("[" + colorYellow + "][\"btnok\"][ OK ][\"\"] ")) + } + b.TextView.Write([]byte(`[-:-:-]["dummy"] [""]`)) } b.Highlight() app.Draw() diff --git a/client.go b/client.go index 863df79..f1f3616 100644 --- a/client.go +++ b/client.go @@ -64,6 +64,8 @@ func (c *Client) Connect() { go c.handleWrite() c.handleRead() + + l("*** Disconnected.") } func (c *Client) handleWrite() { diff --git a/go.mod b/go.mod index 8da949a..5178ef5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module code.rocket9labs.com/tslocum/bgammon-cli go 1.16 require ( - code.rocket9labs.com/tslocum/bgammon v0.0.0-20230913074653-cf99329267a8 + code.rocket9labs.com/tslocum/bgammon v0.0.0-20230919035705-1b65aae28720 code.rocketnine.space/tslocum/cview v1.5.9-0.20230912025026-d5de9a7b0a6c github.com/gdamore/tcell/v2 v2.6.0 github.com/mattn/go-runewidth v0.0.15 // indirect diff --git a/go.sum b/go.sum index 59cc029..69b3ded 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -code.rocket9labs.com/tslocum/bgammon v0.0.0-20230913074653-cf99329267a8 h1:wdSojaTDI9adSY/4exRCTwaon8BOLecQBSmvb5S4r7Q= -code.rocket9labs.com/tslocum/bgammon v0.0.0-20230913074653-cf99329267a8/go.mod h1:LS/m5Zq7/93dP8XJrLkL1T5ZTwtddkN8X9TyRrrdCkQ= +code.rocket9labs.com/tslocum/bgammon v0.0.0-20230919035705-1b65aae28720 h1:KP9x6iRfZY1KnfgdITlhpewFKKnEzYi6sNJtgaWhgj8= +code.rocket9labs.com/tslocum/bgammon v0.0.0-20230919035705-1b65aae28720/go.mod h1:LS/m5Zq7/93dP8XJrLkL1T5ZTwtddkN8X9TyRrrdCkQ= code.rocketnine.space/tslocum/cbind v0.1.5 h1:i6NkeLLNPNMS4NWNi3302Ay3zSU6MrqOT+yJskiodxE= code.rocketnine.space/tslocum/cbind v0.1.5/go.mod h1:LtfqJTzM7qhg88nAvNhx+VnTjZ0SXBJtxBObbfBWo/M= code.rocketnine.space/tslocum/cview v1.5.9-0.20230912025026-d5de9a7b0a6c h1:6PkEnjl48DmwEgGibnOTi7tZGT66HTijiLSitu4eCh8=