Пример #1
0
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
}
Пример #2
0
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
}
Пример #3
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
	}
}
Пример #4
0
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
}
Пример #5
0
// 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
	}
}
Пример #6
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
}
Пример #7
0
// 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)
	}
}
Пример #8
0
// 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
}
Пример #9
0
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)
	}
}
Пример #10
0
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
}
Пример #11
0
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")
	}
}
Пример #12
0
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
}
Пример #13
0
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
}
Пример #14
0
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
}
Пример #15
0
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
}
Пример #16
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
}
Пример #17
0
// 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
}
Пример #18
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
}
Пример #19
0
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)
}
Пример #20
0
func (sm *SystemMenu) Respond(g *gui.Gui, group gui.EventGroup) bool {
	cursor := group.Events[0].Key.Cursor()
	if cursor != nil {
		sm.mx, sm.my = cursor.Point()
	}
	if found, event := group.FindEvent(gin.MouseLButton); found && event.Type == gin.Press {
		if sm.layout.Main.handleClick(sm.mx, sm.my, g) {
			if sm.focus {
				g.DropFocus()
			} else {
				g.TakeFocus(sm)
			}
			sm.focus = true
			base.Log().Printf("focus: %v %v", sm, g.FocusWidget())
			return true
		}
		if sm.focus {
			hit := false
			for _, button := range sm.buttons {
				if button.handleClick(sm.mx, sm.my, g) {
					hit = true
				}
			}
			if hit {
				return true
			}
		}
	} else {
		hit := false
		for _, button := range sm.buttons {
			if button.Respond(group, nil) {
				hit = true
			}
		}
		if hit {
			return true
		}
	}
	return (g.FocusWidget() == sm)
}
Пример #21
0
func init() {
	runtime.LockOSThread()
	sys = system.Make(gos.GetSystemInterface())

	rand.Seed(100)
	// TODO: This should not be OS-specific
	datadir = filepath.Join(os.Args[0], "..", "..")
	base.SetDatadir(datadir)
	base.Log().Printf("Setting datadir: %s", datadir)
	err := house.SetDatadir(datadir)
	if err != nil {
		panic(err.Error())
	}

	var key_binds base.KeyBinds
	base.LoadJson(filepath.Join(datadir, "key_binds.json"), &key_binds)
	key_map = key_binds.MakeKeyMap()
	base.SetDefaultKeyMap(key_map)

	wdx = 1024
	wdy = 750
}
Пример #22
0
func (a *Ai) loadUtils(dir string) {
	root := filepath.Join(filepath.Join(filepath.Dir(a.path), "utils", dir))
	a.watcher.Watch(root)
	filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil || info.IsDir() {
			return nil
		}
		if strings.HasSuffix(info.Name(), ".lua") {
			f, err := os.Open(path)
			if err != nil {
				return nil
			}
			data, err := ioutil.ReadAll(f)
			f.Close()
			if err != nil {
				return nil
			}
			base.Log().Printf("Loaded lua utils file '%s'", path)
			a.L.DoString(string(data))
		}
		return nil
	})
}
Пример #23
0
func (g *Game) UpdateEntLos(ent *Entity, force bool) {
	if ent.los == nil || ent.Stats == nil {
		return
	}
	ex, ey := ent.Pos()
	if !force && ex == ent.los.x && ey == ent.los.y {
		return
	}
	base.Log().Printf("UpdateEntLos(%s): %t (%d, %d) -> (%d, %d)", ent.Name, force, ent.los.x, ent.los.y, ex, ey)
	ent.los.x = ex
	ent.los.y = ey

	g.DetermineLos(ex, ey, ent.Stats.Sight(), ent.los.grid)

	ent.los.minx = len(ent.los.grid)
	ent.los.miny = len(ent.los.grid)
	ent.los.maxx = 0
	ent.los.maxy = 0
	for i := range ent.los.grid {
		for j := range ent.los.grid[i] {
			if ent.los.grid[i][j] {
				if i < ent.los.minx {
					ent.los.minx = i
				}
				if j < ent.los.miny {
					ent.los.miny = j
				}
				if i > ent.los.maxx {
					ent.los.maxx = i
				}
				if j > ent.los.maxy {
					ent.los.maxy = j
				}
			}
		}
	}
}
Пример #24
0
func insertGoalMenu(ui gui.WidgetParent, replace replacer) error {
	chooser, done, err := makeChooseGoalMenu()
	if err != nil {
		return err
	}
	ui.AddChild(chooser)
	go func() {
		m := <-done
		ui.RemoveChild(chooser)
		if m != nil {
			base.Log().Printf("Chose: %v", m)
			err = insertGoalMenu(ui, replace)
			if err != nil {
				base.Error().Printf("Error making goal menu: %v", err)
			}
		} else {
			err := replace(ui)
			if err != nil {
				base.Error().Printf("Error replacing menu: %v", err)
			}
		}
	}()
	return nil
}
Пример #25
0
func doChooserMenu(ui gui.WidgetParent, cm chooserMaker, r replacer, i inserter) error {
	chooser, done, err := cm()
	if err != nil {
		return err
	}
	ui.AddChild(chooser)
	go func() {
		m := <-done
		ui.RemoveChild(chooser)
		if m != nil {
			base.Log().Printf("Chose: %v", m)
			err = i(ui, r)
			if err != nil {
				base.Error().Printf("Error making menu: %v", err)
			}
		} else {
			err := r(ui)
			if err != nil {
				base.Error().Printf("Error replacing menu: %v", err)
			}
		}
	}()
	return nil
}
Пример #26
0
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
}
Пример #27
0
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()
}
Пример #28
0
func main() {
	defer func() {
		if r := recover(); r != nil {
			data := debug.Stack()
			base.Error().Printf("PANIC: %v\n", r)
			base.Error().Printf("PANIC: %s\n", string(data))
			base.CloseLog()
			fmt.Printf("PANIC: %s\n", string(data))
		}
	}()
	base.Log().Printf("Version %s", Version())
	sys.Startup()
	sound.Init()
	render.Init()
	render.Queue(func() {
		sys.CreateWindow(10, 10, wdx, wdy)
		sys.EnableVSync(true)
		err := gl.Init()
		if err != nil {
			panic(err)
		}
		gl.Enable(gl.BLEND)
		gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	})
	base.InitShaders()
	runtime.GOMAXPROCS(8)
	ui, err := gui.Make(gin.In(), gui.Dims{wdx, wdy}, filepath.Join(datadir, "fonts", "skia.ttf"))
	if err != nil {
		panic(err.Error())
	}
	loadAllRegistries()

	// TODO: Might want to be able to reload stuff, but this is sensitive because it
	// is loading textures.  We should probably redo the sprite system so that this
	// is easier to safely handle.
	game.LoadAllEntities()

	// Set up editors
	editors = map[string]house.Editor{
		"room":  house.MakeRoomEditorPanel(),
		"house": house.MakeHouseEditorPanel(),
	}
	for name, editor := range editors {
		path := base.GetStoreVal(fmt.Sprintf("last %s path", name))
		path = filepath.Join(datadir, path)
		if path != "" {
			editor.Load(path)
		}
	}
	editor_name = "room"
	editor = editors[editor_name]

	edit_mode := false
	game.Restart = func() {
		base.Log().Printf("Restarting...")
		ui.RemoveChild(game_box)
		game_box = &lowerLeftTable{gui.MakeAnchorBox(gui.Dims{1024, 768})}
		err = game.InsertStartMenu(game_box)
		if err != nil {
			panic(err)
		}
		ui.AddChild(game_box)
		base.Log().Printf("Restarted")
	}
	game.Restart()

	if base.IsDevel() {
		ui.AddChild(base.MakeConsole())
	}
	sys.Think()
	// Wait until now to create the dictionary because the render thread needs
	// to be running in advance.
	render.Queue(func() {
		ui.Draw()
	})
	render.Purge()

	var profile_output *os.File
	heap_prof_count := 0

	for key_map["quit"].FramePressCount() == 0 {
		sys.Think()
		render.Queue(func() {
			sys.SwapBuffers()
			ui.Draw()
		})
		render.Purge()

		for _, child := range game_box.GetChildren() {
			if gp, ok := child.(*game.GamePanel); ok {
				game_panel = gp
			}
		}

		if base.IsDevel() {
			if key_map["cpu profile"].FramePressCount() > 0 {
				if profile_output == nil {
					profile_output, err = os.Create(filepath.Join(datadir, "cpu.prof"))
					if err == nil {
						err = pprof.StartCPUProfile(profile_output)
						if err != nil {
							base.Log().Printf("Unable to start CPU profile: %v\n", err)
							profile_output.Close()
							profile_output = nil
						}
						base.Log().Printf("profout: %v\n", profile_output)
					} else {
						base.Log().Printf("Unable to start CPU profile: %v\n", err)
					}
				} else {
					pprof.StopCPUProfile()
					profile_output.Close()
					profile_output = nil
				}
			}

			if key_map["heap profile"].FramePressCount() > 0 {
				out, err := os.Create(filepath.Join(datadir, fmt.Sprintf("heap-%d.prof", heap_prof_count)))
				heap_prof_count++
				if err == nil {
					err = pprof.WriteHeapProfile(out)
					out.Close()
					if err != nil {
						base.Warn().Printf("Unable to write heap profile: %v", err)
					}
				} else {
					base.Warn().Printf("Unable to create heap profile: %v", err)
				}
			}

			if key_map["manual mem"].FramePressCount() > 0 {
				base.Log().Printf(memory.TotalAllocations())
			}

			if key_map["game mode"].FramePressCount()%2 == 1 {
				base.Log().Printf("Game mode change: %t", edit_mode)
				if edit_mode {
					ui.RemoveChild(editor)
					ui.AddChild(game_box)
				} else {
					ui.RemoveChild(game_box)
					ui.AddChild(editor)
				}
				edit_mode = !edit_mode

				if key_map["row up"].FramePressCount() > 0 {
					house.Num_rows += 25
				}
				if key_map["row down"].FramePressCount() > 0 {
					house.Num_rows -= 25
				}
				if key_map["steps up"].FramePressCount() > 0 {
					house.Num_steps++
				}
				if key_map["steps down"].FramePressCount() > 0 {
					house.Num_steps--
				}
				if key_map["noise up"].FramePressCount() > 0 {
					house.Noise_rate += 10
				}
				if key_map["noise down"].FramePressCount() > 0 {
					house.Noise_rate -= 10
				}
				if key_map["foo"].FramePressCount() > 0 {
					house.Foo = (house.Foo + 1) % 2
				}
			}

			if edit_mode {
				editMode()
			} else {
				gameMode()
			}
		}
		// Draw a cursor at the cursor - for testing an osx bug in glop.
		// zx, zy := gin.In().GetCursor("Mouse").Point()
		// render.Queue(func() {
		//   gl.Color4ub(255, 0, 0, 255)
		//   gl.Begin(gl.LINES)
		//   {
		//     gl.Vertex2i(int32(zx-25), int32(zy))
		//     gl.Vertex2i(int32(zx+25), int32(zy))
		//     gl.Vertex2i(int32(zx), int32(zy-25))
		//     gl.Vertex2i(int32(zx), int32(zy+25))
		//   }
		//   gl.End()
		// })
	}
}
Пример #29
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
}
Пример #30
0
func (g *Game) Think(dt int64) {
	for _, ent := range g.Ents {
		if !g.all_ents_in_game[ent] {
			g.all_ents_in_game[ent] = true
			g.all_ents_in_memory[ent] = true
		}
	}
	var mark []*Entity
	for ent := range g.all_ents_in_memory {
		if !g.all_ents_in_game[ent] && ent != g.new_ent {
			mark = append(mark, ent)
		}
	}
	for _, ent := range mark {
		delete(g.all_ents_in_game, ent)
		delete(g.all_ents_in_memory, ent)
		ent.Release()
	}

	// Figure out if there are any entities that might be occluded be any
	// furniture, if so we'll want to make that furniture a little transparent.
	for _, floor := range g.House.Floors {
		for _, room := range floor.Rooms {
			for _, furn := range room.Furniture {
				if !furn.Blocks_los {
					continue
				}
				rx, ry := room.Pos()
				x, y2 := furn.Pos()
				x += rx
				y2 += ry
				dx, dy := furn.Dims()
				x2 := x + dx
				y := y2 + dy
				tex := furn.Orientations[furn.Rotation].Texture.Data()
				tex_dy := 2 * (tex.Dy() * ((x2 - y2) - (x - y))) / tex.Dx()
				v1 := y - x
				v2 := y2 - x2
				hit := false
				for _, ent := range g.Ents {
					ex, ey2 := ent.Pos()
					edx, edy := ent.Dims()
					ex2 := ex + edx
					ey := ey2 + edy
					if ex+ey2 < x+y2 || ex+ey2 > x+y2+tex_dy {
						continue
					}
					if ent.Side() != g.Side && !g.TeamLos(g.Side, ex, ey2, edx, edy) {
						continue
					}

					ev1 := ey - ex
					ev2 := ey2 - ex2
					if ev2 >= v1 || ev1 <= v2 {
						continue
					}
					hit = true
					break
				}
				alpha := furn.Alpha()
				if hit {
					furn.SetAlpha(doApproach(alpha, 0.3, dt))
				} else {
					furn.SetAlpha(doApproach(alpha, 1.0, dt))
				}
			}
		}
	}

	switch g.Turn_state {
	case turnStateInit:
		select {
		case <-g.comm.script_to_game:
			base.Log().Printf("ScriptComm: change to turnStateStart")
			g.Turn_state = turnStateStart
			g.script.OnRound(g)
			// g.OnRound()
		default:
		}
	case turnStateStart:
		select {
		case <-g.comm.script_to_game:
			base.Log().Printf("ScriptComm: change to turnStateAiAction")
			g.Turn_state = turnStateAiAction
		default:
		}
	case turnStateScriptOnAction:
		select {
		case exec := <-g.comm.script_to_game:
			if g.current_exec != nil {
				base.Error().Printf("Got an exec from the script when we already had one pending.")
			} else {
				if exec != nil {
					g.current_exec = exec.(ActionExec)
				} else {
					base.Log().Printf("ScriptComm: change to turnStateAiAction")
					g.Turn_state = turnStateAiAction
				}
			}
		default:
		}
	case turnStateMainPhaseOver:
		select {
		case exec := <-g.comm.script_to_game:
			if exec != nil {
				base.Log().Printf("ScriptComm: Got an exec: %v", exec)
				g.current_exec = exec.(ActionExec)
				g.Action_state = doingAction
				ent := g.EntityById(g.current_exec.EntityId())
				g.viewer.RemoveFloorDrawable(g.current_action)
				g.current_action = ent.Actions[g.current_exec.ActionIndex()]
				g.viewer.AddFloorDrawable(g.current_action)
				ent.current_action = g.current_action
			} else {
				g.Turn_state = turnStateEnd
				base.Log().Printf("ScriptComm: change to turnStateEnd for realzes")
			}
		default:
		}

	case turnStateEnd:
		select {
		case <-g.comm.script_to_game:
			g.Turn_state = turnStateStart
			base.Log().Printf("ScriptComm: change to turnStateStart")
			g.OnRound(true)
		default:
		}
	}

	if g.current_exec != nil && g.Action_state != verifyingAction && g.Turn_state != turnStateMainPhaseOver {
		ent := g.EntityById(g.current_exec.EntityId())
		g.viewer.RemoveFloorDrawable(g.current_action)
		g.current_action = ent.Actions[g.current_exec.ActionIndex()]
		g.viewer.AddFloorDrawable(g.current_action)
		ent.current_action = g.current_action
		g.Action_state = verifyingAction
		base.Log().Printf("ScriptComm: request exec verification")
		g.comm.game_to_script <- g.current_exec
	}

	if g.Action_state == verifyingAction {
		select {
		case <-g.comm.script_to_game:
			g.Action_state = doingAction
		default:
		}
	}

	// If there is an action that is currently executing we need to advance that
	// action.
	if g.Action_state == doingAction {
		res := g.current_action.Maintain(dt, g, g.current_exec)
		if g.current_exec != nil {
			base.Log().Printf("ScriptComm: sent action")
			g.current_exec = nil
		}
		switch res {
		case Complete:
			g.current_action.Cancel()
			g.viewer.RemoveFloorDrawable(g.current_action)
			g.current_action = nil
			g.Action_state = noAction
			if g.Turn_state != turnStateMainPhaseOver {
				g.Turn_state = turnStateScriptOnAction
			}
			base.Log().Printf("ScriptComm: Action complete")
			g.comm.game_to_script <- nil
			g.checkWinConditions()

		case InProgress:
		case CheckForInterrupts:
		}
	}

	for _, ent := range g.Ents {
		ent.Think(dt)
		s := ent.Sprite()
		if s != nil {
			if s.AnimState() == "ready" && s.Idle() && g.current_action == nil && ent.current_action != nil {
				g.viewer.RemoveFloorDrawable(g.current_action)
				ent.current_action = nil
			}
		}
	}
	if g.new_ent != nil {
		g.new_ent.Think(dt)
	}
	for i := range g.Ents {
		g.UpdateEntLos(g.Ents[i], false)
	}
	if g.los.denizens.mode == LosModeEntities {
		g.mergeLos(SideHaunt)
	}
	if g.los.intruders.mode == LosModeEntities {
		g.mergeLos(SideExplorers)
	}

	// Do spawn points los stuff
	for _, los := range []*spawnLos{&g.Los_spawns.Denizens, &g.Los_spawns.Intruders} {
		if los.r == nil || los.r.String() != los.Pattern {
			if los.Pattern == "" {
				los.r = nil
			} else {
				var err error
				los.r, err = regexp.Compile("^" + los.Pattern + "$")
				if err != nil {
					base.Warn().Printf("Unable to compile regexp: `%s`", los.Pattern)
					los.Pattern = ""
				}
			}
		}
	}
	for i := 0; i < 2; i++ {
		var los *spawnLos
		var pix [][]byte
		if i == 0 {
			if g.los.denizens.mode == LosModeBlind {
				continue
			}
			los = &g.Los_spawns.Denizens
			pix = g.los.denizens.tex.Pix()
		} else {
			if g.los.intruders.mode == LosModeBlind {
				continue
			}
			los = &g.Los_spawns.Intruders
			pix = g.los.intruders.tex.Pix()
		}
		if los.r == nil {
			continue
		}
		for _, spawn := range g.House.Floors[0].Spawns {
			if !los.r.MatchString(spawn.Name) {
				continue
			}
			sx, sy := spawn.Pos()
			dx, dy := spawn.Dims()
			for x := sx; x < sx+dx; x++ {
				for y := sy; y < sy+dy; y++ {
					if pix[x][y] < house.LosVisibilityThreshold {
						pix[x][y] = house.LosVisibilityThreshold
					}
				}
			}
		}
	}

	for _, tex := range []*house.LosTexture{g.los.denizens.tex, g.los.intruders.tex} {
		pix := tex.Pix()
		amt := dt/6 + 1
		mod := false
		for i := range pix {
			for j := range pix[i] {
				v := int64(pix[i][j])
				if v < house.LosVisibilityThreshold {
					v -= amt
				} else {
					v += amt
				}
				if v < house.LosMinVisibility {
					v = house.LosMinVisibility
				}
				if v < 0 {
					v = 0
				}
				if v > 255 {
					v = 255
				}
				mod = mod || (byte(v) != pix[i][j])
				pix[i][j] = byte(v)
			}
		}
		if mod {
			tex.Remap()
		}
	}

	// Don't do any ai stuff if there is a pending action
	if g.current_action != nil {
		return
	}

	// Also don't do an ai stuff if this isn't the appropriate state
	if g.Turn_state != turnStateAiAction {
		return
	}

	// If any entities are not either ready or dead let's wait until they are
	// before we do any of the ai stuff
	for _, ent := range g.Ents {
		if ent.Side() != SideHaunt && ent.Side() != SideExplorers {
			// Relics and cleanse points and whatnot matter here, and they might not
			// be in a 'ready' state.
			continue
		}
		state := ent.sprite.Sprite().AnimState()
		if state != "ready" && state != "killed" {
			return
		}
		if !ent.sprite.Sprite().Idle() {
			return
		}
	}
	// Do Ai - if there is any to do
	if g.Side == SideHaunt {
		if g.Ai.minions.Active() {
			g.active_ai = g.Ai.minions
			g.Action_state = waitingAction
		} else {
			if g.Ai.denizens.Active() {
				g.active_ai = g.Ai.denizens
				g.Action_state = waitingAction
			}
		}
	} else {
		if g.Ai.intruders.Active() {
			g.active_ai = g.Ai.intruders
			g.Action_state = waitingAction
		}
	}
	if g.Action_state == waitingAction {
		select {
		case exec := <-g.active_ai.ActionExecs():
			if exec != nil {
				g.current_exec = exec
			} else {
				g.Action_state = noAction
				// TODO: indicate that the master ai can go now
			}

		default:
		}
	}
	if g.player_inactive && g.Action_state == noAction && !g.Ai.intruders.Active() && !g.Ai.denizens.Active() && !g.Ai.minions.Active() {
		g.Turn_state = turnStateMainPhaseOver
		base.Log().Printf("ScriptComm: change to turnStateMainPhaseOver")
		g.comm.game_to_script <- nil
		base.Log().Printf("ScriptComm: sent nil")
	}
}