Add custom color support

This commit is contained in:
Trevor Slocum 2020-03-07 06:59:55 -08:00
parent d09c858f71
commit 6a9e65717d
11 changed files with 239 additions and 155 deletions

View file

@ -1,3 +1,6 @@
0.1.8:
- Add custom color support
0.1.7:
- Spawn pieces within view

View file

@ -5,17 +5,24 @@ import (
"io/ioutil"
"os"
"path"
"regexp"
"gitlab.com/tslocum/netris/pkg/event"
"gopkg.in/yaml.v2"
)
type appConfig struct {
Input map[event.GameAction][]string // Keybinds
Name string
Input map[event.GameAction][]string // Keybinds
Colors map[event.GameColor]string
Name string
}
var config = &appConfig{}
var config = &appConfig{
Input: make(map[event.GameAction][]string),
Colors: make(map[event.GameColor]string),
}
var regexpColor = regexp.MustCompile(`^#([0-9a-f]{3}|[0-9a-f]{6})$`)
func defaultConfigPath() string {
homedir, err := os.UserHomeDir()

View file

@ -72,16 +72,30 @@ var (
const DefaultStatusText = "Press Enter to chat, Z/X to rotate, arrow keys or HJKL to move/drop"
var (
renderHLine = []byte("[-:#444444] [-:-]")
renderVLine = []byte("[-:#444444] [-:-]")
renderLTee = []byte("[-:#444444] [-:-]")
renderRTee = []byte("[-:#444444] [-:-]")
renderULCorner = []byte("[-:#444444] [-:-]")
renderURCorner = []byte("[-:#444444] [-:-]")
renderLLCorner = []byte("[-:#444444] [-:-]")
renderLRCorner = []byte("[-:#444444] [-:-]")
renderHLine []byte
renderVLine []byte
renderLTee []byte
renderRTee []byte
renderULCorner []byte
renderURCorner []byte
renderLLCorner []byte
renderLRCorner []byte
)
func setBorderColor(color string) {
singleChar := []byte(fmt.Sprintf("[-:%s] [-:-]", color))
doubleChar := []byte(fmt.Sprintf("[-:%s] [-:-]", color))
renderHLine = singleChar
renderVLine = doubleChar
renderLTee = singleChar
renderRTee = singleChar
renderULCorner = doubleChar
renderURCorner = doubleChar
renderLLCorner = doubleChar
renderLRCorner = doubleChar
}
func resetPlayerSettingsForm() {
playerSettingsNameInput.SetText(nickname)
}

View file

@ -545,76 +545,76 @@ func newTitleMatrixName() *mino.Matrix {
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},
{mino.Point{0, 0}, mino.BlockSolidZ},
{mino.Point{0, 1}, mino.BlockSolidZ},
{mino.Point{0, 2}, mino.BlockSolidZ},
{mino.Point{0, 3}, mino.BlockSolidZ},
{mino.Point{0, 4}, mino.BlockSolidZ},
{mino.Point{1, 3}, mino.BlockSolidZ},
{mino.Point{2, 2}, mino.BlockSolidZ},
{mino.Point{3, 1}, mino.BlockSolidZ},
{mino.Point{4, 0}, mino.BlockSolidZ},
{mino.Point{4, 1}, mino.BlockSolidZ},
{mino.Point{4, 2}, mino.BlockSolidZ},
{mino.Point{4, 3}, mino.BlockSolidZ},
{mino.Point{4, 4}, mino.BlockSolidZ},
// 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},
{mino.Point{7, 0}, mino.BlockSolidO},
{mino.Point{7, 1}, mino.BlockSolidO},
{mino.Point{7, 2}, mino.BlockSolidO},
{mino.Point{7, 3}, mino.BlockSolidO},
{mino.Point{7, 4}, mino.BlockSolidO},
{mino.Point{8, 0}, mino.BlockSolidO},
{mino.Point{9, 0}, mino.BlockSolidO},
{mino.Point{8, 2}, mino.BlockSolidO},
{mino.Point{9, 2}, mino.BlockSolidO},
{mino.Point{8, 4}, mino.BlockSolidO},
{mino.Point{9, 4}, mino.BlockSolidO},
// 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},
{mino.Point{12, 4}, mino.BlockSolidS},
{mino.Point{13, 4}, mino.BlockSolidS},
{mino.Point{14, 0}, mino.BlockSolidS},
{mino.Point{14, 1}, mino.BlockSolidS},
{mino.Point{14, 2}, mino.BlockSolidS},
{mino.Point{14, 3}, mino.BlockSolidS},
{mino.Point{14, 4}, mino.BlockSolidS},
{mino.Point{15, 4}, mino.BlockSolidS},
{mino.Point{16, 4}, mino.BlockSolidS},
// 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},
{mino.Point{19, 0}, mino.BlockSolidI},
{mino.Point{19, 1}, mino.BlockSolidI},
{mino.Point{19, 2}, mino.BlockSolidI},
{mino.Point{19, 3}, mino.BlockSolidI},
{mino.Point{19, 4}, mino.BlockSolidI},
{mino.Point{20, 2}, mino.BlockSolidI},
{mino.Point{20, 4}, mino.BlockSolidI},
{mino.Point{21, 2}, mino.BlockSolidI},
{mino.Point{21, 4}, mino.BlockSolidI},
{mino.Point{22, 0}, mino.BlockSolidI},
{mino.Point{22, 1}, mino.BlockSolidI},
{mino.Point{22, 3}, mino.BlockSolidI},
// 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},
{mino.Point{25, 0}, mino.BlockSolidJ},
{mino.Point{25, 1}, mino.BlockSolidJ},
{mino.Point{25, 2}, mino.BlockSolidJ},
{mino.Point{25, 3}, mino.BlockSolidJ},
{mino.Point{25, 4}, mino.BlockSolidJ},
// 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},
{mino.Point{28, 0}, mino.BlockSolidT},
{mino.Point{29, 0}, mino.BlockSolidT},
{mino.Point{30, 0}, mino.BlockSolidT},
{mino.Point{31, 1}, mino.BlockSolidT},
{mino.Point{29, 2}, mino.BlockSolidT},
{mino.Point{30, 2}, mino.BlockSolidT},
{mino.Point{28, 3}, mino.BlockSolidT},
{mino.Point{29, 4}, mino.BlockSolidT},
{mino.Point{30, 4}, mino.BlockSolidT},
{mino.Point{31, 4}, mino.BlockSolidT},
}
for _, titleBlock := range titleBlocks {

View file

@ -479,18 +479,18 @@ 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
case mino.BlockSolidZ:
newBlock = mino.BlockSolidT
case mino.BlockSolidO:
newBlock = mino.BlockSolidZ
case mino.BlockSolidS:
newBlock = mino.BlockSolidO
case mino.BlockSolidI:
newBlock = mino.BlockSolidS
case mino.BlockSolidJ:
newBlock = mino.BlockSolidI
case mino.BlockSolidT:
newBlock = mino.BlockSolidJ
default:
continue
}

View file

@ -123,6 +123,22 @@ func main() {
log.Fatalf("failed to set keybinds: %s", err)
}
for gameColor, defaultColor := range event.DefaultColors {
currentValue := strings.ToLower(config.Colors[gameColor])
if currentValue == "" {
currentValue = defaultColor
} else if !regexpColor.MatchString(currentValue) {
log.Fatalf("failed to set colors: invalid color provided for piece %s: %s", gameColor, currentValue)
}
config.Colors[gameColor] = currentValue
blockColor := mino.ColorToBlock[gameColor]
if blockColor > 0 {
mino.Colors[blockColor] = []byte(currentValue)
}
}
setBorderColor(config.Colors[event.GameColorBorder])
if nicknameFlag != "" && game.Nickname(nicknameFlag) != "" {
nickname = game.Nickname(nicknameFlag)
} else if config.Name != "" && game.Nickname(config.Name) != "" {

41
pkg/event/color.go Normal file
View file

@ -0,0 +1,41 @@
package event
type GameColor string
const (
GameColorI = "i"
GameColorO = "o"
GameColorT = "t"
GameColorJ = "j"
GameColorL = "l"
GameColorS = "s"
GameColorZ = "z"
GameColorIGhost = "i-ghost"
GameColorOGhost = "o-ghost"
GameColorTGhost = "t-ghost"
GameColorJGhost = "j-ghost"
GameColorLGhost = "l-ghost"
GameColorSGhost = "s-ghost"
GameColorZGhost = "z-ghost"
GameColorGarbage = "garbage"
GameColorBorder = "border"
)
var DefaultColors = map[GameColor]string{
GameColorJ: "#2864ff",
GameColorI: "#00eeee",
GameColorZ: "#ee0000",
GameColorO: "#dddd00",
GameColorT: "#c000cc",
GameColorS: "#00e900",
GameColorL: "#ff7308",
GameColorJGhost: "#6e7bc3",
GameColorIGhost: "#6bbaba",
GameColorZGhost: "#ba6b6b",
GameColorOGhost: "#b1b16b",
GameColorTGhost: "#a16ba8",
GameColorSGhost: "#6bb76b",
GameColorLGhost: "#c3806c",
GameColorGarbage: "#999999",
GameColorBorder: "#444444",
}

View file

@ -1,25 +1,10 @@
package mino
import "gitlab.com/tslocum/netris/pkg/event"
// Dark color ghosts are 60% original overlaid #777777
// Light color ghosts are 40% original overlaid #888888
var Colors = [][]byte{
BlockNone: []byte("#000000"),
BlockGarbage: []byte("#999999"),
BlockGhostBlue: []byte("#6e7bc3"),
BlockGhostCyan: []byte("#6bbaba"),
BlockGhostRed: []byte("#ba6b6b"),
BlockGhostYellow: []byte("#b1b16b"),
BlockGhostMagenta: []byte("#a16ba8"),
BlockGhostGreen: []byte("#6bb76b"),
BlockGhostOrange: []byte("#c3806c"),
BlockSolidBlue: []byte("#2864ff"),
BlockSolidCyan: []byte("#00eeee"),
BlockSolidRed: []byte("#ee0000"),
BlockSolidYellow: []byte("#dddd00"),
BlockSolidMagenta: []byte("#c000cc"),
BlockSolidGreen: []byte("#00e900"),
BlockSolidOrange: []byte("#ff7308"),
}
var Colors = make([][]byte, 16)
type Block int
@ -31,9 +16,9 @@ func (b Block) Rune() rune {
switch b {
case BlockNone:
return ' '
case BlockGhostBlue, BlockGhostCyan, BlockGhostRed, BlockGhostYellow, BlockGhostMagenta, BlockGhostGreen, BlockGhostOrange:
case BlockGhostJ, BlockGhostI, BlockGhostZ, BlockGhostO, BlockGhostT, BlockGhostS, BlockGhostL:
return '▓'
case BlockGarbage, BlockSolidBlue, BlockSolidCyan, BlockSolidRed, BlockSolidYellow, BlockSolidMagenta, BlockSolidGreen, BlockSolidOrange:
case BlockGarbage, BlockSolidJ, BlockSolidI, BlockSolidZ, BlockSolidO, BlockSolidT, BlockSolidS, BlockSolidL:
return '█'
default:
return '?'
@ -43,18 +28,36 @@ func (b Block) Rune() rune {
const (
BlockNone Block = iota
BlockGarbage
BlockGhostBlue
BlockGhostCyan
BlockGhostRed
BlockGhostYellow
BlockGhostMagenta
BlockGhostGreen
BlockGhostOrange
BlockSolidBlue
BlockSolidCyan
BlockSolidRed
BlockSolidYellow
BlockSolidMagenta
BlockSolidGreen
BlockSolidOrange
BlockGhostJ
BlockGhostI
BlockGhostZ
BlockGhostO
BlockGhostT
BlockGhostS
BlockGhostL
BlockSolidJ
BlockSolidI
BlockSolidZ
BlockSolidO
BlockSolidT
BlockSolidS
BlockSolidL
)
var ColorToBlock = map[event.GameColor]Block{
event.GameColorI: BlockSolidI,
event.GameColorO: BlockSolidO,
event.GameColorT: BlockSolidT,
event.GameColorJ: BlockSolidJ,
event.GameColorL: BlockSolidL,
event.GameColorS: BlockSolidS,
event.GameColorZ: BlockSolidZ,
event.GameColorIGhost: BlockGhostI,
event.GameColorOGhost: BlockGhostO,
event.GameColorTGhost: BlockGhostT,
event.GameColorJGhost: BlockGhostJ,
event.GameColorLGhost: BlockGhostL,
event.GameColorSGhost: BlockGhostS,
event.GameColorZGhost: BlockGhostZ,
event.GameColorGarbage: BlockGarbage,
}

View file

@ -481,20 +481,20 @@ func (m *Matrix) SetGameOver() {
i := I(x, y, m.W)
switch m.M[i] {
case BlockSolidBlue:
m.M[i] = BlockGhostBlue
case BlockSolidCyan:
m.M[i] = BlockGhostCyan
case BlockSolidGreen:
m.M[i] = BlockGhostGreen
case BlockSolidMagenta:
m.M[i] = BlockGhostMagenta
case BlockSolidOrange:
m.M[i] = BlockGhostOrange
case BlockSolidRed:
m.M[i] = BlockGhostRed
case BlockSolidYellow:
m.M[i] = BlockGhostYellow
case BlockSolidJ:
m.M[i] = BlockGhostJ
case BlockSolidI:
m.M[i] = BlockGhostI
case BlockSolidS:
m.M[i] = BlockGhostS
case BlockSolidT:
m.M[i] = BlockGhostT
case BlockSolidL:
m.M[i] = BlockGhostL
case BlockSolidZ:
m.M[i] = BlockGhostZ
case BlockSolidO:
m.M[i] = BlockGhostO
}
}
@ -947,9 +947,9 @@ func (m *Matrix) AddTestBlocks() {
}
if y == 2 || (y > 4 && x%2 > 0) {
block = BlockSolidMagenta
block = BlockSolidT
} else {
block = BlockSolidYellow
block = BlockSolidO
}
m.M[I(x, y, m.W)] = block

View file

@ -14,15 +14,15 @@ func TestMatrix(t *testing.T) {
m.AddTestBlocks()
ok := m.SetBlock(9, 0, BlockSolidMagenta, false)
ok := m.SetBlock(9, 0, BlockSolidT, false)
if !ok {
t.Error("failed to set final block after test blocks")
}
ok = m.SetBlock(9, 1, BlockSolidMagenta, false)
ok = m.SetBlock(9, 1, BlockSolidT, false)
if !ok {
t.Error("failed to set final block after test blocks")
}
ok = m.SetBlock(9, 3, BlockSolidMagenta, false)
ok = m.SetBlock(9, 3, BlockSolidT, false)
if !ok {
t.Error("failed to set final block after test blocks")
}
@ -34,17 +34,17 @@ func TestMatrix(t *testing.T) {
m.Clear()
err = m.Add(m.P, BlockSolidBlue, Point{3, 3}, false)
err = m.Add(m.P, BlockSolidJ, Point{3, 3}, false)
if err != nil {
t.Errorf("failed to add initial mino to matrix: %s", err)
}
err = m.Add(m.P, BlockSolidBlue, Point{3, 3}, false)
err = m.Add(m.P, BlockSolidJ, Point{3, 3}, false)
if err == nil {
t.Error("failed to detect collision when adding second mino to matrix")
}
err = m.Add(m.P, BlockSolidBlue, Point{9, 9}, false)
err = m.Add(m.P, BlockSolidJ, Point{9, 9}, false)
if err == nil {
t.Error("failed to detect out of bounds when adding third mino to matrix")
}

View file

@ -79,35 +79,35 @@ func NewPiece(m Mino, loc Point) *Piece {
switch m.Canonical().String() {
case TetrominoI:
pieceType = PieceI
p.Solid = BlockSolidCyan
p.Ghost = BlockGhostCyan
p.Solid = BlockSolidI
p.Ghost = BlockGhostI
case TetrominoO:
pieceType = PieceO
p.Solid = BlockSolidYellow
p.Ghost = BlockGhostYellow
p.Solid = BlockSolidO
p.Ghost = BlockGhostO
case TetrominoJ:
pieceType = PieceJ
p.Solid = BlockSolidBlue
p.Ghost = BlockGhostBlue
p.Solid = BlockSolidJ
p.Ghost = BlockGhostJ
case TetrominoL:
pieceType = PieceL
p.Solid = BlockSolidOrange
p.Ghost = BlockGhostOrange
p.Solid = BlockSolidL
p.Ghost = BlockGhostL
case TetrominoS:
pieceType = PieceS
p.Solid = BlockSolidGreen
p.Ghost = BlockGhostGreen
p.Solid = BlockSolidS
p.Ghost = BlockGhostS
case TetrominoT:
pieceType = PieceT
p.Solid = BlockSolidMagenta
p.Ghost = BlockGhostMagenta
p.Solid = BlockSolidT
p.Ghost = BlockGhostT
case TetrominoZ:
pieceType = PieceZ
p.Solid = BlockSolidRed
p.Ghost = BlockGhostRed
p.Solid = BlockSolidZ
p.Ghost = BlockGhostZ
default:
p.Solid = BlockSolidYellow
p.Ghost = BlockGhostYellow
p.Solid = BlockSolidO
p.Ghost = BlockGhostO
}
p.pivotsCW = AllRotationPivotsCW[pieceType]