aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2024-03-25 18:22:48 +0100
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-20 15:57:09 +0200
commit81d57c0a8466ec55ed6cb04e63528b46209e3768 (patch)
tree689ee96145e83ba755fb0f6995e647cd32f6c8cf
parent7d5302661d163358a0f9f8cc0b4d48f12fd277b0 (diff)
downloadmuhqs-game-81d57c0a8466ec55ed6cb04e63528b46209e3768.tar.gz
muhqs-game-81d57c0a8466ec55ed6cb04e63528b46209e3768.zip
support parsing variadic costs
TODO: * select the variadic components * test the costs type
-rw-r--r--go/game/action.go8
-rw-r--r--go/game/card.go59
-rw-r--r--go/game/cardImplementations.go4
-rw-r--r--go/game/card_test.go14
-rw-r--r--go/game/costs.go62
-rw-r--r--go/game/kraken.go5
6 files changed, 116 insertions, 36 deletions
diff --git a/go/game/action.go b/go/game/action.go
index 0c372ab8..1863590e 100644
--- a/go/game/action.go
+++ b/go/game/action.go
@@ -205,8 +205,8 @@ func NewPlayAction(p *Player, c *Card, args ...interface{}) *PlayAction {
}
if a.costFunc == nil {
- a.costFunc = func(*State) bool {
- cost := c.PlayCosts()
+ a.costFunc = func(s *State) bool {
+ cost := c.PlayCosts.Costs(s)
if p.Resource < cost {
return false
@@ -536,8 +536,8 @@ func (a *BuyAction) resolve(s *State) {
a.player.Store.MoveCard(a.card(), a.player.DiscardPile)
}
-func (a *BuyAction) PayCosts(*State) bool {
- cost := a.card().BuyCost
+func (a *BuyAction) PayCosts(s *State) bool {
+ cost := a.card().BuyCosts.Costs(s)
if cost < 0 || cost > a.player.Resource {
return false
}
diff --git a/go/game/card.go b/go/game/card.go
index e52ad3dc..3507f5fd 100644
--- a/go/game/card.go
+++ b/go/game/card.go
@@ -148,16 +148,16 @@ func getCardImplementation(c *Card) cardImplementation {
const (
CARD_DATA_URL string = "data/cards"
- NOT_BUYABLE int = -1 // Maybe this needs to be changed some day to allow more design space
)
type Card struct {
- Name string
- Set SetIdentifier
- Type CardType
- BuyCost int
- Values map[string]interface{}
- Impl cardImplementation
+ Name string
+ Set SetIdentifier
+ Type CardType
+ BuyCosts *ResourceCosts
+ PlayCosts *ResourceCosts
+ Values map[string]interface{}
+ Impl cardImplementation
}
var cardDefinitions = map[string]map[string][]byte{}
@@ -221,18 +221,29 @@ func (card *Card) parseDefinition(definition []byte) {
card.Type = CardTypeNames[t.(string)]
- bc, found := data["buy"]
- if found {
- card.BuyCost = bc.(int)
- } else {
- card.BuyCost = NOT_BUYABLE
- }
+ bc, bcFound := data["buy"]
delete(data, "buy")
+ pc, pcFound := data["play"]
+ delete(data, "play")
+
for k, v := range data {
card.Values[k.(string)] = v
}
+ if bcFound {
+ card.BuyCosts = ParseCardResourceCosts(bc, card.getEffects())
+ }
+
+ if pcFound {
+ switch card.Type {
+ case CardTypes.Unit:
+ card.PlayCosts = &ResourceCosts{fixed: card.Values["upkeep"].(int)}
+ default:
+ card.PlayCosts = ParseCardResourceCosts(pc, card.getEffects())
+ }
+ }
+
card.Impl = getCardImplementation(card)
}
@@ -322,11 +333,12 @@ func NewCard(cardPath string) *Card {
cardDefinition := getCardDefinition(set, cardName)
c := Card{
- Name: "",
- Set: SetNames[set],
- Type: undefinedCardType,
- BuyCost: NOT_BUYABLE,
- Values: map[string]interface{}{},
+ Name: "",
+ Set: SetNames[set],
+ Type: undefinedCardType,
+ BuyCosts: nil,
+ PlayCosts: nil,
+ Values: map[string]interface{}{},
}
c.parseDefinition(cardDefinition)
return &c
@@ -353,14 +365,5 @@ func (c *Card) IsToken() bool {
}
func (c *Card) IsBuyable() bool {
- return c.BuyCost != NOT_BUYABLE
-}
-
-func (c *Card) PlayCosts() int {
- switch c.Type {
- case CardTypes.Unit:
- return c.Values["upkeep"].(int)
- default:
- return c.Values["play"].(int)
- }
+ return c.BuyCosts != nil
}
diff --git a/go/game/cardImplementations.go b/go/game/cardImplementations.go
index 75ea4dcd..33d874b9 100644
--- a/go/game/cardImplementations.go
+++ b/go/game/cardImplementations.go
@@ -85,7 +85,7 @@ func (*missionaryImpl) fullActions(u *Unit) []*FullAction {
target := a.Target().sel[0].(*Unit)
return func(s *State) {
target.adjustMarks(UnitMarks.Faith, 2)
- if target.Marks(UnitMarks.Faith) > target.Card().BuyCost {
+ if target.Marks(UnitMarks.Faith) > target.Card().BuyCosts.Costs(s) {
target.controller = u.Controller()
}
}
@@ -424,7 +424,7 @@ type devourThePoorImpl struct{ cardImplementationBase }
func (*devourThePoorImpl) onPlay(s *State, _ *Card, kraken *Player, _ *Targets) {
for _, u := range s.EnemyUnits(kraken) {
- if u.Card().BuyCost < 7 {
+ if u.Card().BuyCosts.Costs(s) < 7 {
s.destroyPermanent(u)
}
}
diff --git a/go/game/card_test.go b/go/game/card_test.go
new file mode 100644
index 00000000..72f1489a
--- /dev/null
+++ b/go/game/card_test.go
@@ -0,0 +1,14 @@
+package game
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestLoadingAllCards(t *testing.T) {
+ v := reflect.ValueOf(Sets)
+ for i := 0; i < v.NumField(); i++ {
+ set := v.Field(i).Interface().(SetIdentifier)
+ NewDeckFromCardPaths(set.CardPaths()).Cards()
+ }
+}
diff --git a/go/game/costs.go b/go/game/costs.go
new file mode 100644
index 00000000..9fc40fcb
--- /dev/null
+++ b/go/game/costs.go
@@ -0,0 +1,62 @@
+package game
+
+import (
+ "strconv"
+ "strings"
+)
+
+type ResourceCosts struct {
+ variadicConstraintFunc func(*State) int
+ variadicConstraint string
+ fixed int
+ variadicComponents int
+}
+
+func (c *ResourceCosts) IsVariadic() bool {
+ return c.variadicConstraintFunc != nil || c.variadicComponents > 0
+}
+
+func ParseResourceCosts(costsStr string) *ResourceCosts {
+ costs := ResourceCosts{}
+ for c := range costsStr {
+ if c == 'X' {
+ costs.variadicComponents += 1
+ }
+ }
+ costs.fixed, _ = strconv.Atoi(strings.Replace(costsStr, "X", "", -1))
+ return &costs
+}
+
+func (c *ResourceCosts) Costs(s *State) int {
+ if !c.IsVariadic() {
+ return c.fixed
+ }
+
+ if c.variadicConstraintFunc != nil {
+ return c.fixed + c.variadicConstraintFunc(s)
+ }
+
+ // TODO: implement variadic costs
+ return 0
+}
+
+func ParseCardResourceCosts(_costs interface{}, effects []string) *ResourceCosts {
+ switch c := _costs.(type) {
+ case int:
+ return &ResourceCosts{fixed: c}
+ case string:
+ costs := ParseResourceCosts(c)
+ if !costs.IsVariadic() {
+ return costs
+ }
+
+ for _, effect := range effects {
+ if strings.Contains(effect, "X is") {
+ costs.variadicConstraint = effect
+ }
+ }
+ return costs
+ default:
+ return nil
+ }
+}
diff --git a/go/game/kraken.go b/go/game/kraken.go
index e5db4649..a836cb77 100644
--- a/go/game/kraken.go
+++ b/go/game/kraken.go
@@ -104,7 +104,8 @@ func (ctrl *KrakenControl) krakenTurn() {
}
c := drawn[0]
- if c.BuyCost > kraken.Resource {
+ costs := c.BuyCosts.Costs(s)
+ if costs > kraken.Resource {
log.Println("Kraken discards", c.Name, "because resource to low", kraken.Resource)
kraken.DiscardPile.AddCard(c)
break
@@ -112,7 +113,7 @@ func (ctrl *KrakenControl) krakenTurn() {
kraken.Hand.AddCard(c)
var costFunc ActionCostFunc = func(s *State) bool {
- kraken.Resource -= c.BuyCost
+ kraken.Resource -= costs
return true
}