aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-06-06 16:42:46 -0500
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-20 15:57:18 +0200
commitbcffeac4c5086eba59448d4fe5d79bb786b05de2 (patch)
treecc0b3648f2b070c731225e88b42fb3f4adcb65da
parentc15142c3bcae4316c8580adb7a9f0b223e586ae9 (diff)
downloadmuhqs-game-bcffeac4c5086eba59448d4fe5d79bb786b05de2.tar.gz
muhqs-game-bcffeac4c5086eba59448d4fe5d79bb786b05de2.zip
refactor client activities
Make the activity stack explicit and move reusable activities to the activity package.
-rw-r--r--go/activities/activity.go41
-rw-r--r--go/activities/draft.go (renamed from go/client/draft.go)95
-rw-r--r--go/activities/sealed.go (renamed from go/client/sealed.go)68
-rw-r--r--go/client/main.go17
-rw-r--r--go/client/startMenu.go40
-rw-r--r--go/ui/openUrl.go25
6 files changed, 186 insertions, 100 deletions
diff --git a/go/activities/activity.go b/go/activities/activity.go
new file mode 100644
index 00000000..c082b8c6
--- /dev/null
+++ b/go/activities/activity.go
@@ -0,0 +1,41 @@
+package activities
+
+import (
+ "github.com/hajimehoshi/ebiten/v2"
+)
+
+type ActivityStack struct {
+ activityStack []ebiten.Game
+}
+
+var Activities ActivityStack
+
+type Activity = ebiten.Game
+
+func (s *ActivityStack) PushActivity(a Activity) {
+ s.activityStack = append(s.activityStack, a)
+}
+
+func (s *ActivityStack) PopActivity() Activity {
+ n := len(s.activityStack)
+ a := s.activityStack[n-1]
+ s.activityStack = s.activityStack[:n-1]
+ return a
+}
+
+func (s *ActivityStack) Last() Activity {
+ n := len(s.activityStack)
+ return s.activityStack[n-1]
+}
+
+func PushActivity(a Activity) {
+ Activities.PushActivity(a)
+}
+
+func PopActivity() Activity {
+ return Activities.PopActivity()
+}
+
+func CurActivity() Activity {
+ return Activities.Last()
+}
diff --git a/go/client/draft.go b/go/activities/draft.go
index 3950094f..10ce9671 100644
--- a/go/client/draft.go
+++ b/go/activities/draft.go
@@ -1,4 +1,4 @@
-package main
+package activities
import (
"log"
@@ -10,9 +10,13 @@ import (
"muhq.space/muhqs-game/go/ui"
)
+const (
+ DRAFT_BUTTON_WIDTH = 150
+ DRAFT_BUTTON_HEIGHT = 40
+)
+
type Draft struct {
ui.Collection
- app *app
player *game.Player
ctrl *game.ChanPlayerControl
draft *game.Draft
@@ -22,74 +26,81 @@ type Draft struct {
deckList *ui.PocList
}
-func NewDraft(width, height int, app *app) *Draft {
+func NewDraft(width, height int, playerName string) *Draft {
d := &Draft{
- app: app,
Collection: ui.Collection{Width: width, Height: height},
}
d.AddWidget(ui.NewFixedTextBox(
- (d.Width-START_BUTTON_WIDTH)/2-START_BUTTON_WIDTH,
- (d.Height-START_BUTTON_HEIGHT)/2-3*START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (d.Width-DRAFT_BUTTON_WIDTH)/2-DRAFT_BUTTON_WIDTH,
+ (d.Height-DRAFT_BUTTON_HEIGHT)/2-3*DRAFT_BUTTON_HEIGHT,
+ DRAFT_BUTTON_WIDTH,
+ DRAFT_BUTTON_HEIGHT,
"sets:",
).Centering(true))
d.setInput = ui.NewTextInput(
- (d.Width-START_BUTTON_WIDTH)/2,
- (d.Height-START_BUTTON_HEIGHT)/2-3*START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (d.Width-DRAFT_BUTTON_WIDTH)/2,
+ (d.Height-DRAFT_BUTTON_HEIGHT)/2-3*DRAFT_BUTTON_HEIGHT,
+ DRAFT_BUTTON_WIDTH,
+ DRAFT_BUTTON_HEIGHT,
"base,magic,equipments",
)
d.AddWidget(d.setInput)
d.AddWidget(ui.NewFixedTextBox(
- (d.Width-START_BUTTON_WIDTH)/2-START_BUTTON_WIDTH,
- (d.Height-START_BUTTON_HEIGHT)/2-2*START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (d.Width-DRAFT_BUTTON_WIDTH)/2-DRAFT_BUTTON_WIDTH,
+ (d.Height-DRAFT_BUTTON_HEIGHT)/2-2*DRAFT_BUTTON_HEIGHT,
+ DRAFT_BUTTON_WIDTH,
+ DRAFT_BUTTON_HEIGHT,
"draft:",
).Centering(true))
d.descInput = ui.NewTextInput(
- (d.Width-START_BUTTON_WIDTH)/2,
- (d.Height-START_BUTTON_HEIGHT)/2-2*START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (d.Width-DRAFT_BUTTON_WIDTH)/2,
+ (d.Height-DRAFT_BUTTON_HEIGHT)/2-2*DRAFT_BUTTON_HEIGHT,
+ DRAFT_BUTTON_WIDTH,
+ DRAFT_BUTTON_HEIGHT,
"3x[2;8]",
)
d.AddWidget(d.descInput)
+ d.AddWidget(ui.NewRoundSimpleButton(
+ (d.Width-DRAFT_BUTTON_WIDTH)/2+DRAFT_BUTTON_WIDTH+20,
+ (d.Height-DRAFT_BUTTON_HEIGHT)/2-2*DRAFT_BUTTON_HEIGHT,
+ DRAFT_BUTTON_WIDTH,
+ "?",
+ func(*ui.SimpleButton) {
+ ui.OpenUrl("https://muhq.space/muhqs-game/build/en/rules.html#draft-notation")
+ }))
+
d.AddWidget(ui.NewFixedTextBox(
- (d.Width-START_BUTTON_WIDTH)/2-START_BUTTON_WIDTH,
- (d.Height-START_BUTTON_HEIGHT)/2-START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (d.Width-DRAFT_BUTTON_WIDTH)/2-DRAFT_BUTTON_WIDTH,
+ (d.Height-DRAFT_BUTTON_HEIGHT)/2-DRAFT_BUTTON_HEIGHT,
+ DRAFT_BUTTON_WIDTH,
+ DRAFT_BUTTON_HEIGHT,
"AI:",
).Centering(true))
aiNInput := ui.NewNumberChoice(
- (d.Width-START_BUTTON_WIDTH)/2,
- (d.Height-START_BUTTON_HEIGHT)/2-START_BUTTON_HEIGHT,
+ (d.Width-DRAFT_BUTTON_WIDTH)/2,
+ (d.Height-DRAFT_BUTTON_HEIGHT)/2-DRAFT_BUTTON_HEIGHT,
1,
nil,
)
d.AddWidget(aiNInput)
d.AddWidget(ui.NewSimpleButton(
- (d.Width-START_BUTTON_WIDTH)/2,
- (d.Height-START_BUTTON_HEIGHT)/2,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (d.Width-DRAFT_BUTTON_WIDTH)/2,
+ (d.Height-DRAFT_BUTTON_HEIGHT)/2,
+ DRAFT_BUTTON_WIDTH,
+ DRAFT_BUTTON_HEIGHT,
"Start",
func(*ui.SimpleButton) {
d.startDraft(d.descInput.TextOrLabel(), d.setInput.TextOrLabel(), aiNInput.GetChoosen())
}))
- startMenu := d.app.activities[len(d.app.activities)-1].(*StartMenu)
- d.player = game.NewDraftPlayer(startMenu.playerName)
+ d.player = game.NewDraftPlayer(playerName)
d.ctrl = game.NewChanPlayerControl(d.player)
d.player.Ctrl = d.ctrl
@@ -111,7 +122,7 @@ func (d *Draft) Update() error {
}
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
- d.app.popActivity()
+ PopActivity()
}
return nil
@@ -165,7 +176,7 @@ func (d *Draft) startDraft(desc string, setList string, aiN int) {
}
d.Clear()
- d.deckList = ui.NewPocList(d.Width-SEALED_DECK_STRIP_WIDTH/2, d.Height-START_BUTTON_HEIGHT-20, d.player.Deck)
+ d.deckList = ui.NewPocList(d.Width-SEALED_DECK_STRIP_WIDTH/2, d.Height-DRAFT_BUTTON_HEIGHT-20, d.player.Deck)
d.deckList.Bg(ui.Gray)
{
cardsInDeck := 0
@@ -180,10 +191,10 @@ func (d *Draft) startDraft(desc string, setList string, aiN int) {
d.AddWidget(d.deckList)
d.AddWidget(ui.NewSimpleButton(
- d.Width-SEALED_DECK_STRIP_WIDTH/2-START_BUTTON_WIDTH/2,
- d.Height-START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ d.Width-SEALED_DECK_STRIP_WIDTH/2-DRAFT_BUTTON_WIDTH/2,
+ d.Height-DRAFT_BUTTON_HEIGHT,
+ DRAFT_BUTTON_WIDTH,
+ DRAFT_BUTTON_HEIGHT,
"Done",
func(*ui.SimpleButton) {
d.done()
@@ -193,7 +204,9 @@ func (d *Draft) startDraft(desc string, setList string, aiN int) {
}
func (d *Draft) done() {
- startMenu := d.app.activities[len(d.app.activities)-2].(*StartMenu)
- startMenu.deckInput.SetInput(d.player.Deck.ToList())
- d.app.popActivity()
+ PopActivity()
+}
+
+func (d *Draft) GetDeckList() string {
+ return d.player.Deck.ToList()
}
diff --git a/go/client/sealed.go b/go/activities/sealed.go
index efe1006e..7438e89d 100644
--- a/go/client/sealed.go
+++ b/go/activities/sealed.go
@@ -1,4 +1,4 @@
-package main
+package activities
import (
"github.com/hajimehoshi/ebiten/v2"
@@ -10,46 +10,46 @@ import (
const (
SEALED_DECK_STRIP_WIDTH = 200
+ SEALED_BUTTON_WIDTH = 150
+ SEALED_BUTTON_HEIGHT = 40
)
-type sealed struct {
+type Sealed struct {
ui.Collection
- app *app
setInput *ui.TextInput
pool game.PileOfCards
- deck game.PileOfCards
+ Deck game.PileOfCards
}
-func NewSealed(width, height int, app *app) *sealed {
- s := &sealed{
- app: app,
+func NewSealed(width, height int) *Sealed {
+ s := &Sealed{
Collection: ui.Collection{Width: width, Height: height},
}
s.AddWidget(ui.NewFixedTextBox(
- (s.Width-START_BUTTON_WIDTH)/2-START_BUTTON_WIDTH,
- (s.Height-START_BUTTON_HEIGHT)/2-START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (s.Width-SEALED_BUTTON_WIDTH)/2-SEALED_BUTTON_WIDTH,
+ (s.Height-SEALED_BUTTON_HEIGHT)/2-SEALED_BUTTON_HEIGHT,
+ SEALED_BUTTON_WIDTH,
+ SEALED_BUTTON_HEIGHT,
"sets:",
).Centering(true))
s.setInput = ui.NewTextInput(
- (s.Width-START_BUTTON_WIDTH)/2,
- (s.Height-START_BUTTON_HEIGHT)/2-START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (s.Width-SEALED_BUTTON_WIDTH)/2,
+ (s.Height-SEALED_BUTTON_HEIGHT)/2-SEALED_BUTTON_HEIGHT,
+ SEALED_BUTTON_WIDTH,
+ SEALED_BUTTON_HEIGHT,
"base,equipments,magic",
)
s.AddWidget(s.setInput)
s.AddWidget(ui.NewSimpleButton(
- (s.Width-START_BUTTON_WIDTH)/2,
- (s.Height-START_BUTTON_HEIGHT)/2,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ (s.Width-SEALED_BUTTON_WIDTH)/2,
+ (s.Height-SEALED_BUTTON_HEIGHT)/2,
+ SEALED_BUTTON_WIDTH,
+ SEALED_BUTTON_HEIGHT,
"Start",
func(*ui.SimpleButton) {
s.startSealed(s.setInput.TextOrLabel())
@@ -58,7 +58,7 @@ func NewSealed(width, height int, app *app) *sealed {
return s
}
-func (s *sealed) Update() error {
+func (s *Sealed) Update() error {
if err := ui.TouchManager.Update(); err != nil {
return err
}
@@ -68,17 +68,17 @@ func (s *sealed) Update() error {
}
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
- s.app.popActivity()
+ Activities.PopActivity()
}
return nil
}
-func (s *sealed) Layout(width, height int) (int, int) {
+func (s *Sealed) Layout(width, height int) (int, int) {
return s.Width, s.Height
}
-func (s *sealed) startSealed(setList string) {
+func (s *Sealed) startSealed(setList string) {
sets, err := game.SetListToSets(setList)
if err != nil {
s.setInput.Bg(ui.WarningBg)
@@ -87,7 +87,7 @@ func (s *sealed) startSealed(setList string) {
}
s.pool = game.NewPileOfCards()
- s.deck = game.NewPileOfCards()
+ s.Deck = game.NewPileOfCards()
s.Clear()
@@ -101,7 +101,7 @@ func (s *sealed) startSealed(setList string) {
setDeck.MoveInto(s.pool)
}
- deckList := ui.NewPocList(s.Width-SEALED_DECK_STRIP_WIDTH/2, s.Height-START_BUTTON_HEIGHT-20, s.deck)
+ deckList := ui.NewPocList(s.Width-SEALED_DECK_STRIP_WIDTH/2, s.Height-SEALED_BUTTON_HEIGHT-20, s.Deck)
deckList.Bg(ui.Gray)
s.AddWidget(deckList)
@@ -113,7 +113,7 @@ func (s *sealed) startSealed(setList string) {
}
card := _card.(*game.Card)
- s.pool.MoveCard(card, s.deck)
+ s.pool.MoveCard(card, s.Deck)
grid.ForceRedraw()
deckList.ForceRedraw()
}
@@ -121,18 +121,18 @@ func (s *sealed) startSealed(setList string) {
s.AddWidget(grid)
s.AddWidget(ui.NewSimpleButton(
- s.Width-SEALED_DECK_STRIP_WIDTH/2-START_BUTTON_WIDTH/2,
- s.Height-START_BUTTON_HEIGHT,
- START_BUTTON_WIDTH,
- START_BUTTON_HEIGHT,
+ s.Width-SEALED_DECK_STRIP_WIDTH/2-SEALED_BUTTON_WIDTH/2,
+ s.Height-SEALED_BUTTON_HEIGHT,
+ SEALED_BUTTON_WIDTH,
+ SEALED_BUTTON_HEIGHT,
"Done",
func(*ui.SimpleButton) {
s.done()
}))
}
-func (s *sealed) done() {
- startMenu := s.app.activities[len(s.app.activities)-2].(*StartMenu)
- startMenu.deckInput.SetInput(s.deck.ToList())
- s.app.popActivity()
+func (s *Sealed) done() {
+ Activities.PopActivity()
+ // startMenu := CurActivity().(*StartMenu)
+ // startMenu.deckInput.SetInput(s.deck.ToList())
}
diff --git a/go/client/main.go b/go/client/main.go
index 4d46ed9a..b631269e 100644
--- a/go/client/main.go
+++ b/go/client/main.go
@@ -8,6 +8,7 @@ import (
"github.com/hajimehoshi/ebiten/v2"
+ "muhq.space/muhqs-game/go/activities"
"muhq.space/muhqs-game/go/font"
)
@@ -21,24 +22,14 @@ var startDeckPath string
type app struct {
windowWidth int
windowHeight int
-
- activities []ebiten.Game
-}
-
-func (a *app) pushActivity(activity ebiten.Game) {
- a.activities = append(a.activities, activity)
-}
-
-func (a *app) popActivity() {
- a.activities = a.activities[:len(a.activities)-1]
}
func (a *app) Update() error {
- return a.activities[len(a.activities)-1].Update()
+ return activities.CurActivity().Update()
}
func (a *app) Draw(screen *ebiten.Image) {
- a.activities[len(a.activities)-1].Draw(screen)
+ activities.CurActivity().Draw(screen)
}
func (a *app) Layout(outsideWidth, outsideHeight int) (int, int) {
@@ -86,7 +77,7 @@ func main() {
1 nautics/galley`
}
- app.pushActivity(startMenu)
+ activities.PushActivity(startMenu)
if err := ebiten.RunGame(app); err != nil {
if err != ebiten.Termination {
log.Fatal(err)
diff --git a/go/client/startMenu.go b/go/client/startMenu.go
index 10fa8e1f..10b9e23d 100644
--- a/go/client/startMenu.go
+++ b/go/client/startMenu.go
@@ -3,6 +3,7 @@ package main
import (
"log"
+ "muhq.space/muhqs-game/go/activities"
"muhq.space/muhqs-game/go/game"
"muhq.space/muhqs-game/go/ui"
)
@@ -15,25 +16,28 @@ const (
DECK_LIST_HEIGHT = 500
)
-type StartMenu struct {
+type startMenu struct {
ui.Collection
app *app
deckInput *ui.TextInput
+ draft *activities.Draft
+ sealed *activities.Sealed
+
playerName string
startDeck string
remote string
mapPath string
}
-func NewStartMenu(app *app) *StartMenu {
- m := &StartMenu{app: app}
+func NewStartMenu(app *app) *startMenu {
+ m := &startMenu{app: app}
return m
}
-func (m *StartMenu) build() {
+func (m *startMenu) build() {
deckInput := ui.NewTextInput(
(m.Width-DECK_LIST_WIDTH)/2,
(m.Height-DECK_LIST_HEIGHT)/2,
@@ -101,8 +105,8 @@ func (m *StartMenu) build() {
START_BUTTON_HEIGHT,
"Sealed",
func(*ui.SimpleButton) {
- sealed := NewSealed(m.Width, m.Height, m.app)
- m.app.pushActivity(sealed)
+ sealed := activities.NewSealed(m.Width, m.Height)
+ activities.PushActivity(sealed)
}))
m.AddWidget(ui.NewSimpleButton(
@@ -112,8 +116,8 @@ func (m *StartMenu) build() {
START_BUTTON_HEIGHT,
"Draft",
func(*ui.SimpleButton) {
- draft := NewDraft(m.Width, m.Height, m.app)
- m.app.pushActivity(draft)
+ m.draft = activities.NewDraft(m.Width, m.Height, playerInput.Text())
+ activities.PushActivity(m.draft)
}))
m.AddWidget(ui.NewSimpleButton(
@@ -130,11 +134,23 @@ func (m *StartMenu) build() {
}))
}
-func (m *StartMenu) Update() error {
+func (m *startMenu) Update() error {
if m.Widgets() == nil {
m.build()
}
+ // Get the drafted deck
+ if m.draft != nil {
+ m.deckInput.SetInput(m.draft.GetDeckList())
+ m.draft = nil
+ }
+
+ // Get the sealed deck
+ if m.sealed != nil {
+ m.deckInput.SetInput(m.sealed.Deck.ToList())
+ m.sealed = nil
+ }
+
if err := ui.TouchManager.Update(); err != nil {
return err
}
@@ -142,11 +158,11 @@ func (m *StartMenu) Update() error {
return m.Collection.Update()
}
-func (m *StartMenu) Layout(width, height int) (int, int) {
+func (m *startMenu) Layout(width, height int) (int, int) {
return m.Width, m.Height
}
-func (m *StartMenu) startGame() {
+func (m *startMenu) startGame() {
var state game.State
if m.remote != "" {
log.Fatal("Remote games are currently not implemented")
@@ -162,5 +178,5 @@ func (m *StartMenu) startGame() {
g.gameState.AddNewAiPlayer("kraken", color)
}
- m.app.pushActivity(g.Start())
+ activities.PushActivity(g.Start())
}
diff --git a/go/ui/openUrl.go b/go/ui/openUrl.go
new file mode 100644
index 00000000..7e227ba8
--- /dev/null
+++ b/go/ui/openUrl.go
@@ -0,0 +1,25 @@
+package ui
+
+import (
+ "os/exec"
+ "runtime"
+)
+
+// https://stackoverflow.com/questions/39320371/how-start-web-server-to-open-page-in-browser-in-golang
+// open opens the specified URL in the default browser of the user.
+func OpenUrl(url string) error {
+ var cmd string
+ var args []string
+
+ switch runtime.GOOS {
+ case "windows":
+ cmd = "cmd"
+ args = []string{"/c", "start"}
+ case "darwin":
+ cmd = "open"
+ default: // "linux", "freebsd", "openbsd", "netbsd"
+ cmd = "xdg-open"
+ }
+ args = append(args, url)
+ return exec.Command(cmd, args...).Start()
+}