aboutsummaryrefslogtreecommitdiff
path: root/go/game/targets.go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2023-02-15 13:13:06 +0100
committerFlorian Fischer <florian.fischer@muhq.space>2025-01-27 16:43:49 +0100
commitf9ab2cfdb25eb3fcd85868a2e375326a9c8b6022 (patch)
treeb96f16e6cf4a6dcf93b9557a7219179ab2f46c8d /go/game/targets.go
parent805cbf397589e5cb861f866713c2eb4bec9ce40b (diff)
downloadmuhqs-game-f9ab2cfdb25eb3fcd85868a2e375326a9c8b6022.tar.gz
muhqs-game-f9ab2cfdb25eb3fcd85868a2e375326a9c8b6022.zip
intermediate commit
* fix a lot of target and action bugs * check target selection before adding it to the prompt * use the store view for stores on the map * fix card highlighting in CardGrid * Only prompt for Upkeep-/DiscardActions if appropriate * Add helper for areaEffects granting new FullActions * Add Target() helper selecting the first target to the Action interface * Fix BuyAction and DiscardAction targets * Remember the stores a player has seen
Diffstat (limited to 'go/game/targets.go')
-rw-r--r--go/game/targets.go99
1 files changed, 71 insertions, 28 deletions
diff --git a/go/game/targets.go b/go/game/targets.go
index 99ba5085..440d8922 100644
--- a/go/game/targets.go
+++ b/go/game/targets.go
@@ -93,6 +93,19 @@ func (d *TargetDesc) requirement() TargetRequirement {
case "*":
return TargetRequirement{0, -1}
default:
+ if strings.Contains(d.req, "-") {
+ tokens := strings.SplitN(d.req, "-", 2)
+ min, err := strconv.Atoi(tokens[0])
+ if err != nil {
+ log.Fatalf("failed to parse target requirement %s: %v", d.req, err)
+ }
+ max, err := strconv.Atoi(tokens[1])
+ if err != nil {
+ log.Fatalf("failed to parse target requirement %s: %v", d.req, err)
+ }
+ return TargetRequirement{min, max}
+ }
+
x, err := strconv.Atoi(d.req)
if err != nil {
log.Fatalf("failed to parse target requirement %s: %v", d.req, err)
@@ -101,10 +114,17 @@ func (d *TargetDesc) requirement() TargetRequirement {
}
}
-func (t *Target) RequireSelection() bool {
- return len(t.sel) < t.requirement.min
+func (t *Target) AddSelection(sel interface{}) (err error) {
+ if err = t.constraint(sel); err == nil {
+ t.sel = append(t.sel, sel)
+ }
+ 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) Options() (options []interface{}) {
candidates := targetCandidates(t.desc, t.s)
@@ -116,22 +136,6 @@ func (t *Target) Options() (options []interface{}) {
return options
}
-func (t *Targets) Options() (options []interface{}) {
- return t.ts[t.idx].Options()
-}
-
-func (t *Target) AddSelection(sel interface{}) {
- t.sel = append(t.sel, sel)
-}
-
-func (t *Targets) AddSelection(sel interface{}) {
- t.ts[t.idx].AddSelection(sel)
-}
-
-func (t *Targets) Next() {
- t.idx++
-}
-
func (t *Target) CheckSelection(s *State) error {
if t.RequireSelection() {
return fmt.Errorf("Number of selected targets and required ones does not match")
@@ -151,6 +155,25 @@ func (t *Target) CheckSelection(s *State) error {
return nil
}
+func (t *Targets) AddSelection(sel interface{}) error { return t.ts[t.idx].AddSelection(sel) }
+
+func (t *Targets) HasSelections() bool {
+ for _, t := range t.ts {
+ if !t.HasSelection() {
+ return false
+ }
+ }
+ return true
+}
+
+func (t *Targets) ClearSelections() {
+ for _, t := range t.ts {
+ t.ClearSelection()
+ }
+}
+func (t *Targets) Options() (options []interface{}) { return t.ts[t.idx].Options() }
+func (t *Targets) Next() { t.idx++ }
+
func (t *Targets) CheckTargets(s *State) error {
for _, target := range t.ts {
if err := target.CheckSelection(s); err != nil {
@@ -240,22 +263,26 @@ func attackableTargetConstraint(action Action) TargetConstraintFunc {
}
}
-func rangeTargetConstraint(source interface{}, r int) TargetConstraintFunc {
- var sourcePos Position
- switch source := source.(type) {
+func posFromTileOrPermanent(tileOrPermanent interface{}) Position {
+ switch obj := tileOrPermanent.(type) {
case *Tile:
- sourcePos = source.Position
+ return obj.Position
case Permanent:
- sourcePos = source.Tile().Position
+ return obj.Tile().Position
default:
- log.Fatalf("Unhandled source type %T in rangeTargetConstraint", source)
+ log.Fatalf("Unhandled source type %T in posFromTileOrPermanent", tileOrPermanent)
+ return INVALID_POSITION()
}
+}
+
+func rangeTargetConstraint(source interface{}, r int) TargetConstraintFunc {
+ sourcePos := posFromTileOrPermanent(source)
return func(t interface{}) (err error) {
- p, _ := t.(Permanent)
- if !IsPositionInRange(sourcePos, p.Tile().Position, r) {
+ targetPos := posFromTileOrPermanent(t)
+ if !IsPositionInRange(sourcePos, targetPos, r) {
err = fmt.Errorf("Position %v of target %v not in range %d of source's position %v",
- p.Tile().Position, t, r, sourcePos)
+ targetPos, t, r, sourcePos)
}
return
}
@@ -419,6 +446,16 @@ func parseTileTargetConstraint(desc string, s *State, action Action) []TargetCon
constraints = append(constraints, rangeTargetConstraint(action.Source(), 1))
}
+ if strings.Contains(desc, "free") {
+ constraints = append(constraints, func(t interface{}) (err error) {
+ tile := t.(*Tile)
+ if tile.IsFree() {
+ return nil
+ }
+ return fmt.Errorf("tile %v is occupied by %v", tile, tile.Permanent)
+ })
+ }
+
return constraints
}
@@ -461,7 +498,13 @@ func parseCardTargetConstraint(desc string, s *State, action Action) []TargetCon
case "hand":
pocs = append(pocs, p.Hand)
case "store":
- pocs = append(pocs, p.Store)
+ if p.gameState.Map.HasStores() {
+ for _, s := range p.AvailableStores() {
+ pocs = append(pocs, s)
+ }
+ } else {
+ pocs = append(pocs, p.Store)
+ }
case "discard pile":
pocs = append(pocs, p.DiscardPile)
}