diff --git a/bomb.go b/bomb.go index 90d2819..adc5d4c 100644 --- a/bomb.go +++ b/bomb.go @@ -33,10 +33,10 @@ func (b *Bomb) Dead() bool { return b.done } -func (b *Bomb) Tick(frame int64) { +func (b *Bomb) Tick(game *Game) { b.fti -= 1 if b.fti <= 0 { - b.target.Bombed(b.profile, frame) + b.target.Bombed(b.profile, game.frame) b.done = true log_info("bomb went off on %v", b.target) } diff --git a/broadcast.go b/broadcast.go index 1358c73..dc66a87 100644 --- a/broadcast.go +++ b/broadcast.go @@ -9,8 +9,8 @@ type broadcast struct { start time.Time origin *System dist float64 - nextHitIndex int message string + neighborhood Neighborhood } func NewBroadcast(from *System, template string, args ...interface{}) *broadcast { @@ -21,20 +21,27 @@ func NewBroadcast(from *System, template string, args ...interface{}) *broadcast } } -func (b *broadcast) Tick(frame int64) { +func (b *broadcast) Tick(game *Game) { + if b.neighborhood == nil { + log_info("setting up neighborhood for broadcast: %s", b.message) + b.neighborhood = game.galaxy.Neighborhood(b.origin) + log_info("nearest neighbor: %v", b.neighborhood[0]) + } + b.dist += options.lightSpeed - for ; b.nextHitIndex < len(b.origin.Distances()); b.nextHitIndex += 1 { - candidate := b.origin.Distances()[b.nextHitIndex] - if b.dist < candidate.dist { - break + for len(b.neighborhood) > 0 && b.neighborhood[0].distance <= b.dist { + s := game.galaxy.GetSystemByID(b.neighborhood[0].id) + log_info("broadcast %s has reached %s from %s", b.message, s, b.origin) + s.NotifyInhabitants("message received from system %v:\n\t%s\n", b.origin, b.message) + if len(b.neighborhood) > 1 { + b.neighborhood = b.neighborhood[1:] + } else { + b.neighborhood = nil } - candidate.s.NotifyInhabitants("message received from system %v:\n\t%s\n", b.origin, b.message) } } -func (b *broadcast) Dead() bool { - return b.dist > b.origin.Distances()[len(b.origin.Distances())-1].dist -} +func (b *broadcast) Dead() bool { return b.neighborhood == nil } func (b *broadcast) String() string { return fmt.Sprintf("[broadcast origin: %v message: %s]", b.origin, b.message) diff --git a/commands.go b/commands.go index e1e5e66..7e2a712 100644 --- a/commands.go +++ b/commands.go @@ -212,15 +212,15 @@ func BroadcastCommand(sys *System) Command { func NearbyCommand(sys *System) Command { handler := func(c *Connection, args ...string) { neighbors := c.game.galaxy.Neighborhood(sys) - c.Printf("--------------------------------------------------------------------------------\n") + c.Line() c.Printf("%-4s %-20s %-12s %s\n", "id", "name", "distance", "trip time") - c.Printf("--------------------------------------------------------------------------------\n") + c.Line() for _, neighbor := range neighbors[:25] { - other := index[neighbor.id] + other := c.game.galaxy.GetSystemByID(neighbor.id) dur := NewTravel(c, sys, other).(*TravelState).tripTime() - c.Printf("%-4d %-20s %-12.6v %v\n", other.id, other.name, neighbor.distance, dur) + c.Printf("%-4d %-20s %-12.6vpc %v\n", other.id, other.name, neighbor.distance, dur) } - c.Printf("--------------------------------------------------------------------------------\n") + c.Line() } return Command{ name: "nearby", diff --git a/connection.go b/connection.go index 2dfdec2..70d08f3 100644 --- a/connection.go +++ b/connection.go @@ -40,14 +40,14 @@ func (c *Connection) Dead() bool { return false } -func (c *Connection) Tick(frame int64) { +func (c *Connection) Tick(game *Game) { if c.ConnectionState == nil { log_error("connected client has nil state.") c.Printf("somehow you have a nil state. I don't know what to do so I'm going to kick you off.") c.Close() return } - c.SetState(c.ConnectionState.Tick(c, frame)) + c.SetState(c.ConnectionState.Tick(c, game.frame)) } func (c *Connection) RunCommand(name string, args ...string) { @@ -221,11 +221,3 @@ func (c *Connection) Win(method string) { func (c *Connection) Die(frame int64) { c.SetState(NewDeadState(frame)) } - -func SpawnRandomly() ConnectionState { - sys, err := randomSystem() - if err != nil { - return NewErrorState(fmt.Errorf("unable to create idle state: %v", err)) - } - return Idle(sys) -} diff --git a/dead.go b/dead.go index df92d75..dafd952 100644 --- a/dead.go +++ b/dead.go @@ -17,7 +17,7 @@ func (d *DeadState) Enter(c *Connection) { func (d *DeadState) Tick(c *Connection, frame int64) ConnectionState { if frame-d.start > options.respawnFrames { - return SpawnRandomly() + return c.game.SpawnPlayer() } return d } diff --git a/galaxy.go b/galaxy.go index 3d1c5bf..fca61c4 100644 --- a/galaxy.go +++ b/galaxy.go @@ -70,8 +70,16 @@ func (g *Galaxy) SystemID(name string) int { return g.names[name] } func (g *Galaxy) Neighborhood(sys *System) Neighborhood { neighbors := make(Neighborhood, 0, len(g.systems)) for id, sys2 := range g.systems { + if id == sys.id { + continue + } neighbors = append(neighbors, Neighbor{id: id, distance: sys.DistanceTo(sys2)}) } sort.Sort(neighbors) return neighbors } + +func (g *Galaxy) randomSystem() *System { + id := rand.Intn(len(g.systems)) + return g.GetSystemByID(id) +} diff --git a/game.go b/game.go index 4e5c699..526826a 100644 --- a/game.go +++ b/game.go @@ -136,7 +136,7 @@ func (g *Game) Register(elem GameElement) { func (g *Game) tick() { g.frame += 1 for elem := range g.elems { - elem.Tick(g.frame) + elem.Tick(g) } for elem := range g.elems { if elem.Dead() { @@ -146,7 +146,11 @@ func (g *Game) tick() { } } +func (g *Game) SpawnPlayer() ConnectionState { + return Idle(g.galaxy.randomSystem()) +} + type GameElement interface { - Tick(frame int64) + Tick(*Game) Dead() bool } diff --git a/idle.go b/idle.go index fbb3c75..cc3fc64 100644 --- a/idle.go +++ b/idle.go @@ -104,7 +104,7 @@ func (i *IdleState) scan(c *Connection, args ...string) { return } c.Printf("Scanning the galaxy for signs of life...\n") - c.game.Register(NewScan(i.System)) + c.game.Register(NewScan(i.System, c.game.galaxy.Neighborhood(i.System))) } // "make" is already a keyword diff --git a/lobby.go b/lobby.go index e6e0788..f351911 100644 --- a/lobby.go +++ b/lobby.go @@ -114,7 +114,7 @@ var newGameCommand = Command{ c.Printf("Now playing in game: %s\n\n", game.id) c.Line() c.game.Join(c) - c.SetState(SpawnRandomly()) + c.SetState(game.SpawnPlayer()) }, debug: false, } @@ -135,9 +135,10 @@ Usage: join [game-code]`, " \n\t")) return } id := args[0] - c.game = gm.Get(id) + game := gm.Get(id) + c.game = game log_info("%s Joining game: %s", c.profile.name, c.game.id) - c.SetState(SpawnRandomly()) + c.SetState(game.SpawnPlayer()) c.game.Join(c) }, debug: false, diff --git a/main.go b/main.go index decdd77..a2bb4c1 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ var options struct { frameLength time.Duration colonyCost int frameRate int - lightSpeed float64 + lightSpeed float64 // the distance that light travels in one tick makeBombTime time.Duration makeColonyTime time.Duration makeShieldTime time.Duration diff --git a/scan.go b/scan.go index 110a172..c44749b 100644 --- a/scan.go +++ b/scan.go @@ -12,6 +12,7 @@ type scan struct { nextHitIndex int nextEchoIndex int results []scanResult + neighborhood Neighborhood } type scanResult struct { @@ -38,17 +39,18 @@ func (r *scanResult) playerNames() []string { return names } -func NewScan(origin *System) *scan { +func NewScan(origin *System, n Neighborhood) *scan { return &scan{ - origin: origin, - start: time.Now(), - results: make([]scanResult, 0, len(origin.Distances())), + origin: origin, + start: time.Now(), + results: make([]scanResult, 0, len(origin.Distances())), + neighborhood: n, } } -func (s *scan) Tick(frame int64) { +func (s *scan) Tick(game *Game) { s.dist += options.lightSpeed - s.hits() + s.hits(game) s.echos() } @@ -60,14 +62,17 @@ func (s *scan) String() string { return fmt.Sprintf("[scan origin: %s start_time: %v]", s.origin.name, s.start) } -func (s *scan) hits() { - for ; s.nextHitIndex < len(s.origin.Distances()); s.nextHitIndex += 1 { - candidate := s.origin.Distances()[s.nextHitIndex] - if s.dist < candidate.dist { - break +func (s *scan) hits(game *Game) { + for len(s.neighborhood) > 0 && s.neighborhood[0].distance <= s.dist { + sys := game.galaxy.GetSystemByID(s.neighborhood[0].id) + s.results = append(s.results, s.hitSystem(sys, s.neighborhood[0].distance)) + log_info("scan hit %v. Traveled %v in %v", sys.name, s.neighborhood[0].distance, time.Since(s.start)) + + if len(s.neighborhood) > 1 { + s.neighborhood = s.neighborhood[1:] + } else { + s.neighborhood = nil } - s.results = append(s.results, s.hitSystem(candidate.s, candidate.dist)) - log_info("scan hit %v. Traveled %v in %v", candidate.s.name, candidate.dist, time.Since(s.start)) } } diff --git a/shield.go b/shield.go index 5e483ca..a2be532 100644 --- a/shield.go +++ b/shield.go @@ -54,7 +54,7 @@ type Shield struct { energy float64 } -func (s *Shield) Tick(frame int64) { +func (s *Shield) Tick() { if s.energy < 1000 { s.energy += (1000 - s.energy) * 0.0005 } diff --git a/system.go b/system.go index 57a7f26..8daa006 100644 --- a/system.go +++ b/system.go @@ -25,13 +25,13 @@ type System struct { money int64 } -func (s *System) Tick(frame int64) { +func (s *System) Tick(game *Game) { if s.colonizedBy != nil && s.money > 0 { s.colonizedBy.Deposit(1) s.money -= 1 } if s.Shield != nil { - s.Shield.Tick(frame) + s.Shield.Tick() } } @@ -45,7 +45,6 @@ func (s *System) Reset() { } func (s *System) Arrive(conn *Connection) { - // conn.SetSystem(s) if s.players[conn] { return } @@ -125,11 +124,11 @@ func (s *System) Distances() []Ray { if s.distances == nil { s.distances = make([]Ray, 0, 551) rows, err := db.Query(` - select edges.id_2, edges.distance - from edges - where edges.id_1 = ? - order by distance - ;`, s.id) + select edges.id_2, edges.distance + from edges + where edges.id_1 = ? + order by distance + ;`, s.id) if err != nil { log_error("unable to query for system distances: %v", err) return nil @@ -247,13 +246,3 @@ func indexSystems() map[int]*System { } return index } - -func randomSystem() (*System, error) { - n := len(index) - if n == 0 { - return nil, fmt.Errorf("no planets are known to exist") - } - pick := rand.Intn(n) - sys := index[pick] - return sys, nil -}