You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
3.1 KiB
Go
157 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"time"
|
|
)
|
|
|
|
type Game struct {
|
|
id string
|
|
start time.Time
|
|
end time.Time
|
|
done chan interface{}
|
|
winner string
|
|
winMethod string
|
|
connections map[*Connection]bool
|
|
frame int64
|
|
elems map[GameElement]bool
|
|
galaxy *Galaxy
|
|
}
|
|
|
|
func gamesTable() {
|
|
stmnt := `create table if not exists games (
|
|
id text not null,
|
|
start text not null,
|
|
end text,
|
|
winner text,
|
|
win_method text
|
|
);`
|
|
if _, err := db.Exec(stmnt); err != nil {
|
|
log_error("couldn't create games table: %v", err)
|
|
}
|
|
}
|
|
|
|
func init() { rand.Seed(time.Now().UnixNano()) }
|
|
|
|
func newID() string {
|
|
chars := []rune("ABCDEEEEEEEEFGHJJJJJJJKMNPQQQQQQQRTUVWXXXXXYZZZZZ234677777789")
|
|
id := make([]rune, 0, 4)
|
|
for i := 0; i < cap(id); i++ {
|
|
id = append(id, chars[rand.Intn(len(chars))])
|
|
}
|
|
return string(id)
|
|
}
|
|
|
|
func NewGame() *Game {
|
|
game := &Game{
|
|
id: newID(),
|
|
start: time.Now(),
|
|
done: make(chan interface{}),
|
|
connections: make(map[*Connection]bool, 32),
|
|
elems: make(map[GameElement]bool, 32),
|
|
galaxy: NewGalaxy(),
|
|
}
|
|
if err := game.Create(); err != nil {
|
|
log_error("unable to create game: %v", err)
|
|
}
|
|
for _, system := range index {
|
|
game.Register(system)
|
|
}
|
|
return game
|
|
}
|
|
|
|
func (g *Game) Create() error {
|
|
_, err := db.Exec(`
|
|
insert into games
|
|
(id, start)
|
|
values
|
|
(?, ?)
|
|
;`, g.id, g.start)
|
|
if err != nil {
|
|
return fmt.Errorf("error writing sqlite insert statement to create game: %v")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Game) Store() error {
|
|
_, err := db.Exec(`
|
|
update games
|
|
set end = ?, winner = ?, win_method = ?
|
|
where id = ?
|
|
;`, g.end, g.winner, g.winMethod, g.id)
|
|
return err
|
|
}
|
|
|
|
func (g *Game) Join(conn *Connection) {
|
|
log_info("Player %s has joined game %s", conn.Name(), g.id)
|
|
g.connections[conn] = true
|
|
g.Register(conn)
|
|
}
|
|
|
|
func (g *Game) Quit(conn *Connection) {
|
|
delete(g.connections, conn)
|
|
}
|
|
|
|
func (g *Game) Win(winner *Connection, method string) {
|
|
defer close(g.done)
|
|
g.end = time.Now()
|
|
g.winner = winner.Name()
|
|
g.winMethod = method
|
|
g.Store()
|
|
|
|
log_info("player %s has won by %s victory", winner.Name(), method)
|
|
|
|
for conn, _ := range g.connections {
|
|
conn.Printf("player %s has won by %s victory.\n", winner.Name(), method)
|
|
}
|
|
}
|
|
|
|
func (g *Game) Reset() {
|
|
connections := g.connections
|
|
fresh := NewGame()
|
|
*g = *fresh
|
|
g.connections = connections
|
|
}
|
|
|
|
func (g *Game) Run() {
|
|
ticker := time.Tick(time.Second / time.Duration(options.frameRate))
|
|
for {
|
|
select {
|
|
case <-ticker:
|
|
g.tick()
|
|
case <-g.done:
|
|
for conn, _ := range g.connections {
|
|
conn.Close()
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *Game) Register(elem GameElement) {
|
|
g.elems[elem] = true
|
|
}
|
|
|
|
func (g *Game) tick() {
|
|
g.frame += 1
|
|
for elem := range g.elems {
|
|
elem.Tick(g)
|
|
}
|
|
for elem := range g.elems {
|
|
if elem.Dead() {
|
|
log_info("delete game object: %v", elem)
|
|
delete(g.elems, elem)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *Game) SpawnPlayer() ConnectionState {
|
|
return Idle(g.galaxy.randomSystem())
|
|
}
|
|
|
|
type GameElement interface {
|
|
Tick(*Game)
|
|
Dead() bool
|
|
}
|