func WaypointsFunc(me *game.Entity) lua.GoFunction { return func(L *lua.State) int { if !game.LuaCheckParamsOk(L, "Waypoints") { return 0 } g := me.Game() L.NewTable() count := 0 for _, wp := range g.Waypoints { if wp.Side != me.Side() { continue } count++ L.PushInteger(count) L.NewTable() L.PushString("Name") L.PushString(wp.Name) L.SetTable(-3) L.PushString("Radius") L.PushNumber(wp.Radius) L.SetTable(-3) L.PushString("Pos") game.LuaPushPoint(L, int(wp.X), int(wp.Y)) L.SetTable(-3) L.SetTable(-3) } return 1 } }
func (a *AoeAttack) AiBestTarget(ent *game.Entity, extra_dist int, spec AiAoeTarget) (x, y int, targets []*game.Entity) { ex, ey := ent.Pos() max := 0 best_dist := 10000 var bx, by int var radius int if a.Range > 0 { radius += a.Range } if extra_dist > 0 { radius += extra_dist } for x := ex - radius; x <= ex+radius; x++ { for y := ey - radius; y <= ey+radius; y++ { if !ent.HasLos(x, y, 1, 1) { continue } targets = a.getTargetsAt(ent.Game(), x, y) ok := true count := 0 for i := range targets { if targets[i].Side() != ent.Side() { count++ } else if ent.Side() == game.SideHaunt && spec == AiAoeHitMinionsOk { if targets[i].HauntEnt == nil || targets[i].HauntEnt.Level != game.LevelMinion { ok = false } } else if spec != AiAoeHitAlliesOk { ok = false } } dx := x - ex if dx < 0 { dx = -dx } dy := y - ey if dy < 0 { dy = -dy } dist := dx if dy > dx { dist = dy } if ok && (count > max || count == max && dist < best_dist) { max = count best_dist = dist bx, by = x, y } } } return bx, by, a.getTargetsAt(ent.Game(), bx, by) }
func (a *Move) AiMoveToPos(ent *game.Entity, dst []int, max_ap int) game.ActionExec { base.Log().Printf("PATH: Request move to %v", dst) graph := ent.Game().Graph(ent.Side(), false, nil) src := []int{ent.Game().ToVertex(ent.Pos())} _, path := algorithm.Dijkstra(graph, src, dst) base.Log().Printf("PATH: Found path of length %d", len(path)) ppx, ppy := ent.Pos() if path == nil { return nil } _, xx, yy := ent.Game().FromVertex(path[len(path)-1]) base.Log().Printf("PATH: %d,%d -> %d,%d", ppx, ppy, xx, yy) if ent.Stats.ApCur() < max_ap { max_ap = ent.Stats.ApCur() } path = limitPath(ent, src[0], path, max_ap) _, xx, yy = ent.Game().FromVertex(path[len(path)-1]) base.Log().Printf("PATH: (limited) %d,%d -> %d,%d", ppx, ppy, xx, yy) if len(path) <= 1 { return nil } var exec moveExec exec.SetBasicData(ent, a) exec.Path = path return &exec }
func (a *Interact) AiToggleDoor(ent *game.Entity, door *house.Door) game.ActionExec { if door.AlwaysOpen() { return nil } for fi, f := range ent.Game().House.Floors { for ri, r := range f.Rooms { for di, d := range r.Doors { if d == door { return a.makeDoorExec(ent, fi, ri, di) } } } } return nil }
func (a *Move) findPath(ent *game.Entity, x, y int) { g := ent.Game() dst := g.ToVertex(x, y) if dst != a.dst || !a.calculated { a.dst = dst a.calculated = true src := g.ToVertex(a.ent.Pos()) graph := g.Graph(ent.Side(), true, nil) cost, path := algorithm.Dijkstra(graph, []int{src}, []int{dst}) if len(path) <= 1 { return } algorithm.Map2(path, &a.path, func(a int) [2]int { _, x, y := g.FromVertex(a) return [2]int{int(x), int(y)} }) a.cost = int(cost) a.drawPath(ent, g, graph, src) } }
func limitPath(ent *game.Entity, start int, path []int, max int) []int { total := 0 graph := ent.Game().Graph(ent.Side(), true, nil) for last := 1; last < len(path); last++ { adj, cost := graph.Adjacent(start) found := false for index := range adj { if adj[index] == path[last] { total += int(cost[index]) if total > max { return path[0:last] } start = adj[index] found = true break } } if !found { base.Log().Printf("PATH: DIdn't find, %d / %d", last+1, len(path)) return path[0:last] } } return path }
// Returns an array of all entities of a specified type that are in this // entity's los. The entities in the array will be sorted in ascending order // of distance from this entity. // Format // ents = nearestNEntites(max, kind) // // Input: // max - integer - Maximum number of entities to return // kind - string - One of "intruder" "denizen" "minion" "servitor" // "master" "non-minion" "non-servitor" "non-master" and // "all". The "non-*" parameters indicate denizens only // (i.e. will *not* include intruders) that are not of the // type specified. // // Output: // ents - array[integer] - Array of entity ids. func NearestNEntitiesFunc(me *game.Entity) lua.GoFunction { valid_kinds := map[string]bool{ "intruder": true, "denizen": true, "minion": true, "servitor": true, "master": true, "object": true, } return func(L *lua.State) int { if !game.LuaCheckParamsOk(L, "NearestNEntities", game.LuaInteger, game.LuaString) { return 0 } g := me.Game() max := L.ToInteger(-2) kind := L.ToString(-1) if !valid_kinds[kind] { err_str := fmt.Sprintf("NearestNEntities expects kind in the set ['intruder' 'denizen' 'servitor' 'master' 'minion'], got %s.", kind) base.Warn().Printf(err_str) L.PushString(err_str) L.Error() return 0 } var eds entityDistSlice for _, ent := range g.Ents { if ent.Stats != nil && ent.Stats.HpCur() <= 0 { continue } switch kind { case "intruder": if ent.Side() != game.SideExplorers { continue } case "denizen": if ent.Side() != game.SideHaunt { continue } case "minion": if ent.HauntEnt == nil || ent.HauntEnt.Level != game.LevelMinion { continue } case "servitor": if ent.HauntEnt == nil || ent.HauntEnt.Level != game.LevelServitor { continue } case "master": if ent.HauntEnt == nil || ent.HauntEnt.Level != game.LevelMaster { continue } case "object": if ent.ObjectEnt == nil { continue } } x, y := ent.Pos() dx, dy := ent.Dims() if !me.HasTeamLos(x, y, dx, dy) { continue } eds = append(eds, entityDist{rangedDistBetween(me, ent), ent}) } // TODO: ONLY GUYS THAT EXIST sort.Sort(eds) if max > len(eds) { max = len(eds) } if max < 0 { max = 0 } eds = eds[0:max] // eds contains the results, in order. Now we make a lua table and // populate it with the entity ids of the results. L.NewTable() for i := range eds { L.PushInteger(i + 1) game.LuaPushEntity(L, eds[i].ent) L.SetTable(-3) } return 1 } }