parent
7642fe6d0d
commit
64ca68b4ee
5 changed files with 177 additions and 24 deletions
|
@ -1,5 +1,6 @@
|
|||
1.2.4:
|
||||
- Play forced moves automatically
|
||||
- Support advanced checker movement
|
||||
|
||||
1.2.3:
|
||||
- Fix replaying tabula games
|
||||
|
|
169
game/board.go
169
game/board.go
|
@ -43,11 +43,12 @@ type board struct {
|
|||
spaceRects [][4]int
|
||||
spaceSprites [][]*Sprite // Space contents
|
||||
|
||||
dragging *Sprite
|
||||
draggingSpace int8
|
||||
draggingClick bool // Drag started with mouse click
|
||||
lastDragClick time.Time
|
||||
moving *Sprite // Moving automatically
|
||||
dragging *Sprite
|
||||
draggingSpace int8
|
||||
draggingClick bool // Drag started with mouse click
|
||||
draggingRightClick bool // Movement started with right mouse click
|
||||
lastDragClick time.Time
|
||||
moving *Sprite // Moving automatically
|
||||
|
||||
touchIDs []ebiten.TouchID
|
||||
|
||||
|
@ -113,12 +114,13 @@ type board struct {
|
|||
changePasswordNew *etk.Input
|
||||
changePasswordGrid *etk.Grid
|
||||
|
||||
highlightCheckbox *etk.Checkbox
|
||||
showPipCountCheckbox *etk.Checkbox
|
||||
showMovesCheckbox *etk.Checkbox
|
||||
flipBoardCheckbox *etk.Checkbox
|
||||
accountGrid *etk.Grid
|
||||
settingsGrid *etk.Grid
|
||||
highlightCheckbox *etk.Checkbox
|
||||
showPipCountCheckbox *etk.Checkbox
|
||||
showMovesCheckbox *etk.Checkbox
|
||||
flipBoardCheckbox *etk.Checkbox
|
||||
advancedMovementCheckbox *etk.Checkbox
|
||||
accountGrid *etk.Grid
|
||||
settingsGrid *etk.Grid
|
||||
|
||||
matchStatusGrid *etk.Grid
|
||||
|
||||
|
@ -148,6 +150,7 @@ type board struct {
|
|||
showPipCount bool
|
||||
showMoves bool
|
||||
flipBoard bool
|
||||
advancedMovement bool
|
||||
|
||||
widget *BoardWidget
|
||||
|
||||
|
@ -365,6 +368,20 @@ func NewBoard() *board {
|
|||
}
|
||||
flipBoardLabel.SetVertical(messeji.AlignCenter)
|
||||
|
||||
b.advancedMovementCheckbox = etk.NewCheckbox(b.toggleAdvancedMovementCheckbox)
|
||||
b.advancedMovementCheckbox.SetBorderColor(triangleA)
|
||||
b.advancedMovementCheckbox.SetCheckColor(triangleA)
|
||||
b.advancedMovementCheckbox.SetSelected(b.advancedMovement)
|
||||
|
||||
advancedMovementLabel := &ClickableText{
|
||||
Text: etk.NewText(gotext.Get("Advanced movement")),
|
||||
onSelected: func() {
|
||||
b.advancedMovementCheckbox.SetSelected(!b.advancedMovementCheckbox.Selected())
|
||||
b.toggleAdvancedMovementCheckbox()
|
||||
},
|
||||
}
|
||||
advancedMovementLabel.SetVertical(messeji.AlignCenter)
|
||||
|
||||
accountLabel := etk.NewText(gotext.Get("Account"))
|
||||
accountLabel.SetVertical(messeji.AlignCenter)
|
||||
|
||||
|
@ -372,7 +389,7 @@ func NewBoard() *board {
|
|||
|
||||
checkboxGrid := etk.NewGrid()
|
||||
checkboxGrid.SetColumnSizes(72, 20, -1)
|
||||
checkboxGrid.SetRowSizes(-1, 20, -1, 20, -1, 20, -1, 20, -1)
|
||||
checkboxGrid.SetRowSizes(-1, 20, -1, 20, -1, 20, -1, 20, -1, 20, -1)
|
||||
checkboxGrid.AddChildAt(b.highlightCheckbox, 0, 0, 1, 1)
|
||||
checkboxGrid.AddChildAt(highlightLabel, 2, 0, 1, 1)
|
||||
checkboxGrid.AddChildAt(b.showPipCountCheckbox, 0, 2, 1, 1)
|
||||
|
@ -381,16 +398,26 @@ func NewBoard() *board {
|
|||
checkboxGrid.AddChildAt(movesLabel, 2, 4, 1, 1)
|
||||
checkboxGrid.AddChildAt(b.flipBoardCheckbox, 0, 6, 1, 1)
|
||||
checkboxGrid.AddChildAt(flipBoardLabel, 2, 6, 1, 1)
|
||||
gridY := 8
|
||||
if !AutoEnableTouchInput {
|
||||
checkboxGrid.AddChildAt(b.advancedMovementCheckbox, 0, 8, 1, 1)
|
||||
checkboxGrid.AddChildAt(advancedMovementLabel, 2, 8, 1, 1)
|
||||
gridY += 2
|
||||
}
|
||||
{
|
||||
grid := etk.NewGrid()
|
||||
grid.AddChildAt(accountLabel, 0, 0, 1, 1)
|
||||
grid.AddChildAt(b.accountGrid, 1, 0, 2, 1)
|
||||
checkboxGrid.AddChildAt(grid, 0, 8, 3, 1)
|
||||
checkboxGrid.AddChildAt(grid, 0, gridY, 3, 1)
|
||||
}
|
||||
|
||||
gridSize := 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + 72
|
||||
if !AutoEnableTouchInput {
|
||||
gridSize += 20 + 72
|
||||
}
|
||||
b.settingsGrid.SetBackground(color.RGBA{40, 24, 9, 255})
|
||||
b.settingsGrid.SetColumnSizes(20, -1, -1, 20)
|
||||
b.settingsGrid.SetRowSizes(72, 72+20+72+20+72+20+72+20+72, 20, -1)
|
||||
b.settingsGrid.SetRowSizes(72, gridSize, 20, -1)
|
||||
b.settingsGrid.AddChildAt(settingsLabel, 1, 0, 2, 1)
|
||||
b.settingsGrid.AddChildAt(checkboxGrid, 1, 1, 2, 1)
|
||||
b.settingsGrid.AddChildAt(etk.NewBox(), 1, 2, 1, 1)
|
||||
|
@ -1107,6 +1134,17 @@ func (b *board) toggleFlipBoardCheckbox() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *board) toggleAdvancedMovementCheckbox() error {
|
||||
b.advancedMovement = b.advancedMovementCheckbox.Selected()
|
||||
|
||||
advancedMovement := 0
|
||||
if b.advancedMovement {
|
||||
advancedMovement = 1
|
||||
}
|
||||
b.Client.Out <- []byte(fmt.Sprintf("set advanced %d", advancedMovement))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *board) newSprite(white bool) *Sprite {
|
||||
s := &Sprite{}
|
||||
s.colorWhite = white
|
||||
|
@ -2669,6 +2707,81 @@ func NewBoardWidget() *BoardWidget {
|
|||
}
|
||||
}
|
||||
|
||||
func (bw *BoardWidget) finishClick(cursor image.Point, double bool) {
|
||||
if game.Board.draggingSpace == -1 || len(game.Board.gameState.Available) == 0 {
|
||||
return
|
||||
}
|
||||
rolls := game.Board.gameState.DiceRolls()
|
||||
if len(rolls) == 0 {
|
||||
return
|
||||
}
|
||||
space := game.Board.spaceAt(cursor.X, cursor.Y)
|
||||
if space == -1 || space != game.Board.draggingSpace {
|
||||
return
|
||||
} else if !double {
|
||||
lowest := int8(math.MaxInt8)
|
||||
highest := int8(math.MinInt8)
|
||||
for _, roll := range rolls {
|
||||
if roll < lowest {
|
||||
lowest = roll
|
||||
}
|
||||
if roll > highest {
|
||||
highest = roll
|
||||
}
|
||||
}
|
||||
var roll int8
|
||||
if game.Board.draggingRightClick {
|
||||
roll = lowest
|
||||
} else {
|
||||
roll = highest
|
||||
}
|
||||
var useMove []int8
|
||||
for _, move := range game.Board.gameState.Available {
|
||||
if move[0] != space {
|
||||
continue
|
||||
}
|
||||
diff := bgammon.SpaceDiff(move[0], move[1], game.Board.gameState.Variant)
|
||||
haveRoll := diff == roll && game.Board.gameState.Game.HaveDiceRoll(move[0], move[1]) > 0
|
||||
if !haveRoll && (move[1] == bgammon.SpaceHomePlayer || move[1] == bgammon.SpaceHomeOpponent) {
|
||||
haveRoll = diff <= roll && game.Board.gameState.Game.HaveBearOffDiceRoll(diff) > 0
|
||||
}
|
||||
if haveRoll {
|
||||
useMove = move
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(useMove) == 0 {
|
||||
return
|
||||
}
|
||||
game.Client.Out <- []byte(fmt.Sprintf("mv %d/%d", useMove[0], useMove[1]))
|
||||
return
|
||||
}
|
||||
|
||||
var useMoves [][]int8
|
||||
FINDMOVE:
|
||||
for _, move := range game.Board.gameState.Available {
|
||||
expanded := expandMoves([][]int8{{move[0], space}})
|
||||
for _, m := range expanded {
|
||||
diff := bgammon.SpaceDiff(m[0], m[1], game.Board.gameState.Variant)
|
||||
haveRoll := game.Board.gameState.Game.HaveDiceRoll(m[0], m[1]) > 0
|
||||
if !haveRoll && (m[1] == bgammon.SpaceHomePlayer || m[1] == bgammon.SpaceHomeOpponent) {
|
||||
haveRoll = game.Board.gameState.Game.HaveBearOffDiceRoll(diff) > 0
|
||||
}
|
||||
if !haveRoll {
|
||||
continue FINDMOVE
|
||||
}
|
||||
}
|
||||
useMoves = expanded
|
||||
break
|
||||
}
|
||||
if len(useMoves) == 0 {
|
||||
return
|
||||
}
|
||||
for _, move := range useMoves {
|
||||
game.Client.Out <- []byte(fmt.Sprintf("mv %d/%d", move[0], move[1]))
|
||||
}
|
||||
}
|
||||
|
||||
func (bw *BoardWidget) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
|
||||
if !pressed && !clicked && game.Board.dragging == nil {
|
||||
return false, nil
|
||||
|
@ -2682,6 +2795,34 @@ func (bw *BoardWidget) HandleMouse(cursor image.Point, pressed bool, clicked boo
|
|||
cx, cy := cursor.X, cursor.Y
|
||||
|
||||
if b.dragging == nil {
|
||||
if b.advancedMovement && clicked {
|
||||
const doubleClickDuration = 250 * time.Millisecond
|
||||
space := b.spaceAt(cx, cy)
|
||||
if space != -1 {
|
||||
if time.Since(b.lastDragClick) >= doubleClickDuration {
|
||||
setTime := time.Now()
|
||||
b.draggingSpace = space
|
||||
b.draggingRightClick = ebiten.IsMouseButtonPressed(ebiten.MouseButtonRight)
|
||||
b.lastDragClick = setTime
|
||||
go func() {
|
||||
time.Sleep(doubleClickDuration)
|
||||
game.Lock()
|
||||
defer game.Unlock()
|
||||
if !b.lastDragClick.Equal(setTime) {
|
||||
return
|
||||
}
|
||||
bw.finishClick(cursor, false)
|
||||
b.lastDragClick = time.Now()
|
||||
}()
|
||||
return true, nil
|
||||
}
|
||||
bw.finishClick(cursor, true)
|
||||
b.lastDragClick = time.Now()
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// TODO allow grabbing multiple pieces by grabbing further down the stack
|
||||
if !handled && b.playerTurn() && clicked && (b.lastDragClick.IsZero() || time.Since(b.lastDragClick) >= 50*time.Millisecond) {
|
||||
s, space := b.spriteAt(cx, cy)
|
||||
|
|
13
game/game.go
13
game/game.go
|
@ -1444,7 +1444,14 @@ func (g *Game) handleEvent(e interface{}) {
|
|||
case *bgammon.EventMoved:
|
||||
lg(gotext.Get("%s moved %s", ev.Player, bgammon.FormatMoves(ev.Moves)))
|
||||
if ev.Player == g.Client.Username && !g.Board.gameState.Spectating && !g.Board.gameState.Forced {
|
||||
return
|
||||
var delta int8
|
||||
for _, move := range ev.Moves {
|
||||
delta = move[1] - move[0]
|
||||
break
|
||||
}
|
||||
if (delta < 0) == (g.Board.gameState.Variant == bgammon.VariantTabula) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
g.Board.Lock()
|
||||
|
@ -1492,6 +1499,10 @@ func (g *Game) handleEvent(e interface{}) {
|
|||
b.showMovesCheckbox.SetSelected(b.showMoves)
|
||||
b.flipBoard = ev.Flip
|
||||
b.flipBoardCheckbox.SetSelected(b.flipBoard)
|
||||
if !AutoEnableTouchInput {
|
||||
b.advancedMovement = ev.Advanced
|
||||
b.advancedMovementCheckbox.SetSelected(b.advancedMovement)
|
||||
}
|
||||
if g.needLayoutBoard {
|
||||
g.layoutBoard()
|
||||
}
|
||||
|
|
6
go.mod
6
go.mod
|
@ -3,9 +3,9 @@ module code.rocket9labs.com/tslocum/boxcars
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
code.rocket9labs.com/tslocum/bgammon v0.0.0-20240111071346-3eb433e57356
|
||||
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240111071420-cf312f82fe00
|
||||
code.rocket9labs.com/tslocum/etk v0.0.0-20240110043858-127665c19898
|
||||
code.rocket9labs.com/tslocum/bgammon v0.0.0-20240111193402-262ad93e51c2
|
||||
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240111193502-f01ac821f8ba
|
||||
code.rocket9labs.com/tslocum/etk v0.0.0-20240111201928-bde57bc0aca8
|
||||
code.rocket9labs.com/tslocum/tabula v0.0.0-20240108183445-695ea428ae21
|
||||
code.rocketnine.space/tslocum/kibodo v1.0.3-0.20240110043547-31f31eb07497
|
||||
code.rocketnine.space/tslocum/messeji v1.0.6-0.20240109205105-4ffeffdd2441
|
||||
|
|
12
go.sum
12
go.sum
|
@ -1,11 +1,11 @@
|
|||
code.rocket9labs.com/tslocum/bei v0.0.0-20240108012722-6db380cc190b h1:Y0a14Kf/hSYepSmp4ZfDeE4CZZGBGBS97CNjCbKJm0c=
|
||||
code.rocket9labs.com/tslocum/bei v0.0.0-20240108012722-6db380cc190b/go.mod h1:tS60/VNAJphKvDBkSLQhKALa15msIAuWWfEKNc4oFZc=
|
||||
code.rocket9labs.com/tslocum/bgammon v0.0.0-20240111071346-3eb433e57356 h1:7D4HYPNbhugFbnRgACpvbAzzzElY9McrDsGyMnzLz6M=
|
||||
code.rocket9labs.com/tslocum/bgammon v0.0.0-20240111071346-3eb433e57356/go.mod h1:65vhSKgeQb6ccjUm5NJlbBdwuAH3VSFoSApZ/aVG3+4=
|
||||
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240111071420-cf312f82fe00 h1:bfEFJAS+nWLzqjvwcyJIdl1ZzClpSShOEXiIyhuiY20=
|
||||
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240111071420-cf312f82fe00/go.mod h1:+QuJeLxK5sWeQZnLxxjLmF0rBNY89R1PHXDgSUXu9mk=
|
||||
code.rocket9labs.com/tslocum/etk v0.0.0-20240110043858-127665c19898 h1:DfKN6JwNQPxDbt5KpXtqNr64gFRfgJ37Lv6lY7YWuWM=
|
||||
code.rocket9labs.com/tslocum/etk v0.0.0-20240110043858-127665c19898/go.mod h1:ZZDAzxFb3FzgluVsKLlh9wfE/0VcO0nmwkRB8lrxgwA=
|
||||
code.rocket9labs.com/tslocum/bgammon v0.0.0-20240111193402-262ad93e51c2 h1:H51VlgdBfZbqnRCqjgBY5WLSs2FeUVznBGZahrfU90M=
|
||||
code.rocket9labs.com/tslocum/bgammon v0.0.0-20240111193402-262ad93e51c2/go.mod h1:65vhSKgeQb6ccjUm5NJlbBdwuAH3VSFoSApZ/aVG3+4=
|
||||
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240111193502-f01ac821f8ba h1:9KpLZT8DAOV0Uk5rJZfNVdfn3MTGBM8gy3MEx3qM8aY=
|
||||
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240111193502-f01ac821f8ba/go.mod h1:ZzucsodM8kqL3y3GYzDYrEUNrDlLlzMux7WVmJ06ZBI=
|
||||
code.rocket9labs.com/tslocum/etk v0.0.0-20240111201928-bde57bc0aca8 h1:5Qu0E2FEAuxi15hp6MQgRYttBJbNN1LhtiGRVros1qY=
|
||||
code.rocket9labs.com/tslocum/etk v0.0.0-20240111201928-bde57bc0aca8/go.mod h1:RrN0szXD27BMmCX63/t9SbD1CYDHXaf72y8IozXSzyg=
|
||||
code.rocket9labs.com/tslocum/tabula v0.0.0-20240108183445-695ea428ae21 h1:1VG88tdhCSVv7wGoIKQe8A8KfBXJsdz5pDsyP4ymDwk=
|
||||
code.rocket9labs.com/tslocum/tabula v0.0.0-20240108183445-695ea428ae21/go.mod h1:WEJXESKXqrMFLAArikQ79lpRibNeeE1C0VruxXYMF5M=
|
||||
code.rocketnine.space/tslocum/kibodo v1.0.3-0.20240110043547-31f31eb07497 h1:QpzLvcDV7DsaeFKrQZcHkDfq1PqsHcwUVnRXRKBAxe0=
|
||||
|
|
Loading…
Reference in a new issue