func InsertStartMenu(ui gui.WidgetParent) error { var sm StartMenu datadir := base.GetDataDir() err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "start", "layout.json"), "json", &sm.layout) if err != nil { return err } sm.buttons = []ButtonLike{ &sm.layout.Menu.Continue, &sm.layout.Menu.Versus, &sm.layout.Menu.Online, &sm.layout.Menu.Settings, } sm.layout.Menu.Continue.f = func(interface{}) {} sm.layout.Menu.Versus.f = func(interface{}) { ui.RemoveChild(&sm) ui.AddChild(MakeGamePanel("versus/basic.lua", nil, nil)) } sm.layout.Menu.Settings.f = func(interface{}) {} sm.layout.Menu.Online.f = func(interface{}) { ui.RemoveChild(&sm) err := InsertOnlineMenu(ui) if err != nil { base.Error().Printf("Unable to make Online Menu: %v", err) return } } ui.AddChild(&sm) return nil }
func InsertCreditsMenu(ui gui.WidgetParent) error { var cm CreditsMenu datadir := base.GetDataDir() err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "start", "credits", "layout.json"), "json", &cm.layout) if err != nil { return err } cm.buttons = []ButtonLike{ &cm.layout.Back, &cm.layout.Up, &cm.layout.Down, } cm.layout.Back.f = func(interface{}) { ui.RemoveChild(&cm) InsertStartMenu(ui) } d := base.GetDictionary(cm.layout.Credits.Size) cm.layout.Credits.Scroll.Height = len(cm.layout.Credits.Lines) * int(d.MaxHeight()) cm.layout.Down.valid_func = func() bool { return cm.layout.Credits.Scroll.Height > cm.layout.Credits.Scroll.Dy } cm.layout.Up.valid_func = cm.layout.Down.valid_func cm.layout.Down.f = func(interface{}) { cm.layout.Credits.Scroll.Down() } cm.layout.Up.f = func(interface{}) { cm.layout.Credits.Scroll.Up() } cm.ui = ui ui.AddChild(&cm) return nil }
func MakeMainBar(game *Game) (*MainBar, error) { var mb MainBar datadir := base.GetDataDir() err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "main_bar.json"), "json", &mb.layout) if err != nil { return nil, err } mb.all_buttons = []*Button{ &mb.layout.EndTurn, &mb.layout.UnitLeft, &mb.layout.UnitRight, &mb.layout.ActionLeft, &mb.layout.ActionRight, } mb.no_actions_buttons = []*Button{ &mb.layout.EndTurn, &mb.layout.UnitLeft, &mb.layout.UnitRight, } mb.layout.EndTurn.f = buttonFuncEndTurn mb.layout.UnitRight.f = buttonFuncUnitRight mb.layout.UnitRight.key = gin.Tab mb.layout.UnitLeft.f = buttonFuncUnitLeft mb.layout.UnitLeft.key = gin.ShiftTab mb.layout.ActionLeft.f = buttonFuncActionLeft mb.layout.ActionRight.f = buttonFuncActionRight mb.game = game return &mb, nil }
func chooserFromFile(gp *GamePanel) lua.GoFunction { return func(L *lua.State) int { if !LuaCheckParamsOk(L, "ChooserFromFile", LuaString) { return 0 } gp.script.syncStart() defer gp.script.syncEnd() path := filepath.Join(base.GetDataDir(), L.ToString(-1)) chooser, done, err := makeChooserFromOptionBasicsFile(path) if err != nil { base.Error().Printf("Error making chooser: %v", err) return 0 } gp.AnchorBox.AddChild(chooser, gui.Anchor{0.5, 0.5, 0.5, 0.5}) gp.script.syncEnd() res := <-done L.NewTable() for i, s := range res { L.PushInteger(i + 1) L.PushString(s) L.SetTable(-3) } gp.script.syncStart() gp.AnchorBox.RemoveChild(chooser) return 1 } }
// Returns a map from player name to the path of that player's file. func GetAllPlayers() map[string]string { root := filepath.Join(base.GetDataDir(), "players") players := make(map[string]string) filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } f, err := os.Open(path) if err != nil { base.Warn().Printf("Unable to open player file: %s.", path) return nil } defer f.Close() dec := gob.NewDecoder(f) var name string err = dec.Decode(&name) if err != nil { base.Warn().Printf("Unable to read player file: %s.", path) return nil } players[name] = path return nil }) return players }
func LoadAllEntities() { base.RemoveRegistry("entities") base.RegisterRegistry("entities", make(map[string]*entityDef)) basedir := base.GetDataDir() base.RegisterAllObjectsInDir("entities", filepath.Join(basedir, "entities"), ".json", "json") base.RegisterAllObjectsInDir("entities", filepath.Join(basedir, "objects"), ".json", "json") }
func MakeChooser(opts []Option) (*Chooser, <-chan []string, error) { var ch Chooser datadir := base.GetDataDir() err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "chooser", "layout.json"), "json", &ch.layout) if err != nil { return nil, nil, err } ch.options = opts ch.buttons = []*Button{ &ch.layout.Up, &ch.layout.Down, &ch.layout.Back, &ch.layout.Next, } ch.non_scroll_buttons = []*Button{ &ch.layout.Back, &ch.layout.Next, } ch.layout.Up.f = func(interface{}) { ch.layout.Options.Up() } ch.layout.Down.f = func(interface{}) { ch.layout.Options.Down() } done := make(chan []string, 1) ch.selected = make(map[int]bool) ch.layout.Back.f = func(interface{}) { done <- nil close(done) } ch.layout.Next.f = func(interface{}) { var res []string for i := range ch.options { if ch.selected[i] { res = append(res, ch.options[i].String()) } } done <- res close(done) } ch.layout.Next.valid_func = func() bool { return ch.selector(-1, ch.selected, false) } ch.min, ch.max = 1, 1 if ch.min == 1 && ch.max == 1 { ch.selector = SelectExactlyOne } else { ch.selector = SelectInRange(ch.min, ch.max) } ch.info_region = gui.Region{ gui.Point{ch.layout.Info.X, ch.layout.Info.Y}, gui.Dims{ch.layout.Info.Dx, ch.layout.Info.Dy}, } return &ch, done, nil }
func pickFromN(gp *GamePanel) lua.GoFunction { return func(L *lua.State) int { if !LuaCheckParamsOk(L, "PickFromN", LuaInteger, LuaInteger, LuaTable) { return 0 } min := L.ToInteger(-3) max := L.ToInteger(-2) var options []hui.Option var option_names []string L.PushNil() for L.Next(-2) != 0 { name := L.ToString(-2) option_names = append(option_names, name) path := L.ToString(-1) if !filepath.IsAbs(path) { path = filepath.Join(base.GetDataDir(), path) } option := iconWithText{ Name: name, Icon: texture.Object{Path: base.Path(path)}, } options = append(options, &option) L.Pop(1) } var selector hui.Selector if min == 1 && max == 1 { selector = hui.SelectExactlyOne } else { selector = hui.SelectInRange(min, max) } var chooser *hui.RosterChooser done := make(chan struct{}) on_complete := func(m map[int]bool) { gp.RemoveChild(chooser) L.NewTable() count := 0 for i := range options { if m[i] { count++ L.PushInteger(count) L.PushString(option_names[i]) L.SetTable(-3) } } done <- struct{}{} } chooser = hui.MakeRosterChooser(options, selector, on_complete, nil) gp.script.syncStart() gp.AddChild(chooser, gui.Anchor{0.5, 0.5, 0.5, 0.5}) gp.script.syncEnd() <-done return 1 } }
func SavePlayer(p *Player) error { hash := fnv.New64() hash.Write([]byte(p.Name)) name := fmt.Sprintf("%x.player", hash.Sum64()) f, err := os.Create(filepath.Join(base.GetDataDir(), "players", name)) if err != nil { return err } defer f.Close() base.SetStoreVal("last player", name) return EncodePlayer(f, p) }
func registerMoves() map[string]func() game.Action { move_actions := make(map[string]*MoveDef) base.RemoveRegistry("actions-move_actions") base.RegisterRegistry("actions-move_actions", move_actions) base.RegisterAllObjectsInDir("actions-move_actions", filepath.Join(base.GetDataDir(), "actions", "movement"), ".json", "json") makers := make(map[string]func() game.Action) for name := range move_actions { cname := name makers[cname] = func() game.Action { a := Move{Defname: cname} base.GetObject("actions-move_actions", &a) return &a } } return makers }
func registerBasicConditions() { registry_name := "conditions-basic_conditions" base.RemoveRegistry(registry_name) base.RegisterRegistry(registry_name, make(map[string]*BasicConditionDef)) base.RegisterAllObjectsInDir(registry_name, filepath.Join(base.GetDataDir(), "conditions", "basic_conditions"), ".json", "json") names := base.GetAllNamesInRegistry(registry_name) for _, name := range names { cname := name f := func() Condition { c := BasicCondition{Defname: cname} base.GetObject(registry_name, &c) return &c } condition_makers[name] = f } }
func registerInteracts() map[string]func() game.Action { interact_actions := make(map[string]*InteractDef) base.RemoveRegistry("actions-interact_actions") base.RegisterRegistry("actions-interact_actions", interact_actions) base.RegisterAllObjectsInDir("actions-interact_actions", filepath.Join(base.GetDataDir(), "actions", "interacts"), ".json", "json") makers := make(map[string]func() game.Action) for name := range interact_actions { cname := name makers[cname] = func() game.Action { a := Interact{Defname: cname} base.GetObject("actions-interact_actions", &a) return &a } } return makers }
func MakeRosterChooser(options []Option, selector Selector, on_complete func(map[int]bool), on_undo func()) *RosterChooser { var rc RosterChooser rc.options = options err := base.LoadAndProcessObject(filepath.Join(base.GetDataDir(), "ui", "widgets", "roster_chooser.json"), "json", &rc.layout) if err != nil { base.Error().Printf("Failed to create RosterChooser: %v", err) return nil } rc.Request_dims = gui.Dims{ rc.layout.Down.Data().Dx() + rc.layout.Option.Dx, rc.layout.Num_options*rc.layout.Option.Dy + 2*int(base.GetDictionary(15).MaxHeight()), } rc.selected = make(map[int]bool) rc.selector = selector rc.on_complete = on_complete rc.on_undo = on_undo rc.render.options = make([]gui.Region, len(rc.options)) return &rc }
func registerSummonActions() map[string]func() game.Action { summons_actions := make(map[string]*SummonActionDef) base.RemoveRegistry("actions-summons_actions") base.RegisterRegistry("actions-summons_actions", summons_actions) base.RegisterAllObjectsInDir("actions-summons_actions", filepath.Join(base.GetDataDir(), "actions", "summons"), ".json", "json") makers := make(map[string]func() game.Action) for name := range summons_actions { cname := name makers[cname] = func() game.Action { a := SummonAction{Defname: cname} base.GetObject("actions-summons_actions", &a) if a.Ammo > 0 { a.Current_ammo = a.Ammo } else { a.Current_ammo = -1 } return &a } } return makers }
func (e *Entity) drawReticle(pos mathgl.Vec2, rgba [4]float64) { if !e.hovered && !e.selected && !e.controlled { return } gl.PushAttrib(gl.CURRENT_BIT) r := byte(rgba[0] * 255) g := byte(rgba[1] * 255) b := byte(rgba[2] * 255) a := byte(rgba[3] * 255) switch { case e.controlled: gl.Color4ub(0, 0, r, a) case e.selected: gl.Color4ub(r, g, b, a) default: gl.Color4ub(r, g, b, byte((int(a)*200)>>8)) } glow := texture.LoadFromPath(filepath.Join(base.GetDataDir(), "ui", "glow.png")) dx := float64(e.last_render_width + 0.5) dy := float64(e.last_render_width * 150 / 100) glow.Render(float64(pos.X), float64(pos.Y), dx, dy) gl.PopAttrib() }
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 Init() { var err error system, err = fmod.EventSystemCreate() if err != nil { base.Error().Printf("Unable to create sound system: %v", err) return } err = system.Init(32, fmod.INIT_NORMAL, nil, fmod.EVENT_INIT_NORMAL) if err != nil { base.Error().Printf("Unable to initialize sound system: %v", err) return } version, _ := system.GetVersion() base.Log().Printf("Fmod version %x", version) err = system.SetMediaPath(filepath.Join(base.GetDataDir(), "sound") + "/") if err != nil { base.Error().Printf("Unable to set media path: %v\n", err) return } err = system.LoadPath("Haunts.fev", nil) if err != nil { base.Error().Printf("Unable to load fev: %v\n", err) return } freq = time.Millisecond * 3 approach = 0.01 music_volume = make(chan float64, 1) music_start = make(chan string, 1) param_control = make(chan paramRequest, 1) music_stop = make(chan bool, 1) go musicControl() }
func MakeEntityPlacer(game *Game, roster_names []string, roster_costs []int, min, max int, pattern string) (*EntityPlacer, <-chan []*Entity, error) { var ep EntityPlacer err := base.LoadAndProcessObject(filepath.Join(base.GetDataDir(), "ui", "entity_placer", "config.json"), "json", &ep.layout) if err != nil { return nil, nil, err } if len(roster_names) != len(roster_costs) { return nil, nil, errors.New("Must have as many names as costs.") } if len(roster_names) <= 0 || len(roster_names) > ep.layout.Roster.Max_options { return nil, nil, errors.New(fmt.Sprintf("Can't have more than %d ents in a roster.", ep.layout.Roster.Max_options)) } ep.layout.Undo.valid_func = func() bool { return len(ep.ents) > 0 } ep.layout.Undo.f = func(interface{}) { ent := ep.ents[len(ep.ents)-1] ep.points += ep.roster[ent.Name] ep.ents = ep.ents[0 : len(ep.ents)-1] algorithm.Choose2(&game.Ents, func(e *Entity) bool { return e != ent }) game.viewer.RemoveDrawable(ent) } ep.layout.Done.valid_func = func() bool { return ep.points >= 0 && min <= (max-ep.points) } done := make(chan []*Entity) ep.layout.Done.f = func(interface{}) { done <- ep.ents close(done) house.PopSpawnRegexp() game.viewer.RemoveDrawable(game.new_ent) game.new_ent = nil } ep.roster_names = roster_names ep.roster = make(map[string]int) for i, name := range ep.roster_names { ep.roster[name] = roster_costs[i] } ep.game = game ep.show_points = !(min == 1 && max == 1) ep.points = max ep.pattern = pattern house.PushSpawnRegexp(ep.pattern) x := ep.layout.Roster.X for _, name := range ep.roster_names { var b Button b.X = x x += (ep.layout.Roster.X2 - ep.layout.Roster.X) / (ep.layout.Roster.Max_options - 1) b.Y = ep.layout.Roster.Y ent := Entity{Defname: name} base.GetObject("entities", &ent) b.Texture = ent.Still cost := ep.roster[name] b.valid_func = func() bool { return ep.points >= cost } b.f = func(interface{}) { ep.game.viewer.RemoveDrawable(ep.game.new_ent) ep.game.new_ent = MakeEntity(ent.Name, ep.game) ep.game.viewer.AddDrawable(ep.game.new_ent) } ep.ent_buttons = append(ep.ent_buttons, &b) } ep.buttons = []*Button{ &ep.layout.Undo, &ep.layout.Done, } for _, b := range ep.ent_buttons { ep.buttons = append(ep.buttons, b) } return &ep, done, nil }
func startGameScript(gp *GamePanel, path string, player *Player, data map[string]string) { // Clear out the panel, now the script can do whatever it wants player.Script_path = path gp.AnchorBox = gui.MakeAnchorBox(gui.Dims{1024, 768}) base.Log().Printf("startGameScript") if !filepath.IsAbs(path) { path = filepath.Join(base.GetDataDir(), "scripts", filepath.FromSlash(path)) } // The game script runs in a separate go routine and functions that need to // communicate with the game will do so via channels - DUH why did i even // write this comment? prog, err := ioutil.ReadFile(path) if err != nil { base.Error().Printf("Unable to load game script file %s: %v", path, err) return } gp.script = &gameScript{} base.Log().Printf("script = %p", gp.script) gp.script.L = lua.NewState() gp.script.L.OpenLibs() gp.script.L.SetExecutionLimit(25000) gp.script.L.NewTable() LuaPushSmartFunctionTable(gp.script.L, FunctionTable{ "ChooserFromFile": func() { gp.script.L.PushGoFunctionAsCFunction(chooserFromFile(gp)) }, "StartScript": func() { gp.script.L.PushGoFunctionAsCFunction(startScript(gp, player)) }, "SaveGameState": func() { gp.script.L.PushGoFunctionAsCFunction(saveGameState(gp)) }, "LoadGameState": func() { gp.script.L.PushGoFunctionAsCFunction(loadGameState(gp)) }, "DoExec": func() { gp.script.L.PushGoFunctionAsCFunction(doExec(gp)) }, "SelectEnt": func() { gp.script.L.PushGoFunctionAsCFunction(selectEnt(gp)) }, "FocusPos": func() { gp.script.L.PushGoFunctionAsCFunction(focusPos(gp)) }, "SelectHouse": func() { gp.script.L.PushGoFunctionAsCFunction(selectHouse(gp)) }, "LoadHouse": func() { gp.script.L.PushGoFunctionAsCFunction(loadHouse(gp)) }, "SaveStore": func() { gp.script.L.PushGoFunctionAsCFunction(saveStore(gp, player)) }, "ShowMainBar": func() { gp.script.L.PushGoFunctionAsCFunction(showMainBar(gp, player)) }, "SpawnEntityAtPosition": func() { gp.script.L.PushGoFunctionAsCFunction(spawnEntityAtPosition(gp)) }, "GetSpawnPointsMatching": func() { gp.script.L.PushGoFunctionAsCFunction(getSpawnPointsMatching(gp)) }, "SpawnEntitySomewhereInSpawnPoints": func() { gp.script.L.PushGoFunctionAsCFunction(spawnEntitySomewhereInSpawnPoints(gp)) }, "IsSpawnPointInLos": func() { gp.script.L.PushGoFunctionAsCFunction(isSpawnPointInLos(gp)) }, "PlaceEntities": func() { gp.script.L.PushGoFunctionAsCFunction(placeEntities(gp)) }, "RoomAtPos": func() { gp.script.L.PushGoFunctionAsCFunction(roomAtPos(gp)) }, "SetLosMode": func() { gp.script.L.PushGoFunctionAsCFunction(setLosMode(gp)) }, "GetAllEnts": func() { gp.script.L.PushGoFunctionAsCFunction(getAllEnts(gp)) }, "DialogBox": func() { gp.script.L.PushGoFunctionAsCFunction(dialogBox(gp)) }, "PickFromN": func() { gp.script.L.PushGoFunctionAsCFunction(pickFromN(gp)) }, "SetGear": func() { gp.script.L.PushGoFunctionAsCFunction(setGear(gp)) }, "BindAi": func() { gp.script.L.PushGoFunctionAsCFunction(bindAi(gp)) }, "SetVisibility": func() { gp.script.L.PushGoFunctionAsCFunction(setVisibility(gp)) }, "EndPlayerInteraction": func() { gp.script.L.PushGoFunctionAsCFunction(endPlayerInteraction(gp)) }, "GetLos": func() { gp.script.L.PushGoFunctionAsCFunction(getLos(gp)) }, "SetVisibleSpawnPoints": func() { gp.script.L.PushGoFunctionAsCFunction(setVisibleSpawnPoints(gp)) }, "SetCondition": func() { gp.script.L.PushGoFunctionAsCFunction(setCondition(gp)) }, "SetPosition": func() { gp.script.L.PushGoFunctionAsCFunction(setPosition(gp)) }, "SetHp": func() { gp.script.L.PushGoFunctionAsCFunction(setHp(gp)) }, "SetAp": func() { gp.script.L.PushGoFunctionAsCFunction(setAp(gp)) }, "RemoveEnt": func() { gp.script.L.PushGoFunctionAsCFunction(removeEnt(gp)) }, "PlayAnimations": func() { gp.script.L.PushGoFunctionAsCFunction(playAnimations(gp)) }, "PlayMusic": func() { gp.script.L.PushGoFunctionAsCFunction(playMusic(gp)) }, "StopMusic": func() { gp.script.L.PushGoFunctionAsCFunction(stopMusic(gp)) }, "SetMusicParam": func() { gp.script.L.PushGoFunctionAsCFunction(setMusicParam(gp)) }, "PlaySound": func() { gp.script.L.PushGoFunctionAsCFunction(playSound(gp)) }, "SetWaypoint": func() { gp.script.L.PushGoFunctionAsCFunction(setWaypoint(gp)) }, "RemoveWaypoint": func() { gp.script.L.PushGoFunctionAsCFunction(removeWaypoint(gp)) }, "Rand": func() { gp.script.L.PushGoFunctionAsCFunction(randFunc(gp)) }, "Sleep": func() { gp.script.L.PushGoFunctionAsCFunction(sleepFunc(gp)) }, }) gp.script.L.SetMetaTable(-2) gp.script.L.SetGlobal("Script") registerUtilityFunctions(gp.script.L) if player.Lua_store != nil { loadGameStateRaw(gp, player.Game_state) err := LuaDecodeTable(bytes.NewBuffer(player.Lua_store), gp.script.L, gp.game) if err != nil { base.Warn().Printf("Error decoding lua state: %v", err) } gp.script.L.SetGlobal("store") } else { gp.script.L.NewTable() gp.script.L.SetGlobal("store") } gp.script.sync = make(chan struct{}) base.Log().Printf("Sync: %p", gp.script.sync) res := gp.script.L.DoString(string(prog)) if !res { base.Error().Printf("There was an error running script %s:\n%s", path, prog) } else { base.Log().Printf("No_init: %v\n", player.No_init) go func() { gp.script.L.NewTable() for k, v := range data { gp.script.L.PushString(k) gp.script.L.PushString(v) gp.script.L.SetTable(-3) } gp.script.L.SetGlobal("__data") gp.script.L.SetExecutionLimit(250000) if player.No_init { gp.script.syncStart() loadGameStateRaw(gp, player.Game_state) gp.game.script = gp.script gp.script.syncEnd() } else { gp.script.L.DoString("Init(__data)") if gp.game.Side == SideHaunt { gp.game.Ai.minions.Activate() gp.game.Ai.denizens.Activate() gp.game.player_inactive = gp.game.Ai.denizens.Active() } else { gp.game.Ai.intruders.Activate() gp.game.player_inactive = gp.game.Ai.intruders.Active() } } if gp.game == nil { base.Error().Printf("Script failed to load a house during Init().") } else { gp.game.comm.script_to_game <- nil } }() } }
func InsertOnlineMenu(ui gui.WidgetParent) error { var sm OnlineMenu datadir := base.GetDataDir() err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "start", "online", "layout.json"), "json", &sm.layout) if err != nil { return err } sm.buttons = []ButtonLike{ &sm.layout.Back, &sm.layout.Unstarted.Up, &sm.layout.Unstarted.Down, &sm.layout.Active.Up, &sm.layout.Active.Down, &sm.layout.User, &sm.layout.NewGame, } sm.control.in = make(chan struct{}) sm.control.out = make(chan struct{}) sm.layout.Back.f = func(interface{}) { ui.RemoveChild(&sm) InsertStartMenu(ui) } sm.ui = ui var net_id mrgnet.NetId fmt.Sscanf(base.GetStoreVal("netid"), "%d", &net_id) if net_id == 0 { net_id = mrgnet.NetId(mrgnet.RandomId()) base.SetStoreVal("netid", fmt.Sprintf("%d", net_id)) } in_newgame := false sm.layout.NewGame.f = func(interface{}) { if in_newgame { return } in_newgame = true go func() { var req mrgnet.NewGameRequest req.Id = net_id var resp mrgnet.NewGameResponse done := make(chan bool, 1) go func() { mrgnet.DoAction("new", req, &resp) done <- true }() select { case <-done: case <-time.After(10 * time.Second): resp.Err = "Couldn't connect to server." } <-sm.control.in defer func() { in_newgame = false sm.control.out <- struct{}{} }() if resp.Err != "" { sm.layout.Error.err = resp.Err base.Error().Printf("Couldn't make new game: %v", resp.Err) return } ui.RemoveChild(&sm) err := InsertMapChooser( ui, func(name string) { ui.AddChild(MakeGamePanel(name, nil, nil, resp.Game_key)) }, InsertOnlineMenu, ) if err != nil { base.Error().Printf("Error making Map Chooser: %v", err) } }() } for _, _glb := range []*gameListBox{&sm.layout.Active, &sm.layout.Unstarted} { glb := _glb glb.Up.f = func(interface{}) { glb.Scroll.Up() } glb.Down.f = func(interface{}) { glb.Scroll.Down() } glb.update = make(chan mrgnet.ListGamesResponse) } go func() { var resp mrgnet.ListGamesResponse mrgnet.DoAction("list", mrgnet.ListGamesRequest{Id: net_id, Unstarted: true}, &resp) sm.layout.Unstarted.update <- resp }() go func() { var resp mrgnet.ListGamesResponse mrgnet.DoAction("list", mrgnet.ListGamesRequest{Id: net_id, Unstarted: false}, &resp) sm.layout.Active.update <- resp }() sm.layout.User.Button.f = func(interface{}) { var req mrgnet.UpdateUserRequest req.Name = sm.layout.User.Entry.text req.Id = net_id var resp mrgnet.UpdateUserResponse go func() { mrgnet.DoAction("user", req, &resp) <-sm.control.in sm.layout.User.SetText(resp.Name) sm.update_alpha = 1.0 sm.update_time = time.Now() sm.control.out <- struct{}{} }() } go func() { var resp mrgnet.UpdateUserResponse mrgnet.DoAction("user", mrgnet.UpdateUserRequest{Id: net_id}, &resp) <-sm.control.in sm.layout.User.SetText(resp.Name) sm.update_alpha = 1.0 sm.update_time = time.Now() sm.control.out <- struct{}{} }() ui.AddChild(&sm) return nil }
// bindAi(target, source) // bindAi("denizen", "denizen.lua") // bindAi("intruder", "intruder.lua") // bindAi("minions", "minions.lua") // bindAi(ent, "fudgecake.lua") // special sources: "human", "inactive", and in the future: "net" // special targets: "denizen", "intruder", "minions", or an entity table func bindAi(gp *GamePanel) lua.GoFunction { return func(L *lua.State) int { if !LuaCheckParamsOk(L, "BindAi", LuaAnything, LuaString) { return 0 } gp.script.syncStart() defer gp.script.syncEnd() source := L.ToString(-1) if L.IsTable(-2) { L.PushString("id") L.GetTable(-3) target := EntityId(L.ToInteger(-1)) L.Pop(1) ent := gp.game.EntityById(target) if ent == nil { base.Error().Printf("Referenced an entity with id == %d which doesn't exist.", target) return 0 } ent.Ai_file_override = base.Path(filepath.Join(base.GetDataDir(), "ais", filepath.FromSlash(L.ToString(-1)))) ent.LoadAi() return 0 } target := L.ToString(-2) switch target { case "denizen": switch source { case "human": gp.game.Ai.denizens = inactiveAi{} case "net": base.Error().Printf("bindAi('denizen', 'net') is not implemented.") return 0 default: gp.game.Ai.denizens = nil path := filepath.Join(base.GetDataDir(), "ais", source) gp.game.Ai.Path.Denizens = path ai_maker(path, gp.game, nil, &gp.game.Ai.denizens, DenizensAi) if gp.game.Ai.denizens == nil { gp.game.Ai.denizens = inactiveAi{} } } case "intruder": switch source { case "human": gp.game.Ai.intruders = inactiveAi{} case "net": base.Error().Printf("bindAi('intruder', 'net') is not implemented.") return 0 default: gp.game.Ai.intruders = nil path := filepath.Join(base.GetDataDir(), "ais", source) gp.game.Ai.Path.Intruders = path ai_maker(path, gp.game, nil, &gp.game.Ai.intruders, IntrudersAi) if gp.game.Ai.intruders == nil { gp.game.Ai.intruders = inactiveAi{} } } case "minions": gp.game.Ai.minions = nil path := filepath.Join(base.GetDataDir(), "ais", source) gp.game.Ai.Path.Minions = path ai_maker(path, gp.game, nil, &gp.game.Ai.minions, MinionsAi) if gp.game.Ai.minions == nil { gp.game.Ai.minions = inactiveAi{} } default: base.Error().Printf("Specified unknown Ai target '%s'", target) return 0 } return 0 } }
func InsertMapChooser(ui gui.WidgetParent, chosen func(string), resert func(ui gui.WidgetParent) error) error { var bops []OptionBasic datadir := base.GetDataDir() err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "start", "versus", "map_select.json"), "json", &bops) if err != nil { base.Error().Printf("Unable to insert MapChooser: %v", err) return err } var opts []Option algorithm.Map2(bops, &opts, func(ob OptionBasic) Option { return &ob }) for _, opt := range opts { base.Log().Printf(opt.String()) } var ch Chooser err = base.LoadAndProcessObject(filepath.Join(datadir, "ui", "chooser", "layout.json"), "json", &ch.layout) if err != nil { base.Error().Printf("Unable to insert MapChooser: %v", err) return err } ch.options = opts ch.buttons = []*Button{ &ch.layout.Up, &ch.layout.Down, &ch.layout.Back, &ch.layout.Next, } ch.non_scroll_buttons = []*Button{ &ch.layout.Back, &ch.layout.Next, } ch.layout.Up.f = func(interface{}) { ch.layout.Options.Up() } ch.layout.Down.f = func(interface{}) { ch.layout.Options.Down() } ch.selected = make(map[int]bool) ch.layout.Back.f = func(interface{}) { ui.RemoveChild(&ch) err := resert(ui) if err != nil { base.Error().Printf("Unable to make Start Menu: %v", err) return } } ch.layout.Next.f = func(interface{}) { for i := range ch.options { if ch.selected[i] { ui.RemoveChild(&ch) chosen(ch.options[i].String()) } } } ch.layout.Next.valid_func = func() bool { return ch.selector(-1, ch.selected, false) } ch.min, ch.max = 1, 1 if ch.min == 1 && ch.max == 1 { ch.selector = SelectExactlyOne } else { ch.selector = SelectInRange(ch.min, ch.max) } ch.info_region = gui.Region{ gui.Point{ch.layout.Info.X, ch.layout.Info.Y}, gui.Dims{ch.layout.Info.Dx, ch.layout.Info.Dy}, } ui.AddChild(&ch) return nil }
func InsertOnlineMenu(ui gui.WidgetParent) error { var sm OnlineMenu datadir := base.GetDataDir() err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "start", "online", "layout.json"), "json", &sm.layout) if err != nil { return err } sm.buttons = []ButtonLike{ &sm.layout.Back, &sm.layout.Unstarted.Up, &sm.layout.Unstarted.Down, &sm.layout.Active.Up, &sm.layout.Active.Down, &sm.layout.User, } sm.layout.Back.f = func(interface{}) { ui.RemoveChild(&sm) InsertStartMenu(ui) } var net_id mrgnet.NetId fmt.Sscanf(base.GetStoreVal("netid"), "%d", &net_id) if net_id == 0 { net_id = mrgnet.NetId(mrgnet.RandomId()) base.SetStoreVal("netid", fmt.Sprintf("%d", net_id)) } for _, _glb := range []*gameListBox{&sm.layout.Active, &sm.layout.Unstarted} { glb := _glb glb.Up.f = func(interface{}) { glb.Scroll.Up() } glb.Down.f = func(interface{}) { glb.Scroll.Down() } glb.update = make(chan mrgnet.ListGamesResponse) } go func() { var resp mrgnet.ListGamesResponse mrgnet.DoAction("list", mrgnet.ListGamesRequest{Id: net_id, Unstarted: true}, &resp) sm.layout.Unstarted.update <- resp }() go func() { var resp mrgnet.ListGamesResponse mrgnet.DoAction("list", mrgnet.ListGamesRequest{Id: net_id, Unstarted: false}, &resp) sm.layout.Active.update <- resp }() sm.update_user = make(chan mrgnet.UpdateUserResponse) sm.layout.User.Button.f = func(interface{}) { var req mrgnet.UpdateUserRequest req.Name = sm.layout.User.Entry.text req.Id = net_id var resp mrgnet.UpdateUserResponse go func() { mrgnet.DoAction("user", req, &resp) sm.update_user <- resp }() } go func() { var resp mrgnet.UpdateUserResponse mrgnet.DoAction("user", mrgnet.UpdateUserRequest{Id: net_id}, &resp) sm.update_user <- resp }() ui.AddChild(&sm) return nil }
func makeChooseVersusMetaMenu() (*Chooser, <-chan []string, error) { path := filepath.Join(base.GetDataDir(), "ui", "start", "versus", "meta.json") return makeChooserFromOptionBasicsFile(path) }