server/game.go
Stephen McQuay f8378cf89b Got game working again
I just moved some old code into the game struct; probably still merits some
cleanup in the main loop.
2013-09-20 12:15:10 -06:00

202 lines
4.4 KiB
Go

package main
import (
"bitbucket.org/hackerbots/bot"
v "bitbucket.org/hackerbots/vector"
"log"
"sort"
"time"
)
const maxPlayer = 128
type game struct {
id string
players map[*player]bool
projectiles map[*bot.Projectile]bool
splosions map[*bot.Splosion]bool
register chan *player
unregister chan *player
turn int
width, height float64
spectators map[*Spectator]bool
sregister chan *Spectator
sunregister chan *Spectator
kill chan bool
}
func NewGame(id string, width, height float64) *game {
g := &game{
id: id,
register: make(chan *player),
unregister: make(chan *player, maxPlayer),
projectiles: make(map[*bot.Projectile]bool),
splosions: make(map[*bot.Splosion]bool),
players: make(map[*player]bool),
turn: 0,
width: width,
height: height,
spectators: make(map[*Spectator]bool),
sregister: make(chan *Spectator),
sunregister: make(chan *Spectator),
kill: make(chan bool, maxPlayer),
}
return g
}
func (g *game) run() {
started := false
var t0, t1 time.Time
payload := bot.NewBoardstate()
for {
select {
case <-g.kill:
log.Printf("game %s: received kill signal, dying gracefully", g.id)
games.Lock()
for player := range g.players {
close(player.send)
}
delete(games.m, g.id)
games.Unlock()
return
case p := <-g.register:
g.players[p] = true
started = true
case p := <-g.unregister:
delete(g.players, p)
close(p.send)
case s := <-g.sregister:
g.spectators[s] = true
case s := <-g.sunregister:
delete(g.spectators, s)
close(s.send)
case <-time.Tick(time.Duration(*tick) * time.Millisecond):
// XXX: This is very racy!! It was at bottom of loop and empty
// stuff was going out
payload.EmptySlices()
if started && len(g.players) == 0 {
g.kill <- true
}
g.turn++
payload.Turn = g.turn
t0 = time.Now()
if *verbose {
log.Printf("\033[2JTurn: %v", g.turn)
log.Printf("Players: %v", len(g.players))
log.Printf("Projectiles: %v", len(g.projectiles))
log.Printf("Explosions: %v", len(g.splosions))
}
robots_remaining := 0
for p := range g.players {
if p.Robot.Health > 0 {
robots_remaining++
// TODO: measure if this would be better to go and wait ...
p.scan(g.players)
p.nudge()
if p.Robot.FireAt != nil {
proj := p.fire(g.projectiles)
if proj != nil {
g.projectiles[proj] = true
}
}
}
payload.Robots = append(payload.Robots, p.Robot)
}
sort.Sort(bot.RobotSorter{Robots: payload.Robots})
payload.Projectiles = append(payload.Projectiles,
g.nudgeProjectiles()...,
)
for s := range g.splosions {
// XXX: s.tick()
payload.Splosions = append(payload.Splosions, *s)
}
if robots_remaining <= 1 && len(g.players) > 1 {
for p := range g.players {
if p.Robot.Health > 0 {
log.Printf("Robot %v Wins", p.Robot.Id)
log.Printf("game over: %+v", g)
return
}
p.reset()
}
payload.Reset = true
} else {
payload.Reset = false
}
t1 = time.Now()
if *verbose {
log.Printf("Turn Processes %v\n", t1.Sub(t0))
}
for p := range g.players {
p.send <- payload
}
for s := range g.spectators {
s.send <- payload
}
t1 = time.Now()
if *verbose {
log.Printf("Sent Payload %v\n", t1.Sub(t0))
}
}
}
}
func (g *game) nudgeProjectiles() (rprojectiles []bot.Projectile) {
for p := range g.projectiles {
newPos := v.Move(p.Position, p.MoveTo, float64(p.Speed), delta)
hit_player := false
for player := range g.players {
if player.Robot.Id == p.Id {
continue
}
dist := v.Distance(player.Robot.Position, p.Position)
if dist < 5.0 {
hit_player = true
}
}
if v.Distance(p.Position, p.MoveTo) < 5 || hit_player {
delete(g.projectiles, p)
// Spawn a splosion
splo := &bot.Splosion{
Id: p.Id,
Position: p.Position,
Radius: p.Radius,
MaxDamage: 10,
MinDamage: 5,
Lifespan: 8,
}
g.splosions[splo] = true
for player := range g.players {
dist := v.Distance(player.Robot.Position, p.Position)
if dist < float64(p.Radius) {
// TODO map damage Max to Min based on distance from explosion
if player.Robot.Health > 0 {
player.Robot.Health -= p.Damage
if player.Robot.Health <= 0 {
}
}
}
}
}
p.Position.X = newPos.X
p.Position.Y = newPos.Y
}
return
}