I hope this works out in the end.

slack
Jordan Orelli 10 years ago
parent a821ab04e4
commit f4587c18a2

@ -14,15 +14,14 @@ type Bomb struct {
fti int64 // frames to impact fti int64 // frames to impact
} }
func NewBomb(from *Connection, to *System) *Bomb { func NewBomb(conn *Connection, from, to *System) *Bomb {
origin := from.System() dist := from.DistanceTo(to)
dist := origin.DistanceTo(to)
fti := int64(dist / (options.lightSpeed * options.bombSpeed)) fti := int64(dist / (options.lightSpeed * options.bombSpeed))
eta := time.Duration(fti) * time.Second / time.Duration(options.frameRate) eta := time.Duration(fti) * time.Second / time.Duration(options.frameRate)
log_info("bomb from: %s to: %s ETA: %v", from.Name(), to.Label(), eta) log_info("bomb from: %v to: %v ETA: %v", from, to, eta)
return &Bomb{ return &Bomb{
profile: from, profile: conn,
origin: origin, origin: from,
target: to, target: to,
fti: fti, fti: fti,
start: time.Now(), start: time.Now(),
@ -38,10 +37,10 @@ func (b *Bomb) Tick(frame int64) {
if b.fti <= 0 { if b.fti <= 0 {
b.target.Bombed(b.profile) b.target.Bombed(b.profile)
b.done = true b.done = true
log_info("bomb went off on %s", b.target.Label()) log_info("bomb went off on %v", b.target)
} }
} }
func (b *Bomb) String() string { func (b *Bomb) String() string {
return fmt.Sprintf("[bomb from: %s to: %s lived: %s]", b.origin.Label(), b.target.Label(), time.Since(b.start)) return fmt.Sprintf("[bomb from: %v to: %v lived: %s]", b.origin, b.target, time.Since(b.start))
} }

@ -28,7 +28,7 @@ func (b *broadcast) Tick(frame int64) {
if b.dist < candidate.dist { if b.dist < candidate.dist {
break break
} }
candidate.s.NotifyInhabitants("message received from system %s:\n\t%s\n", b.origin.Label(), b.message) candidate.s.NotifyInhabitants("message received from system %v:\n\t%s\n", b.origin, b.message)
} }
} }
@ -37,5 +37,5 @@ func (b *broadcast) Dead() bool {
} }
func (b *broadcast) String() string { func (b *broadcast) String() string {
return fmt.Sprintf("[broadcast origin: %s message: %s]", b.origin.name, b.message) return fmt.Sprintf("[broadcast origin: %v message: %s]", b.origin, b.message)
} }

