aboutsummaryrefslogtreecommitdiff
path: root/go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-08-15 16:51:07 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-15 23:52:20 +0200
commiteecc2f0161b1e10b1ff580623857bd563dbe952c (patch)
tree77c2322b6db25d9edfc93c6ebfadcefe26f6693e /go
parent909a84f907171637a6cd1bb0846e0d1ca758063c (diff)
downloadmuhqs-game-eecc2f0161b1e10b1ff580623857bd563dbe952c.tar.gz
muhqs-game-eecc2f0161b1e10b1ff580623857bd563dbe952c.zip
improve timing of declared actions
Diffstat (limited to 'go')
-rw-r--r--go/game/action.go1
-rw-r--r--go/game/state.go48
-rw-r--r--go/game/state_test.go34
3 files changed, 63 insertions, 20 deletions
diff --git a/go/game/action.go b/go/game/action.go
index d2c46928..1b89265d 100644
--- a/go/game/action.go
+++ b/go/game/action.go
@@ -226,6 +226,7 @@ func (a *PileDropAction) String() string {
return s[:len(s)-1] + " ]"
}
+func (*PileDropAction) Speed() ActionSpeed { return fast }
func (*PileDropAction) PayCosts(*LocalState) bool { return true }
func newPileDropAction(perm Permanent, tile *Tile, pile []Permanent) *PileDropAction {
diff --git a/go/game/state.go b/go/game/state.go
index b72da192..fd79b114 100644
--- a/go/game/state.go
+++ b/go/game/state.go
@@ -357,7 +357,6 @@ func (s *LocalState) isValidBuy(a *BuyAction) error {
return fmt.Errorf("%s' controls no unit on a store containing %s",
a.player.Name, card.Name)
}
-
} else if !slices.Contains(a.player.Store.cards, card) {
return fmt.Errorf("%s's store does not contain %s", a.player.Name, card.Name)
}
@@ -458,35 +457,48 @@ func (s *LocalState) pushAction(a Action) {
s.stack.push(a)
}
-type ErrDeclareSlowAction struct {
+type ErrDeclareAction struct {
reason string
}
-func (err ErrDeclareSlowAction) Error() string {
+func (err ErrDeclareAction) Error() string {
return err.reason
}
+var (
+ ErrDeclareActionWrongPhase = ErrDeclareAction{"wrong phase"}
+ ErrDeclareActionStackNotEmpty = ErrDeclareAction{"stack not empty"}
+)
+
+func (s *LocalState) checkActionTiming(a Action) error {
+ switch a.(type) {
+ case *BuyAction:
+ if s.activePhase != Phases.BuyPhase || s.activePlayerId != a.Controller().Id {
+ return ErrDeclareActionWrongPhase
+ }
+ case *UpkeepAction:
+ if s.activePhase != Phases.UpkeepPhase || s.activePlayerId != a.Controller().Id {
+ return ErrDeclareActionWrongPhase
+ }
+ default:
+ if a.Speed() == ActionSpeeds.Slow {
+ if !s.stack.IsEmpty() {
+ return ErrDeclareActionStackNotEmpty
+ } else if s.activePlayerId != a.Controller().Id || s.activePhase != Phases.ActionPhase {
+ return ErrDeclareActionWrongPhase
+ }
+ }
+ }
+ return nil
+}
+
func (s *LocalState) declareAction(a Action) {
var err error
err = a.CheckTargets(s)
if err == nil {
- switch a.(type) {
- case *BuyAction:
- if s.activePhase != Phases.BuyPhase {
- err = errors.New("cards can only be bought during one's buy phase")
- }
- case *FreeAction:
- default:
- if a.Speed() == ActionSpeeds.Slow {
- if !s.stack.IsEmpty() {
- err = ErrDeclareSlowAction{"stack not empty"}
- } else if s.activePlayerId != a.Controller().Id || s.activePhase != Phases.ActionPhase {
- err = ErrDeclareSlowAction{"not action phase"}
- }
- }
- }
+ err = s.checkActionTiming(a)
}
if err == nil {
diff --git a/go/game/state_test.go b/go/game/state_test.go
index ad7fdca7..6a9d6eb8 100644
--- a/go/game/state_test.go
+++ b/go/game/state_test.go
@@ -6,17 +6,47 @@ import (
func TestDeclareActions(t *testing.T) {
s := NewLocalState()
- s.SetMap(newEmpty2x2Map())
+ m := newEmpty2x2Map()
+ s.SetMap(m)
+
p := s.AddNewPlayer("p", NewDeck())
+ p.Store.AddCard(NewCard("base/sword"))
p.Ctrl = newMockPlayerControl(p)
o := s.AddNewPlayer("o", NewDeck())
o.Ctrl = newMockPlayerControl(o)
+
a := s.addNewUnit(NewCard("base/archer"), Position{0, 0}, p)
k := s.addNewUnit(NewCard("base/knight"), Position{1, 1}, o)
+
sa := NewAttackAction(a)
sa.Target().AddSelection(k)
s.declareAction(sa)
if !s.stack.IsEmpty() {
- t.Fatal("declared slow action during upkeep")
+ t.Fatal("declared attack action during upkeep")
+ }
+
+ ma := NewMoveAction(a)
+ ma.Target().AddSelection(m.TileAt(Position{1, 0}))
+ s.declareAction(ma)
+ if !s.stack.IsEmpty() {
+ t.Fatal("declared move action during upkeep")
+ }
+
+ ba := newBuyAction(p)
+ ba.Target().AddSelection(p.Store.Cards()[0])
+ s.declareAction(ba)
+ if !s.stack.IsEmpty() {
+ t.Fatal("declared buy action during upkeep")
+ }
+
+ s.activePhase = Phases.ActionPhase
+ s.declareAction(sa)
+ if s.stack.IsEmpty() {
+ t.Fatal("attack action not declared")
+ }
+
+ s.declareAction(ma)
+ if len(s.stack.Actions) == 2 {
+ t.Fatal("declared move action with non empty stack")
}
}