aboutsummaryrefslogtreecommitdiff
path: root/go
diff options
context:
space:
mode:
Diffstat (limited to 'go')
-rw-r--r--go/game/action_test.go32
-rw-r--r--go/game/attack.go18
-rw-r--r--go/game/tile.go30
-rw-r--r--go/game/unit_test.go50
4 files changed, 129 insertions, 1 deletions
diff --git a/go/game/action_test.go b/go/game/action_test.go
index 5fa0b64d..b7a92bae 100644
--- a/go/game/action_test.go
+++ b/go/game/action_test.go
@@ -111,6 +111,7 @@ func TestAttackAction(t *testing.T) {
mapDef := `map: |1-
H T
SSS
+
symbols:
T: tower
H: house
@@ -126,6 +127,8 @@ symbols:
t1 := s.addNewUnit(NewCard("base/fighter"), Position{0, 0}, o)
t2 := s.addNewUnit(NewCard("base/fighter"), Position{0, 1}, o)
+ t3 := s.addNewUnit(NewCard("base/fighter"), Position{0, 2}, o)
+
a := s.addNewUnit(NewCard("base/archer"), Position{2, 0}, p)
ca := s.addNewUnit(NewCard("base/cavalry_archer"), Position{2, 1}, p)
@@ -147,4 +150,33 @@ symbols:
if ca.Damage() > 0 {
t.Fatal("cavalry archer took damage in range combat from melee unit")
}
+
+ aa3 := NewAttackAction(a)
+ err = aa3.Target().AddSelection(t2)
+ if err != nil {
+ t.Fatal("unexpected target error:", err)
+ }
+ s.ResolveAction(aa3)
+ if t2.Damage() != 2 {
+ t.Fatal("fighter did not took 1 damage")
+ }
+ if !t2.IsDestroyed() {
+ t.Fatal("fighter is still alive")
+ }
+ if ca.Damage() > 0 {
+ t.Fatal("archer took damage in range combat from melee unit")
+ }
+
+ aa4 := NewAttackAction(a)
+ err = aa4.Target().AddSelection(t3)
+ if err != nil {
+ t.Fatal("unexpected target error:", err)
+ }
+ s.ResolveAction(aa4)
+ if t3.Damage() != 1 {
+ t.Fatal("fighter did not took 1 damage")
+ }
+ if ca.Damage() > 0 {
+ t.Fatal("archer took damage in range combat from melee unit")
+ }
}
diff --git a/go/game/attack.go b/go/game/attack.go
index 9be465f2..6b33e8d9 100644
--- a/go/game/attack.go
+++ b/go/game/attack.go
@@ -32,6 +32,24 @@ func (a Attack) DamageInRange(r int) int {
return a.attacks[r-1]
}
+// Ranged reports if the attack has more range than 1.
+func (a Attack) Ranged() bool {
+ return a.MaxRange() > 1
+}
+
+// Extend increases the MaxRange by amount.
+func (a *Attack) Extend(amount int) {
+ d := a.DamageInRange(a.MaxRange())
+ for range amount {
+ a.attacks = append(a.attacks, d)
+ }
+}
+
+// Shorten decreases the MaxRange by amount.
+func (a *Attack) Shorten(amount int) {
+ a.attacks = a.attacks[:len(a.attacks)-amount]
+}
+
func (a Attack) String() string {
if INVALID_ATTACK(a) {
return "invalid attack"
diff --git a/go/game/tile.go b/go/game/tile.go
index 06770ff3..d5a256d9 100644
--- a/go/game/tile.go
+++ b/go/game/tile.go
@@ -97,6 +97,31 @@ var farmEffect areaEffect = newGrantFullActionEffect("misc/farmer",
}
}, "gain 3 resource", "farmAction")
+var towerEffect areaEffect = newDynamicAreaEffect(
+ func(p Permanent) {
+ var u *Unit
+ var ok bool
+ if u, ok = p.(*Unit); !ok {
+ return
+ }
+ if u.Attack.MaxRange() < 2 {
+ return
+ }
+ u.Attack.Extend(1)
+ },
+ func(p Permanent) {
+ var u *Unit
+ var ok bool
+ if u, ok = p.(*Unit); !ok {
+ return
+ }
+ if u.Attack.MaxRange() < 3 {
+ return
+ }
+ u.Attack.Shorten(1)
+ },
+)
+
type Tile struct {
Position Position
Permanent Permanent
@@ -131,8 +156,11 @@ func NewTileFromString(raw string, pos Position) (Tile, error) {
t := Tile{Position: pos, Type: tileType, Water: water, Raw: raw}
- if tileType == TileTypes.Farm {
+ switch tileType {
+ case TileTypes.Farm:
t.effects = append(t.effects, farmEffect)
+ case TileTypes.Tower:
+ t.effects = append(t.effects, towerEffect)
}
return t, nil
diff --git a/go/game/unit_test.go b/go/game/unit_test.go
index f2a15ddc..e707c560 100644
--- a/go/game/unit_test.go
+++ b/go/game/unit_test.go
@@ -79,3 +79,53 @@ symbols:
t.Fatalf("archer's mele attack is not 2")
}
}
+
+func TestAttackablePerms(t *testing.T) {
+ mapDef := `map: |1-
+ HST
+ HSF
+ TSW
+symbols:
+ T: tower
+ H: house
+ F: farm
+ S: street
+ W: deep water
+`
+ s := NewLocalState()
+ r := strings.NewReader(mapDef)
+ m, _ := readMap(r)
+ s.SetMap(m)
+
+ p := s.AddNewPlayer("player", NewDeck())
+ o := s.AddNewPlayer("opponent", NewDeck())
+
+ a := s.addNewUnit(NewCard("base/archer"), Position{2, 0}, p)
+ units := []*Unit{}
+ for x := range 3 {
+ for y := range 3 {
+ var u *Unit
+ pos := Position{x, y}
+ if x == 2 && y == 0 {
+ continue
+ } else if x == 2 && y == 2 {
+ u = s.addNewUnit(NewCard("nautics/fisher"), pos, o)
+ } else {
+ u = s.addNewUnit(NewCard("misc/farmer"), pos, o)
+ }
+ units = append(units, u)
+ }
+ }
+
+ aTiles := a.AttackableTiles(m)
+ is := len(aTiles)
+ if is != 6 {
+ t.Fatal("6 attackable tiles expected not:", is)
+ }
+
+ aPerms := a.AttackableEnemyPermanents(m)
+ is = len(aPerms)
+ if is != 6 {
+ t.Fatal("6 attackable permanents expected not:", is)
+ }
+}