@ -3,52 +3,98 @@ package main
import ( import (
"fmt" "fmt"
"sort" "sort"
"strconv" // "strconv"
"strings" "strings"
) )
var commandRegistry map[string]*Command var commandRegistry map[string]*Command
type Command struct { type Command struct {
name string name string
help string help string
handler func(*Connection, ...string) arity int
mobile bool variadic bool
debug bool // marks command as a debug mode command handler func(*Connection, ...string)
debug bool // marks command as a debug mode command
} }
var infoCommand = &Command{ type CommandSuite interface {
name: "info", GetCommand(name string) *Command
help: "gives you some info about your current position", Commands() []Command
handler: func(conn *Connection, args ...string) {
conn.Printf("current planet: %s\n", conn.System().name)
conn.Printf("bombs: %d\n", conn.bombs)
conn.Printf("money: %d space duckets\n", conn.money)
},
} }
var nearbyCommand = &Command{ func (c Command) GetCommand(name string) *Command {
name: "nearby", if name == c.name {
help: "list objects nearby", return &c
handler: func(conn *Connection, args ...string) { }
system := conn.System() return nil
neighbors, err := system.Nearby(25) }
if err != nil {
log_error("unable to get neighbors: %v", err) func (c Command) Commands() []Command {
return return []Command{c}
} }
conn.Printf("--------------------------------------------------------------------------------\n")
conn.Printf("%-4s %-20s %s\n", "id", "name", "distance") type CommandSet []Command
conn.Printf("--------------------------------------------------------------------------------\n")
for _, neighbor := range neighbors { func (c CommandSet) GetCommand(name string) *Command {
other := index[neighbor.id] for _, cmd := range c {
conn.Printf("%-4d %-20s %v\n", other.id, other.name, neighbor.distance) if cmd.name == name {
return &cmd
} }
conn.Printf("--------------------------------------------------------------------------------\n") }
}, return nil
} }
var helpCommand = &Command{ func (c CommandSet) Commands() []Command {
return []Command(c)
}
// var gotoCommand = &Command{
// name: "goto",
// help: "travel between systems",
// arity: 1,
// handler: func(c *Connection, args ...string) {
// dest, err := GetSystem(args[0])
// if err != nil {
// c.Printf("%v\n", err)
// break
// }
// return NewTravel(c, i.System, dest)
// },
// }
// var infoCommand = &Command{
// name: "info",
// help: "gives you some info about your current position",
// handler: func(conn *Connection, args ...string) {
// conn.Printf("current planet: %v\n", conn.System())
// conn.Printf("bombs: %d\n", conn.bombs)
// conn.Printf("money: %d space duckets\n", conn.money)
// },
// }
// var nearbyCommand = &Command{
// name: "nearby",
// help: "list objects nearby",
// handler: func(conn *Connection, args ...string) {
// system := conn.System()
// neighbors, err := system.Nearby(25)
// if err != nil {
// log_error("unable to get neighbors: %v", err)
// return
// }
// conn.Printf("--------------------------------------------------------------------------------\n")
// conn.Printf("%-4s %-20s %s\n", "id", "name", "distance")
// conn.Printf("--------------------------------------------------------------------------------\n")
// for _, neighbor := range neighbors {
// other := index[neighbor.id]
// conn.Printf("%-4d %-20s %v\n", other.id, other.name, neighbor.distance)
// }
// conn.Printf("--------------------------------------------------------------------------------\n")
// },
// }
var helpCommand = Command{
name: "help", name: "help",
help: "helpful things to help you", help: "helpful things to help you",
handler: func(conn *Connection, args ...string) { handler: func(conn *Connection, args ...string) {
@ -93,7 +139,7 @@ systems. Star systems that are farther away take longer to communicate with.
}, },
} }
var commandsCommand = &Command{ var commandsCommand = Command{
name: "commands", name: "commands",
help: "gives you a handy list of commands", help: "gives you a handy list of commands",
handler: func(conn *Connection, args ...string) { handler: func(conn *Connection, args ...string) {
@ -111,84 +157,84 @@ var commandsCommand = &Command{
}, },
} }
var scanCommand = &Command{ // var scanCommand = &Command{
name: "scan", // name: "scan",
help: "super duper scan", // help: "super duper scan",
handler: func(conn *Connection, args ...string) { // handler: func(conn *Connection, args ...string) {
if !conn.CanScan() { // if !conn.CanScan() {
conn.Printf("scanners are still recharging. Can scan again in %v\n", conn.NextScan()) // conn.Printf("scanners are still recharging. Can scan again in %v\n", conn.NextScan())
return // return
} // }
currentGame.Register(NewScan(conn.System())) // currentGame.Register(NewScan(conn.System()))
conn.RecordScan() // conn.RecordScan()
}, // },
} // }
var broadcastCommand = &Command{ // var broadcastCommand = &Command{
name: "broadcast", // name: "broadcast",
help: "broadcast a message for all systems to hear", // help: "broadcast a message for all systems to hear",
handler: func(conn *Connection, args ...string) { // handler: func(conn *Connection, args ...string) {
msg := strings.Join(args, " ") // msg := strings.Join(args, " ")
system := conn.System() // system := conn.System()
b := NewBroadcast(system, msg) // b := NewBroadcast(system, msg)
log_info("player %s send broadcast from system %s: %v\n", conn.Name(), system.Label(), msg) // log_info("player %s send broadcast from system %s: %v\n", conn.Name(), system.Label(), msg)
currentGame.Register(b) // currentGame.Register(b)
}, // },
} // }
var gotoCommand = &Command{ // var gotoCommand = &Command{
name: "goto", // name: "goto",
help: "moves to a different system, specified by either name or ID", // help: "moves to a different system, specified by either name or ID",
handler: func(conn *Connection, args ...string) { // handler: func(conn *Connection, args ...string) {
dest_name := strings.Join(args, " ") // dest_name := strings.Join(args, " ")
to, ok := nameIndex[dest_name] // to, ok := nameIndex[dest_name]
if ok { // if ok {
conn.TravelTo(to) // conn.TravelTo(to)
return // return
} // }
//
id_n, err := strconv.Atoi(dest_name) // id_n, err := strconv.Atoi(dest_name)
if err != nil { // if err != nil {
conn.Printf(`hmm, I don't know a system by the name "%s", try something else`, dest_name) // conn.Printf(`hmm, I don't know a system by the name "%s", try something else`, dest_name)
return // return
} // }
//
to, ok = index[id_n] // to, ok = index[id_n]
if !ok { // if !ok {
conn.Printf(`oh dear, there doesn't seem to be a system with id %d`, id_n) // conn.Printf(`oh dear, there doesn't seem to be a system with id %d`, id_n)
return // return
} // }
conn.TravelTo(to) // conn.TravelTo(to)
}, // },
} // }
var mineCommand = &Command{ // var mineCommand = &Command{
name: "mine", // name: "mine",
help: "mines the current system for resources", // help: "mines the current system for resources",
handler: func(conn *Connection, args ...string) { // handler: func(conn *Connection, args ...string) {
conn.Mine() // conn.Mine()
}, // },
} // }
var colonizeCommand = &Command{ // var colonizeCommand = &Command{
name: "colonize", // name: "colonize",
help: "establishes a mining colony on the current system", // help: "establishes a mining colony on the current system",
handler: func(conn *Connection, arg ...string) { // handler: func(conn *Connection, arg ...string) {
system := conn.System() // system := conn.System()
if conn.money > 2000 { // if conn.money > 2000 {
conn.Withdraw(2000) // conn.Withdraw(2000)
if system.colonizedBy != nil { // if system.colonizedBy != nil {
system.colonizedBy.Printf("your colony on %s has been stolen by %s\n", system.Label(), conn.Name()) // system.colonizedBy.Printf("your colony on %s has been stolen by %s\n", system.Label(), conn.Name())
} // }
system.colonizedBy = conn // system.colonizedBy = conn
conn.Printf("set up a mining colony on %s\n", conn.System().name) // conn.Printf("set up a mining colony on %s\n", conn.System().name)
} else { // } else {
conn.Printf("not enough money! it costs 2000 duckets to start a mining colony\n") // conn.Printf("not enough money! it costs 2000 duckets to start a mining colony\n")
} // }
}, // },
} // }
var winCommand = &Command{ var winCommand = Command{
name: "win", name: "win",
help: "win the game.", help: "win the game.",
debug: true, debug: true,
@ -197,49 +243,49 @@ var winCommand = &Command{
}, },
} }
var bombCommand = &Command{ // var bombCommand = &Command{
name: "bomb", // name: "bomb",
help: "bombs a system, with a big space bomb", // help: "bombs a system, with a big space bomb",
handler: func(conn *Connection, args ...string) { // handler: func(conn *Connection, args ...string) {
dest_name := strings.Join(args, " ") // dest_name := strings.Join(args, " ")
to, ok := nameIndex[dest_name] // to, ok := nameIndex[dest_name]
if ok { // if ok {
conn.SendBomb(to) // conn.SendBomb(to)
return // return
} // }
//
id_n, err := strconv.Atoi(dest_name) // id_n, err := strconv.Atoi(dest_name)
if err != nil { // if err != nil {
conn.Printf(`hmm, I don't know a system by the name "%s", try something else\n`, dest_name) // conn.Printf(`hmm, I don't know a system by the name "%s", try something else\n`, dest_name)
return // return
} // }
//
to, ok = index[id_n] // to, ok = index[id_n]
if !ok { // if !ok {
conn.Printf(`oh dear, there doesn't seem to be a system with id %d\n`, id_n) // conn.Printf(`oh dear, there doesn't seem to be a system with id %d\n`, id_n)
return // return
} // }
conn.SendBomb(to) // conn.SendBomb(to)
}, // },
} // }
var mkBombCommand = &Command{ // var mkBombCommand = &Command{
name: "mkbomb", // name: "mkbomb",
help: "make a bomb. Costs 500 space duckets", // help: "make a bomb. Costs 500 space duckets",
handler: func(conn *Connection, args ...string) { // handler: func(conn *Connection, args ...string) {
if conn.money < 500 { // if conn.money < 500 {
conn.Printf("not enough money! Bombs cost 500 space duckets to build, you only have %d in the bank.\n", conn.money) // conn.Printf("not enough money! Bombs cost 500 space duckets to build, you only have %d in the bank.\n", conn.money)
return // return
} // }
conn.Withdraw(500) // conn.Withdraw(500)
conn.bombs += 1 // conn.bombs += 1
conn.Printf("built a bomb!\n") // conn.Printf("built a bomb!\n")
conn.Printf("bombs: %d\n", conn.bombs) // conn.Printf("bombs: %d\n", conn.bombs)
conn.Printf("money: %d space duckets\n", conn.money) // conn.Printf("money: %d space duckets\n", conn.money)
}, // },
} // }
var playersCommand = &Command{ var playersCommand = Command{
name: "players", name: "players",
help: "lists the connected players", help: "lists the connected players",
handler: func(conn *Connection, args ...string) { handler: func(conn *Connection, args ...string) {
@ -249,69 +295,10 @@ var playersCommand = &Command{
}, },
} }
var balCommand = &Command{ var balCommand = Command{
name: "bal", name: "bal",
help: "displays your current balance in space duckets", help: "displays your current balance in space duckets",
handler: func(conn *Connection, args ...string) { handler: func(conn *Connection, args ...string) {
fmt.Fprintln(conn, conn.money) fmt.Fprintln(conn, conn.money)
}, },
} }
func isCommand(name string) bool {
_, ok := commandRegistry[name]
return ok
}
func runCommand(conn *Connection, name string, args ...string) {
cmd, ok := commandRegistry[name]
if !ok {
conn.Printf("no such command: %s\n", name)
return
}
if conn.dead {
conn.Printf("you're dead.\n")
return
}
if conn.InTransit() && !cmd.mobile {
conn.Printf("command %s can not be used while in transit\n", name)
return
}
if conn.IsMining() {
conn.StopMining()
}
cmd.handler(conn, args...)
}
func registerCommand(c *Command) {
if c.debug {
if options.debug {
commandRegistry[c.name] = c
log_info("registered debug command: %s", c.name)
}
} else {
commandRegistry[c.name] = c
log_info("registered command: %s", c.name)
}
}
func setupCommands() {
commandRegistry = make(map[string]*Command, 16)
registerCommand(bombCommand)
registerCommand(broadcastCommand)
registerCommand(colonizeCommand)
registerCommand(commandsCommand)
registerCommand(gotoCommand)
registerCommand(helpCommand)
registerCommand(infoCommand)
registerCommand(mineCommand)
registerCommand(mkBombCommand)
registerCommand(nearbyCommand)
registerCommand(playersCommand)
registerCommand(scanCommand)
registerCommand(winCommand)
registerCommand(balCommand)
}

@ -10,37 +10,25 @@ import (
) )
type Connection struct { type Connection struct {
net.Conn
*bufio.Reader *bufio.Reader
profile *Profile net.Conn
location *System ConnectionState
dest *System bombs int
travelRemaining int64 colonies []*System
lastScan time.Time kills int
lastBomb time.Time lastBomb time.Time
kills int lastScan time.Time
dead bool money int
money int profile *Profile
colonies []*System
bombs int
state PlayerState // this is wrong...
} }
type PlayerState int
const (
idle PlayerState = iota
dead
inTransit
mining
)
func NewConnection(conn net.Conn) *Connection { func NewConnection(conn net.Conn) *Connection {
c := &Connection{ c := &Connection{
Conn: conn, Conn: conn,
Reader: bufio.NewReader(conn), Reader: bufio.NewReader(conn),
bombs: 1, bombs: 1,
} }
c.SetState(SpawnRandomly())
currentGame.Join(c) currentGame.Join(c)
return c return c
} }
@ -84,59 +72,59 @@ func (c *Connection) Dead() bool {
} }
func (c *Connection) Tick(frame int64) { func (c *Connection) Tick(frame int64) {
// fuck if c.ConnectionState == nil {
switch c.state { log_error("connected client has nil state.")
case idle: c.Printf("somehow you have a nil state. I don't know what to do so I'm going to kick you off.")
case dead: c.Close()
case inTransit: return
c.travelRemaining -= 1
if c.travelRemaining == 0 {
c.land()
}
case mining:
sys := c.System()
if sys == nil {
log_error("a player is in the mining state with no system. what?")
break
}
if sys.money <= 0 {
c.Printf("system %s is all out of space duckets.\n", sys.Label())
c.StopMining()
} else {
c.Deposit(1)
sys.money -= 1
}
default:
log_error("connection %v has invalid state wtf", c)
} }
c.SetState(c.ConnectionState.Tick(c, frame))
} }
func (c *Connection) TravelTo(dest *System) { func (c *Connection) RunCommand(name string, args ...string) {
dist := c.System().DistanceTo(dest) defer func() {
c.travelRemaining = int64(dist / (options.lightSpeed * options.playerSpeed)) if r := recover(); r != nil {
t := time.Duration(c.travelRemaining) * (time.Second / time.Duration(options.frameRate)) c.Printf("shit is *really* fucked up.")
c.Printf("traveling to: %s. ETA: %v\n", dest.Label(), t) log_error("recovered: %v", r)
c.location.Leave(c) }
c.location = nil }()
c.dest = dest cmd := c.GetCommand(name)
c.state = inTransit // fuck everything about this if cmd == nil {
c.Printf("No such command: %v\n", name)
return
}
cmd.handler(c, args...)
} }
func (c *Connection) SendBomb(target *System) { func (c *Connection) SetState(s ConnectionState) {
if c.bombs <= 0 { if c.ConnectionState == s {
fmt.Fprintln(c, "cannot send bomb: no bombs left")
return return
} }
if time.Since(c.lastBomb) < 5*time.Second { log_info("set state: %v", s)
fmt.Fprintln(c, "cannod send bomb: bombs are reloading") if c.ConnectionState != nil {
return log_info("exit state: %v", c.ConnectionState)
c.ConnectionState.Exit(c)
} }
c.bombs -= 1 log_info("enter state: %v", s)
c.lastBomb = time.Now() s.Enter(c)
bomb := NewBomb(c, target) c.ConnectionState = s
currentGame.Register(bomb) }
c.Printf("sending bomb to system %v\n", target.Label())
} // func (c *Connection) SendBomb(target *System) {
// if c.bombs <= 0 {
// fmt.Fprintln(c, "cannot send bomb: no bombs left")
// return
// }
// if time.Since(c.lastBomb) < 5*time.Second {
// fmt.Fprintln(c, "cannod send bomb: bombs are reloading")
// return
// }
// c.bombs -= 1
// c.lastBomb = time.Now()
// bomb := NewBomb(c, target)
// currentGame.Register(bomb)
// c.Printf("sending bomb to system %v\n", target)
// }
func (c *Connection) ReadLines(out chan []string) { func (c *Connection) ReadLines(out chan []string) {
defer close(out) defer close(out)
@ -164,22 +152,6 @@ func (c *Connection) Printf(template string, args ...interface{}) (int, error) {
return fmt.Fprintf(c, template, args...) return fmt.Fprintf(c, template, args...)
} }
func (c *Connection) land() {
c.Printf("you have arrived at %v\n", c.dest.Label())
c.location = c.dest
c.location.Arrive(c)
c.dest = nil
c.state = idle
}
func (c *Connection) SetSystem(s *System) {
c.location = s
}
func (c *Connection) System() *System {
return c.location
}
func (c *Connection) Close() error { func (c *Connection) Close() error {
log_info("player disconnecting: %s", c.Name()) log_info("player disconnecting: %s", c.Name())
currentGame.Quit(c) currentGame.Quit(c)
@ -196,10 +168,6 @@ func (c *Connection) Name() string {
return c.profile.name return c.profile.name
} }
func (c *Connection) InTransit() bool {
return c.location == nil
}
func (c *Connection) RecordScan() { func (c *Connection) RecordScan() {
fmt.Fprintln(c, "scanning known systems for signs of life") fmt.Fprintln(c, "scanning known systems for signs of life")
c.lastScan = time.Now() c.lastScan = time.Now()
@ -238,26 +206,6 @@ func (c *Connection) MadeKill(victim *Connection) {
} }
} }
func (c *Connection) Mine() {
switch c.state {
case idle:
c.Printf("now mining %s. %v space duckets remaining.\n", c.System().name, c.System().money)
fmt.Fprintln(c, "(press enter to stop mining)")
c.state = mining
default:
c.Printf("no\n")
}
}
func (c *Connection) StopMining() {
c.Printf("done mining\n")
c.state = idle
}
func (c *Connection) IsMining() bool {
return c.state == mining
}
func (c *Connection) Withdraw(n int) { func (c *Connection) Withdraw(n int) {
c.money -= n c.money -= n
} }
@ -273,25 +221,30 @@ func (c *Connection) Win(method string) {
currentGame.Win(c, method) currentGame.Win(c, method)
} }
func (c *Connection) Die() { type ConnectionState interface {
c.Printf("you were bombed. You will respawn in 1 minutes.\n") CommandSuite
c.dead = true String() string
c.System().Leave(c) Enter(c *Connection)
time.AfterFunc(30*time.Second, func() { Tick(c *Connection, frame int64) ConnectionState
c.Printf("respawn in 30 seconds.\n") Exit(c *Connection)
})
time.AfterFunc(time.Minute, c.Respawn)
} }
func (c *Connection) Respawn() { // No-op enter struct, for composing connection states that have no interesitng
c.dead = false // Enter mechanic.
type NopEnter struct{}
WUT: func (n NopEnter) Enter(c *Connection) {}
s, err := randomSystem()
// No-op exit struct, for composing connection states that have no interesting
// Exit mechanic.
type NopExit struct{}
func (n NopExit) Exit(c *Connection) {}
func SpawnRandomly() ConnectionState {
sys, err := randomSystem()
if err != nil { if err != nil {
log_error("error in respawn: %v", err) return NewErrorState(fmt.Errorf("unable to create idle state: %v", err))
goto WUT
} }
s.Arrive(c) return Idle(sys)
} }

