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 (exec *moveExec) measureCost(ent *game.Entity, g *game.Game) int { if len(exec.Path) == 0 { base.Error().Printf("Zero length path") return -1 } if g.ToVertex(ent.Pos()) != exec.Path[0] { base.Error().Printf("Path doesn't begin at ent's position, %d != %d", g.ToVertex(ent.Pos()), exec.Path[0]) return -1 } graph := g.Graph(ent.Side(), true, nil) v := g.ToVertex(ent.Pos()) cost := 0 for _, step := range exec.Path[1:] { dsts, costs := graph.Adjacent(v) ok := false prev := v base.Log().Printf("Adj(%d):", v) for j := range dsts { base.Log().Printf("Node %d", dsts[j]) if dsts[j] == step { cost += int(costs[j]) v = dsts[j] ok = true break } } base.Log().Printf("%d -> %d: %t", prev, v, ok) if !ok { return -1 } } return cost }
func loadHouse(gp *GamePanel) lua.GoFunction { return func(L *lua.State) int { if !LuaCheckParamsOk(L, "LoadHouse", LuaString) { return 0 } gp.script.syncStart() defer gp.script.syncEnd() name := L.ToString(-1) def := house.MakeHouseFromName(name) if def == nil || len(def.Floors) == 0 { base.Error().Printf("No house exists with the name '%s'.", name) return 0 } gp.game = makeGame(def) gp.game.viewer.Edit_mode = true gp.game.script = gp.script base.Log().Printf("script = %p", gp.game.script) gp.AnchorBox = gui.MakeAnchorBox(gui.Dims{1024, 768}) gp.AnchorBox.AddChild(gp.game.viewer, gui.Anchor{0.5, 0.5, 0.5, 0.5}) gp.AnchorBox.AddChild(MakeOverlay(gp.game), gui.Anchor{0.5, 0.5, 0.5, 0.5}) base.Log().Printf("Done making stuff") return 0 } }
// Performs a move action to the closest one of any of the specifed inputs // points. The movement can be restricted to not spend more than a certain // amount of ap. // Format: // success, p = DoMove(dsts, max_ap) // // Input: // dsts - array[table[x,y]] - Array of all points that are acceptable // destinations. // max_ap - integer - Maxmium ap to spend while doing this move, if the // required ap exceeds this the entity will still move // as far as possible towards a destination. // // Output: // success = bool - True iff the move made it to a position in dsts. // p - table[x,y] - New position of this entity, or nil if the move failed. func DoMoveFunc(a *Ai) lua.GoFunction { return func(L *lua.State) int { if !game.LuaCheckParamsOk(L, "DoMove", game.LuaArray, game.LuaInteger) { return 0 } me := a.ent max_ap := L.ToInteger(-1) L.Pop(1) cur_ap := me.Stats.ApCur() if max_ap > cur_ap { max_ap = cur_ap } n := int(L.ObjLen(-1)) dsts := make([]int, n)[0:0] for i := 1; i <= n; i++ { L.PushInteger(i) L.GetTable(-2) x, y := game.LuaToPoint(L, -1) dsts = append(dsts, me.Game().ToVertex(x, y)) L.Pop(1) } var move *actions.Move var ok bool for i := range me.Actions { move, ok = me.Actions[i].(*actions.Move) if ok { break } } if !ok { // TODO: what to do here? This poor guy didn't have a move action :( L.PushNil() L.PushNil() return 2 } exec := move.AiMoveToPos(me, dsts, max_ap) if exec != nil { a.execs <- exec <-a.pause // TODO: Need to get a resolution x, y := me.Pos() v := me.Game().ToVertex(x, y) complete := false for i := range dsts { if v == dsts[i] { complete = true break } } L.PushBoolean(complete) game.LuaPushPoint(L, x, y) base.Log().Printf("Finished move") } else { base.Log().Printf("Didn't bother moving") L.PushBoolean(true) L.PushNil() } return 2 } }
func (a *AoeAttack) AiAttackPosition(ent *game.Entity, x, y int) game.ActionExec { if !ent.HasLos(x, y, 1, 1) { base.Log().Printf("Don't have los") return nil } if a.Ap > ent.Stats.ApCur() { base.Log().Printf("Don't have the ap") return nil } var exec aoeExec exec.SetBasicData(ent, a) exec.X, exec.Y = x, y return &exec }
// Returns an array of all points that can be reached by walking from a // specific location that end in a certain general area. Assumes that a 1x1 // unit is doing the walking. // Format: // points = AllPathablePoints(src, dst, min, max) // // Inputs: // src - table[x,y] - Where the path starts. // dst - table[x,y] - Another point near where the path should go. // min - integer - Minimum distance from dst that the path should end at. // max - integer - Maximum distance from dst that the path should end at. // // Outputs: // points - array[table[x,y]] func AllPathablePointsFunc(a *Ai) lua.GoFunction { return func(L *lua.State) int { if !game.LuaCheckParamsOk(L, "AllPathablePoints", game.LuaPoint, game.LuaPoint, game.LuaInteger, game.LuaInteger) { return 0 } min := L.ToInteger(-2) max := L.ToInteger(-1) x1, y1 := game.LuaToPoint(L, -4) x2, y2 := game.LuaToPoint(L, -3) a.ent.Game().DetermineLos(x2, y2, max, grid) var dst []int for x := x2 - max; x <= x2+max; x++ { for y := y2 - max; y <= y2+max; y++ { if x > x2-min && x < x2+min && y > y2-min && y < y2+min { continue } if x < 0 || y < 0 || x >= len(grid) || y >= len(grid[0]) { continue } if !grid[x][y] { continue } dst = append(dst, a.ent.Game().ToVertex(x, y)) } } vis := 0 for i := range grid { for j := range grid[i] { if grid[i][j] { vis++ } } } base.Log().Printf("Visible: %d", vis) graph := a.ent.Game().Graph(a.ent.Side(), true, nil) src := []int{a.ent.Game().ToVertex(x1, y1)} reachable := algorithm.ReachableDestinations(graph, src, dst) L.NewTable() base.Log().Printf("%d/%d reachable from (%d, %d) -> (%d, %d)", len(reachable), len(dst), x1, y1, x2, y2) for i, v := range reachable { _, x, y := a.ent.Game().FromVertex(v) L.PushInteger(i + 1) game.LuaPushPoint(L, x, y) L.SetTable(-3) } return 1 } }
// Need a goroutine for each ai - all things will go through is so that things // stay synchronized func (a *Ai) masterRoutine() { for { select { case <-a.terminate: if a.watcher != nil { a.watcher.Close() } close(a.active_query) return case a.active = <-a.active_set: if a.active == false { if a.ent == nil { base.Log().Printf("Evaluating = false") } else { base.Log().Printf("Ent %p inactivated", a.ent) } a.evaluating = false } case a.active_query <- a.active: case <-a.exec_query: if a.active { select { case a.pause <- struct{}{}: default: } } if a.active && !a.evaluating { a.evaluating = true go func() { if a.ent == nil { base.Log().Printf("Eval master") } else { base.Log().Printf("Eval ent: %p", a.ent) } base.Log().Printf("Evaluating lua script: %s", a.Prog) // Reset the execution limit in case it was set to 0 due to a // previous error a.L.SetExecutionLimit(2500000) // DoString will panic, and we can catch that, calling it manually // will exit() if it fails, which we cannot catch a.L.DoString("Think()") if a.ent == nil { base.Log().Printf("Completed master") } else { base.Log().Printf("Completed ent: %p", a.ent) } a.active_set <- false a.execs <- nil base.Log().Printf("Sent nil value") }() } } } }
// Returns true iff the position specified is a valid position to click in the // text area. Also sets everything up so that if te.Entry.entering can be set // to true to begin editing at that position. func (te *TextEntry) setCursor(mx, my int) bool { if !pointInsideRect(mx, my, te.Entry.bounds.x, te.Entry.bounds.y, te.Entry.bounds.dx, te.Entry.bounds.dy) { te.Entry.ghost.offset = -1 return false } d := base.GetDictionary(te.Button.Text.Size) last_dx := 0 base.Log().Printf("Inside") te.Entry.ghost.index = -1 for i := range te.Entry.text { w := int(d.StringWidth(te.Entry.text[0 : i+1])) avg := (last_dx + w) / 2 if pointInsideRect(mx, my, te.Entry.bounds.x, te.Entry.bounds.y, avg, te.Entry.bounds.dy) { te.Entry.ghost.offset = last_dx te.Entry.ghost.index = i break } last_dx = w } if te.Entry.ghost.index < 0 { te.Entry.ghost.offset = int(d.StringWidth(te.Entry.text)) te.Entry.ghost.index = len(te.Entry.text) } return true }
func (b *Button) RenderAt(x, y int) { gl.Color4ub(255, 255, 255, byte(b.shade*255)) if b.Texture.Path != "" { b.Texture.Data().RenderNatural(b.X+x, b.Y+y) b.bounds.x = b.X + x b.bounds.y = b.Y + y b.bounds.dx = b.Texture.Data().Dx() b.bounds.dy = b.Texture.Data().Dy() } else { d := base.GetDictionary(b.Text.Size) b.bounds.x = b.X + x b.bounds.y = b.Y + y b.bounds.dx = int(d.StringWidth(b.Text.String)) b.bounds.dy = int(d.MaxHeight()) base.Log().Printf("Button '%s' @ %d %d %d %d", b.Text.String, b.bounds.x, b.bounds.y, b.bounds.dx, b.bounds.dy) var just gui.Justification switch b.Text.Justification { case "center": just = gui.Center b.bounds.x -= b.bounds.dx / 2 case "left": just = gui.Left case "right": just = gui.Right b.bounds.x -= b.bounds.dx default: just = gui.Center b.bounds.x -= b.bounds.dx / 2 b.Text.Justification = "center" base.Warn().Printf("Failed to indicate valid aligmnent, '%s' is not valid.", b.Text.Justification) } d.RenderString(b.Text.String, float64(b.X+x), float64(b.Y+y), 0, d.MaxHeight(), just) } }
func execMinionFunc(a *Ai) lua.GoFunction { return func(L *lua.State) int { base.Log().Printf("Exec minion") if !game.LuaNumParamsOk(L, 1, "execMinion") { return 0 } ent := game.LuaToEntity(L, a.game, -1) if ent == nil { game.LuaDoError(L, "Tried to execMinion entity which doesn't exist.") return 0 } if ent.HauntEnt == nil || ent.HauntEnt.Level != game.LevelMinion { game.LuaDoError(L, fmt.Sprintf("Tried to execMinion entity with Id=%d, which is not a minion.", ent.Id)) return 0 } if !ent.Ai.Active() { game.LuaDoError(L, fmt.Sprintf("Tried to execMinion entity with Id=%d, which is not active.", ent.Id)) return 0 } exec := <-ent.Ai.ActionExecs() if exec != nil { a.execs <- exec } <-a.pause return 0 } }
func InsertVersusMenu(ui gui.WidgetParent, replace func(gui.WidgetParent) error) error { // return doChooserMenu(ui, makeChooseVersusMetaMenu, replace, inserter(insertGoalMenu)) chooser, done, err := makeChooseVersusMetaMenu() if err != nil { return err } ui.AddChild(chooser) go func() { m := <-done ui.RemoveChild(chooser) if m != nil && len(m) == 1 { base.Log().Printf("Chose: %v", m) switch m[0] { case "Select House": ui.AddChild(MakeGamePanel("versus/basic.lua", nil, map[string]string{"map": "select"}, "")) case "Random House": ui.AddChild(MakeGamePanel("versus/basic.lua", nil, map[string]string{"map": "random"}, "")) case "Continue": ui.AddChild(MakeGamePanel("versus/basic.lua", nil, map[string]string{"map": "continue"}, "")) default: base.Error().Printf("Unknown meta choice '%s'", m[0]) return } } else { err := replace(ui) if err != nil { base.Error().Printf("Error replacing menu: %v", err) } } }() return nil }
// Distributes the ents among the spawn points. Since this is done randomly // it might not work, so there is a very small chance that not all spawns will // have an ent given to them, even if it is possible to distrbiute them // properly. Regardless, at least some will be spawned. func spawnEnts(g *Game, ents []*Entity, spawns []*house.SpawnPoint) { sort.Sort(orderSpawnsSmallToBig(spawns)) sanity := 100 var places []entSpawnPair for sanity > 0 { sanity-- places = places[0:0] sort.Sort(orderEntsBigToSmall(ents)) //slightly shuffle the ents for i := range ents { j := i + rand.Intn(5) - 2 if j >= 0 && j < len(ents) { ents[i], ents[j] = ents[j], ents[i] } } // Go through each ent and try to place it in an unused spawn point used_spawns := make(map[*house.SpawnPoint]bool) for _, ent := range ents { for _, spawn := range spawns { if used_spawns[spawn] { continue } if spawn.Dx < ent.Dx || spawn.Dy < ent.Dy { continue } used_spawns[spawn] = true places = append(places, entSpawnPair{ent, spawn}) break } } if len(places) == len(spawns) { break } } if sanity > 0 { base.Log().Printf("Placed all objects with %d sanity remaining", sanity) } else { base.Warn().Printf("Only able to place %d out of %d objects", len(places), len(spawns)) } for _, place := range places { place.ent.X = float64(place.spawn.X + rand.Intn(place.spawn.Dx-place.ent.Dx+1)) place.ent.Y = float64(place.spawn.Y + rand.Intn(place.spawn.Dy-place.ent.Dy+1)) g.viewer.AddDrawable(place.ent) g.Ents = append(g.Ents, place.ent) base.Log().Printf("Using object '%s' at (%.0f, %.0f)", place.ent.Name, place.ent.X, place.ent.Y) } }
// Decodes a value from the reader and pushes it onto the stack func LuaDecodeValue(r io.Reader, L *lua.State, g *Game) error { var le luaEncodable err := binary.Read(r, binary.LittleEndian, &le) if err != nil { return err } switch le { case luaEncBool: var v byte err = binary.Read(r, binary.LittleEndian, &v) L.PushBoolean(v == 1) case luaEncNumber: var f float64 err = binary.Read(r, binary.LittleEndian, &f) L.PushNumber(f) case luaEncNil: L.PushNil() case luaEncEntity: var id uint64 err = binary.Read(r, binary.LittleEndian, &id) ent := g.EntityById(EntityId(id)) LuaPushEntity(L, ent) if ent != nil { base.Log().Printf("LUA: Push Ent %s", ent.Name) } else { base.Log().Printf("LUA: Push Ent NIL") } case luaEncTable: err = LuaDecodeTable(r, L, g) case luaEncString: var length uint32 err = binary.Read(r, binary.LittleEndian, &length) if err != nil { return err } sb := make([]byte, length) err = binary.Read(r, binary.LittleEndian, &sb) L.PushString(string(sb)) default: return errors.New(fmt.Sprintf("Unknown lua value id == %d.", le)) } if err != nil { return err } return nil }
func (e *Entity) LoadAi() { filename := e.Ai_path.String() if e.Ai_file_override != "" { filename = e.Ai_file_override.String() } if filename == "" { base.Log().Printf("No ai for %s", e.Name) e.Ai = inactiveAi{} return } ai_maker(filename, e.Game(), e, &e.Ai, EntityAi) if e.Ai == nil { e.Ai = inactiveAi{} base.Log().Printf("Failed to make Ai for '%s' with %s", e.Name, filename) } else { base.Log().Printf("Made Ai for '%s' with %s", e.Name, filename) } }
func (a *Ai) Activate() { if a.ent != nil { base.Log().Printf("Activated entity: %v", a.ent.Name) } reload := false for { select { case <-a.watcher.Event: reload = true default: goto no_more_events } } no_more_events: if reload { a.setupLuaState() base.Log().Printf("Reloaded lua state for '%p'", a) } a.active_set <- true }
func (g *Game) checkWinConditions() { return // Check for explorer win conditions explorer_win := false if explorer_win { base.Log().Printf("Explorers won - kaboom") } // Check for haunt win condition - all intruders dead haunts_win := true for i := range g.Ents { if g.Ents[i].Side() == SideExplorers { haunts_win = false } } if haunts_win { base.Log().Printf("Haunts won - kaboom") } }
// Ripped from game/ai/ai.go - should probably sync up with it func registerUtilityFunctions(L *lua.State) { L.Register("print", func(L *lua.State) int { var res string n := L.GetTop() for i := -n; i < 0; i++ { res += LuaStringifyParam(L, i) + " " } base.Log().Printf("GameScript(%p): %s", L, res) return 0 }) }
func (g *Game) setup() { g.gameDataTransient.alloc() g.all_ents_in_game = make(map[*Entity]bool) g.all_ents_in_memory = make(map[*Entity]bool) for i := range g.Ents { base.Log().Printf("Ungob, ent: %p", g.Ents[i]) if g.Ents[i].Side() == g.Side { base.Log().Printf("Ungob, ent: %p", g.Ents[i]) g.UpdateEntLos(g.Ents[i], true) } } if g.Side == SideHaunt { g.viewer.Los_tex = g.los.intruders.tex } else { g.viewer.Los_tex = g.los.denizens.tex } g.Ai.minions = inactiveAi{} g.Ai.denizens = inactiveAi{} g.Ai.intruders = inactiveAi{} }
func (e *Entity) LoadAi() { filename := e.Ai_file_override.String() if filename == "" { e.Ai = inactiveAi{} return } ai_maker(filename, e.Game(), e, &e.Ai, EntityAi) base.Log().Printf("Made Ai for '%s'", e.Name) if e.Ai == nil { e.Ai = inactiveAi{} } }
func (a *Move) Maintain(dt int64, g *game.Game, ae game.ActionExec) game.MaintenanceStatus { if ae != nil { exec := ae.(*moveExec) a.ent = g.EntityById(ae.EntityId()) if len(exec.Path) == 0 { base.Error().Printf("Got a move exec with a path length of 0: %v", exec) return game.Complete } a.cost = exec.measureCost(a.ent, g) if a.cost > a.ent.Stats.ApCur() { base.Error().Printf("Got a move that required more ap than available: %v", exec) base.Error().Printf("Path: %v", exec.Path) return game.Complete } if a.cost == -1 { base.Error().Printf("Got a move that followed an invalid path: %v", exec) base.Error().Printf("Path: %v", exec.Path) if a.ent == nil { base.Error().Printf("ENT was Nil!") } else { x, y := a.ent.Pos() v := g.ToVertex(x, y) base.Error().Printf("Ent pos: (%d, %d) -> (%d)", x, y, v) } return game.Complete } algorithm.Map2(exec.Path, &a.path, func(v int) [2]int { _, x, y := g.FromVertex(v) return [2]int{x, y} }) base.Log().Printf("Path Validated: %v", exec) a.ent.Stats.ApplyDamage(-a.cost, 0, status.Unspecified) src := g.ToVertex(a.ent.Pos()) graph := g.Graph(a.ent.Side(), true, nil) a.drawPath(a.ent, g, graph, src) } // Do stuff factor := float32(math.Pow(2, a.ent.Walking_speed)) dist := a.ent.DoAdvance(factor*float32(dt)/200, a.path[0][0], a.path[0][1]) for dist > 0 { if len(a.path) == 1 { a.ent.DoAdvance(0, 0, 0) a.ent.Info.RoomsExplored[a.ent.CurrentRoom()] = true a.ent = nil return game.Complete } a.path = a.path[1:] a.ent.Info.RoomsExplored[a.ent.CurrentRoom()] = true dist = a.ent.DoAdvance(dist, a.path[0][0], a.path[0][1]) } return game.InProgress }
func (rc *RosterChooser) Respond(ui *gui.Gui, group gui.EventGroup) bool { base.Log().Printf("RosterChooser.Respond") if found, event := group.FindEvent('l'); found && event.Type == gin.Press { rc.focus += rc.layout.Num_options return true } if found, event := group.FindEvent('o'); found && event.Type == gin.Press { rc.focus -= rc.layout.Num_options return true } if found, event := group.FindEvent(gin.MouseLButton); found && event.Type == gin.Press { x, y := event.Key.Cursor().Point() gp := gui.Point{x, y} if gp.Inside(rc.render.down) { rc.focus += rc.layout.Num_options return true } else if gp.Inside(rc.render.up) { rc.focus -= rc.layout.Num_options return true } else if gp.Inside(rc.render.all_options) { for i := range rc.render.options { if gp.Inside(rc.render.options[i]) { rc.selector(i, rc.selected, true) return true } } } else if gp.Inside(rc.render.done) { if rc.selector(-1, rc.selected, false) { base.Log().Printf("calling on-complete") rc.on_complete(rc.selected) } return true } else if rc.on_undo != nil && gp.Inside(rc.render.undo) { rc.on_undo() return true } } return false }
func MakeGamePanel(script string, p *Player, data map[string]string, game_key mrgnet.GameKey) *GamePanel { var gp GamePanel gp.AnchorBox = gui.MakeAnchorBox(gui.Dims{1024, 768}) if p == nil { p = &Player{} } base.Log().Printf("Script path: %s / %s", script, p.Script_path) if script == "" { script = p.Script_path } startGameScript(&gp, script, p, data, game_key) return &gp }
func doExec(gp *GamePanel) lua.GoFunction { return func(L *lua.State) int { if !LuaCheckParamsOk(L, "DoExec", LuaTable) { return 0 } L.PushString("__encoded") L.GetTable(-2) str := L.ToString(-1) L.Pop(1) var execs []ActionExec base.Log().Printf("Decoding from: '%s'", str) err := base.FromBase64FromGob(&execs, str) if err != nil { base.Error().Printf("Error decoding exec: %v", err) return 0 } if len(execs) != 1 { base.Error().Printf("Error decoding exec: Found %d execs instead of exactly 1.", len(execs)) return 0 } base.Log().Printf("ScriptComm: Exec: %v", execs[0]) gp.game.comm.script_to_game <- execs[0] base.Log().Printf("ScriptComm: Sent exec") <-gp.game.comm.game_to_script base.Log().Printf("ScriptComm: exec done") done := make(chan bool) gp.script.syncStart() go func() { for i := range gp.game.Ents { gp.game.Ents[i].Sprite().Wait([]string{"ready", "killed"}) } done <- true }() gp.script.syncEnd() <-done return 0 } }
func dialogBox(gp *GamePanel) lua.GoFunction { return func(L *lua.State) int { if L.GetTop() == 1 { if !LuaCheckParamsOk(L, "DialogBox", LuaString) { return 0 } } else { if !LuaCheckParamsOk(L, "DialogBox", LuaString, LuaTable) { return 0 } } gp.script.syncStart() defer gp.script.syncEnd() path := L.ToString(1) var args map[string]string if L.GetTop() > 1 { args = make(map[string]string) L.PushValue(2) L.PushNil() for L.Next(-2) != 0 { args[L.ToString(-2)] = L.ToString(-1) L.Pop(1) } L.Pop(1) } box, output, err := MakeDialogBox(filepath.ToSlash(path), args) if err != nil { base.Error().Printf("Error making dialog: %v", err) return 0 } gp.AnchorBox.AddChild(box, gui.Anchor{0.5, 0.5, 0.5, 0.5}) gp.script.syncEnd() var choices []string for choice := range output { choices = append(choices, choice) } base.Log().Printf("Dialog box press: %v", choices) gp.script.syncStart() gp.AnchorBox.RemoveChild(box) L.NewTable() for i, choice := range choices { L.PushInteger(i + 1) L.PushString(choice) L.SetTable(-3) } return 1 } }
func (he *HouseEditor) Load(path string) error { house, err := MakeHouseFromPath(path) if err != nil { return err } base.Log().Printf("Loaded %s\n", path) house.Normalize() he.house = *house he.viewer.SetBounds() for _, tab := range he.widgets { tab.Reload() } return err }
func MakeUiSelectMap(gp *GamePanel) (gui.Widget, <-chan string, error) { var ui UiSelectMap datadir := base.GetDataDir() err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "select_map", "config.json"), "json", &ui.layout) if err != nil { return nil, nil, err } ui.region.Dx = 1024 ui.region.Dy = 768 var options []hui.Option // TODO: may want to reload the registry on this one? If we want to pik up // new changes to files that is. for _, name := range base.GetAllNamesInRegistry("houses") { var mo MapOption mo.house_def = house.MakeHouseFromName(name) mo.layout = &ui.layout options = append(options, &mo) } out := make(chan string, 2) chooser := hui.MakeRosterChooser(options, hui.SelectExactlyOne, func(m map[int]bool) { var index int base.Log().Printf("On complete: %v", m) for index = range m { out <- options[index].(*MapOption).house_def.Name base.Log().Printf("Sent '%s'", options[index].(*MapOption).house_def.Name) break } base.Log().Printf("Closing") close(out) }, nil) ui.chooser = chooser return &ui, out, nil }
func selectHouse(gp *GamePanel) lua.GoFunction { return func(L *lua.State) int { if !LuaCheckParamsOk(L, "SelectHouse") { return 0 } gp.script.syncStart() defer gp.script.syncEnd() selector, output, err := MakeUiSelectMap(gp) if err != nil { base.Error().Printf("Error selecting map: %v", err) return 0 } gp.AnchorBox.AddChild(selector, gui.Anchor{0.5, 0.5, 0.5, 0.5}) gp.script.syncEnd() name := <-output base.Log().Printf("Received '%s'", name) gp.script.syncStart() gp.AnchorBox.RemoveChild(selector) base.Log().Printf("Removed seletor") L.PushString(name) return 1 } }
// Tries to place new_ent in the game at its current position. Returns true // on success, false otherwise. // pattern is a regexp that matches only the names of all valid spawn points. func (g *Game) placeEntity(pattern string) bool { if g.new_ent == nil { base.Log().Printf("No new ent") return false } re, err := regexp.Compile(pattern) if err != nil { base.Error().Printf("Failed to compile regexp: '%s': %v", pattern, err) return false } g.new_ent.Info.RoomsExplored[g.new_ent.CurrentRoom()] = true ix, iy := int(g.new_ent.X), int(g.new_ent.Y) idx, idy := g.new_ent.Dims() r, f, _ := g.House.Floors[0].RoomFurnSpawnAtPos(ix, iy) if r == nil || f != nil { return false } for _, e := range g.Ents { x, y := e.Pos() dx, dy := e.Dims() r1 := image.Rect(x, y, x+dx, y+dy) r2 := image.Rect(ix, iy, ix+idx, iy+idy) if r1.Overlaps(r2) { return false } } // Check for spawn points for _, spawn := range g.House.Floors[0].Spawns { if !re.MatchString(spawn.Name) { continue } x, y := spawn.Pos() dx, dy := spawn.Dims() if ix < x || ix+idx > x+dx { continue } if iy < y || iy+idy > y+dy { continue } g.Ents = append(g.Ents, g.new_ent) g.new_ent = nil return true } return false }
func (gdt *gameDataTransient) alloc() { if gdt.los.denizens.tex != nil { return } gdt.los.denizens.tex = house.MakeLosTexture() gdt.los.intruders.tex = house.MakeLosTexture() gdt.los.full_merger = make([]bool, house.LosTextureSizeSquared) gdt.los.merger = make([][]bool, house.LosTextureSize) for i := range gdt.los.merger { gdt.los.merger[i] = gdt.los.full_merger[i*house.LosTextureSize : (i+1)*house.LosTextureSize] } gdt.comm.script_to_game = make(chan interface{}, 1) gdt.comm.game_to_script = make(chan interface{}, 1) gdt.script = &gameScript{} base.Log().Printf("script = %p", gdt.script) }
func placeEntities(gp *GamePanel) lua.GoFunction { return func(L *lua.State) int { if !LuaCheckParamsOk(L, "PlaceEntities", LuaString, LuaTable, LuaInteger, LuaInteger) { return 0 } gp.script.syncStart() defer gp.script.syncEnd() L.PushNil() var names []string var costs []int for L.Next(-4) != 0 { L.PushInteger(1) L.GetTable(-2) names = append(names, L.ToString(-1)) L.Pop(1) L.PushInteger(2) L.GetTable(-2) costs = append(costs, L.ToInteger(-1)) L.Pop(2) } ep, done, err := MakeEntityPlacer(gp.game, names, costs, L.ToInteger(-2), L.ToInteger(-1), L.ToString(-4)) if err != nil { base.Error().Printf("Unable to make entity placer: %v", err) return 0 } gp.AnchorBox.AddChild(ep, gui.Anchor{0, 0, 0, 0}) for i, kid := range gp.AnchorBox.GetChildren() { base.Log().Printf("Kid[%d] = %s", i, kid.String()) } gp.script.syncEnd() ents := <-done L.NewTable() for i := range ents { L.PushInteger(i + 1) LuaPushEntity(L, ents[i]) L.SetTable(-3) } gp.script.syncStart() gp.AnchorBox.RemoveChild(ep) return 1 } }