aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-08-06 15:23:17 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-06 15:28:34 +0200
commita1f59ce10276211e44aef3f55d5ef1a41ebbcc95 (patch)
tree191fcec80b73b786a89004c5fd94afcd0e8be50b
parenta0345c11f8035b300330e6b7c59a654c1e1e231d (diff)
downloadmuhqs-game-a1f59ce10276211e44aef3f55d5ef1a41ebbcc95.tar.gz
muhqs-game-a1f59ce10276211e44aef3f55d5ef1a41ebbcc95.zip
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.
-rw-r--r--data/cards/base/missionary.yml4
-rw-r--r--data/cards/base/recruit.yml1
-rw-r--r--go/game/cardImplementations.go11
-rw-r--r--go/game/cardImplementations_test.go59
-rw-r--r--go/game/permanent.go6
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])