@ -0,0 +1,31 @@
package main
import ()
type DeadState struct {
CommandSuite
start int64
}
func NewDeadState(died int64) ConnectionState {
return &DeadState{start: died}
}
func (d *DeadState) Enter(c *Connection) {
c.Printf("You are dead.\n")
}
func (d *DeadState) Tick(c *Connection, frame int64) ConnectionState {
if frame-d.start > options.respawnFrames {
return SpawnRandomly()
}
return d
}
func (d *DeadState) Exit(c *Connection) {
c.Printf("You're alive again.\n")
}
func (d *DeadState) String() string {
return "dead"
}

@ -1,6 +1,7 @@
package main package main
import ( import (
"fmt"
"strings" "strings"
) )
@ -9,6 +10,7 @@ const (
E_No_Data E_No_Data
E_No_DB E_No_DB
E_No_Port E_No_Port
E_Bad_Duration
) )
type errorGroup []error type errorGroup []error
@ -31,3 +33,32 @@ func (g *errorGroup) AddError(err error) {
} }
*g = append(*g, err) *g = append(*g, err)
} }
// ErrorState represents a valid client state indicating that the client has
// hit an error. On tick, the client will be disconnected. ErrorState is both
// a valid ConnectionState and a valid error value.
type ErrorState struct {
CommandSuite
error
NopEnter
NopExit
}
func NewErrorState(e error) *ErrorState {
return &ErrorState{error: e}
}
func (e *ErrorState) Tick(c *Connection, frame int64) ConnectionState {
c.Printf("something went wrong: %v", e.error)
log_error("player hit error: %v", e.error)
c.Close()
return nil
}
func (e *ErrorState) String() string {
return fmt.Sprintf("error state: %v", e.error)
}
func (e *ErrorState) RunCommand(c *Connection, name string, args ...string) ConnectionState {
return e
}

