From 67faa0f3bf6fb047d19372c9b671a45887b99f6e Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Wed, 3 Sep 2025 12:37:52 +0200 Subject: implement the patrician --- data/cards/exp1/patrician.yml | 21 +++++++++++++++++++ go/game/action.go | 12 +++++++++++ go/game/cardImplementations.go | 40 +++++++++++++++++++++++++++++++++++++ go/game/cardImplementations_test.go | 40 +++++++++++++++++++++++++++++++++++++ latex/cards/de/exp1/patrician.tex | 14 +++++++++++++ latex/cards/en/exp1/patrician.tex | 14 +++++++++++++ latex/sets/de/exp1.tex | 1 + 7 files changed, 142 insertions(+) create mode 100644 data/cards/exp1/patrician.yml create mode 100644 latex/cards/de/exp1/patrician.tex create mode 100644 latex/cards/en/exp1/patrician.tex diff --git a/data/cards/exp1/patrician.yml b/data/cards/exp1/patrician.yml new file mode 100644 index 00000000..d83cf7e4 --- /dev/null +++ b/data/cards/exp1/patrician.yml @@ -0,0 +1,21 @@ +type: unit +name: + en: Patrician + de: Patrizier +health: 1 +movement: 1 +buy: 7 +upkeep: 2 +effect: + en: + - "2: Gain +1 movement this turn" + - "3: Gain +1 attack this turn" + - "5: Gain +1 armor this turn" + - "7: Draw a card" + - "9: Create a Recruit token in range 1" + de: + - "2: Gain +1 movement this turn" + - "3: Gain +1 attack this turn" + - "5: Gain +1 armor this turn" + - "7: Draw a card" + - "9: Create a Recruit token in range 1" diff --git a/go/game/action.go b/go/game/action.go index 856ea6bc..91ea223c 100644 --- a/go/game/action.go +++ b/go/game/action.go @@ -660,6 +660,18 @@ type FreeAction struct { desc string } +// newControllerCostFunc returns a new cost function checking the controller's resource and decreasing it accordingly. +func newControllerResourceCostFunc(p Permanent, amount int) ActionCostFunc { + return func(s *LocalState) bool { + c := p.Controller() + if c.Resource < amount { + return false + } + c.Resource -= amount + return true + } +} + func NewFreeAction(p Permanent, resolveProto ActionFuncPrototype, costFunc ActionCostFunc, desc string, ) *FreeAction { diff --git a/go/game/cardImplementations.go b/go/game/cardImplementations.go index 58bbc75e..478e1681 100644 --- a/go/game/cardImplementations.go +++ b/go/game/cardImplementations.go @@ -755,6 +755,45 @@ func (*illusionImpl) onETB(s *LocalState, p Permanent) { }, p.Card().getEffects()[0])) } +type patricianImpl struct{ cardImplementationBase } + +func (*patricianImpl) freeActions(p Permanent) []*FreeAction { + u := p.(*Unit) + m := NewFreeAction(u, func(a Action) ActionResolveFunc { + return func(s *LocalState) { + s.addEotEffect(newMovementModificationEffect(u, 1)) + } + }, newControllerResourceCostFunc(u, 2), "2: +1 movement") + + a := NewFreeAction(u, func(a Action) ActionResolveFunc { + return func(s *LocalState) { + s.addEotEffect(newAttackModificationEffect(u, 1)) + } + }, newControllerResourceCostFunc(u, 3), "3: +1 attack") + + ar := NewFreeAction(u, func(a Action) ActionResolveFunc { + return func(s *LocalState) { + s.addEotEffect(newTmpEffect(p, "+1 armor")) + } + }, newControllerResourceCostFunc(u, 5), "5: +1 armor") + + d := NewFreeAction(u, func(a Action) ActionResolveFunc { + return func(s *LocalState) { + a.Controller().DrawN(1) + } + }, newControllerResourceCostFunc(u, 7), "7: Draw 1") + + r := NewFreeAction(u, func(a Action) ActionResolveFunc { + return func(s *LocalState) { + t := a.Target().sel[0].(*Tile) + s.addNewUnit(NewCard("base/recruit"), t.Position, u.Controller()) + } + }, newControllerResourceCostFunc(u, 9), "9: CreateRecruit") + r.targets = newTargets(newTarget(p.Controller().gameState, newTargetDesc("adjacent available tile"), r)) + + return []*FreeAction{m, a, ar, d, r} +} + func init() { cardImplementations = map[string]cardImplementation{ "base/advisor": &advisorImpl{}, @@ -805,5 +844,6 @@ func init() { "exp1/illusion": &illusionImpl{}, "exp1/illusionist": &illusionistImpl{}, + "exp1/patrician": &patricianImpl{}, } } diff --git a/go/game/cardImplementations_test.go b/go/game/cardImplementations_test.go index eb3ec567..4a353443 100644 --- a/go/game/cardImplementations_test.go +++ b/go/game/cardImplementations_test.go @@ -256,3 +256,43 @@ func TestBanner(t *testing.T) { t.Fatal("wormtongue not sped up by banner") } } + +func TestPatrician(t *testing.T) { + s, _, player, _ := newMockState() + p := s.addNewUnit(NewCard("exp1/patrician"), Position{1, 0}, player) + fas := p.FreeActions + if len(fas) != 5 { + t.Fatal("patrician does not have 5 free actions") + } + + player.Resource = 5 + s.declareAction(fas[0]) + if player.Resource != 3 { + t.Fatal("patrician move did not cost 2 resource") + } + s.stack.pop() + if p.Movement.Range != 2 { + t.Fatal("patrician movement is not increased") + } + + player.Resource = 5 + s.declareAction(fas[1]) + if player.Resource != 2 { + t.Fatal("patrician attack did not cost 3 resource") + } + s.stack.pop() + if p.Attack.DamageInRange(1) != 1 { + t.Fatal("patrician has no melee") + } + + player.Resource = 5 + s.declareAction(fas[2]) + if player.Resource != 0 { + t.Fatal("patrician armor did not cost 5 resource") + } + s.stack.pop() + x, err := p.XEffect("armor") + if err != nil || x != 1 { + t.Fatal("patrician has no armor") + } +} diff --git a/latex/cards/de/exp1/patrician.tex b/latex/cards/de/exp1/patrician.tex new file mode 100644 index 00000000..b34be5e7 --- /dev/null +++ b/latex/cards/de/exp1/patrician.tex @@ -0,0 +1,14 @@ +\documentclass{standalone} +\usepackage[ngerman]{babel} +\input{common.tex} + +\begin{document} +\begin{tikzpicture} +\cardtypeUnit{Patrizier} +\cardbuycost{7} +\cardsplitcontent{Leben: 1\\Bewegung: 1}{2: Gain +1 movement this turn\\ 3: Gain +1 attack this turn\\ 5: Gain +1 armor this turn\\ 7: Draw a card\\ 9: Create a Recruit token in range 1} +\cardplaycost{2} +\cardmodule{exp1} +\cardborder +\end{tikzpicture} +\end{document} diff --git a/latex/cards/en/exp1/patrician.tex b/latex/cards/en/exp1/patrician.tex new file mode 100644 index 00000000..ae55d711 --- /dev/null +++ b/latex/cards/en/exp1/patrician.tex @@ -0,0 +1,14 @@ +\documentclass{standalone} +\usepackage[english]{babel} +\input{common.tex} + +\begin{document} +\begin{tikzpicture} +\cardtypeUnit{Patrician} +\cardbuycost{7} +\cardsplitcontent{Health: 1\\Movement: 1}{2: Gain +1 movement this turn\\ 3: Gain +1 attack this turn\\ 5: Gain +1 armor this turn\\ 7: Draw a card\\ 9: Create a Recruit token in range 1} +\cardplaycost{2} +\cardmodule{exp1} +\cardborder +\end{tikzpicture} +\end{document} diff --git a/latex/sets/de/exp1.tex b/latex/sets/de/exp1.tex index 187b5b56..fee8baae 100644 --- a/latex/sets/de/exp1.tex +++ b/latex/sets/de/exp1.tex @@ -25,6 +25,7 @@ \includestandalone{cards/de/exp1/illusionist} \includestandalone{cards/de/exp1/illusion} \includestandalone{cards/de/exp1/macabre_clown} +\includestandalone{cards/de/exp1/patrician} \includestandalone{cards/de/exp1/power_to_the_people!} \includestandalone{cards/de/exp1/push!} \includestandalone{cards/de/exp1/ramm} -- cgit v1.2.3