Пример #1
0
func (f *Floor) removeInvalidDoors() {
	for _, room := range f.Rooms {
		room.Doors = algorithm.Choose(room.Doors, func(a interface{}) bool {
			_, other_door := f.FindMatchingDoor(room, a.(*Door))
			return other_door != nil && !other_door.temporary
		}).([]*Door)
	}
}
Пример #2
0
func ChooserSpec(c gospec.Context) {
	c.Specify("Choose on []int", func() {
		a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
		var b []int
		b = algorithm.Choose(a, func(v interface{}) bool { return v.(int)%2 == 0 }).([]int)
		c.Expect(b, ContainsInOrder, []int{0, 2, 4, 6, 8})

		b = algorithm.Choose(a, func(v interface{}) bool { return v.(int)%2 == 1 }).([]int)
		c.Expect(b, ContainsInOrder, []int{1, 3, 5, 7, 9})

		b = algorithm.Choose(a, func(v interface{}) bool { return true }).([]int)
		c.Expect(b, ContainsInOrder, a)

		b = algorithm.Choose(a, func(v interface{}) bool { return false }).([]int)
		c.Expect(b, ContainsInOrder, []int{})

		b = algorithm.Choose([]int{}, func(v interface{}) bool { return false }).([]int)
		c.Expect(b, ContainsInOrder, []int{})
	})

	c.Specify("Choose on []string", func() {
		a := []string{"foo", "bar", "wing", "ding", "monkey", "machine"}
		var b []string
		b = algorithm.Choose(a, func(v interface{}) bool { return v.(string) > "foo" }).([]string)
		c.Expect(b, ContainsInOrder, []string{"wing", "monkey", "machine"})

		b = algorithm.Choose(a, func(v interface{}) bool { return v.(string) < "foo" }).([]string)
		c.Expect(b, ContainsInOrder, []string{"bar", "ding"})
	})
}
Пример #3
0
func (g *Game) Think() {
	g.GameThinks++

	algorithm.Choose(&g.Ents, func(e Ent) bool { return e.Alive() })

	for i := range g.Ents {
		g.Ents[i].PreThink(g)
	}

	g.manaSource.Think(g.Ents)

	// Advance players, check for collisions, add segments
	for i := range g.Ents {
		if !g.Ents[i].Alive() {
			continue
		}
		g.Ents[i].Think(g)
		pos := g.Ents[i].Pos()
		pos.X = clamp(pos.X, 0, float64(g.Dx))
		pos.Y = clamp(pos.Y, 0, float64(g.Dy))
		g.Ents[i].SetPos(pos)
	}
	moved := make(map[int]bool)
	for i := range g.Ents {
		for j := range g.Ents {
			if i == j || g.Ents[i].Exiled() || g.Ents[j].Exiled() {
				continue
			}
			dist := g.Ents[i].Pos().Sub(g.Ents[j].Pos()).Mag()
			if dist > 25 {
				continue
			}
			if dist < 0.01 {
				continue
			}
			if dist <= 0.5 {
				dist = 0.5
			}
			force := 20.0 * (25 - dist)
			g.Ents[i].ApplyForce(g.Ents[i].Pos().Sub(g.Ents[j].Pos()).Norm().Scale(force))
			moved[i] = true
		}
	}
}
Пример #4
0
func (f *fireProcess) Think(g *game.Game) {
	player, ok := g.Ents[f.Gid].(*game.PlayerEnt)
	if !ok {
		return
	}
	f.Pos = player.Position
	f.Stored *= 0.97
	if f.rng == nil {
		f.rng = cmwc.MakeGoodCmwc()
		f.rng.SeedWithDevRand()
	}
	max := int(f.Stored / 15)
	algorithm.Choose(&f.explosions, func(e fireExplosion) bool { return !e.Done() })
	if len(f.explosions) < max {
		f.explosions = append(f.explosions, fireDoLine(f.rng, player.Position, player.Angle, f.Stored, 3, g.Levels[player.CurrentLevel]))
	}
	for i := range f.explosions {
		f.explosions[i].Think()
	}
	f.thinks++
}
Пример #5
0
func (s *Sprite) Think(dt int64) {
	if s.thinks == 0 {
		s.shared.facings[0].Load()
		s.togo = s.shared.node_data[s.anim_node].time
	}
	s.thinks++
	if dt < 0 {
		return
		// panic("Can't have dt < 0")
	}

	// Check for waiters
	defer func() {
		if s.NumPendingCmds() > 0 {
			return
		}
		for i := range s.waiters {
			for _, state := range s.waiters[i].states {
				if state == s.AnimState() {
					s.waiters[i].c <- struct{}{}
					s.waiters[i].states = nil
				}
			}
			algorithm.Choose(&s.waiters, func(w *waiter) bool {
				return w.states != nil
			})
		}
	}()

	var path []*yed.Node
	if len(s.pending_cmds) > 0 && len(s.path) == 0 {
		if s.pending_cmds[0].group == nil {
			path = s.findPathForCmd(s.pending_cmds[0], s.anim_node)
		} else if s.pending_cmds[0].group.ready() {
			t := s.pending_cmds[0].group.eta[s]
			t -= dt
			if t <= 0 {
				path = s.pending_cmds[0].group.paths[s]
				s.anim_node = path[0]
				s.doTrigger()
				s.togo = s.shared.node_data[s.anim_node].time
				path = path[1:]
			}
			s.pending_cmds[0].group.eta[s] = t
		}
	}
	if path != nil {
		s.applyPath(path)
		s.pending_cmds = s.pending_cmds[1:]
	}

	if len(s.path) > 0 && s.anim_node.Group() != nil {
		// If the current node is in a group that has an edge to the next node
		// then we want to follow that edge immediately rather than waiting for
		// the time for this frame to elapse
		for i := 0; i < s.anim_node.NumGroupOutputs(); i++ {
			edge := s.anim_node.GroupOutput(i)
			if edge.Src() == s.anim_node {
				continue
			}
			if edge.Dst() == s.path[0] {
				s.togo = 0
			}
		}
	}
	if s.togo >= dt {
		s.togo -= dt
		if s.facing != s.prev_facing {
			s.shared.facings[s.prev_facing].Unload()
			s.shared.facings[s.facing].Load()
			s.prev_facing = s.facing
		}
		return
	}
	dt -= s.togo
	var next *yed.Node
	if len(s.path) > 0 {
		next = s.path[0]
		s.path = s.path[1:]
	} else {
		edge := selectAnEdge(s.anim_node, s.shared.edge_data, []string{""})
		if edge != nil {
			next = edge.Dst()
		} else {
			next = s.anim_node
		}
	}
	var edge *yed.Edge
	if next != nil {
		edge = edgeTo(s.anim_node, next)
		face := s.shared.edge_data[edge].facing
		if face != 0 {
			s.facing = (s.facing + face + len(s.shared.facings)) % len(s.shared.facings)
		}
	}
	s.anim_node = next
	s.doTrigger()
	s.togo = s.shared.node_data[s.anim_node].time
	s.Think(dt)
}
Пример #6
0
func (g *Game) ThinkGame() {
	// cache wall data
	if g.local.temp.AllWalls == nil || g.local.temp.AllWallsDirty {
		g.local.temp.AllWallsDirty = false
		g.local.temp.AllWalls = nil
		g.local.temp.WallCache = nil
		g.local.temp.VisibleWallCache = nil

		// Can't use a nil slice, otherwise we'll run this block every Think for levels
		// with no walls.
		allWalls := make([]linear.Seg2, 0)
		base.DoOrdered(g.Level.Room.Walls, func(a, b string) bool { return a < b }, func(_ string, walls linear.Poly) {
			for i := range walls {
				allWalls = append(allWalls, walls.Seg(i))
			}
		})
		g.local.temp.AllWalls = allWalls
		g.local.temp.WallCache = &wallCache{}
		g.local.temp.WallCache.SetWalls(g.Level.Room.Dx, g.Level.Room.Dy, allWalls, 100)
		g.local.temp.VisibleWallCache = &wallCache{}
		g.local.temp.VisibleWallCache.SetWalls(g.Level.Room.Dx, g.Level.Room.Dy, allWalls, stats.LosPlayerHorizon)
		g.local.pathingData = makePathingData(&g.Level.Room)
	}

	// cache ent data
	for _, ent := range g.local.temp.AllEnts {
		if ent.Dead() {
			if _, ok := ent.(*PlayerEnt); ok {
				var id int64
				_, err := fmt.Sscanf(string(ent.Id()), "Engine:%d", &id)
				if err != nil {
					_, err = fmt.Sscanf(string(ent.Id()), "Ai:%d", &id)
					id = -id // Ai's engine ids are negative
				}
				if err != nil {
					base.Error().Printf("Unable to parse player id '%v'", ent.Id())
				} else {
					if engineData, ok := g.Engines[id]; ok {
						if !ok {
							base.Error().Printf("Unable to find engine %d for player %v", id, ent.Id())
						} else {
							engineData.CountdownFrames = 60 * 10
							base.Log().Printf("%v died, counting down....", *engineData)
						}
					}
				}
			}
			ent.OnDeath(g)
			g.RemoveEnt(ent.Id())
		}
	}

	// Death countdown
	base.DoOrdered(g.Engines, func(a, b int64) bool { return a < b }, func(_ int64, engineData *PlayerData) {
		if engineData.CountdownFrames > 0 {
			engineData.CountdownFrames--
			if engineData.CountdownFrames == 0 {
				g.AddPlayers([]*PlayerData{engineData})
			}
		}
	})

	if g.local.temp.AllEnts == nil || g.local.temp.AllEntsDirty {
		g.local.temp.AllEnts = g.local.temp.AllEnts[0:0]
		g.DoForEnts(func(gid Gid, ent Ent) {
			g.local.temp.AllEnts = append(g.local.temp.AllEnts, ent)
		})
		g.local.temp.AllEntsDirty = false
	}
	if g.local.temp.EntGrid == nil {
		g.local.temp.EntGrid = MakeEntCache(g.Level.Room.Dx, g.Level.Room.Dy)
	}
	g.local.temp.EntGrid.SetEnts(g.local.temp.AllEnts)

	for _, proc := range g.Processes {
		proc.Think(g)
	}
	algorithm.Choose(&g.Processes, func(proc Process) bool { return !proc.Dead() })

	// Advance players, check for collisions, add segments
	eps := 1.0e-3
	for _, ent := range g.local.temp.AllEnts {
		ent.Think(g)
		for _, ab := range ent.Abilities() {
			ab.Think(ent, g)
		}
		pos := ent.Pos()
		pos.X = clamp(pos.X, eps, float64(g.Level.Room.Dx)-eps)
		pos.Y = clamp(pos.Y, eps, float64(g.Level.Room.Dy)-eps)
		ent.SetPos(pos)
	}

	var nearby []Ent
	for i := 0; i < len(g.local.temp.AllEnts); i++ {
		outerEnt := g.local.temp.AllEnts[i]
		outerSize := outerEnt.Stats().Size()
		if outerSize == 0 {
			continue
		}
		g.local.temp.EntGrid.EntsInRange(outerEnt.Pos(), 100, &nearby)
		for _, innerEnt := range nearby {
			innerSize := innerEnt.Stats().Size()
			if innerSize == 0 {
				continue
			}
			distSq := outerEnt.Pos().Sub(innerEnt.Pos()).Mag2()
			colDist := innerSize + outerSize
			if distSq > colDist*colDist {
				continue
			}
			if distSq < 0.015625 { // this means that dist < 0.125
				continue
			}
			dist := math.Sqrt(distSq)
			force := 50.0 * (colDist - dist)
			innerEnt.ApplyForce(innerEnt.Pos().Sub(outerEnt.Pos()).Scale(force / dist))
		}
	}

	g.Level.ManaSource.Think(g.Ents)
}
Пример #7
0
func (g *Game) Think() {
	g.GameThinks++
	if g.Setup != nil {
		return
	}
	defer base.StackCatcher()

	// cache wall data
	if g.temp.AllWalls == nil || g.temp.AllWallsDirty {
		g.temp.AllWalls = make(map[Gid][]linear.Seg2)
		g.temp.WallCache = make(map[Gid]*wallCache)
		g.temp.VisibleWallCache = make(map[Gid]*wallCache)
		for gid := range g.Levels {
			var allWalls []linear.Seg2
			base.DoOrdered(g.Levels[gid].Room.Walls, func(a, b string) bool { return a < b }, func(_ string, walls linear.Poly) {
				for i := range walls {
					allWalls = append(allWalls, walls.Seg(i))
				}
			})
			// g.DoForEnts(func(entGid Gid, ent Ent) {
			// 	if ent.Level() == gid {
			// 		for _, walls := range ent.Walls() {
			// 			for i := range walls {
			// 				allWalls = append(allWalls, walls.Seg(i))
			// 			}
			// 		}
			// 	}
			// })
			g.temp.AllWalls[gid] = allWalls
			g.temp.WallCache[gid] = &wallCache{}
			g.temp.WallCache[gid].SetWalls(g.Levels[gid].Room.Dx, g.Levels[gid].Room.Dy, allWalls, 100)
			g.temp.VisibleWallCache[gid] = &wallCache{}
			g.temp.VisibleWallCache[gid].SetWalls(g.Levels[gid].Room.Dx, g.Levels[gid].Room.Dy, allWalls, stats.LosPlayerHorizon)
			base.Log().Printf("WallCache: %v", g.temp.WallCache)
		}
		g.Moba.losCache.SetWallCache(g.temp.VisibleWallCache[GidInvadersStart])
	}

	// cache ent data
	for _, ent := range g.temp.AllEnts {
		if ent.Dead() {
			if _, ok := ent.(*PlayerEnt); ok {
				var id int64
				_, err := fmt.Sscanf(string(ent.Id()), "Engine:%d", &id)
				if err != nil {
					base.Error().Printf("Unable to parse player id '%v'", ent.Id())
				} else {
					if engineData, ok := g.Engines[id]; ok {
						if !ok {
							base.Error().Printf("Unable to find engine %d for player %v", id, ent.Id())
						} else {
							engineData.CountdownFrames = 60 * 10
						}
					}
				}
			}
			ent.OnDeath(g)
			g.RemoveEnt(ent.Id())
		}
	}

	// Death countdown
	for engineId, engineData := range g.Engines {
		if engineData.CountdownFrames > 0 {
			engineData.CountdownFrames--
			if engineData.CountdownFrames == 0 {
				// TODO: It's a bit janky to do it like this, right?
				g.AddPlayers([]int64{engineId}, engineData.Side)
			}
		}
	}

	if g.temp.AllEnts == nil || g.temp.AllEntsDirty {
		g.temp.AllEnts = g.temp.AllEnts[0:0]
		g.DoForEnts(func(gid Gid, ent Ent) {
			g.temp.AllEnts = append(g.temp.AllEnts, ent)
		})
		g.temp.AllEntsDirty = false
	}

	for _, proc := range g.Processes {
		proc.Think(g)
	}
	algorithm.Choose(&g.Processes, func(proc Process) bool { return proc.Phase() != PhaseComplete })

	// Advance players, check for collisions, add segments
	for _, ent := range g.temp.AllEnts {
		ent.Think(g)
		pos := ent.Pos()
		eps := 1.0e-3
		pos.X = clamp(pos.X, eps, float64(g.Levels[ent.Level()].Room.Dx)-eps)
		pos.Y = clamp(pos.Y, eps, float64(g.Levels[ent.Level()].Room.Dy)-eps)
		ent.SetPos(pos)
	}

	for i := 0; i < len(g.temp.AllEnts); i++ {
		for j := i + 1; j < len(g.temp.AllEnts); j++ {
			outerEnt := g.temp.AllEnts[i]
			innerEnt := g.temp.AllEnts[j]
			distSq := outerEnt.Pos().Sub(innerEnt.Pos()).Mag2()
			colDist := outerEnt.Stats().Size() + innerEnt.Stats().Size()
			if distSq > colDist*colDist {
				continue
			}
			if distSq < 0.0001 {
				continue
			}
			if distSq <= 0.25 {
				distSq = 0.25
			}
			dist := math.Sqrt(distSq)
			force := 50.0 * (colDist - dist)
			outerEnt.ApplyForce(outerEnt.Pos().Sub(innerEnt.Pos()).Scale(force / dist))
			innerEnt.ApplyForce(innerEnt.Pos().Sub(outerEnt.Pos()).Scale(force / dist))
		}
	}

	switch {
	case g.Moba != nil:
		g.ThinkMoba()
	case g.Standard != nil:
		panic("Thinkgs aren't implemented, like thinking on mana sources")
		// Do standard thinking
	default:
		panic("Game mode not set")
	}
}
Пример #8
0
func (input *Input) UnregisterEventListener(listener Listener) {
	algorithm.Choose(&input.listeners, func(l Listener) bool { return l != listener })
}