@ -0,0 +1,79 @@
package main
import (
"fmt"
)
var idleCommands = CommandSet{
balCommand,
commandsCommand,
helpCommand,
playersCommand,
}
type IdleState struct {
CommandSuite
*System
}
func Idle(sys *System) ConnectionState {
return &IdleState{idleCommands, sys}
}
func (i *IdleState) String() string {
return fmt.Sprintf("idle on %v", i.System)
}
func (i *IdleState) Enter(c *Connection) {
c.Printf("You have landed on %v.\n", i.System)
}
func (i *IdleState) Tick(c *Connection, frame int64) ConnectionState {
return i
}
func (i *IdleState) Exit(c *Connection) {
c.Printf("Now leaving %v.\n", i.System)
}
func (i *IdleState) travelTo(c *Connection, args ...string) {
dest, err := GetSystem(args[0])
if err != nil {
c.Printf("%v\n", err)
return
}
c.SetState(NewTravel(c, i.System, dest))
}
func (i *IdleState) GetCommand(name string) *Command {
return idleCommands.GetCommand(name)
}
// func (i *IdleState) RunCommand(c *Connection, name string, args ...string) ConnectionState {
// switch name {
// case "goto":
// dest, err := GetSystem(args[0])
// if err != nil {
// c.Printf("%v\n", err)
// break
// }
// return NewTravel(c, i.System, dest)
// case "nearby":
// neighbors, err := i.Nearby(25)
// if err != nil {
// log_error("unable to get neighbors: %v", err)
// break
// }
// c.Printf("--------------------------------------------------------------------------------\n")
// c.Printf("%-4s %-20s %s\n", "id", "name", "distance")
// c.Printf("--------------------------------------------------------------------------------\n")
// for _, neighbor := range neighbors {
// other := index[neighbor.id]
// c.Printf("%-4d %-20s %v\n", other.id, other.name, neighbor.distance)
// }
// c.Printf("--------------------------------------------------------------------------------\n")
// default:
// c.Printf("No such command: %v\n", name)
// }
// return i
// }

