339 lines
7.4 KiB
Go
339 lines
7.4 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"math/rand"
|
|
"time"
|
|
|
|
"git.sr.ht/~tslocum/netris/pkg/event"
|
|
"git.sr.ht/~tslocum/netris/pkg/game"
|
|
"git.sr.ht/~tslocum/netris/pkg/mino"
|
|
"github.com/rivo/tview"
|
|
)
|
|
|
|
var (
|
|
playerForm *tview.Form
|
|
|
|
titleVisible bool
|
|
titleScreen int
|
|
titleSelectedButton int
|
|
drawTitle = make(chan struct{}, game.CommandQueueSize)
|
|
|
|
buttonA *tview.Button
|
|
buttonB *tview.Button
|
|
buttonC *tview.Button
|
|
|
|
buttonLabelA *tview.TextView
|
|
buttonLabelB *tview.TextView
|
|
buttonLabelC *tview.TextView
|
|
|
|
titleMatrixL = newTitleMatrixSide()
|
|
titleMatrix = newTitleMatrixName()
|
|
titleMatrixR = newTitleMatrixSide()
|
|
titlePiecesL []*mino.Piece
|
|
titlePiecesR []*mino.Piece
|
|
)
|
|
|
|
func previousTitleButton() {
|
|
if titleSelectedButton == 0 {
|
|
return
|
|
}
|
|
|
|
titleSelectedButton--
|
|
}
|
|
|
|
func nextTitleButton() {
|
|
if titleSelectedButton == 2 {
|
|
return
|
|
}
|
|
|
|
titleSelectedButton++
|
|
}
|
|
|
|
func setTitleVisible(visible bool) {
|
|
if titleVisible == visible {
|
|
return
|
|
}
|
|
|
|
titleVisible = visible
|
|
|
|
if !titleVisible {
|
|
app.SetRoot(gameGrid, true)
|
|
|
|
app.SetFocus(nil)
|
|
} else {
|
|
titleScreen = 0
|
|
titleSelectedButton = 0
|
|
|
|
drawTitle <- struct{}{}
|
|
|
|
app.SetRoot(titleContainerGrid, true)
|
|
|
|
updateTitle()
|
|
}
|
|
}
|
|
|
|
func updateTitle() {
|
|
if titleScreen == 1 {
|
|
buttonA.SetLabel("Player Settings")
|
|
buttonLabelA.SetText("\nChange name")
|
|
|
|
buttonB.SetLabel("Game Settings")
|
|
buttonLabelB.SetText("\nChange keybindings")
|
|
|
|
buttonC.SetLabel("Return")
|
|
buttonLabelC.SetText("\nReturn to the last screen")
|
|
} else {
|
|
if joinedGame {
|
|
buttonA.SetLabel("Resume")
|
|
buttonLabelA.SetText("\nResume game in progress")
|
|
|
|
buttonB.SetLabel("Settings")
|
|
buttonLabelB.SetText("\nChange player name, keybindings, etc")
|
|
|
|
buttonC.SetLabel("Quit")
|
|
buttonLabelC.SetText("\nQuit game")
|
|
} else {
|
|
buttonA.SetLabel("Play")
|
|
buttonLabelA.SetText("\nPlay with others online")
|
|
|
|
buttonB.SetLabel("Practice")
|
|
buttonLabelB.SetText("\nPlay by yourself")
|
|
|
|
buttonC.SetLabel("Settings")
|
|
buttonLabelC.SetText("\nPlayer name, keybindings, etc.")
|
|
}
|
|
}
|
|
|
|
if titleScreen > 1 {
|
|
return
|
|
}
|
|
|
|
switch titleSelectedButton {
|
|
case 1:
|
|
app.SetFocus(buttonB)
|
|
case 2:
|
|
app.SetFocus(buttonC)
|
|
default:
|
|
app.SetFocus(buttonA)
|
|
}
|
|
}
|
|
|
|
func handleTitle() {
|
|
var t *time.Ticker
|
|
for {
|
|
if t == nil {
|
|
t = time.NewTicker(850 * time.Millisecond)
|
|
} else {
|
|
select {
|
|
case <-t.C:
|
|
case <-drawTitle:
|
|
if t != nil {
|
|
t.Stop()
|
|
}
|
|
|
|
t = time.NewTicker(850 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
if !titleVisible {
|
|
continue
|
|
}
|
|
|
|
titleMatrixL.ClearOverlay()
|
|
|
|
for _, p := range titlePiecesL {
|
|
p.Y -= 1
|
|
if p.Y < -3 {
|
|
p.Y = titleMatrixL.H + 2
|
|
}
|
|
if rand.Intn(4) == 0 {
|
|
p.Mino = p.Rotate(1, 0)
|
|
p.ApplyRotation(1, 0)
|
|
}
|
|
|
|
for _, m := range p.Mino {
|
|
titleMatrixL.SetBlock(p.X+m.X, p.Y+m.Y, p.Solid, true)
|
|
}
|
|
}
|
|
|
|
titleMatrixR.ClearOverlay()
|
|
|
|
for _, p := range titlePiecesR {
|
|
p.Y -= 1
|
|
if p.Y < -3 {
|
|
p.Y = titleMatrixL.H + 2
|
|
}
|
|
if rand.Intn(4) == 0 {
|
|
p.Mino = p.Rotate(1, 0)
|
|
p.ApplyRotation(1, 0)
|
|
}
|
|
|
|
for _, m := range p.Mino {
|
|
if titleMatrixR.Block(p.X+m.X, p.Y+m.Y) != mino.BlockNone {
|
|
continue
|
|
}
|
|
|
|
titleMatrixR.SetBlock(p.X+m.X, p.Y+m.Y, p.Solid, true)
|
|
}
|
|
}
|
|
|
|
app.QueueUpdateDraw(renderTitle)
|
|
}
|
|
}
|
|
|
|
func renderTitle() {
|
|
var newBlock mino.Block
|
|
for i, b := range titleMatrix.M {
|
|
switch b {
|
|
case mino.BlockSolidRed:
|
|
newBlock = mino.BlockSolidMagenta
|
|
case mino.BlockSolidYellow:
|
|
newBlock = mino.BlockSolidRed
|
|
case mino.BlockSolidGreen:
|
|
newBlock = mino.BlockSolidYellow
|
|
case mino.BlockSolidCyan:
|
|
newBlock = mino.BlockSolidGreen
|
|
case mino.BlockSolidBlue:
|
|
newBlock = mino.BlockSolidCyan
|
|
case mino.BlockSolidMagenta:
|
|
newBlock = mino.BlockSolidBlue
|
|
default:
|
|
continue
|
|
}
|
|
|
|
titleMatrix.M[i] = newBlock
|
|
}
|
|
|
|
titleName.Clear()
|
|
titleName.Write(renderMatrix(titleMatrix))
|
|
|
|
titleL.Clear()
|
|
titleL.Write(renderMatrix(titleMatrixL))
|
|
|
|
titleR.Clear()
|
|
titleR.Write(renderMatrix(titleMatrixR))
|
|
}
|
|
|
|
func newTitleMatrixSide() *mino.Matrix {
|
|
ev := make(chan interface{})
|
|
go func() {
|
|
for range ev {
|
|
}
|
|
}()
|
|
|
|
draw := make(chan event.DrawObject)
|
|
go func() {
|
|
for range draw {
|
|
}
|
|
}()
|
|
|
|
m := mino.NewMatrix(21, 24, 0, 1, ev, draw, mino.MatrixCustom)
|
|
|
|
return m
|
|
}
|
|
|
|
func newTitleMatrixName() *mino.Matrix {
|
|
ev := make(chan interface{})
|
|
go func() {
|
|
for range ev {
|
|
}
|
|
}()
|
|
|
|
draw := make(chan event.DrawObject)
|
|
go func() {
|
|
for range draw {
|
|
}
|
|
}()
|
|
|
|
m := mino.NewMatrix(36, 7, 0, 1, ev, draw, mino.MatrixCustom)
|
|
|
|
baseStart := 1
|
|
centerStart := (m.W / 2) - 17
|
|
|
|
var titleBlocks = []struct {
|
|
mino.Point
|
|
mino.Block
|
|
}{
|
|
// N
|
|
{mino.Point{0, 0}, mino.BlockSolidRed},
|
|
{mino.Point{0, 1}, mino.BlockSolidRed},
|
|
{mino.Point{0, 2}, mino.BlockSolidRed},
|
|
{mino.Point{0, 3}, mino.BlockSolidRed},
|
|
{mino.Point{0, 4}, mino.BlockSolidRed},
|
|
{mino.Point{1, 3}, mino.BlockSolidRed},
|
|
{mino.Point{2, 2}, mino.BlockSolidRed},
|
|
{mino.Point{3, 1}, mino.BlockSolidRed},
|
|
{mino.Point{4, 0}, mino.BlockSolidRed},
|
|
{mino.Point{4, 1}, mino.BlockSolidRed},
|
|
{mino.Point{4, 2}, mino.BlockSolidRed},
|
|
{mino.Point{4, 3}, mino.BlockSolidRed},
|
|
{mino.Point{4, 4}, mino.BlockSolidRed},
|
|
|
|
// E
|
|
{mino.Point{7, 0}, mino.BlockSolidYellow},
|
|
{mino.Point{7, 1}, mino.BlockSolidYellow},
|
|
{mino.Point{7, 2}, mino.BlockSolidYellow},
|
|
{mino.Point{7, 3}, mino.BlockSolidYellow},
|
|
{mino.Point{7, 4}, mino.BlockSolidYellow},
|
|
{mino.Point{8, 0}, mino.BlockSolidYellow},
|
|
{mino.Point{9, 0}, mino.BlockSolidYellow},
|
|
{mino.Point{8, 2}, mino.BlockSolidYellow},
|
|
{mino.Point{9, 2}, mino.BlockSolidYellow},
|
|
{mino.Point{8, 4}, mino.BlockSolidYellow},
|
|
{mino.Point{9, 4}, mino.BlockSolidYellow},
|
|
|
|
// T
|
|
{mino.Point{12, 4}, mino.BlockSolidGreen},
|
|
{mino.Point{13, 4}, mino.BlockSolidGreen},
|
|
{mino.Point{14, 0}, mino.BlockSolidGreen},
|
|
{mino.Point{14, 1}, mino.BlockSolidGreen},
|
|
{mino.Point{14, 2}, mino.BlockSolidGreen},
|
|
{mino.Point{14, 3}, mino.BlockSolidGreen},
|
|
{mino.Point{14, 4}, mino.BlockSolidGreen},
|
|
{mino.Point{15, 4}, mino.BlockSolidGreen},
|
|
{mino.Point{16, 4}, mino.BlockSolidGreen},
|
|
|
|
// R
|
|
{mino.Point{19, 0}, mino.BlockSolidCyan},
|
|
{mino.Point{19, 1}, mino.BlockSolidCyan},
|
|
{mino.Point{19, 2}, mino.BlockSolidCyan},
|
|
{mino.Point{19, 3}, mino.BlockSolidCyan},
|
|
{mino.Point{19, 4}, mino.BlockSolidCyan},
|
|
{mino.Point{20, 2}, mino.BlockSolidCyan},
|
|
{mino.Point{20, 4}, mino.BlockSolidCyan},
|
|
{mino.Point{21, 2}, mino.BlockSolidCyan},
|
|
{mino.Point{21, 4}, mino.BlockSolidCyan},
|
|
{mino.Point{22, 0}, mino.BlockSolidCyan},
|
|
{mino.Point{22, 1}, mino.BlockSolidCyan},
|
|
{mino.Point{22, 3}, mino.BlockSolidCyan},
|
|
|
|
// I
|
|
{mino.Point{25, 0}, mino.BlockSolidBlue},
|
|
{mino.Point{25, 1}, mino.BlockSolidBlue},
|
|
{mino.Point{25, 2}, mino.BlockSolidBlue},
|
|
{mino.Point{25, 3}, mino.BlockSolidBlue},
|
|
{mino.Point{25, 4}, mino.BlockSolidBlue},
|
|
|
|
// S
|
|
{mino.Point{28, 0}, mino.BlockSolidMagenta},
|
|
{mino.Point{29, 0}, mino.BlockSolidMagenta},
|
|
{mino.Point{30, 0}, mino.BlockSolidMagenta},
|
|
{mino.Point{31, 1}, mino.BlockSolidMagenta},
|
|
{mino.Point{29, 2}, mino.BlockSolidMagenta},
|
|
{mino.Point{30, 2}, mino.BlockSolidMagenta},
|
|
{mino.Point{28, 3}, mino.BlockSolidMagenta},
|
|
{mino.Point{29, 4}, mino.BlockSolidMagenta},
|
|
{mino.Point{30, 4}, mino.BlockSolidMagenta},
|
|
{mino.Point{31, 4}, mino.BlockSolidMagenta},
|
|
}
|
|
|
|
for _, titleBlock := range titleBlocks {
|
|
if !m.SetBlock(centerStart+titleBlock.X, baseStart+titleBlock.Y, titleBlock.Block, false) {
|
|
log.Fatalf("failed to set title block %s", titleBlock.Point)
|
|
}
|
|
}
|
|
|
|
return m
|
|
}
|