Beispiel #1
0
// 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
}
Beispiel #2
0
func (g *Game) TeamLos(side Side, x, y, dx, dy int) bool {
	var team_los [][]byte
	if side == SideExplorers {
		team_los = g.los.intruders.tex.Pix()
	} else if side == SideHaunt {
		team_los = g.los.denizens.tex.Pix()
	} else {
		base.Warn().Printf("Can only ask for TeamLos for the intruders and denizens.")
		return false
	}
	if team_los == nil {
		return false
	}
	for i := x; i < x+dx; i++ {
		for j := y; j < y+dy; j++ {
			if i < 0 || j < 0 || i >= len(team_los) || j >= len(team_los[0]) {
				continue
			}
			if team_los[i][j] >= house.LosVisibilityThreshold {
				return true
			}
		}
	}
	return false
}
Beispiel #3
0
func makeAi(path string, g *game.Game, ent *game.Entity, dst_iface *game.Ai, kind game.AiKind) {
	ai_struct := new(Ai)
	ai_struct.path = path
	var err error
	ai_struct.watcher, err = fsnotify.NewWatcher()
	if err != nil {
		base.Warn().Printf("Unable to create a filewatcher - '%s' will not reload ai files dynamically: %v", path, err)
		ai_struct.watcher = nil
	}
	ai_struct.ent = ent
	ai_struct.game = g

	ai_struct.active_set = make(chan bool)
	ai_struct.active_query = make(chan bool)
	ai_struct.exec_query = make(chan struct{})
	ai_struct.pause = make(chan struct{})
	ai_struct.terminate = make(chan struct{})
	ai_struct.execs = make(chan game.ActionExec)
	ai_struct.kind = kind

	err = ai_struct.setupLuaState()
	if err != nil {
		base.Error().Printf("Unable to make ai: %v", err)
		if ai_struct.watcher != nil {
			ai_struct.watcher.Close()
		}
		dst_iface = nil
		return
	}
	go ai_struct.masterRoutine()

	*dst_iface = ai_struct
}
Beispiel #4
0
func UpdatePlayer(p *Player, L *lua.State) {
	buffer := bytes.NewBuffer(nil)
	L.GetGlobal("store")
	err := LuaEncodeTable(buffer, L, -1)
	if err != nil {
		base.Warn().Printf("Error encoding lua state: %v", err)
	}
	L.Pop(1)
	p.Lua_store = buffer.Bytes()
}
Beispiel #5
0
// Returns true iff the action was set
// This function will return false if there is no selected entity, if the
// action cannot be selected (because it is invalid or the entity has
// insufficient Ap), or if there is an action currently executing.
func (g *Game) SetCurrentAction(action Action) bool {
	if g.Action_state != noAction && g.Action_state != preppingAction {
		return false
	}
	// the action should be one that belongs to the current entity, if not then
	// we need to bail out immediately
	if g.selected_ent == nil {
		base.Warn().Printf("Tried to SetCurrentAction() without a selected entity.")
		return action == nil
	}
	if action != nil {
		valid := false
		for _, a := range g.selected_ent.Actions {
			if a == action {
				valid = true
				break
			}
		}
		if !valid {
			base.Warn().Printf("Tried to SetCurrentAction() with an action that did not belong to the selected entity.")
			return action == nil
		}
	}
	if g.current_action != nil {
		g.current_action.Cancel()
	}
	if action == nil {
		g.Action_state = noAction
	} else {
		g.Action_state = preppingAction
	}
	g.viewer.RemoveFloorDrawable(g.current_action)
	g.current_action = action
	if g.current_action != nil {
		g.viewer.AddFloorDrawable(g.current_action)
	}
	return true
}
Beispiel #6
0
func (g *Game) SpawnEntity(spawn *Entity, x, y int) bool {
	for i := range g.Ents {
		cx, cy := g.Ents[i].Pos()
		if cx == x && cy == y {
			base.Warn().Printf("Can't spawn entity at (%d, %d) - already occupied by '%s'.", x, y, g.Ents[i].Name)
			return false
		}
	}
	spawn.X = float64(x)
	spawn.Y = float64(y)
	spawn.Info.RoomsExplored[spawn.CurrentRoom()] = true
	g.Ents = append(g.Ents, spawn)
	return true
}
Beispiel #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)
	}
}
Beispiel #8
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
}
Beispiel #9
0
func (t *TextArea) RenderString(s string) {
	var just gui.Justification
	switch t.Justification {
	case "center":
		just = gui.Center
	case "left":
		just = gui.Left
	case "right":
		just = gui.Right
	default:
		base.Warn().Printf("Unknown justification '%s' in main gui bar.", t.Justification)
		t.Justification = "center"
	}
	px := float64(t.X)
	py := float64(t.Y)
	d := base.GetDictionary(t.Size)
	d.RenderString(s, px, py, 0, d.MaxHeight(), just)
}
Beispiel #10
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()
		// })
	}
}
Beispiel #11
0
func editMode() {
	draggingAndZooming(editor.GetViewer())
	if ui.FocusWidget() == nil {
		for name := range editors {
			if key_map[fmt.Sprintf("%s editor", name)].FramePressCount() > 0 && ui.FocusWidget() == nil {
				ui.RemoveChild(editor)
				editor_name = name
				editor = editors[editor_name]
				loadAllRegistries()
				editor.Reload()
				ui.AddChild(editor)
			}
		}

		if key_map["save"].FramePressCount() > 0 && chooser == nil {
			path, err := editor.Save()
			if err != nil {
				base.Warn().Printf("Failed to save: %v", err.Error())
			}
			if path != "" && err == nil {
				base.SetStoreVal(fmt.Sprintf("last %s path", editor_name), base.TryRelative(datadir, path))
			}
		}

		if key_map["load"].FramePressCount() > 0 && chooser == nil {
			callback := func(path string, err error) {
				ui.DropFocus()
				ui.RemoveChild(anchor)
				chooser = nil
				anchor = nil
				err = editor.Load(path)
				if err != nil {
					base.Warn().Printf("Failed to load: %v", err.Error())
				} else {
					base.SetStoreVal(fmt.Sprintf("last %s path", editor_name), base.TryRelative(datadir, path))
				}
			}
			chooser = gui.MakeFileChooser(filepath.Join(datadir, fmt.Sprintf("%ss", editor_name)), callback, gui.MakeFileFilter(fmt.Sprintf(".%s", editor_name)))
			anchor = gui.MakeAnchorBox(gui.Dims{wdx, wdy})
			anchor.AddChild(chooser, gui.Anchor{0.5, 0.5, 0.5, 0.5})
			ui.AddChild(anchor)
			ui.TakeFocus(chooser)
		}

		// Don't select tabs in an editor if we're doing some other sort of command
		ok_to_select := true
		for _, v := range key_map {
			if v.FramePressCount() > 0 {
				ok_to_select = false
				break
			}
		}
		if ok_to_select {
			for i := 1; i <= 9; i++ {
				if gin.In().GetKey(gin.KeyId('0'+i)).FramePressCount() > 0 {
					editor.SelectTab(i - 1)
				}
			}
		}
	}
}
Beispiel #12
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")
	}
}
Beispiel #13
0
// Returns an array of all entities of a specified type that are in this
// entity's los.  The entities in the array will be sorted in ascending order
// of distance from this entity.
//    Format
//    ents = nearestNEntites(max, kind)
//
//    Input:
//    max  - integer - Maximum number of entities to return
//    kind - string  - One of "intruder" "denizen" "minion" "servitor"
//                     "master" "non-minion" "non-servitor" "non-master" and
//                     "all".  The "non-*" parameters indicate denizens only
//                     (i.e. will *not* include intruders) that are not of the
//                     type specified.
//
//    Output:
//    ents - array[integer] - Array of entity ids.
func NearestNEntitiesFunc(me *game.Entity) lua.GoFunction {
	valid_kinds := map[string]bool{
		"intruder": true,
		"denizen":  true,
		"minion":   true,
		"servitor": true,
		"master":   true,
		"object":   true,
	}
	return func(L *lua.State) int {
		if !game.LuaCheckParamsOk(L, "NearestNEntities", game.LuaInteger, game.LuaString) {
			return 0
		}
		g := me.Game()
		max := L.ToInteger(-2)
		kind := L.ToString(-1)
		if !valid_kinds[kind] {
			err_str := fmt.Sprintf("NearestNEntities expects kind in the set ['intruder' 'denizen' 'servitor' 'master' 'minion'], got %s.", kind)
			base.Warn().Printf(err_str)
			L.PushString(err_str)
			L.Error()
			return 0
		}
		var eds entityDistSlice
		for _, ent := range g.Ents {
			if ent.Stats != nil && ent.Stats.HpCur() <= 0 {
				continue
			}
			switch kind {
			case "intruder":
				if ent.Side() != game.SideExplorers {
					continue
				}
			case "denizen":
				if ent.Side() != game.SideHaunt {
					continue
				}
			case "minion":
				if ent.HauntEnt == nil || ent.HauntEnt.Level != game.LevelMinion {
					continue
				}
			case "servitor":
				if ent.HauntEnt == nil || ent.HauntEnt.Level != game.LevelServitor {
					continue
				}
			case "master":
				if ent.HauntEnt == nil || ent.HauntEnt.Level != game.LevelMaster {
					continue
				}
			case "object":
				if ent.ObjectEnt == nil {
					continue
				}
			}
			x, y := ent.Pos()
			dx, dy := ent.Dims()
			if !me.HasTeamLos(x, y, dx, dy) {
				continue
			}
			eds = append(eds, entityDist{rangedDistBetween(me, ent), ent})
		}
		// TODO: ONLY GUYS THAT EXIST
		sort.Sort(eds)
		if max > len(eds) {
			max = len(eds)
		}
		if max < 0 {
			max = 0
		}
		eds = eds[0:max]

		// eds contains the results, in order.  Now we make a lua table and
		// populate it with the entity ids of the results.
		L.NewTable()
		for i := range eds {
			L.PushInteger(i + 1)
			game.LuaPushEntity(L, eds[i].ent)
			L.SetTable(-3)
		}
		return 1
	}
}
Beispiel #14
0
func (m *MainBar) Draw(region gui.Region) {
	m.region = region
	gl.Enable(gl.TEXTURE_2D)
	m.layout.Background.Data().Bind()
	gl.Color4d(1, 1, 1, 1)
	gl.Begin(gl.QUADS)
	gl.TexCoord2d(0, 0)
	gl.Vertex2i(region.X, region.Y)

	gl.TexCoord2d(0, -1)
	gl.Vertex2i(region.X, region.Y+region.Dy)

	gl.TexCoord2d(1, -1)
	gl.Vertex2i(region.X+region.Dx, region.Y+region.Dy)

	gl.TexCoord2d(1, 0)
	gl.Vertex2i(region.X+region.Dx, region.Y)
	gl.End()

	buttons := m.no_actions_buttons
	if m.ent != nil && len(m.ent.Actions) > m.layout.Actions.Count {
		buttons = m.all_buttons
	}
	for _, button := range buttons {
		button.RenderAt(region.X, region.Y)
	}

	ent := m.game.HoveredEnt()
	if ent == nil {
		ent = m.ent
	}
	if ent != nil && ent.Stats != nil {
		gl.Color4d(1, 1, 1, 1)
		ent.Still.Data().Bind()
		tdx := ent.Still.Data().Dx()
		tdy := ent.Still.Data().Dy()
		cx := region.X + m.layout.CenterStillFrame.X
		cy := region.Y + m.layout.CenterStillFrame.Y
		gl.Begin(gl.QUADS)
		gl.TexCoord2d(0, 0)
		gl.Vertex2i(cx-tdx/2, cy-tdy/2)

		gl.TexCoord2d(0, -1)
		gl.Vertex2i(cx-tdx/2, cy+tdy/2)

		gl.TexCoord2d(1, -1)
		gl.Vertex2i(cx+tdx/2, cy+tdy/2)

		gl.TexCoord2d(1, 0)
		gl.Vertex2i(cx+tdx/2, cy-tdy/2)
		gl.End()

		m.layout.Name.RenderString(ent.Name)
		m.layout.Ap.RenderString(fmt.Sprintf("Ap:%d", ent.Stats.ApCur()))
		m.layout.Hp.RenderString(fmt.Sprintf("Hp:%d", ent.Stats.HpCur()))
		m.layout.Corpus.RenderString(fmt.Sprintf("Corpus:%d", ent.Stats.Corpus()))
		m.layout.Ego.RenderString(fmt.Sprintf("Ego:%d", ent.Stats.Ego()))

		gl.Color4d(1, 1, 1, 1)
		m.layout.Divider.Data().Bind()
		tdx = m.layout.Divider.Data().Dx()
		tdy = m.layout.Divider.Data().Dy()
		cx = region.X + m.layout.Name.X
		cy = region.Y + m.layout.Name.Y - 5
		gl.Begin(gl.QUADS)
		gl.TexCoord2d(0, 0)
		gl.Vertex2i(cx-tdx/2, cy-tdy/2)

		gl.TexCoord2d(0, -1)
		gl.Vertex2i(cx-tdx/2, cy+(tdy+1)/2)

		gl.TexCoord2d(1, -1)
		gl.Vertex2i(cx+(tdx+1)/2, cy+(tdy+1)/2)

		gl.TexCoord2d(1, 0)
		gl.Vertex2i(cx+(tdx+1)/2, cy-tdy/2)
		gl.End()
	}
	if m.ent != nil && m.ent.Stats != nil {
		// Actions
		{
			spacing := m.layout.Actions.Icon_size * float64(m.layout.Actions.Count)
			spacing = m.layout.Actions.Width - spacing
			spacing /= float64(m.layout.Actions.Count - 1)
			m.state.Actions.space = spacing
			s := m.layout.Actions.Icon_size
			num_actions := len(m.ent.Actions)
			xpos := m.layout.Actions.X

			if num_actions > m.layout.Actions.Count {
				xpos -= m.state.Actions.scroll_pos * (s + spacing)
			}
			d := base.GetDictionary(10)
			var r gui.Region
			r.X = int(m.layout.Actions.X)
			r.Y = int(m.layout.Actions.Y - d.MaxHeight())
			r.Dx = int(m.layout.Actions.Width)
			r.Dy = int(m.layout.Actions.Icon_size + d.MaxHeight())
			r.PushClipPlanes()

			gl.Color4d(1, 1, 1, 1)
			for i, action := range m.ent.Actions {

				// Highlight the selected action
				if action == m.game.current_action {
					gl.Disable(gl.TEXTURE_2D)
					gl.Color4d(1, 0, 0, 1)
					gl.Begin(gl.QUADS)
					gl.Vertex3d(xpos-2, m.layout.Actions.Y-2, 0)
					gl.Vertex3d(xpos-2, m.layout.Actions.Y+s+2, 0)
					gl.Vertex3d(xpos+s+2, m.layout.Actions.Y+s+2, 0)
					gl.Vertex3d(xpos+s+2, m.layout.Actions.Y-2, 0)
					gl.End()
				}
				gl.Enable(gl.TEXTURE_2D)
				action.Icon().Data().Bind()
				if action.Preppable(m.ent, m.game) {
					gl.Color4d(1, 1, 1, 1)
				} else {
					gl.Color4d(0.5, 0.5, 0.5, 1)
				}
				gl.Begin(gl.QUADS)
				gl.TexCoord2d(0, 0)
				gl.Vertex3d(xpos, m.layout.Actions.Y, 0)

				gl.TexCoord2d(0, -1)
				gl.Vertex3d(xpos, m.layout.Actions.Y+s, 0)

				gl.TexCoord2d(1, -1)
				gl.Vertex3d(xpos+s, m.layout.Actions.Y+s, 0)

				gl.TexCoord2d(1, 0)
				gl.Vertex3d(xpos+s, m.layout.Actions.Y, 0)
				gl.End()
				gl.Disable(gl.TEXTURE_2D)

				ypos := m.layout.Actions.Y - d.MaxHeight() - 2
				d.RenderString(fmt.Sprintf("%d", i+1), xpos+s/2, ypos, 0, d.MaxHeight(), gui.Center)

				xpos += spacing + m.layout.Actions.Icon_size
			}

			r.PopClipPlanes()

			// Now, if there is a selected action, position it between the arrows
			if m.state.Actions.selected != nil {
				// a := m.state.Actions.selected
				d := base.GetDictionary(15)
				x := m.layout.Actions.X + m.layout.Actions.Width/2
				y := float64(m.layout.ActionLeft.Y)
				str := fmt.Sprintf("%s:%dAP", m.state.Actions.selected.String(), m.state.Actions.selected.AP())
				gl.Color4d(1, 1, 1, 1)
				d.RenderString(str, x, y, 0, d.MaxHeight(), gui.Center)
			}
		}

		// Conditions
		{
			gl.Color4d(1, 1, 1, 1)
			c := m.layout.Conditions
			d := base.GetDictionary(int(c.Size))
			ypos := c.Y + c.Height - d.MaxHeight() + m.state.Conditions.scroll_pos
			var r gui.Region
			r.X = int(c.X)
			r.Y = int(c.Y)
			r.Dx = int(c.Width)
			r.Dy = int(c.Height)
			r.PushClipPlanes()
			for _, s := range m.ent.Stats.ConditionNames() {
				d.RenderString(s, c.X+c.Width/2, ypos, 0, d.MaxHeight(), gui.Center)
				ypos -= float64(d.MaxHeight())
			}

			r.PopClipPlanes()
		}

		// Gear
		if m.ent.ExplorerEnt != nil && m.ent.ExplorerEnt.Gear != nil {
			gear := m.ent.ExplorerEnt.Gear
			layout := m.layout.Gear
			icon := gear.Small_icon.Data()
			icon.RenderNatural(int(layout.X), int(layout.Y))
			d := base.GetDictionary(10)
			d.RenderString("Gear", layout.X+float64(icon.Dx())/2, layout.Y-d.MaxHeight(), 0, d.MaxHeight(), gui.Center)
		}
	}

	// Mouseover text
	if m.state.MouseOver.active {
		var x int
		switch m.state.MouseOver.location {
		case mouseOverActions:
			x = int(m.layout.Actions.X + m.layout.Actions.Width/2)
		case mouseOverConditions:
			x = int(m.layout.Conditions.X + m.layout.Conditions.Width/2)
		case mouseOverGear:
		default:
			base.Warn().Printf("Got an unknown mouseover location: %d", m.state.MouseOver.location)
			m.state.MouseOver.active = false
		}
		y := m.layout.Background.Data().Dy() - 40
		d := base.GetDictionary(15)
		d.RenderString(m.state.MouseOver.text, float64(x), float64(y), 0, d.MaxHeight(), gui.Center)
	}
}