From bcffeac4c5086eba59448d4fe5d79bb786b05de2 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 6 Jun 2025 16:42:46 -0500 Subject: refactor client activities Make the activity stack explicit and move reusable activities to the activity package. --- go/activities/activity.go | 41 +++++++++ go/activities/draft.go | 212 ++++++++++++++++++++++++++++++++++++++++++++++ go/activities/sealed.go | 138 ++++++++++++++++++++++++++++++ 3 files changed, 391 insertions(+) create mode 100644 go/activities/activity.go create mode 100644 go/activities/draft.go create mode 100644 go/activities/sealed.go (limited to 'go/activities') 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/activities/draft.go b/go/activities/draft.go new file mode 100644 index 00000000..10ce9671 --- /dev/null +++ b/go/activities/draft.go @@ -0,0 +1,212 @@ +package activities + +import ( + "log" + + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/inpututil" + + "muhq.space/muhqs-game/go/game" + "muhq.space/muhqs-game/go/ui" +) + +const ( + DRAFT_BUTTON_WIDTH = 150 + DRAFT_BUTTON_HEIGHT = 40 +) + +type Draft struct { + ui.Collection + player *game.Player + ctrl *game.ChanPlayerControl + draft *game.Draft + + setInput *ui.TextInput + descInput *ui.TextInput + deckList *ui.PocList +} + +func NewDraft(width, height int, playerName string) *Draft { + d := &Draft{ + Collection: ui.Collection{Width: width, Height: height}, + } + + d.AddWidget(ui.NewFixedTextBox( + (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-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-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-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-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-DRAFT_BUTTON_WIDTH)/2, + (d.Height-DRAFT_BUTTON_HEIGHT)/2-DRAFT_BUTTON_HEIGHT, + 1, + nil, + ) + d.AddWidget(aiNInput) + + d.AddWidget(ui.NewSimpleButton( + (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()) + })) + + d.player = game.NewDraftPlayer(playerName) + d.ctrl = game.NewChanPlayerControl(d.player) + d.player.Ctrl = d.ctrl + + return d +} + +func (d *Draft) Update() error { + if n := d.ctrl.RecvNotification(); n != nil { + log.Println("Received draft pick: %v\n", n) + d.presentPack(n) + } + + if err := ui.TouchManager.Update(); err != nil { + return err + } + + if err := d.Collection.Update(); err != nil { + return err + } + + if inpututil.IsKeyJustPressed(ebiten.KeyEscape) { + PopActivity() + } + + return nil +} + +func (d *Draft) presentPack(n *game.PlayerNotification) { + pack := n.Context.(game.PileOfCards) + grid := ui.NewCardGrid(0, 0, d.Width-SEALED_DECK_STRIP_WIDTH, d.Height, 0.5, pack).Columns(3) + selectCard := func(x, y int) { + _card := grid.FindObjectAt(x, y) + if _card == nil { + return + } + + card := _card.(*game.Card) + d.RemoveWidget(grid) + d.ctrl.SendAction(game.NewDraftPick(d.player, pack, card)) + } + grid.RegisterHandler("click", selectCard) + d.AddWidget(grid) +} + +func (d *Draft) Layout(width, height int) (int, int) { + return d.Width, d.Height +} + +func (d *Draft) startDraft(desc string, setList string, aiN int) { + + log.Printf("starting %s draft from '%s'\n", desc, setList) + + var sets []game.SetIdentifier + var err error + if sets, err = game.SetListToSets(setList); err != nil { + d.setInput.Bg(ui.WarningBg) + d.setInput.SetInput("") + return + } + + d.draft = game.NewDraft([]*game.Player{d.player}, desc, sets) + + log.Println(aiN) + for _ = range aiN { + log.Println("add ai") + d.draft.AddRandomAi() + } + + if !d.draft.Valid() { + d.descInput.Bg(ui.WarningBg) + d.descInput.SetInput("") + return + } + d.Clear() + + 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 + d.deckList.RegisterHandler("update", func() error { + if n := d.player.Deck.Size(); n > cardsInDeck { + d.deckList.ForceRedraw() + cardsInDeck = n + } + return nil + }) + } + d.AddWidget(d.deckList) + + d.AddWidget(ui.NewSimpleButton( + 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() + })) + + go d.draft.Run() +} + +func (d *Draft) done() { + PopActivity() +} + +func (d *Draft) GetDeckList() string { + return d.player.Deck.ToList() +} diff --git a/go/activities/sealed.go b/go/activities/sealed.go new file mode 100644 index 00000000..7438e89d --- /dev/null +++ b/go/activities/sealed.go @@ -0,0 +1,138 @@ +package activities + +import ( + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/inpututil" + + "muhq.space/muhqs-game/go/game" + "muhq.space/muhqs-game/go/ui" +) + +const ( + SEALED_DECK_STRIP_WIDTH = 200 + SEALED_BUTTON_WIDTH = 150 + SEALED_BUTTON_HEIGHT = 40 +) + +type Sealed struct { + ui.Collection + + setInput *ui.TextInput + + pool game.PileOfCards + Deck game.PileOfCards +} + +func NewSealed(width, height int) *Sealed { + s := &Sealed{ + Collection: ui.Collection{Width: width, Height: height}, + } + + s.AddWidget(ui.NewFixedTextBox( + (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-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-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()) + })) + + return s +} + +func (s *Sealed) Update() error { + if err := ui.TouchManager.Update(); err != nil { + return err + } + + if err := s.Collection.Update(); err != nil { + return err + } + + if inpututil.IsKeyJustPressed(ebiten.KeyEscape) { + Activities.PopActivity() + } + + return nil +} + +func (s *Sealed) Layout(width, height int) (int, int) { + return s.Width, s.Height +} + +func (s *Sealed) startSealed(setList string) { + sets, err := game.SetListToSets(setList) + if err != nil { + s.setInput.Bg(ui.WarningBg) + s.setInput.SetInput("") + return + } + + s.pool = game.NewPileOfCards() + s.Deck = game.NewPileOfCards() + + s.Clear() + + for _, set := range sets { + setDeck := game.NewDeck() + for _, c := range game.NewDeckFromCardPaths(set.CardPaths()).Cards() { + if c.IsBuyable() { + setDeck.AddCard(c) + } + } + setDeck.MoveInto(s.pool) + } + + 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) + + grid := ui.NewCardGrid(0, 0, s.Width-SEALED_DECK_STRIP_WIDTH, s.Height, 0.5, s.pool).Columns(3) + selectCard := func(x, y int) { + _card := grid.FindObjectAt(x, y) + if _card == nil { + return + } + + card := _card.(*game.Card) + s.pool.MoveCard(card, s.Deck) + grid.ForceRedraw() + deckList.ForceRedraw() + } + grid.RegisterHandler("click", selectCard) + s.AddWidget(grid) + + s.AddWidget(ui.NewSimpleButton( + 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() { + Activities.PopActivity() + // startMenu := CurActivity().(*StartMenu) + // startMenu.deckInput.SetInput(s.deck.ToList()) +} -- cgit v1.2.3