package game import ( "fmt" "log" "strconv" "strings" "golang.org/x/exp/slices" ) type UnitState int const ( Paralysis UnitState = iota + 1 Poison Panic Rage Ward ) type Attack struct { Damage int Range int } func (a *Attack) String() string { if a.Range == 1 { return fmt.Sprintf("%d", a.Damage) } return fmt.Sprintf("%d range %d", a.Damage, a.Range) } func parseAttack(attack string) Attack { tokens := strings.Split(attack, " ") a, err := strconv.Atoi(tokens[0]) if err != nil { log.Fatalf("Attack %s has no valid Damage value\n", attack) } r := 1 if len(tokens) == 3 { r, err = strconv.Atoi(tokens[2]) if err != nil { log.Fatalf("Attack %s has no valid Range value\n", attack) } } return Attack{a, r} } type Unit struct { PermanentBase Health int Movement int Attack Attack Upkeep int FullActions []*FullActionPrototype FreeActions []*FreeActionPrototype States []UnitState // Effects []Effects AvailMoveActions int AvailAttackActions int } func NewUnit(cardPath string, tile *Tile, owner *Player) *Unit { card := NewCard(cardPath) u := &Unit{ NewPermanentBase(card, tile, owner), card.Values["health"].(int), card.Values["movement"].(int), parseAttack(card.Values["attack"].(string)), card.Values["upkeep"].(int), []*FullActionPrototype{}, []*FreeActionPrototype{}, []UnitState{}, 1, 1, } tile.Permanent = u return u } func (u *Unit) move(s *State, tile *Tile) { if !slices.Contains(u.MoveRangeTiles(s.Map), tile) { log.Panicf("Unit %s at %v can not move to %v", u.Card.Name, u.Tile.Position, tile.Position) } if tile.Permanent != nil { log.Panicf("Unit %s at %v can not move to occupied %v", u.Card.Name, u.Tile.Position, tile.Position) } u.Tile.Permanent = nil u.Tile = tile } func (u *Unit) MoveRangeTiles(m *Map) []*Tile { tiles := []*Tile{} for _, pos := range PositionsInRange(u.Tile.Position, u.Movement, false) { tile := m.TileAt(pos) if u.IsAvailableTile(tile) { tiles = append(tiles, tile) } } return tiles } func (u *Unit) AttackableTiles(m *Map) []*Tile { return TilesInRange(m, u, u.Attack.Range) } func (u *Unit) AttackablePermanents(m *Map) []Permanent { permanents := []Permanent{} for _, t := range u.AttackableTiles(m) { if t.Permanent != nil && t.Permanent.Attackable() { permanents = append(permanents, t.Permanent) } } return permanents } func (u *Unit) IsAvailableTile(tile *Tile) bool { return tile.IsFree() } func (u *Unit) Fight(p Permanent) { p.AddDamage(u.Attack.Damage) } func (u *Unit) IsDestroyed() bool { return u.PermanentBase.Damage >= u.Health } func (u *Unit) Attackable() bool { return true } func (u *Unit) HasFullAction() bool { return len(u.FullActions) > 0 } func (u *Unit) FullAction() { } func (u *Unit) GetAvailActionPrototypes() []ActionPrototype { prototypes := []ActionPrototype{} if u.AvailMoveActions > 0 { prototypes = append(prototypes, NewMoveActionPrototype(u)) } if u.AvailAttackActions > 0 { prototypes = append(prototypes, NewAttackActionPrototype(u)) } for _, p := range u.FullActions { prototypes = append(prototypes, p) } for _, p := range u.FreeActions { prototypes = append(prototypes, p) } return prototypes }