diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2024-03-25 18:22:48 +0100 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-08-20 15:57:09 +0200 |
| commit | 81d57c0a8466ec55ed6cb04e63528b46209e3768 (patch) | |
| tree | 689ee96145e83ba755fb0f6995e647cd32f6c8cf | |
| parent | 7d5302661d163358a0f9f8cc0b4d48f12fd277b0 (diff) | |
| download | muhqs-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.go | 8 | ||||
| -rw-r--r-- | go/game/card.go | 59 | ||||
| -rw-r--r-- | go/game/cardImplementations.go | 4 | ||||
| -rw-r--r-- | go/game/card_test.go | 14 | ||||
| -rw-r--r-- | go/game/costs.go | 62 | ||||
| -rw-r--r-- | go/game/kraken.go | 5 |
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 } |
