Support joining private matches

This commit is contained in:
Trevor Slocum 2023-09-18 21:23:56 -07:00
parent 9266c363f2
commit 2a7fd00f41
5 changed files with 88 additions and 17 deletions

84
app.go
View File

@ -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))

View File

@ -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()

View File

@ -64,6 +64,8 @@ func (c *Client) Connect() {
go c.handleWrite()
c.handleRead()
l("*** Disconnected.")
}
func (c *Client) handleWrite() {

2
go.mod
View File

@ -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

4
go.sum
View File

@ -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=