aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go/TODO2
-rw-r--r--go/client/game.go173
-rw-r--r--go/game/targets.go31
-rw-r--r--go/ui/button.go13
-rw-r--r--go/ui/cardGrid.go1
-rw-r--r--go/ui/prompt.go8
6 files changed, 154 insertions, 74 deletions
diff --git a/go/TODO b/go/TODO
index fbcc92f8..201cc37c 100644
--- a/go/TODO
+++ b/go/TODO
@@ -1,3 +1,5 @@
+* implement different highlighting used for selection and candidates
+* implement representation of next target and current seelction in prompt
* implement pile dropping
* implement artifcat action
* move
diff --git a/go/client/game.go b/go/client/game.go
index 32fb5f2f..5ae2fbe8 100644
--- a/go/client/game.go
+++ b/go/client/game.go
@@ -26,6 +26,8 @@ const (
STATE_BAR_WIDTH = 300
POC_BUTTON_WIDTH = 150
+
+ AUTO_PROGRESS_PROMPT = true
)
type Game struct {
@@ -70,11 +72,7 @@ func newGame(app *app) *Game {
"Pass",
func(*ui.SimpleButton) {
if g.prompt != nil {
- a := g.prompt.Confirm()
- g.declareAction(a)
- g.RemoveWidget(g.prompt)
- g.prompt = nil
-
+ g.progressPrompt()
} else if g.hasPriority {
g.passPriority()
}
@@ -108,6 +106,11 @@ func (g *Game) addActivePlayer(name string, deckList string) *Game {
return g.initPlayerUi(p)
}
+func (g *Game) addPrompt(action game.Action, prompt string) {
+ g.prompt = ui.NewPrompt(g.Height/2, g.Width, action, prompt)
+ g.AddWidget(g.prompt)
+}
+
func (g *Game) getPlayer(name string) *game.Player {
for _, p := range g.gameState.Players {
if p.Name == name {
@@ -227,7 +230,7 @@ func (g *Game) addActionChoice(perm game.Permanent, x, y int) {
g.removeChoice()
a := actions[c.GetChoosen(x, y)]
if a.Targets() != nil && a.Targets().RequireSelection() {
- g.selectedObject = a
+ g.addPrompt(a, fmt.Sprintf("Select targets for %v", a))
} else {
g.declareAction(a)
}
@@ -242,7 +245,23 @@ func (g *Game) removeChoice() {
g.choice = nil
}
-func (g *Game) AddHighlight(obj interface{}) {
+func (g *Game) progressPrompt() {
+ a := g.prompt.Action()
+ targets := a.Targets()
+ if targets.RequireSelection() {
+ targets.Next()
+ } else {
+ g.declareAction(a)
+ g.removePrompt()
+ }
+}
+
+func (g *Game) removePrompt() {
+ g.RemoveWidget(g.prompt)
+ g.prompt = nil
+}
+
+func (g *Game) addHighlight(obj interface{}) {
switch obj := obj.(type) {
case ui.HandCard:
g.handLayer.AddHighlightCard(obj.C)
@@ -257,18 +276,27 @@ func (g *Game) AddHighlight(obj interface{}) {
}
}
+func (g *Game) addHighlights(objs []interface{}) {
+ for _, obj := range objs {
+ g.addHighlight(obj)
+ }
+}
+
func (g *Game) clearMapHighlights() {
g.mapView.ClearPermanentsHighlights()
g.mapView.ClearTileHighlights()
g.mapView.ForceRedraw()
}
-func (g *Game) declareAction(a game.Action) {
- g.playerCtrl.SendAction(a)
+func (g *Game) clearHighlights() {
g.clearMapHighlights()
g.handLayer.ClearHighlights()
+}
+
+func (g *Game) declareAction(a game.Action) {
+ g.playerCtrl.SendAction(a)
+ g.clearHighlights()
g.hasPriority = false
- g.hidePassButton()
g.stateBar.ForceRedraw()
}
@@ -280,6 +308,34 @@ func (g *Game) hidePassButton() {
g.RemoveWidget(g.passButton)
}
+func (g *Game) updatePassButton() {
+ if g.prompt == nil && !g.hasPriority {
+ g.hidePassButton()
+ }
+
+ passButtonLabel := "pass"
+ if g.prompt != nil {
+ targets := g.prompt.Action().Targets()
+ if targets.RequireSelection() {
+ if !targets.Cur().HasSelection() {
+ g.hidePassButton()
+ return
+ }
+ passButtonLabel = "next"
+ } else {
+ passButtonLabel = "confirm"
+ }
+
+ if AUTO_PROGRESS_PROMPT && !targets.Cur().AllowSelection() {
+ g.progressPrompt()
+ return
+ }
+ }
+
+ g.showPassButton()
+ g.passButton.UpdateLabel(passButtonLabel)
+}
+
func (g *Game) passPriority() {
g.declareAction(game.NewPassPriority(g.activePlayer))
}
@@ -290,7 +346,6 @@ func (g *Game) handlePlayerNotifications() {
log.Println("Received", n)
switch n.Notification {
case game.PriorityNotification:
- g.showPassButton()
g.hasPriority = true
case game.DeclaredActionNotification:
@@ -318,10 +373,7 @@ func (g *Game) handlePlayerNotifications() {
g.showStore()
}
}
-
- g.prompt = ui.NewPrompt(g.Height/2, g.Width, ctx.Action, ctx.Prompt)
- g.AddWidget(g.prompt)
- g.showPassButton()
+ g.addPrompt(ctx.Action, ctx.Prompt)
}
g.stateBar.ForceRedraw()
@@ -348,77 +400,81 @@ func (g *Game) findObjectAt(x, y int) interface{} {
return nil
}
-func (g *Game) handleTargetSelection(obj interface{}) {
- a := g.selectedObject.(game.Action)
- err := a.Targets().AddSelection(obj)
- if err != nil {
- log.Println("Not added", obj, "as target for", a, "because", err)
- }
-
- if !a.Targets().RequireSelection() {
- g.declareAction(a)
- g.selectedObject = nil
- }
-}
-
func (g *Game) handleSelection(obj interface{}, x, y int) {
if obj == nil {
fmt.Printf("No object found at cursor position (%d, %d)\n", x, y)
return
}
- if _, ok := g.selectedObject.(game.Action); ok {
- g.handleTargetSelection(obj)
- } else {
- switch obj := obj.(type) {
- case *game.Tile:
- if g.storesOnMap && obj.Type == game.TileTypes.Store && g.activePlayer.KnowsStore(obj.Position) {
- if g.storeView != nil {
- g.hideStore()
- }
+ switch obj := obj.(type) {
+ case *game.Tile:
+ if g.storesOnMap && obj.Type == game.TileTypes.Store &&
+ g.activePlayer.KnowsStore(obj.Position) {
- g.storeView = ui.NewPocList(x, y, g.gameState.Map.StoreOn(obj.Position))
- g.showStore()
+ if g.storeView != nil {
+ g.hideStore()
}
- case game.Permanent:
- perm := obj
- g.addPermActionChoice(perm, x, y)
+ g.storeView = ui.NewPocList(x, y, g.gameState.Map.StoreOn(obj.Position))
+ g.showStore()
+ }
- case ui.HandCard:
- g.selectedObject = game.NewPlayAction(g.activePlayer, obj.C)
- g.handLayer.HighlightCard(obj.C)
+ case game.Permanent:
+ perm := obj
+ g.addPermActionChoice(perm, x, y)
- default:
- log.Panicf("Object of type %T not handled", obj)
+ case ui.HandCard:
+ a := game.NewPlayAction(g.activePlayer, obj.C)
+ if a.Targets().RequireSelection() {
+ g.addPrompt(a, fmt.Sprintf("Select targets to play %v", obj.C.Name))
+ g.handLayer.HighlightCard(obj.C)
+ } else {
+ g.declareAction(a)
}
+
+ default:
+ log.Panicf("Object of type %T not handled", obj)
}
}
-func (g *Game) highlightTargets() {
- a, ok := g.selectedObject.(game.Action)
- if !ok {
+func (g *Game) updateHighlight() {
+ g.clearHighlights()
+ if g.prompt == nil {
return
}
- options := a.Targets().Options()
- for _, option := range options {
- g.AddHighlight(option)
+ a := g.prompt.Action()
+ if pa, ok := a.(*game.PlayAction); ok {
+ g.addHighlight(ui.HandCard{C: pa.Card})
+ }
+
+ targets := a.Targets()
+ if len(targets.Targets()) == 0 {
+ return
+ }
+
+ for _, t := range targets.Targets() {
+ g.addHighlights(t.Selection())
+ }
+
+ target := targets.Cur()
+ if target.AllowSelection() {
+ options := target.Options()
+ g.addHighlights(options)
}
}
func (g *Game) Update() error {
g.handlePlayerNotifications()
- g.highlightTargets()
+ g.updateHighlight()
+ g.updatePassButton()
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
x, y := ebiten.CursorPosition()
obj := g.findObjectAt(x, y)
if g.prompt != nil {
- if err := g.prompt.Add(obj); err == nil {
- g.AddHighlight(obj)
- } else {
+ if err := g.prompt.Add(obj); err != nil {
log.Println("Not added", obj, "to active prompt:", err)
g.handleSelection(obj, x, y)
}
@@ -431,8 +487,7 @@ func (g *Game) Update() error {
g.removeChoice()
g.selectedObject = nil
g.ResetHover()
- g.clearMapHighlights()
- g.handLayer.ClearHighlights()
+ g.clearHighlights()
g.hideStore()
g.RemoveWidget(g.discardPileView)
if g.prompt != nil {
diff --git a/go/game/targets.go b/go/game/targets.go
index 75f3f53c..df522565 100644
--- a/go/game/targets.go
+++ b/go/game/targets.go
@@ -121,9 +121,11 @@ func (t *Target) AddSelection(sel interface{}) (err error) {
return
}
-func (t *Target) RequireSelection() bool { return len(t.sel) < t.requirement.min }
-func (t *Target) HasSelection() bool { return len(t.sel) > 0 }
-func (t *Target) ClearSelection() { t.sel = []interface{}{} }
+func (t *Target) RequireSelection() bool { return len(t.sel) < t.requirement.min }
+func (t *Target) HasSelection() bool { return len(t.sel) > 0 }
+func (t *Target) AllowSelection() bool { return len(t.sel) < t.requirement.max }
+func (t *Target) ClearSelection() { t.sel = []interface{}{} }
+func (t *Target) Selection() []interface{} { return t.sel }
func (t *Target) Options() (options []interface{}) {
candidates := t.candidates()
@@ -172,7 +174,9 @@ func (t *Targets) ClearSelections() {
}
}
func (t *Targets) Options() (options []interface{}) { return t.ts[t.idx].Options() }
+func (t *Targets) Cur() *Target { return t.ts[t.idx] }
func (t *Targets) Next() { t.idx++ }
+func (t *Targets) Targets() []*Target { return t.ts }
func (t *Targets) CheckTargets(s *State) error {
for _, target := range t.ts {
@@ -532,10 +536,25 @@ func (t *Target) candidates() []interface{} {
return utils.TypedSliceToInterfaceSlice(t.s.Permanents)
} else if strings.Contains(t.desc, "tile") {
return utils.TypedSliceToInterfaceSlice(t.s.Map.AllTiles())
- } else if t.desc == "hand card" {
+ } else if strings.Contains(t.desc, "card") {
cards := NewPileOfCards()
- for _, p := range t.s.Players {
- cards.AddPoc(p.Hand)
+ switch t.desc {
+ case "hand card":
+ for _, p := range t.s.Players {
+ cards.AddPoc(p.Hand)
+ }
+ case "store card":
+ if t.s.Map.HasStores() {
+ for _, store := range t.s.Map.Stores {
+ cards.AddPoc(store)
+ }
+ } else {
+ for _, p := range t.s.Players {
+ cards.AddPoc(p.Store)
+ }
+ }
+ default:
+ log.Panicf("Unimplemented card options for %s", t.desc)
}
return utils.TypedSliceToInterfaceSlice(cards.Cards())
}
diff --git a/go/ui/button.go b/go/ui/button.go
index eac3c2e4..50f78a3d 100644
--- a/go/ui/button.go
+++ b/go/ui/button.go
@@ -19,8 +19,8 @@ type SimpleButton struct {
WidgetBase
label string
OnClick func(b *SimpleButton)
- BG color.Color
- FG color.Color
+ Bg color.Color
+ Fg color.Color
}
func NewSimpleButton(x, y, w, h int, label string, onClick func(b *SimpleButton)) *SimpleButton {
@@ -32,15 +32,20 @@ func NewSimpleButton(x, y, w, h int, label string, onClick func(b *SimpleButton)
func (b *SimpleButton) render() *ebiten.Image {
img := ebiten.NewImage(b.Width, b.Height)
- ebitenutil.DrawRect(img, float64(0), float64(0), float64(b.Width), float64(b.Height), b.BG)
+ ebitenutil.DrawRect(img, float64(0), float64(0), float64(b.Width), float64(b.Height), b.Bg)
bounds := text.BoundString(font.Font24, b.label)
x := b.Width/2 - centerTextXOffset(bounds)
y := b.Height/2 - centerTextYOffset(bounds)
- text.Draw(img, b.label, font.Font24, x, y, b.FG)
+ text.Draw(img, b.label, font.Font24, x, y, b.Fg)
return img
}
func (b *SimpleButton) Click(x, y int) {
b.OnClick(b)
}
+
+func (b *SimpleButton) UpdateLabel(label string) {
+ b.label = label
+ b.ForceRedraw()
+}
diff --git a/go/ui/cardGrid.go b/go/ui/cardGrid.go
index f6720ca1..1b86fe35 100644
--- a/go/ui/cardGrid.go
+++ b/go/ui/cardGrid.go
@@ -98,7 +98,6 @@ func (w *CardGrid) render() *ebiten.Image {
op.GeoM.Translate(xOffset, yOffset)
if slices.Contains(w.highlights, card) {
- log.Println("Highlighting card", card.Name)
op.ColorM.Scale(1, 0, 0, 0.5)
}
diff --git a/go/ui/prompt.go b/go/ui/prompt.go
index 93c4b4cd..c0b11d94 100644
--- a/go/ui/prompt.go
+++ b/go/ui/prompt.go
@@ -28,6 +28,10 @@ func NewPrompt(y, width int, action game.Action, promptText string) *Prompt {
return p
}
+func (p *Prompt) Action() game.Action {
+ return p.action
+}
+
func (p *Prompt) Add(obj interface{}) error {
if handCard, ok := obj.(HandCard); ok {
obj = handCard.C
@@ -36,10 +40,6 @@ func (p *Prompt) Add(obj interface{}) error {
return p.action.Targets().AddSelection(obj)
}
-func (p *Prompt) Confirm() game.Action {
- return p.action
-}
-
func (p *Prompt) Height() int {
return PROMPT_HEIGHT
}