aboutsummaryrefslogtreecommitdiff
path: root/go/game/state.go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2023-01-25 21:10:44 +0100
committerFlorian Fischer <florian.fischer@muhq.space>2025-01-27 16:43:44 +0100
commit8720ebf9c74d9e11001772b5c00c293fa3a8b9e5 (patch)
tree70013771c425746318d290b5cadad0bbc1a48abb /go/game/state.go
parent73d40903aecad3efcf7c6055c133f0db86558203 (diff)
downloadmuhqs-game-8720ebf9c74d9e11001772b5c00c293fa3a8b9e5.tar.gz
muhqs-game-8720ebf9c74d9e11001772b5c00c293fa3a8b9e5.zip
intermediate commit
Diffstat (limited to 'go/game/state.go')
-rw-r--r--go/game/state.go101
1 files changed, 68 insertions, 33 deletions
diff --git a/go/game/state.go b/go/game/state.go
index 1a6ae093..29267c28 100644
--- a/go/game/state.go
+++ b/go/game/state.go
@@ -6,6 +6,7 @@ import (
"math/rand"
"strconv"
"strings"
+ "time"
)
type State struct {
@@ -17,15 +18,17 @@ type State struct {
DiscardPiles []*DiscardPile
Players []*Player
ActivePlayerId int
+ ActivePhase PhaseType
Permanents []Permanent
Units []*Unit
Artifacts []*Artifact
- Rand rand.Rand
+ Rand *rand.Rand
}
func NewState() *State {
s := &State{}
s.Stack = NewStack(s)
+ s.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
return s
}
@@ -38,33 +41,32 @@ func (s *State) Loop() []*Player {
winners := []*Player{}
for len(winners) == 0 {
for i, p := range s.Players {
- log.Printf("Starting %s turn %d\n", p.Name, p.Turn)
s.ActivePlayerId = i
p.Turn++
if p.Deck.IsEmpty() {
log.Printf("Shuffle %s pile into the deck\n", p.Name)
p.DiscardPile.MoveInto(p.Deck)
- p.Deck.Shuffle()
+ p.Deck.Shuffle(s.Rand)
}
- log.Printf("%s draw\n", p.Name)
+ s.ActivePhase = drawPhase
p.Draw()
- log.Printf("%s Upkeep\n", p.Name)
+ s.ActivePhase = upkeepPhase
p.Upkeep()
s.PhaseChange(i)
- log.Printf("%s Actions\n", p.Name)
+ s.ActivePhase = actionPhase
p.ActionPhase()
s.PhaseChange(i)
- log.Printf("%s Buystep\n", p.Name)
- p.BuyStep()
+ s.ActivePhase = buyPhase
+ p.BuyPhase()
s.PhaseChange(i)
- log.Printf("%s Discard\n", p.Name)
- p.DiscardStep()
+ s.ActivePhase = discardPhase
+ p.DiscardPhase()
winners = s.Map.WinCondition(s)
}
@@ -75,7 +77,7 @@ func (s *State) Loop() []*Player {
func (s *State) PushAction(a Action) {
if !a.PayCosts(s) {
- log.Fatalf("Cost for a could not be paid")
+ log.Fatalf("Cost for %s could not be paid", a)
}
s.Stack.Push(a)
}
@@ -84,6 +86,11 @@ func (s *State) DeclareAction(a Action) {
if !s.Stack.IsEmpty() {
log.Fatalf("Slow action can not be declared while other actions are on the stack")
}
+
+ if s.ActivePhase != actionPhase {
+ log.Fatalf("Slow action can not be declared during one's actions phase")
+ }
+
s.PushAction(a)
}
@@ -101,14 +108,14 @@ func (s *State) AllPassing() bool {
case *PassPriorityAction:
log.Printf("%s passed %d/%d\n", p.Name, i, nPlayers)
default:
- s.Stack.Push(a)
+ s.DeclareAction(a)
return false
}
}
return true
}
-func (s *State) PhaseChange(activePlaerId int) {
+func (s *State) PhaseChange(activePlayerId int) {
log.Println("Phase change")
for !s.AllPassing() {
s.Stack.Resolve()
@@ -122,19 +129,6 @@ func (s *State) broadcastNotification(n PlayerNotification) {
}
}
-func (s *State) Upkeep(p *Player) {
- p.Ressource += s.Map.RessourceGain
- // TODO: handle upkeep trigger
- for _, unit := range s.Units {
- if unit.Controller != p {
- continue
- }
-
- // TODO: let players decide if they want to pay the upkeep
- p.Ressource -= unit.Upkeep
- }
-}
-
func (s *State) AddPermanent(perm Permanent) {
s.Permanents = append(s.Permanents, perm)
switch p := perm.(type) {
@@ -191,6 +185,7 @@ func (s *State) DestroyPermanent(p Permanent) {
case *Artifact:
s.Artifacts = removePtr(s.Artifacts, p)
}
+ p.GetOwner().DiscardPile.AddCard(p.GetCard())
}
func (s *State) Fight(p1, p2 Permanent) {
@@ -208,26 +203,49 @@ func (s *State) MoveUnit(u *Unit, t *Tile) {
u.move(s, t)
}
-func (s *State) EnemyUnits(player *Player) []*Unit {
- // TODO: support coop / teams
- enemyUnits := []*Unit{}
+func (s *State) FilterUnits(filter func(*Unit) bool) []*Unit {
+ units := []*Unit{}
for _, u := range s.Units {
- if u.GetController() != player {
- enemyUnits = append(enemyUnits, u)
+ if filter(u) {
+ units = append(units, u)
}
}
- return enemyUnits
+ return units
+}
+
+func (s *State) OwnUnits(player *Player) []*Unit {
+ return s.FilterUnits(func(u *Unit) bool {
+ return u.GetController() == player
+ })
+}
+
+func (s *State) EnemyUnits(player *Player) []*Unit {
+ return s.FilterUnits(func(u *Unit) bool {
+ // TODO: support coop / teams
+ return u.GetController() != player
+ })
}
func (s *State) ResolvePlay(p *Player, c *Card, targets interface{}) {
switch c.Type {
case UnitType:
s.AddNewUnit(c, targets.(Position), p)
+ case ArtifactType:
+ s.AddNewArtifact(c, targets.(Position), p)
+ default:
+ log.Printf("Resolving unhandled card type: %s\n", c.Type.String())
+ }
+
+ if !c.IsPermanent() {
+ p.DiscardPile.AddCard(c)
}
- p.DiscardPile.AddCard(c)
}
func (s *State) SpawnTiles(p *Player) []*Tile {
+ if p.Name == "The Kraken" {
+ return s.KrakenSpawnTiles()
+ }
+
spawns := s.Map.FilterTiles(func(t *Tile) bool {
if t.Type != TileTypes.Spawn {
return false
@@ -238,3 +256,20 @@ func (s *State) SpawnTiles(p *Player) []*Tile {
return spawns
}
+
+func (s *State) AvailableSpawnTiles(p *Player, c *Card) []*Tile {
+ if !c.IsPermanent() {
+ log.Fatalf("AvailableSpawnTiles called for %s", c.Type.String())
+ }
+
+ candidates := s.SpawnTiles(p)
+ tiles := []*Tile{}
+
+ for _, candidate := range candidates {
+ if candidate.IsAvailableForCard(c) {
+ tiles = append(tiles, candidate)
+ }
+ }
+
+ return tiles
+}