@ -11,15 +11,18 @@ import (
) )
var options struct { var options struct {
lightSpeed float64 bombSpeed float64
frameRate int debug bool
moneySigma float64 economic int
moneyMean float64 frameRate int
playerSpeed float64 frameLength time.Duration
bombSpeed float64 lightSpeed float64
economic int moneyMean float64
debug bool moneySigma float64
speckPath string playerSpeed float64
respawnTime time.Duration
respawnFrames int64
speckPath string
} }
var ( var (
@ -49,37 +52,30 @@ func handleConnection(conn *Connection) {
defer conn.Close() defer conn.Close()
conn.Login() conn.Login()
conn.Respawn()
c := make(chan []string) c := make(chan []string)
go conn.ReadLines(c) go conn.ReadLines(c)
for parts := range c { for parts := range c {
if isCommand(parts[0]) { conn.RunCommand(parts[0], parts[1:]...)
runCommand(conn, parts[0], parts[1:]...)
continue
}
switch parts[0] {
case "quit":
return
default:
conn.Printf("hmm I'm not sure I know that one.\n")
}
} }
} }
// converts a duration in human time to a number of in-game frames
func durToFrames(dur time.Duration) int64 {
return int64(dur / options.frameLength)
}
func main() { func main() {
flag.Parse() flag.Parse()
dbconnect() dbconnect()
options.frameLength = time.Second / time.Duration(options.frameRate)
options.respawnFrames = durToFrames(options.respawnTime)
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
info_log = log.New(os.Stdout, "[INFO] ", 0) info_log = log.New(os.Stdout, "[INFO] ", 0)
error_log = log.New(os.Stderr, "[ERROR] ", 0) error_log = log.New(os.Stderr, "[ERROR] ", 0)
setupDb() setupDb()
setupCommands()
listener, err := net.Listen("tcp", ":9220") listener, err := net.Listen("tcp", ":9220")
if err != nil { if err != nil {
bail(E_No_Port, "unable to start server: %v", err) bail(E_No_Port, "unable to start server: %v", err)
@ -113,4 +109,5 @@ func init() {
flag.Float64Var(&options.moneySigma, "money-sigma", 1500, "standard deviation in money per system") flag.Float64Var(&options.moneySigma, "money-sigma", 1500, "standard deviation in money per system")
flag.BoolVar(&options.debug, "debug", false, "puts the game in debug mode") flag.BoolVar(&options.debug, "debug", false, "puts the game in debug mode")
flag.StringVar(&options.speckPath, "speck-path", "/projects/exo/expl.speck", "path to exoplanet speck file") flag.StringVar(&options.speckPath, "speck-path", "/projects/exo/expl.speck", "path to exoplanet speck file")
flag.DurationVar(&options.respawnTime, "respawn-time", 60*time.Second, "time for player respawn")
} }

@ -0,0 +1,43 @@
package main
import (
"fmt"
)
type MiningState struct {
CommandSuite
sys *System
mined int
}
func Mine(sys *System) ConnectionState {
return &MiningState{sys: sys}
}
func (m *MiningState) Enter(c *Connection) {
c.Printf("Mining %v. %v space duckets remaining.\n", m.sys, m.sys.money)
}
func (m *MiningState) Tick(c *Connection, frame int64) ConnectionState {
if m.sys.money <= 0 {
c.Printf("system %s is all out of space duckets.\n", m.sys)
return Idle(m.sys)
} else {
c.Deposit(1)
m.mined += 1
m.sys.money -= 1
return m
}
}
func (m *MiningState) Exit(c *Connection) {
if m.sys.money == 0 {
c.Printf("Done mining %v. Mined %v space duckets total. %v space duckets remain on %v, and it can be mined again.", m.sys, m.mined, m.sys.money, m.sys)
} else {
c.Printf("Done mining %v. Mined %v space duckets total. No space duckets remain on %v, and it can't be mined again.", m.sys, m.mined, m.sys)
}
}
func (m *MiningState) String() string {
return fmt.Sprintf("mining %v", m.sys)
}

@ -70,7 +70,7 @@ func (s *scan) hits() {
} }
func (s *scan) hitSystem(sys *System, dist float64) scanResult { func (s *scan) hitSystem(sys *System, dist float64) scanResult {
sys.NotifyInhabitants("scan detected from %s\n", s.origin.Label()) sys.NotifyInhabitants("scan detected from %v\n", s.origin)
r := scanResult{ r := scanResult{
system: sys, system: sys,
colonizedBy: sys.colonizedBy, colonizedBy: sys.colonizedBy,
@ -95,7 +95,7 @@ func (s *scan) echos() {
if res.Empty() { if res.Empty() {
continue continue
} }
s.origin.NotifyInhabitants("results from scan of %s:\n", res.system.Label()) s.origin.NotifyInhabitants("results from scan of %v:\n", res.system)
s.origin.NotifyInhabitants("\tdistance: %v\n", s.origin.DistanceTo(res.system)) s.origin.NotifyInhabitants("\tdistance: %v\n", s.origin.DistanceTo(res.system))
inhabitants := res.playerNames() inhabitants := res.playerNames()
if inhabitants != nil { if inhabitants != nil {

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"math" "math"
"math/rand" "math/rand"
"strconv"
"time" "time"
) )
@ -24,6 +25,22 @@ type System struct {
money int64 money int64
} }
func GetSystem(id string) (*System, error) {
idNum, err := strconv.Atoi(id)
if err == nil {
sys, ok := index[idNum]
if !ok {
return nil, fmt.Errorf("No such system: %v", idNum)
}
return sys, nil
}
sys, ok := nameIndex[id]
if !ok {
return nil, fmt.Errorf("No such system: %v", id)
}
return sys, nil
}
func (s *System) Tick(frame int64) { func (s *System) Tick(frame int64) {
if s.colonizedBy != nil { if s.colonizedBy != nil {
s.colonizedBy.Deposit(1) s.colonizedBy.Deposit(1)
@ -40,22 +57,22 @@ func (s *System) Reset() {
} }
func (s *System) Arrive(conn *Connection) { func (s *System) Arrive(conn *Connection) {
conn.SetSystem(s) // conn.SetSystem(s)
log_info("player %s has arrived at system %s", conn.Name(), s.Label()) log_info("player %s has arrived at system %v", conn.Name(), s)
if s.players == nil { if s.players == nil {
s.players = make(map[*Connection]bool, 8) s.players = make(map[*Connection]bool, 8)
} }
s.players[conn] = true s.players[conn] = true
if s.planets == 1 { if s.planets == 1 {
conn.Printf("you are in the system %s. There is %d planet here.\n", s.Label(), s.planets) conn.Printf("you are in the system %v. There is %d planet here.\n", s, s.planets)
} else { } else {
conn.Printf("you are in the system %s. There are %d planets here.\n", s.Label(), s.planets) conn.Printf("you are in the system %v. There are %d planets here.\n", s, s.planets)
} }
} }
func (s *System) Leave(p *Connection) { func (s *System) Leave(p *Connection) {
delete(s.players, p) delete(s.players, p)
p.location = nil // p.location = nil
} }
func (s *System) NotifyInhabitants(template string, args ...interface{}) { func (s *System) NotifyInhabitants(template string, args ...interface{}) {
@ -146,7 +163,7 @@ func (s *System) Distances() []Ray {
func (s *System) Bombed(bomber *Connection) { func (s *System) Bombed(bomber *Connection) {
s.EachConn(func(conn *Connection) { s.EachConn(func(conn *Connection) {
conn.Die() // conn.Die()
bomber.MadeKill(conn) bomber.MadeKill(conn)
}) })
if s.colonizedBy != nil { if s.colonizedBy != nil {
@ -174,15 +191,10 @@ func bombNotice(to_id, from_id int) {
}) })
} }
// for players to read. func (s System) String() string {
func (s System) Label() string {
return fmt.Sprintf("%s (id: %v)", s.name, s.id) return fmt.Sprintf("%s (id: %v)", s.name, s.id)
} }
func (e System) String() string {
return fmt.Sprintf("<name: %s x: %v y: %v z: %v planets: %v>", e.name, e.x, e.y, e.z, e.planets)
}
type Neighbor struct { type Neighbor struct {
id int id int
distance float64 distance float64
@ -247,7 +259,7 @@ func indexSystems() map[int]*System {
index[p.id] = &p index[p.id] = &p
nameIndex[p.name] = &p nameIndex[p.name] = &p
p.money = int64(rand.NormFloat64()*options.moneySigma + options.moneyMean) p.money = int64(rand.NormFloat64()*options.moneySigma + options.moneyMean)
log_info("seeded system %s with %v monies", p.Label(), p.money) log_info("seeded system %v with %v monies", p, p.money)
} }
return index return index
} }
@ -257,8 +269,7 @@ func randomSystem() (*System, error) {
if n == 0 { if n == 0 {
return nil, fmt.Errorf("no planets are known to exist") return nil, fmt.Errorf("no planets are known to exist")
} }
pick := rand.Intn(n) pick := rand.Intn(n)
planet := index[pick] sys := index[pick]
return planet, nil return sys, nil
} }

@ -0,0 +1,41 @@
package main
import (
"fmt"
)
type TravelState struct {
CommandSuite
start *System
dest *System
travelled float64
dist float64
}
func NewTravel(c *Connection, start, dest *System) ConnectionState {
return &TravelState{
start: start,
dest: dest,
dist: start.DistanceTo(dest),
}
}
func (t *TravelState) Enter(c *Connection) {
c.Printf("Leaving %v, bound for %v.\n", t.start, t.dest)
}
func (t *TravelState) Tick(c *Connection, frame int64) ConnectionState {
t.travelled += options.playerSpeed * options.lightSpeed
if t.travelled >= t.dist {
return Idle(t.dest)
}
return t
}
func (t *TravelState) Exit(c *Connection) {
c.Printf("You have arrived at %v.\n", t.dest)
}
func (t *TravelState) String() string {
return fmt.Sprintf("Traveling from %v to %v", t.start, t.dest)
}
Loading…
Cancel
Save