コード例 #1
0
ファイル: script.go プロジェクト: FlyingCar/haunts
func removeEnt(gp *GamePanel) lua.GoFunction {
	return func(L *lua.State) int {
		if !LuaCheckParamsOk(L, "RemoveEnt", LuaEntity) {
			return 0
		}
		ent := LuaToEntity(L, gp.game, -1)
		if ent == nil {
			base.Warn().Printf("Tried to RemoveEnt on an entity that doesn't exist.")
			return 0
		}
		removed := false
		for i := range gp.game.Ents {
			if gp.game.Ents[i] == ent {
				gp.game.Ents[i] = gp.game.Ents[len(gp.game.Ents)-1]
				gp.game.Ents = gp.game.Ents[0 : len(gp.game.Ents)-1]
				gp.game.viewer.RemoveDrawable(ent)
				removed = true
				break
			}
		}
		if !removed {
			base.Warn().Printf("Tried to RemoveEnt an entity that wasn't in the game.")
		}
		return 0
	}
}
コード例 #2
0
ファイル: player.go プロジェクト: RickDakan/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
}
コード例 #3
0
ファイル: script.go プロジェクト: FlyingCar/haunts
func setCondition(gp *GamePanel) lua.GoFunction {
	return func(L *lua.State) int {
		if !LuaCheckParamsOk(L, "SetCondition", LuaEntity, LuaString, LuaBoolean) {
			return 0
		}
		gp.script.syncStart()
		defer gp.script.syncEnd()
		ent := LuaToEntity(L, gp.game, -3)
		if ent == nil {
			base.Warn().Printf("Tried to SetCondition on an entity that doesn't exist.")
			return 0
		}
		if ent.Stats == nil {
			base.Warn().Printf("Tried to SetCondition on an entity that doesn't have stats.")
			return 0
		}
		name := L.ToString(-2)
		if L.ToBoolean(-1) {
			ent.Stats.ApplyCondition(status.MakeCondition(name))
		} else {
			ent.Stats.RemoveCondition(name)
		}
		return 0
	}
}
コード例 #4
0
ファイル: ai.go プロジェクト: FlyingCar/haunts
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

	ai_struct.setupLuaState()
	go ai_struct.masterRoutine()

	*dst_iface = ai_struct
}
コード例 #5
0
ファイル: los.go プロジェクト: FlyingCar/haunts
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
}
コード例 #6
0
ファイル: ui_button.go プロジェクト: FlyingCar/haunts
func (b *Button) RenderAt(x, y int) {
	gl.Color4ub(255, 255, 255, byte(b.shade*255))
	if b.Texture.Path != "" {
		b.Texture.Data().RenderNatural(b.X+x, b.Y+y)
		b.bounds.x = b.X + x
		b.bounds.y = b.Y + y
		b.bounds.dx = b.Texture.Data().Dx()
		b.bounds.dy = b.Texture.Data().Dy()
	} else {
		d := base.GetDictionary(b.Text.Size)
		b.bounds.x = b.X + x
		b.bounds.y = b.Y + y
		b.bounds.dx = int(d.StringWidth(b.Text.String))
		b.bounds.dy = int(d.MaxHeight())
		base.Log().Printf("Button '%s' @ %d %d %d %d", b.Text.String, b.bounds.x, b.bounds.y, b.bounds.dx, b.bounds.dy)
		var just gui.Justification
		switch b.Text.Justification {
		case "center":
			just = gui.Center
			b.bounds.x -= b.bounds.dx / 2
		case "left":
			just = gui.Left
		case "right":
			just = gui.Right
			b.bounds.x -= b.bounds.dx
		default:
			just = gui.Center
			b.bounds.x -= b.bounds.dx / 2
			b.Text.Justification = "center"
			base.Warn().Printf("Failed to indicate valid aligmnent, '%s' is not valid.", b.Text.Justification)
		}
		d.RenderString(b.Text.String, float64(b.X+x), float64(b.Y+y), 0, d.MaxHeight(), just)
	}
}
コード例 #7
0
ファイル: player.go プロジェクト: RickDakan/haunts
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()
}
コード例 #8
0
ファイル: script.go プロジェクト: FlyingCar/haunts
func setAp(gp *GamePanel) lua.GoFunction {
	return func(L *lua.State) int {
		if !LuaCheckParamsOk(L, "SetAp", LuaEntity, LuaInteger) {
			return 0
		}
		gp.script.syncStart()
		defer gp.script.syncEnd()
		ent := LuaToEntity(L, gp.game, -2)
		if ent == nil {
			base.Warn().Printf("Tried to SetAp on an entity that doesn't exist.")
			return 0
		}
		if ent.Stats == nil {
			base.Warn().Printf("Tried to SetAp on an entity that doesn't have stats.")
			return 0
		}
		ent.Stats.SetAp(L.ToInteger(-1))
		return 0
	}
}
コード例 #9
0
ファイル: game.go プロジェクト: RickDakan/haunts
// 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
}
コード例 #10
0
ファイル: game.go プロジェクト: RickDakan/haunts
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
}
コード例 #11
0
ファイル: game.go プロジェクト: RickDakan/haunts
// 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)
	}
}
コード例 #12
0
ファイル: script.go プロジェクト: FlyingCar/haunts
func setPosition(gp *GamePanel) lua.GoFunction {
	return func(L *lua.State) int {
		if !LuaCheckParamsOk(L, "SetPosition", LuaEntity, LuaPoint) {
			return 0
		}
		gp.script.syncStart()
		defer gp.script.syncEnd()
		ent := LuaToEntity(L, gp.game, -2)
		if ent == nil {
			base.Warn().Printf("Tried to SetPosition on an entity that doesn't exist.")
			return 0
		}
		x, y := LuaToPoint(L, -1)
		ent.X = float64(x)
		ent.Y = float64(y)
		return 0
	}
}
コード例 #13
0
ファイル: ui_main_bar.go プロジェクト: RickDakan/haunts
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)
}
コード例 #14
0
ファイル: script.go プロジェクト: FlyingCar/haunts
func saveStore(gp *GamePanel, player *Player) lua.GoFunction {
	return func(L *lua.State) int {
		if !LuaCheckParamsOk(L, "SaveStore") {
			return 0
		}
		gp.script.syncStart()
		defer gp.script.syncEnd()
		UpdatePlayer(player, gp.script.L)
		str, err := base.ToGobToBase64(gp.game)
		if err != nil {
			base.Error().Printf("Error gobbing game state: %v", err)
			return 0
		}
		player.Game_state = str
		player.Name = "autosave"
		err = SavePlayer(player)
		if err != nil {
			base.Warn().Printf("Unable to save player: %v", err)
		}
		return 0
	}
}
コード例 #15
0
ファイル: script.go プロジェクト: FlyingCar/haunts
func playAnimations(gp *GamePanel) lua.GoFunction {
	return func(L *lua.State) int {
		if !LuaCheckParamsOk(L, "PlayAnimations", LuaEntity, LuaArray) {
			return 0
		}
		gp.script.syncStart()
		ent := LuaToEntity(L, gp.game, -2)
		if ent == nil {
			base.Warn().Printf("Tried to PlayAnimation on an entity that doesn't exist.")
			return 0
		}
		gp.script.syncEnd()
		ent.Sprite().Wait([]string{"ready", "killed"})
		if ent.Sprite().AnimState() == "ready" {
			L.PushNil()
			for L.Next(-2) != 0 {
				ent.Sprite().Command(L.ToString(-1))
				L.Pop(1)
			}
			ent.Sprite().Wait([]string{"ready", "killed"})
		}
		return 0
	}
}
コード例 #16
0
ファイル: ui_main_bar.go プロジェクト: RickDakan/haunts
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)
	}
}
コード例 #17
0
ファイル: entity.go プロジェクト: RickDakan/haunts
// 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
	}
}
コード例 #18
0
ファイル: los.go プロジェクト: FlyingCar/haunts
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:
			base.Log().Printf("ScriptComm: turnStateMainPhaseOver default")
		}

	case turnStateEnd:
		select {
		case <-g.comm.script_to_game:
			g.Turn_state = turnStateStart
			base.Log().Printf("ScriptComm: change to turnStateStart")
			g.OnRound()
		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.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")
	}
}
コード例 #19
0
ファイル: script.go プロジェクト: FlyingCar/haunts
func startGameScript(gp *GamePanel, path string, player *Player, data map[string]string) {
	// Clear out the panel, now the script can do whatever it wants
	player.Script_path = path
	gp.AnchorBox = gui.MakeAnchorBox(gui.Dims{1024, 768})
	base.Log().Printf("startGameScript")
	if !filepath.IsAbs(path) {
		path = filepath.Join(base.GetDataDir(), "scripts", filepath.FromSlash(path))
	}

	// The game script runs in a separate go routine and functions that need to
	// communicate with the game will do so via channels - DUH why did i even
	// write this comment?
	prog, err := ioutil.ReadFile(path)
	if err != nil {
		base.Error().Printf("Unable to load game script file %s: %v", path, err)
		return
	}
	gp.script = &gameScript{}
	base.Log().Printf("script = %p", gp.script)

	gp.script.L = lua.NewState()
	gp.script.L.OpenLibs()
	gp.script.L.SetExecutionLimit(25000)
	gp.script.L.NewTable()
	LuaPushSmartFunctionTable(gp.script.L, FunctionTable{
		"ChooserFromFile":                   func() { gp.script.L.PushGoFunctionAsCFunction(chooserFromFile(gp)) },
		"StartScript":                       func() { gp.script.L.PushGoFunctionAsCFunction(startScript(gp, player)) },
		"SaveGameState":                     func() { gp.script.L.PushGoFunctionAsCFunction(saveGameState(gp)) },
		"LoadGameState":                     func() { gp.script.L.PushGoFunctionAsCFunction(loadGameState(gp)) },
		"DoExec":                            func() { gp.script.L.PushGoFunctionAsCFunction(doExec(gp)) },
		"SelectEnt":                         func() { gp.script.L.PushGoFunctionAsCFunction(selectEnt(gp)) },
		"FocusPos":                          func() { gp.script.L.PushGoFunctionAsCFunction(focusPos(gp)) },
		"SelectHouse":                       func() { gp.script.L.PushGoFunctionAsCFunction(selectHouse(gp)) },
		"LoadHouse":                         func() { gp.script.L.PushGoFunctionAsCFunction(loadHouse(gp)) },
		"SaveStore":                         func() { gp.script.L.PushGoFunctionAsCFunction(saveStore(gp, player)) },
		"ShowMainBar":                       func() { gp.script.L.PushGoFunctionAsCFunction(showMainBar(gp, player)) },
		"SpawnEntityAtPosition":             func() { gp.script.L.PushGoFunctionAsCFunction(spawnEntityAtPosition(gp)) },
		"GetSpawnPointsMatching":            func() { gp.script.L.PushGoFunctionAsCFunction(getSpawnPointsMatching(gp)) },
		"SpawnEntitySomewhereInSpawnPoints": func() { gp.script.L.PushGoFunctionAsCFunction(spawnEntitySomewhereInSpawnPoints(gp)) },
		"IsSpawnPointInLos":                 func() { gp.script.L.PushGoFunctionAsCFunction(isSpawnPointInLos(gp)) },
		"PlaceEntities":                     func() { gp.script.L.PushGoFunctionAsCFunction(placeEntities(gp)) },
		"RoomAtPos":                         func() { gp.script.L.PushGoFunctionAsCFunction(roomAtPos(gp)) },
		"SetLosMode":                        func() { gp.script.L.PushGoFunctionAsCFunction(setLosMode(gp)) },
		"GetAllEnts":                        func() { gp.script.L.PushGoFunctionAsCFunction(getAllEnts(gp)) },
		"DialogBox":                         func() { gp.script.L.PushGoFunctionAsCFunction(dialogBox(gp)) },
		"PickFromN":                         func() { gp.script.L.PushGoFunctionAsCFunction(pickFromN(gp)) },
		"SetGear":                           func() { gp.script.L.PushGoFunctionAsCFunction(setGear(gp)) },
		"BindAi":                            func() { gp.script.L.PushGoFunctionAsCFunction(bindAi(gp)) },
		"SetVisibility":                     func() { gp.script.L.PushGoFunctionAsCFunction(setVisibility(gp)) },
		"EndPlayerInteraction":              func() { gp.script.L.PushGoFunctionAsCFunction(endPlayerInteraction(gp)) },
		"GetLos":                            func() { gp.script.L.PushGoFunctionAsCFunction(getLos(gp)) },
		"SetVisibleSpawnPoints":             func() { gp.script.L.PushGoFunctionAsCFunction(setVisibleSpawnPoints(gp)) },
		"SetCondition":                      func() { gp.script.L.PushGoFunctionAsCFunction(setCondition(gp)) },
		"SetPosition":                       func() { gp.script.L.PushGoFunctionAsCFunction(setPosition(gp)) },
		"SetHp":                             func() { gp.script.L.PushGoFunctionAsCFunction(setHp(gp)) },
		"SetAp":                             func() { gp.script.L.PushGoFunctionAsCFunction(setAp(gp)) },
		"RemoveEnt":                         func() { gp.script.L.PushGoFunctionAsCFunction(removeEnt(gp)) },
		"PlayAnimations":                    func() { gp.script.L.PushGoFunctionAsCFunction(playAnimations(gp)) },
		"PlayMusic":                         func() { gp.script.L.PushGoFunctionAsCFunction(playMusic(gp)) },
		"StopMusic":                         func() { gp.script.L.PushGoFunctionAsCFunction(stopMusic(gp)) },
		"SetMusicParam":                     func() { gp.script.L.PushGoFunctionAsCFunction(setMusicParam(gp)) },
		"PlaySound":                         func() { gp.script.L.PushGoFunctionAsCFunction(playSound(gp)) },
		"SetWaypoint":                       func() { gp.script.L.PushGoFunctionAsCFunction(setWaypoint(gp)) },
		"RemoveWaypoint":                    func() { gp.script.L.PushGoFunctionAsCFunction(removeWaypoint(gp)) },
		"Rand":                              func() { gp.script.L.PushGoFunctionAsCFunction(randFunc(gp)) },
		"Sleep":                             func() { gp.script.L.PushGoFunctionAsCFunction(sleepFunc(gp)) },
	})
	gp.script.L.SetMetaTable(-2)
	gp.script.L.SetGlobal("Script")

	registerUtilityFunctions(gp.script.L)
	if player.Lua_store != nil {
		loadGameStateRaw(gp, player.Game_state)
		err := LuaDecodeTable(bytes.NewBuffer(player.Lua_store), gp.script.L, gp.game)
		if err != nil {
			base.Warn().Printf("Error decoding lua state: %v", err)
		}
		gp.script.L.SetGlobal("store")
	} else {
		gp.script.L.NewTable()
		gp.script.L.SetGlobal("store")
	}
	gp.script.sync = make(chan struct{})
	base.Log().Printf("Sync: %p", gp.script.sync)
	res := gp.script.L.DoString(string(prog))
	if !res {
		base.Error().Printf("There was an error running script %s:\n%s", path, prog)
	} else {
		base.Log().Printf("No_init: %v\n", player.No_init)
		go func() {
			gp.script.L.NewTable()
			for k, v := range data {
				gp.script.L.PushString(k)
				gp.script.L.PushString(v)
				gp.script.L.SetTable(-3)
			}
			gp.script.L.SetGlobal("__data")
			gp.script.L.SetExecutionLimit(250000)
			if player.No_init {
				gp.script.syncStart()
				loadGameStateRaw(gp, player.Game_state)
				gp.game.script = gp.script
				gp.script.syncEnd()
			} else {
				gp.script.L.DoString("Init(__data)")
				if gp.game.Side == SideHaunt {
					gp.game.Ai.minions.Activate()
					gp.game.Ai.denizens.Activate()
					gp.game.player_inactive = gp.game.Ai.denizens.Active()
				} else {
					gp.game.Ai.intruders.Activate()
					gp.game.player_inactive = gp.game.Ai.intruders.Active()
				}

			}
			if gp.game == nil {
				base.Error().Printf("Script failed to load a house during Init().")
			} else {
				gp.game.comm.script_to_game <- nil
			}
		}()
	}
}