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) } }
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"}) }) }
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 } } }
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++ }
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) }
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) }
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") } }
func (input *Input) UnregisterEventListener(listener Listener) { algorithm.Choose(&input.listeners, func(l Listener) bool { return l != listener }) }