aboutsummaryrefslogtreecommitdiff
path: root/go/game/attack.go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-08-02 14:47:01 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-20 15:57:33 +0200
commitc696829f9e37e9f3752fdb89ebaadd4b3b237bea (patch)
treea205a17da9618e04f61e44d49cb028ede23dd732 /go/game/attack.go
parentca083639a4b52215b39bb863031f71c0a8209ee9 (diff)
downloadmuhqs-game-c696829f9e37e9f3752fdb89ebaadd4b3b237bea.tar.gz
muhqs-game-c696829f9e37e9f3752fdb89ebaadd4b3b237bea.zip
add support for flexible attacks
Diffstat (limited to 'go/game/attack.go')
-rw-r--r--go/game/attack.go70
1 files changed, 62 insertions, 8 deletions
diff --git a/go/game/attack.go b/go/game/attack.go
index 6b33e8d9..e7d2e836 100644
--- a/go/game/attack.go
+++ b/go/game/attack.go
@@ -7,15 +7,30 @@ import (
"strings"
)
+type FlexAttack = func(*Unit, *Tile) (int, bool)
+
// Attack contains all damage values for each attackable range.
// The damage value for range 1 is stored at index 0, the value for range 2 at index 1 and so on.
type Attack struct {
- attacks []int
+ attacks []int
+ flexAttack FlexAttack
+}
+
+// Valid reports if there are attackable ranges.
+func (a Attack) Valid() bool {
+ return len(a.attacks) > 0 || a.flexAttack != nil
}
-// INVALID_ATTACK reports if there are no attackable ranges.
-func INVALID_ATTACK(a Attack) bool {
- return len(a.attacks) == 0
+// DamageForTile returns the damage inflicted by this attack to a tile
+func (a Attack) DamageForTile(u *Unit, t *Tile) (int, bool) {
+ if a.flexAttack != nil {
+ return a.flexAttack(u, t)
+ }
+
+ o := u.Tile().Position
+ trgt := t.Position
+ d := DistanceBetweenPositions(o, trgt)
+ return a.DamageInRange(d), IsPositionInRange(o, trgt, a.MaxRange())
}
// MaxRange returns the biggest attackable range.
@@ -23,9 +38,18 @@ func (a Attack) MaxRange() int {
return len(a.attacks)
}
+// Copy returns a copy of the attack
+func (a Attack) Copy() Attack {
+ copy := Attack{}
+ for _, v := range a.attacks {
+ copy.attacks = append(copy.attacks, v)
+ }
+ return copy
+}
+
// DamageInRange returns the damage in a certain range.
func (a Attack) DamageInRange(r int) int {
- if r > a.MaxRange() {
+ if r == 0 || r > a.MaxRange() {
return 0
}
@@ -51,7 +75,7 @@ func (a *Attack) Shorten(amount int) {
}
func (a Attack) String() string {
- if INVALID_ATTACK(a) {
+ if !a.Valid() {
return "invalid attack"
}
@@ -65,7 +89,7 @@ func (a Attack) String() string {
func parseAttack(attack any) Attack {
if damage, ok := attack.(int); ok {
- return Attack{[]int{damage}}
+ return Attack{attacks: []int{damage}}
}
attackStr := attack.(string)
@@ -89,5 +113,35 @@ func parseAttack(attack any) Attack {
attacks = append(attacks, a)
}
- return Attack{attacks}
+ return Attack{attacks: attacks}
+}
+
+func flexibleRangeAttack(constraint func(*Unit, *Tile) bool) FlexAttack {
+ return func(u *Unit, t *Tile) (int, bool) {
+ baseAttack := u.Attack
+ pos := u.Tile().Position
+ d := DistanceBetweenPositions(pos, t.Position)
+ if IsPositionInRange(pos, t.Position, baseAttack.MaxRange()) {
+ return baseAttack.DamageInRange(d), true
+ }
+
+ if constraint(u, t) {
+ return baseAttack.DamageInRange(baseAttack.MaxRange()), true
+ }
+
+ return 0, false
+ }
+}
+
+func pikeConstraint(u *Unit, t *Tile) bool {
+ if o, ok := t.Permanent.(*Unit); ok {
+ d := DistanceBetweenPositions(u.Tile().Position, t.Position)
+
+ return d < 3 && o.Movement.Range > 2
+ }
+ return false
+}
+
+func pikeAttack() FlexAttack {
+ return flexibleRangeAttack(pikeConstraint)
}