aboutsummaryrefslogtreecommitdiff
path: root/go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2023-02-08 12:44:07 +0100
committerFlorian Fischer <florian.fischer@muhq.space>2025-01-27 16:43:48 +0100
commit5dae3b7e97669bc6ad5dfc61bbb1903aeb03aaf3 (patch)
tree62ce4be85d1014d797cfadbebe38e6a11872dbf3 /go
parentbb7810a4bb0ee1a3c21de67e857ca41596646da3 (diff)
downloadmuhqs-game-5dae3b7e97669bc6ad5dfc61bbb1903aeb03aaf3.tar.gz
muhqs-game-5dae3b7e97669bc6ad5dfc61bbb1903aeb03aaf3.zip
intermediate commit
* detect tokens and do not add them to pile of cards * only add spells not already in exile to their owners discard pile * add the played card to onPlay callback
Diffstat (limited to 'go')
-rw-r--r--go/game/card.go25
-rw-r--r--go/game/cardImplementations.go56
-rw-r--r--go/game/cardParsing.go6
-rw-r--r--go/game/pileOfCards.go9
-rw-r--r--go/game/state.go9
-rw-r--r--go/game/store.go11
6 files changed, 80 insertions, 36 deletions
diff --git a/go/game/card.go b/go/game/card.go
index c1c74490..a6abffd1 100644
--- a/go/game/card.go
+++ b/go/game/card.go
@@ -80,7 +80,7 @@ type cardImplementation interface {
onEntering(*Tile)
onLeaving(*Tile)
- onPlay(*State, *Player, *Targets)
+ onPlay(*State, *Card, *Player, *Targets)
onPile(containing Permanent)
onUnpile(containing Permanent)
onDrop(dropped Permanent)
@@ -98,12 +98,12 @@ func (*cardImplementationBase) freeActions(Permanent) []*FreeAction { return nil
func (*cardImplementationBase) stateBasedActions(*State, Permanent) {}
-func (*cardImplementationBase) onEntering(*Tile) {}
-func (*cardImplementationBase) onLeaving(*Tile) {}
-func (*cardImplementationBase) onPlay(*State, *Player, *Targets) {}
-func (*cardImplementationBase) onPile(Permanent) {}
-func (*cardImplementationBase) onUnpile(Permanent) {}
-func (*cardImplementationBase) onDrop(Permanent) {}
+func (*cardImplementationBase) onEntering(*Tile) {}
+func (*cardImplementationBase) onLeaving(*Tile) {}
+func (*cardImplementationBase) onPlay(*State, *Card, *Player, *Targets) {}
+func (*cardImplementationBase) onPile(Permanent) {}
+func (*cardImplementationBase) onUnpile(Permanent) {}
+func (*cardImplementationBase) onDrop(Permanent) {}
// Map of all card implementations
var cardImplementations map[string]cardImplementation
@@ -312,6 +312,17 @@ func (c *Card) IsPermanent() bool {
c.Type == CardTypes.Potion
}
+func (c *Card) IsToken() bool {
+ if v, found := c.Values["token"]; found {
+ b, ok := v.(bool)
+ if !ok {
+ log.Fatalf("Invalid value for %s token value: %v", c.Name, v)
+ }
+ return b
+ }
+ return false
+}
+
func (c *Card) IsBuyable() bool {
return c.BuyCost != NOT_BUYABLE
}
diff --git a/go/game/cardImplementations.go b/go/game/cardImplementations.go
index 63c97ca7..3a7a729a 100644
--- a/go/game/cardImplementations.go
+++ b/go/game/cardImplementations.go
@@ -4,6 +4,14 @@ import (
"log"
)
+func adjustMelee(p Permanent, damage int) {
+ if u, ok := p.(*Unit); ok && !INVALID_ATTACK(u.Attack) {
+ u.Attack.attacks[0] += damage
+ }
+}
+
+// ====== Base Set ======
+
type advisorImpl struct{ cardImplementationBase }
func (*advisorImpl) fullActions(u *Unit) []*FullAction {
@@ -39,18 +47,22 @@ func (*missionaryImpl) fullActions(u *Unit) []*FullAction {
type swordImpl struct{ cardImplementationBase }
-func (*swordImpl) onPile(p Permanent) {
- if u, ok := p.(*Unit); ok && !INVALID_ATTACK(u.Attack) {
- u.Attack.attacks[0] += 1
- }
-}
+func (*swordImpl) onPile(p Permanent) { adjustMelee(p, 1) }
+func (*swordImpl) onUnpile(p Permanent) { adjustMelee(p, -1) }
-func (*swordImpl) onUnpile(p Permanent) {
- if u, ok := p.(*Unit); ok && !INVALID_ATTACK(u.Attack) {
- u.Attack.attacks[0] -= 1
- }
+type greatSwordImpl struct{ cardImplementationBase }
+
+func (*greatSwordImpl) onPile(p Permanent) { adjustMelee(p, 2) }
+func (*greatSwordImpl) onUnpile(p Permanent) { adjustMelee(p, -2) }
+
+type misinformationImpl struct{ cardImplementation }
+
+func (*misinformationImpl) onPlay(s *State, c *Card, _ *Player, _ *Targets) {
+ s.Exile.AddCard(c)
}
+// ====== Nautics Set ======
+
type fishTrapAoE struct{}
func (*fishTrapAoE) onEntering(p Permanent) {
@@ -147,15 +159,17 @@ func (*sailorImpl) onUnpile(containing Permanent) {
}
}
+// ====== Kraken Set ======
+
type tidesChangeImpl struct{ cardImplementation }
-func (*tidesChangeImpl) onPlay(s *State, _ *Player, _ *Targets) {
+func (*tidesChangeImpl) onPlay(s *State, _ *Card, _ *Player, _ *Targets) {
s.Map.redistributeStoreCards(s.Rand)
}
type dejaVuImpl struct{ cardImplementation }
-func (*dejaVuImpl) onPlay(s *State, _ *Player, _ *Targets) {
+func (*dejaVuImpl) onPlay(s *State, _ *Card, _ *Player, _ *Targets) {
for _, p := range s.Players {
if !p.IsKraken() {
p.Resource = s.Map.ResourceGain
@@ -165,7 +179,7 @@ func (*dejaVuImpl) onPlay(s *State, _ *Player, _ *Targets) {
type devourThePoorImpl struct{ cardImplementation }
-func (*devourThePoorImpl) onPlay(s *State, kraken *Player, _ *Targets) {
+func (*devourThePoorImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
for _, u := range s.EnemyUnits(kraken) {
if u.Card().BuyCost < 7 {
s.DestroyPermanent(u)
@@ -233,7 +247,7 @@ func (i *frostPylonImpl) onLeaving(t *Tile) {
type giganticHailImpl struct{ cardImplementation }
-func (*giganticHailImpl) onPlay(s *State, kraken *Player, _ *Targets) {
+func (*giganticHailImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
emptyTiles := s.Map.FreeTiles()
choices := len(emptyTiles)
for i := 0; i < 3; i++ {
@@ -250,7 +264,7 @@ func (*giganticHailImpl) onPlay(s *State, kraken *Player, _ *Targets) {
type soldOutImpl struct{ cardImplementation }
-func (*soldOutImpl) onPlay(s *State, kraken *Player, _ *Targets) {
+func (*soldOutImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
nStores := len(s.Map.Stores)
storePositions := make([]Position, 0, nStores)
for pos := range s.Map.Stores {
@@ -266,13 +280,13 @@ func (*soldOutImpl) onPlay(s *State, kraken *Player, _ *Targets) {
type supriseImpl struct{ cardImplementation }
-func (*supriseImpl) onPlay(s *State, kraken *Player, _ *Targets) {
+func (*supriseImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
kraken.Ctrl.(*KrakenControl).activeSuprise = true
}
type tentacleSlapImpl struct{ cardImplementation }
-func (*tentacleSlapImpl) onPlay(s *State, kraken *Player, _ *Targets) {
+func (*tentacleSlapImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
x := 0
for _, p := range s.Players {
if p.IsKraken() {
@@ -291,7 +305,7 @@ func (*tentacleSlapImpl) onPlay(s *State, kraken *Player, _ *Targets) {
type unholyCannonballImpl struct{ cardImplementation }
-func (*unholyCannonballImpl) onPlay(s *State, kraken *Player, _ *Targets) {
+func (*unholyCannonballImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
krakenTiles := s.Map.FilterTiles(func(t *Tile) bool { return t.Raw == "the kraken" })
if len(krakenTiles) != 1 {
log.Fatal("No kraken tile found in Map")
@@ -320,9 +334,11 @@ func (*unholyCannonballImpl) onPlay(s *State, kraken *Player, _ *Targets) {
func init() {
cardImplementations = map[string]cardImplementation{
- "base/advisor": &advisorImpl{},
- "base/missionary": &missionaryImpl{},
- "base/sword": &swordImpl{},
+ "base/advisor": &advisorImpl{},
+ "base/missionary": &missionaryImpl{},
+ "base/sword": &swordImpl{},
+ "base/greatsword": &greatSwordImpl{},
+ "base/misinformation": &misinformationImpl{},
"nautics/captain": &captainImpl{},
"nautics/fish_trap": &fishTrapImpl{},
diff --git a/go/game/cardParsing.go b/go/game/cardParsing.go
index de1c7be4..315de293 100644
--- a/go/game/cardParsing.go
+++ b/go/game/cardParsing.go
@@ -16,7 +16,7 @@ type dynamicCardImplementation struct {
_stateBasedActions func(*State, Permanent)
_onEntering func(*Tile)
_onLeaving func(*Tile)
- _onPlay func(*State, *Player, *Targets)
+ _onPlay func(*State, *Card, *Player, *Targets)
_onPile func(Permanent)
_onUnpile func(Permanent)
_onDrop func(Permanent)
@@ -61,9 +61,9 @@ func (impl *dynamicCardImplementation) onLeaving(t *Tile) {
}
}
-func (impl *dynamicCardImplementation) onPlay(s *State, p *Player, t *Targets) {
+func (impl *dynamicCardImplementation) onPlay(s *State, c *Card, p *Player, t *Targets) {
if impl._onPlay != nil {
- impl._onPlay(s, p, t)
+ impl._onPlay(s, c, p, t)
}
}
diff --git a/go/game/pileOfCards.go b/go/game/pileOfCards.go
index 427bba47..0a5eaa97 100644
--- a/go/game/pileOfCards.go
+++ b/go/game/pileOfCards.go
@@ -41,11 +41,16 @@ func (poc *PileOfCardsBase) Cards() []*Card {
}
func (poc *PileOfCardsBase) AddCards(cards []*Card) {
- poc.cards = append(poc.cards, cards...)
+ for _, card := range cards {
+ poc.AddCard(card)
+ }
}
func (poc *PileOfCardsBase) AddCard(card *Card) {
- poc.cards = append(poc.cards, card)
+ // Tokens can not be part of any pile of cards
+ if !card.IsToken() {
+ poc.cards = append(poc.cards, card)
+ }
}
func (poc *PileOfCardsBase) RemoveCard(card *Card) {
diff --git a/go/game/state.go b/go/game/state.go
index 5a4714f7..7a54ddc0 100644
--- a/go/game/state.go
+++ b/go/game/state.go
@@ -392,14 +392,15 @@ func (s *State) resolvePlay(p *Player, c *Card, targets *Targets) {
s.addNewEquipment(c, tile.Position, p)
}
case CardTypes.Spell:
- c.Impl.onPlay(s, p, targets)
+ c.Impl.onPlay(s, c, p, targets)
default:
log.Printf("Resolving unhandled card type: %s\n", c.Type.String())
}
- if c.IsPermanent() {
- } else {
- p.DiscardPile.AddCard(c)
+ if c.Type == CardTypes.Spell {
+ if !s.Exile.Contains(c) {
+ p.DiscardPile.AddCard(c)
+ }
}
}
diff --git a/go/game/store.go b/go/game/store.go
index 46c136e0..73153980 100644
--- a/go/game/store.go
+++ b/go/game/store.go
@@ -1,5 +1,9 @@
package game
+import (
+ "log"
+)
+
type Store struct {
PileOfCardsBase
}
@@ -8,3 +12,10 @@ func NewStore() *Store {
s := &Store{PileOfCardsBase{[]*Card{}}}
return s
}
+
+func (s *Store) AddCard(card *Card) {
+ if !card.IsBuyable() {
+ log.Fatalf("Non buyable card %s can not be added to a store", card.Name)
+ }
+ s.PileOfCardsBase.AddCard(card)
+}