From a1f59ce10276211e44aef3f55d5ef1a41ebbcc95 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Wed, 6 Aug 2025 15:23:17 +0200 Subject: update missionary Limit the range of the missionary's full action but increase its effectivnes. The missionary could only really be used unthreatened over multiple turns. Since any unit can be disbanded during upkeep before it is evangelized, the missionary is only a slow destroy effect. Now it is way more potent controlling cheaper units with the first action but it has to be close to the enemy unit making it more vulnerable. --- data/cards/base/missionary.yml | 4 +-- data/cards/base/recruit.yml | 1 + go/game/cardImplementations.go | 11 ++++--- go/game/cardImplementations_test.go | 59 +++++++++++++++++++++++++++++++++++++ go/game/permanent.go | 6 ++++ 5 files changed, 73 insertions(+), 8 deletions(-) diff --git a/data/cards/base/missionary.yml b/data/cards/base/missionary.yml index ccb41ba4..0db06939 100644 --- a/data/cards/base/missionary.yml +++ b/data/cards/base/missionary.yml @@ -7,5 +7,5 @@ movement: 2 buy: 10 upkeep: 2 full_action: - en: Put two faith marks on target Unit. If there are more faith marks than the units buying cost you control that unit - de: Lege zwei Glaubens-Marken auf eine Ziel-Unit. Du kontrollierst die Unit falls mehr Glaubens-Marken auf ihr liegen als ihre Kauf-Kosten + en: Put five faith marks on target Unit in range 3. If the faith marks are equal to or more than the units buying cost you control that unit + de: Lege fünf Glaubens-Marken auf eine Ziel-Unit in Range 3. Du kontrollierst die Unit falls glwich viele oder mehr Glaubens-Marken auf ihr liegen als ihre Kauf-Kosten diff --git a/data/cards/base/recruit.yml b/data/cards/base/recruit.yml index 48a00014..a6dfa27b 100644 --- a/data/cards/base/recruit.yml +++ b/data/cards/base/recruit.yml @@ -7,3 +7,4 @@ attack: 1 health: 1 movement: 1 upkeep: 0 +buy: 0 diff --git a/go/game/cardImplementations.go b/go/game/cardImplementations.go index 007c2335..3d43fe42 100644 --- a/go/game/cardImplementations.go +++ b/go/game/cardImplementations.go @@ -81,18 +81,17 @@ type missionaryImpl struct{ cardImplementationBase } func (*missionaryImpl) fullActions(u *Unit) []*FullAction { resolvePrototype := func(a Action) ActionResolveFunc { - u := a.Source().(*Unit) target := a.Target().sel[0].(*Unit) return func(s *LocalState) { - target.adjustMarks(UnitMarks.Faith, 2) - if target.Marks(UnitMarks.Faith) > target.Card().BuyCosts.Costs(s) { - target.controller = u.Controller() + target.adjustMarks(UnitMarks.Faith, 5) + if target.Card().BuyCosts != nil && target.Marks(UnitMarks.Faith) >= target.Card().BuyCosts.Costs(s) { + target.changeController(a.Controller()) } } } s := u.Controller().gameState - a := newFullAction(u, resolvePrototype, "put faith ...") - a.targets = newTargets(newTarget(s, newTargetDesc("unit"), a)) + a := newFullAction(u, resolvePrototype, "put 5 faith ...") + a.targets = newTargets(newTarget(s, newTargetDesc("unit in range 3"), a)) return []*FullAction{a} } diff --git a/go/game/cardImplementations_test.go b/go/game/cardImplementations_test.go index b962677c..5160816e 100644 --- a/go/game/cardImplementations_test.go +++ b/go/game/cardImplementations_test.go @@ -131,3 +131,62 @@ symbols: t.Fatal("unexpected valid target") } } + +func TestMissionary(t *testing.T) { + mapDef := `map: |1- + SSS + SSS + SHS +symbols: + S: street + H: house +` + s := NewLocalState() + + m, _ := readMap(strings.NewReader(mapDef)) + s.SetMap(m) + + player := s.AddNewPlayer("p", NewDeck()) + opo := s.AddNewPlayer("o", NewDeck()) + + mis := s.addNewUnit(NewCard("base/missionary"), Position{0, 0}, player) + king := s.addNewUnit(NewCard("misc/king"), Position{0, 2}, opo) + k := s.addNewUnit(NewCard("base/knight"), Position{2, 0}, opo) + r := s.addNewUnit(NewCard("base/recruit"), Position{2, 1}, opo) + + a := mis.FullActions[0] + err := a.Target().AddSelection(king) + if err != nil { + t.Fatal("invalid target:", err) + } + + for range 20 { + a.resolve(s) + if king.controller != king.owner { + t.Fatal("king not controlled by its owner") + } + } + + a.Target().ClearSelection() + _ = a.Target().AddSelection(k) + + a.resolve(s) + if k.controller != k.owner { + t.Fatal("knight not controlled by its owner") + } + + s.ResolveAction(a) + if k.controller != player { + t.Fatal("knight not controlled by player") + } + + // recruit + a.Target().ClearSelection() + _ = a.Target().AddSelection(r) + s.ResolveAction(a) + if r.controller != player { + t.Fatal("recruit not controlled by player") + } + + // TODO: test return to owner +} diff --git a/go/game/permanent.go b/go/game/permanent.go index 09a8829c..503084a2 100644 --- a/go/game/permanent.go +++ b/go/game/permanent.go @@ -19,6 +19,7 @@ type Permanent interface { ContainingPerm() Permanent Pile() []Permanent Controller() *Player + changeController(*Player) Owner() *Player Effects() []string HasEffect(string) bool @@ -89,6 +90,11 @@ func (p *permanentBase) Pile() []Permanent { return p.pile } func (p *permanentBase) Controller() *Player { return p.controller } func (p *permanentBase) Owner() *Player { return p.owner } +func (p *permanentBase) changeController(c *Player) { + p.controller = c + +} + func FmtPermanent(p Permanent) string { typeIndicator := strings.ToUpper(p.Card().Type.String()[:1]) -- cgit v1.2.3