aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go/game/player.go25
-rw-r--r--go/game/stack.go17
-rw-r--r--go/game/state.go83
3 files changed, 88 insertions, 37 deletions
diff --git a/go/game/player.go b/go/game/player.go
index f7f5be7c..2edbe923 100644
--- a/go/game/player.go
+++ b/go/game/player.go
@@ -111,7 +111,7 @@ func (p *Player) reduceResource(amount int) {
}
}
-func (p *Player) upkeep() {
+func (p *Player) upkeep() []*Player {
p.gainResource(p.ResourceGain())
// TODO: handle upkeep triggers
@@ -125,7 +125,7 @@ func (p *Player) upkeep() {
}
}
if !controllsUnits {
- return
+ return nil
}
a, err := prompt(p.Ctrl, newUpkeepPrompt(p))
@@ -139,30 +139,33 @@ func (p *Player) upkeep() {
// FIXME: upkeep action is special paying is part of its effect
p.gameState.declareAction(a)
- p.gameState.stack.resolve()
+ return p.gameState.stack.resolve()
}
-func (p *Player) actionPhase() {
+func (p *Player) actionPhase() []*Player {
for {
a, err := promptAction(p.Ctrl)
if err != nil {
// FIXME
}
if _, ok := a.(*PassPriority); ok {
- return
+ return nil
}
if a == nil {
log.Fatal("Received nil action from ", p.Name)
}
p.gameState.declareAction(a)
- p.gameState.stack.resolve()
+ w := p.gameState.stack.resolve()
+ if len(w) > 0 {
+ return w
+ }
}
}
-func (p *Player) buyPhase() {
+func (p *Player) buyPhase() []*Player {
s := p.gameState
if p.Store.Size() == 0 && s.Map().HasStores() && len(p.knownStores) == 0 {
- return
+ return nil
}
a, err := promptBuy(p.Ctrl)
if err != nil {
@@ -170,13 +173,15 @@ func (p *Player) buyPhase() {
}
if _, ok := a.(*PassPriority); ok {
- return
+ return nil
}
if a.Targets().HasSelections() {
s.declareAction(a)
- s.stack.resolve()
+ return s.stack.resolve()
}
+
+ return nil
}
func (p *Player) discardHand() {
diff --git a/go/game/stack.go b/go/game/stack.go
index a4ba6a49..62783bf2 100644
--- a/go/game/stack.go
+++ b/go/game/stack.go
@@ -45,11 +45,22 @@ func (s *Stack) pop() {
}
}
-func (s *Stack) resolve() {
+func (s *Stack) resolve() []*Player {
for !s.IsEmpty() {
- for !s.gameState.allPassing(false) {
+ for {
+ passing, w := s.gameState.allPassing(false)
+ if len(w) > 0 {
+ return w
+ }
+ if passing {
+ break
+ }
}
s.pop()
- s.gameState.stateBasedActions()
+ w := s.gameState.stateBasedActions()
+ if len(w) > 0 {
+ return w
+ }
}
+ return nil
}
diff --git a/go/game/state.go b/go/game/state.go
index 16670263..73374c6a 100644
--- a/go/game/state.go
+++ b/go/game/state.go
@@ -154,8 +154,7 @@ func (s *LocalState) Loop() []*Player {
s._map.distributeStoreCards(poc, s.Rand)
}
- winners := []*Player{}
- for len(winners) == 0 {
+ for {
for _, p := range s.players {
s.activePlayerId = p.Id
p.Turn++
@@ -170,27 +169,44 @@ func (s *LocalState) Loop() []*Player {
p.Draw()
s.activePhase = Phases.UpkeepPhase
- p.upkeep()
- s.phaseChange()
+ winners := p.upkeep()
+ if len(winners) > 0 {
+ return winners
+ }
+ winners = s.phaseChange()
+ if len(winners) > 0 {
+ return winners
+ }
s.activePhase = Phases.ActionPhase
- p.actionPhase()
- s.phaseChange()
+ winners = p.actionPhase()
+ if len(winners) > 0 {
+ return winners
+ }
+ winners = s.phaseChange()
+ if len(winners) > 0 {
+ return winners
+ }
s.activePhase = Phases.BuyPhase
- p.buyPhase()
- s.phaseChange()
+ winners = p.buyPhase()
+ if len(winners) > 0 {
+ return winners
+ }
+ winners = s.phaseChange()
+ if len(winners) > 0 {
+ return winners
+ }
s.activePhase = Phases.DiscardStep
p.discardStep()
- s.endOfTurn()
-
- winners = s._map.WinCondition(s)
+ winners = s.endOfTurn()
+ if len(winners) > 0 {
+ return winners
+ }
}
}
-
- return winners
}
func (s *LocalState) addTrigger(trigger Trigger) {
@@ -232,7 +248,7 @@ func (s *LocalState) handleTriggers() {
}
}
-func (s *LocalState) stateBasedActions() {
+func (s *LocalState) stateBasedActions() []*Player {
for _, p := range s.permanents {
p.Card().Impl.stateBasedActions(s, p)
@@ -242,6 +258,9 @@ func (s *LocalState) stateBasedActions() {
}
s.handleTriggers()
+
+ w := s._map.WinCondition(s)
+ return w
}
func (s *LocalState) IsValidPlay(a *PlayAction) error {
@@ -273,7 +292,7 @@ func (s *LocalState) IsValidMove(a *MoveAction) error {
u := a.Source().(*Unit)
tile := relaxedTileTarget(a, a.Target().sel[0])
- if !slices.Contains(u.MoveRangeTiles(s._map), tile) {
+ if !slices.Contains(u.MoveRangeTiles(), tile) {
return fmt.Errorf("Unit %s@%v can not move to %s",
u.card.Name, u.tile.Position, tile.Position.String())
}
@@ -508,7 +527,7 @@ func (s *LocalState) orderTriggeredActions(triggeredActions []*TriggeredAction)
return orderedActions
}
-func (s *LocalState) allPassing(skipFirst bool) bool {
+func (s *LocalState) allPassing(skipFirst bool) (bool, []*Player) {
nPlayers := len(s.players)
i := 0
if skipFirst {
@@ -516,7 +535,10 @@ func (s *LocalState) allPassing(skipFirst bool) bool {
}
for ; i < nPlayers; i++ {
p := s.players[(i+s.activePlayerId-1)%nPlayers]
- s.stateBasedActions()
+ w := s.stateBasedActions()
+ if len(w) > 0 {
+ return false, w
+ }
p.Ctrl.SendNotification(newPriorityNotification())
_a, err := p.Ctrl.RecvAction()
if err != nil {
@@ -530,18 +552,31 @@ func (s *LocalState) allPassing(skipFirst bool) bool {
log.Fatal("received nil action from ", p.Name, " at ", s.activePhase)
default:
s.declareAction(a)
- return false
+ return false, nil
}
}
- return true
+ return true, nil
}
-func (s *LocalState) phaseChange() {
+func (s *LocalState) phaseChange() []*Player {
skipFirst := true
- for !s.allPassing(skipFirst) {
- s.stack.resolve()
+ for {
+ passing, w := s.allPassing(skipFirst)
+ if len(w) > 0 {
+ return w
+ }
+ if passing {
+ break
+ }
+
+ w = s.stack.resolve()
+ if len(w) > 0 {
+ return w
+ }
+
skipFirst = false
}
+ return nil
}
func (s *LocalState) broadcastNotification(n PlayerNotification) {
@@ -825,7 +860,7 @@ func (s *LocalState) addEotEffect(e effect) {
s.eotEffects = append(s.eotEffects, e)
}
-func (s *LocalState) endOfTurn() {
+func (s *LocalState) endOfTurn() []*Player {
// Move all outstanding equipment cards to the discard pile
for _, e := range s.outstandingEquipment {
s.ActivePlayer().DiscardPile.AddCard(e)
@@ -837,7 +872,7 @@ func (s *LocalState) endOfTurn() {
s.eotEffects = nil
s.events = append(s.events, newEotEvent())
- s.stateBasedActions()
+ return s.stateBasedActions()
}
// ResolveAction resolves an action without using the stack.