예제 #1
0
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
}
예제 #2
0
파일: entity.go 프로젝트: genbattle/haunts
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")
}
예제 #3
0
파일: player.go 프로젝트: genbattle/haunts
// 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
}
예제 #4
0
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
}
예제 #5
0
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
}
예제 #6
0
파일: player.go 프로젝트: genbattle/haunts
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)
}
예제 #7
0
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
}
예제 #8
0
파일: move.go 프로젝트: genbattle/haunts
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
}
예제 #9
0
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
	}
}
예제 #10
0
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.Credits,
		&sm.layout.Menu.Versus,
		&sm.layout.Menu.Online,
		&sm.layout.Menu.Settings,
	}
	sm.layout.Menu.Credits.f = func(interface{}) {
		ui.RemoveChild(&sm)
		err := InsertCreditsMenu(ui)
		if err != nil {
			base.Error().Printf("Unable to make Credits Menu: %v", err)
			return
		}
	}
	sm.layout.Menu.Versus.f = func(interface{}) {
		ui.RemoveChild(&sm)
		err := InsertMapChooser(
			ui,
			func(name string) {
				ui.AddChild(MakeGamePanel(name, nil, nil, ""))
			},
			InsertStartMenu,
		)
		if err != nil {
			base.Error().Printf("Unable to make Map Chooser: %v", err)
			return
		}
	}
	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
}
예제 #11
0
func MakeSystemMenu(gp *GamePanel, player *Player) (gui.Widget, error) {
	var sm SystemMenu
	datadir := base.GetDataDir()
	err := base.LoadAndProcessObject(filepath.Join(datadir, "ui", "system", "layout.json"), "json", &sm.layout)
	if err != nil {
		return nil, err
	}

	sm.layout.Main.f = func(interface{}) {}

	sm.buttons = []ButtonLike{
		&sm.layout.Sub.Return,
		&sm.layout.Sub.Save,
	}

	sm.layout.Sub.Return.f = func(_ui interface{}) {
		ui := _ui.(*gui.Gui)
		gp.game.Ents = nil
		gp.game.Think(1) // This should clean things up
		ui.DropFocus()
		Restart()
	}

	sm.layout.Sub.Save.Entry.text = player.Name
	sm.layout.Sub.Save.Button.f = func(interface{}) {
		UpdatePlayer(player, gp.script.L)
		str, err := base.ToGobToBase64(gp.game)
		if err != nil {
			base.Error().Printf("Error gobbing game state: %v", err)
			return
		}
		player.Game_state = str
		player.Name = sm.layout.Sub.Save.Text()
		player.No_init = true
		base.Log().Printf("Saving player: %v", player)
		err = SavePlayer(player)
		if err != nil {
			base.Warn().Printf("Unable to save player: %v", err)
			return
		}
		sm.saved_time = time.Now()
		sm.saved_alpha = 1.0
	}

	return &sm, nil
}
예제 #12
0
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
}
예제 #13
0
func registerAoeAttacks() map[string]func() game.Action {
	aoe_actions := make(map[string]*AoeAttackDef)
	base.RemoveRegistry("actions-aoe_actions")
	base.RegisterRegistry("actions-aoe_actions", aoe_actions)
	base.RegisterAllObjectsInDir("actions-aoe_actions", filepath.Join(base.GetDataDir(), "actions", "aoe_attacks"), ".json", "json")
	makers := make(map[string]func() game.Action)
	for name := range aoe_actions {
		cname := name
		makers[cname] = func() game.Action {
			a := AoeAttack{Defname: cname}
			base.GetObject("actions-aoe_actions", &a)
			if a.Ammo > 0 {
				a.Current_ammo = a.Ammo
			} else {
				a.Current_ammo = -1
			}
			return &a
		}
	}
	return makers
}
예제 #14
0
파일: entity.go 프로젝트: genbattle/haunts
func (e *Entity) drawReticle(pos mathgl.Vec2, rgba [4]float64) {
	if !e.hovered && !e.selected && !e.controlled {
		return
	}
	gl.PushAttrib(gl.CURRENT_BIT)
	r := gl.Ubyte(rgba[0] * 255)
	g := gl.Ubyte(rgba[1] * 255)
	b := gl.Ubyte(rgba[2] * 255)
	a := gl.Ubyte(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, gl.Ubyte((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()
}
예제 #15
0
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
}
예제 #16
0
func registerBasicAttacks() map[string]func() game.Action {
	attack_actions := make(map[string]*BasicAttackDef)
	base.RemoveRegistry("actions-attack_actions")
	base.RegisterRegistry("actions-attack_actions", attack_actions)
	base.RegisterAllObjectsInDir("actions-attack_actions", filepath.Join(base.GetDataDir(), "actions", "basic_attacks"), ".json", "json")
	makers := make(map[string]func() game.Action)
	for name := range attack_actions {
		cname := name
		makers[cname] = func() game.Action {
			a := BasicAttack{Defname: cname}
			base.GetObject("actions-attack_actions", &a)
			if !a.Target_allies && !a.Target_enemies {
				base.Error().Printf("Basic Attack '%s' cannot target anything!  Either Target_allies or Target_enemies must be true", a.Name)
			}
			if a.Ammo > 0 {
				a.Current_ammo = a.Ammo
			} else {
				a.Current_ammo = -1
			}
			return &a
		}
	}
	return makers
}
예제 #17
0
파일: manager.go 프로젝트: genbattle/haunts
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()
}
예제 #18
0
func makeChooseVersusMetaMenu() (*Chooser, <-chan []string, error) {
	path := filepath.Join(base.GetDataDir(), "ui", "start", "versus", "meta.json")
	return makeChooserFromOptionBasicsFile(path)
}
예제 #19
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
}
예제 #20
0
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

	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(5 * 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.Up.valid_func = func() bool {
			return glb.Scroll.Height > glb.Scroll.Dy
		}
		glb.Down.f = func(interface{}) {
			glb.Scroll.Down()
		}
		glb.Down.valid_func = func() bool {
			return glb.Scroll.Height > glb.Scroll.Dy
		}

		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
}
예제 #21
0
func MakeDialogBox(source string, args map[string]string) (*MediumDialogBox, <-chan string, error) {
	var mdb MediumDialogBox
	datadir := base.GetDataDir()
	err := base.LoadAndProcessObject(filepath.Join(datadir, source), "json", &mdb.data)
	if err != nil {
		return nil, nil, err
	}
	err = base.LoadAndProcessObject(filepath.Join(datadir, "ui", "dialog", fmt.Sprintf("%s.json", mdb.data.Size)), "json", &mdb.layout)
	if err != nil {
		return nil, nil, err
	}

	if _, ok := mdb.data.Pages["Start"]; !ok {
		return nil, nil, errors.New("Section 'Start' was not specified.")
	}

	// Make sure that all of the pages specified by "Next"s are available
	// in the map
	for _, page := range mdb.data.Pages {
		if page.Next != "" {
			return nil, nil, errors.New(fmt.Sprintf("Specified 'Next': '%s' on a page, but must be in a section on the page.", page.Next))
		}
		for _, section := range page.Sections {
			if section.Next == "" {
				continue
			}
			if _, ok := mdb.data.Pages[section.Next]; !ok {
				return nil, nil, errors.New(fmt.Sprintf("Section '%s' specified but doesn't exist.", section.Next))
			}
		}
		if _, ok := mdb.layout.Formats[page.Format]; !ok {
			return nil, nil, errors.New(fmt.Sprintf("Unknown dialog box format '%s'.", page.Format))
		}
		if len(page.Sections) != len(mdb.layout.Formats[page.Format].Sections) {
			return nil, nil, errors.New(fmt.Sprintf("Format '%s' requires exactly %d sections.", page.Format, len(mdb.layout.Formats[page.Format].Sections)))
		}
	}

	mdb.data.cur_page = "Start"
	mdb.format = mdb.layout.Formats[mdb.data.Pages[mdb.data.cur_page].Format]

	// return nil, nil, errors.New(fmt.Sprintf("Unknown format string: '%s'.", format))

	mdb.buttons = []*Button{
		&mdb.layout.Next,
		&mdb.layout.Prev,
	}

	mdb.result = make(chan string, 1)

	mdb.layout.Next.valid_func = func() bool {
		sections := mdb.data.Pages[mdb.data.cur_page].Sections
		return len(sections) == 1
	}

	mdb.layout.Next.f = func(_data interface{}) {
		sections := mdb.data.Pages[mdb.data.cur_page].Sections
		if len(sections) == 1 {
			if sections[0].Next == "" {
				if !mdb.done {
					close(mdb.result)
					mdb.done = true
				}
			} else {
				mdb.data.prev = append(mdb.data.prev, mdb.data.cur_page)
				mdb.data.cur_page = sections[0].Next
				mdb.format = mdb.layout.Formats[mdb.data.Pages[mdb.data.cur_page].Format]
			}
		}
	}

	mdb.layout.Prev.valid_func = func() bool {
		return len(mdb.data.prev) > 0
	}

	mdb.layout.Prev.f = func(_data interface{}) {
		if len(mdb.data.prev) > 0 {
			mdb.data.cur_page = mdb.data.prev[len(mdb.data.prev)-1]
			mdb.data.prev = mdb.data.prev[0 : len(mdb.data.prev)-1]
			mdb.format = mdb.layout.Formats[mdb.data.Pages[mdb.data.cur_page].Format]
		}
	}

	mdb.data.process(args)

	return &mdb, mdb.result, nil
}
예제 #22
0
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.Choose(&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
}