aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-08-15 16:49:59 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-15 23:52:20 +0200
commit909a84f907171637a6cd1bb0846e0d1ca758063c (patch)
treea4fbea85f8294934bf8bbf81705fc0261484b51a
parentc1bc6f873f8ce7d6a1e348957dcdc36b6cc13e9d (diff)
downloadmuhqs-game-909a84f907171637a6cd1bb0846e0d1ca758063c.tar.gz
muhqs-game-909a84f907171637a6cd1bb0846e0d1ca758063c.zip
add message support to the game client
-rw-r--r--go/client/game.go50
-rw-r--r--go/ui/buffer.go33
2 files changed, 72 insertions, 11 deletions
diff --git a/go/client/game.go b/go/client/game.go
index f726c95d..dd8a9b39 100644
--- a/go/client/game.go
+++ b/go/client/game.go
@@ -18,8 +18,13 @@ const (
DEFAULT_BUTTON_HEIGHT = 40
PASS_BUTTON_WIDTH = 100
- RESOLVE_BUTTON_X = 500
- STACK_BUFFER_WIDTH = 300
+ RESOLVE_BUTTON_X = 500
+
+ STACK_BUFFER_WIDTH = 300
+ STACK_BUFFER_HEIGHT = 400
+
+ MESSAGE_BUFFER_HEIGHT = 200
+ MESSAGE_BUFFER_MARGIN = 10
HOVER_THRESHOLD = 60
@@ -52,6 +57,7 @@ type Game struct {
storeButton *ui.SimpleButton
stackBuffer *ui.Buffer
prompt *ui.Prompt
+ messageBuffer *ui.Buffer
triggers []*game.TriggeredAction
ui.Collection
@@ -90,7 +96,9 @@ func newGame(app *app, gameState game.State) *Game {
DEFAULT_BUTTON_HEIGHT,
"Pass",
func(*ui.SimpleButton) {
- if g.prompt != nil {
+ if g.visible(g.messageBuffer) {
+ g.hide(g.messageBuffer)
+ } else if g.prompt != nil {
g.progressPrompt()
} else if g.hasPriority {
g.passPriority()
@@ -106,8 +114,16 @@ func newGame(app *app, gameState game.State) *Game {
g.reset()
})
- g.stackBuffer = ui.NewBuffer(g.Width-STACK_BUFFER_WIDTH, g.passButton.Y-400,
- STACK_BUFFER_WIDTH, 400)
+ g.stackBuffer = ui.NewBuffer(
+ g.Width-STACK_BUFFER_WIDTH, g.passButton.Y-400,
+ STACK_BUFFER_WIDTH, STACK_BUFFER_HEIGHT)
+
+ g.messageBuffer = ui.NewBuffer(
+ MESSAGE_BUFFER_MARGIN,
+ g.Height-DEFAULT_BUTTON_HEIGHT-MESSAGE_BUFFER_HEIGHT-MESSAGE_BUFFER_MARGIN,
+ g.Width-2*MESSAGE_BUFFER_MARGIN,
+ MESSAGE_BUFFER_HEIGHT,
+ )
return g
}
@@ -168,7 +184,7 @@ func (g *Game) initPlayerUi(player *game.Player) *Game {
DEFAULT_BUTTON_HEIGHT,
"DiscardPile",
func(*ui.SimpleButton) {
- if idx := g.FindWidget(g.discardPileView); idx == -1 {
+ if !g.visible(g.discardPileView) {
g.discardPileView.ForceRedraw()
g.AddWidget(g.discardPileView)
} else {
@@ -235,6 +251,20 @@ func (g *Game) hideStore() {
g.RemoveWidget(g.storeView)
}
+func (g *Game) showMessage(message string) {
+ g.messageBuffer.ClearLines()
+ g.messageBuffer.Bg(color.RGBA{0x80, 0x80, 0x80, 0x80})
+ g.messageBuffer.AddText(message)
+ g.show(g.messageBuffer)
+}
+
+func (g *Game) showError(message string) {
+ g.messageBuffer.ClearLines()
+ g.messageBuffer.Bg(color.RGBA{0xe0, 0x10, 0x10, 0x80})
+ g.messageBuffer.AddText(message)
+ g.show(g.messageBuffer)
+}
+
func (g *Game) addPermActionChoice(perm game.Permanent, x, y int) {
if len(perm.Pile()) == 0 {
g.addActionChoice(perm, x, y)
@@ -418,6 +448,10 @@ func (g *Game) declareAction(a game.Action) {
g.stateBar.ForceRedraw()
}
+func (g *Game) visible(w ui.Widget) bool {
+ return g.FindWidget(w) != -1
+}
+
// show ensures a widget is visible by adding it to the collection or moving it to the last position.
func (g *Game) show(w ui.Widget) {
idx := g.FindWidget(w)
@@ -429,7 +463,7 @@ func (g *Game) show(w ui.Widget) {
}
func (g *Game) hide(w ui.Widget) {
- g.RemoveWidget(g.passButton)
+ g.RemoveWidget(w)
}
func (g *Game) updateButtons() {
@@ -503,7 +537,7 @@ func (g *Game) handlePlayerNotifications() {
}
a := n.Context.(game.Action)
g.stackBuffer.AddLine(a.String())
- if !g.gameState.Stack().IsEmpty() && g.FindWidget(g.stackBuffer) == -1 {
+ if !g.gameState.Stack().IsEmpty() && !g.visible(g.stackBuffer) {
g.AddWidget(g.stackBuffer)
}
diff --git a/go/ui/buffer.go b/go/ui/buffer.go
index 8294c905..7a69766d 100644
--- a/go/ui/buffer.go
+++ b/go/ui/buffer.go
@@ -22,17 +22,28 @@ type Buffer struct {
font *text.GoTextFace
lineSpacing float64
xMargin float64
+ bg color.Color
+ fg color.Color
}
func NewBuffer(x, y int, width, height int) *Buffer {
- b := &Buffer{NewWidgetBase(x, y, width, height), []string{}, 0, font.Font18, 1.5, 10.}
+ b := &Buffer{
+ NewWidgetBase(x, y, width, height),
+ []string{},
+ 0,
+ font.Font18,
+ 1.5,
+ 10.,
+ BUFFER_BACKGROUND,
+ BUFFER_FOREGROUND,
+ }
b.renderImpl = func() *ebiten.Image { return b.render() }
return b
}
func (b *Buffer) render() *ebiten.Image {
img := ebiten.NewImage(b.Width, b.Height)
- img.Fill(BUFFER_BACKGROUND)
+ img.Fill(b.bg)
var y float64 = -b.font.Size
for _, line := range b.lines[b.pos:] {
_, h := text.Measure(line, b.font, b.font.Size*b.lineSpacing)
@@ -41,7 +52,7 @@ func (b *Buffer) render() *ebiten.Image {
break
}
op := &text.DrawOptions{}
- op.ColorScale.ScaleWithColor(BUFFER_FOREGROUND)
+ op.ColorScale.ScaleWithColor(b.fg)
op.GeoM.Translate(b.xMargin, float64(y))
op.LineSpacing = b.font.Size * b.lineSpacing
text.Draw(img, line, b.font, op)
@@ -58,6 +69,12 @@ func (b *Buffer) AddLine(line string) {
b.AddLines([]string{line})
}
+func (b *Buffer) AddText(text string) {
+ // TODO: auto break text
+ lines := []string{text}
+ b.AddLines(lines)
+}
+
func (b *Buffer) ClearLines() {
b.lines = []string{}
b.ForceRedraw()
@@ -102,3 +119,13 @@ func (b *Buffer) Scroll(x, y int) {
}
b.ForceRedraw()
}
+
+func (b *Buffer) Bg(bg color.Color) *Buffer {
+ b.bg = bg
+ return b
+}
+
+func (b *Buffer) Fg(fg color.Color) *Buffer {
+ b.fg = fg
+ return b
+}