From c696829f9e37e9f3752fdb89ebaadd4b3b237bea Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 2 Aug 2025 14:47:01 +0200 Subject: add support for flexible attacks --- go/game/attack.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 8 deletions(-) (limited to 'go/game/attack.go') 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) } -- cgit v1.2.3