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
}
func NewBomb(from *Connection, to *System) *Bomb {
origin := from.System()
dist := origin.DistanceTo(to)
func NewBomb(conn *Connection, from, to *System) *Bomb {
dist := from.DistanceTo(to)
fti := int64(dist / (options.lightSpeed * options.bombSpeed))
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{
profile: from,
origin: origin,
profile: conn,
origin: from,
target: to,
fti: fti,
start: time.Now(),
@ -38,10 +37,10 @@ func (b *Bomb) Tick(frame int64) {
if b.fti <= 0 {
b.target.Bombed(b.profile)
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 {
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 {
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 {
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 (
"fmt"
"sort"
"strconv"
// "strconv"
"strings"
)
var commandRegistry map[string]*Command
type Command struct {
name string
help string
handler func(*Connection, ...string)
mobile bool
debug bool // marks command as a debug mode command
name string
help string
arity int
variadic bool
handler func(*Connection, ...string)
debug bool // marks command as a debug mode command
}
var infoCommand = &Command{
name: "info",
help: "gives you some info about your current position",
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)
},
type CommandSuite interface {
GetCommand(name string) *Command
Commands() []Command
}
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)
func (c Command) GetCommand(name string) *Command {
if name == c.name {
return &c
}
return nil
}
func (c Command) Commands() []Command {
return []Command{c}
}
type CommandSet []Command
func (c CommandSet) GetCommand(name string) *Command {
for _, cmd := range c {
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",
help: "helpful things to help you",
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",
help: "gives you a handy list of commands",
handler: func(conn *Connection, args ...string) {
@ -111,84 +157,84 @@ var commandsCommand = &Command{
},
}
var scanCommand = &Command{
name: "scan",
help: "super duper scan",
handler: func(conn *Connection, args ...string) {
if !conn.CanScan() {
conn.Printf("scanners are still recharging. Can scan again in %v\n", conn.NextScan())
return
}
currentGame.Register(NewScan(conn.System()))
conn.RecordScan()
},
}
var broadcastCommand = &Command{
name: "broadcast",
help: "broadcast a message for all systems to hear",
handler: func(conn *Connection, args ...string) {
msg := strings.Join(args, " ")
system := conn.System()
b := NewBroadcast(system, msg)
log_info("player %s send broadcast from system %s: %v\n", conn.Name(), system.Label(), msg)
currentGame.Register(b)
},
}
var gotoCommand = &Command{
name: "goto",
help: "moves to a different system, specified by either name or ID",
handler: func(conn *Connection, args ...string) {
dest_name := strings.Join(args, " ")
to, ok := nameIndex[dest_name]
if ok {
conn.TravelTo(to)
return
}
id_n, err := strconv.Atoi(dest_name)
if err != nil {
conn.Printf(`hmm, I don't know a system by the name "%s", try something else`, dest_name)
return
}
to, ok = index[id_n]
if !ok {
conn.Printf(`oh dear, there doesn't seem to be a system with id %d`, id_n)
return
}
conn.TravelTo(to)
},
}
var mineCommand = &Command{
name: "mine",
help: "mines the current system for resources",
handler: func(conn *Connection, args ...string) {
conn.Mine()
},
}
var colonizeCommand = &Command{
name: "colonize",
help: "establishes a mining colony on the current system",
handler: func(conn *Connection, arg ...string) {
system := conn.System()
if conn.money > 2000 {
conn.Withdraw(2000)
if system.colonizedBy != nil {
system.colonizedBy.Printf("your colony on %s has been stolen by %s\n", system.Label(), conn.Name())
}
system.colonizedBy = conn
conn.Printf("set up a mining colony on %s\n", conn.System().name)
} else {
conn.Printf("not enough money! it costs 2000 duckets to start a mining colony\n")
}
},
}
var winCommand = &Command{
// var scanCommand = &Command{
// name: "scan",
// help: "super duper scan",
// handler: func(conn *Connection, args ...string) {
// if !conn.CanScan() {
// conn.Printf("scanners are still recharging. Can scan again in %v\n", conn.NextScan())
// return
// }
// currentGame.Register(NewScan(conn.System()))
// conn.RecordScan()
// },
// }
// var broadcastCommand = &Command{
// name: "broadcast",
// help: "broadcast a message for all systems to hear",
// handler: func(conn *Connection, args ...string) {
// msg := strings.Join(args, " ")
// system := conn.System()
// b := NewBroadcast(system, msg)
// log_info("player %s send broadcast from system %s: %v\n", conn.Name(), system.Label(), msg)
// currentGame.Register(b)
// },
// }
// var gotoCommand = &Command{
// name: "goto",
// help: "moves to a different system, specified by either name or ID",
// handler: func(conn *Connection, args ...string) {
// dest_name := strings.Join(args, " ")
// to, ok := nameIndex[dest_name]
// if ok {
// conn.TravelTo(to)
// return
// }
//
// id_n, err := strconv.Atoi(dest_name)
// if err != nil {
// conn.Printf(`hmm, I don't know a system by the name "%s", try something else`, dest_name)
// return
// }
//
// to, ok = index[id_n]
// if !ok {
// conn.Printf(`oh dear, there doesn't seem to be a system with id %d`, id_n)
// return
// }
// conn.TravelTo(to)
// },
// }
// var mineCommand = &Command{
// name: "mine",
// help: "mines the current system for resources",
// handler: func(conn *Connection, args ...string) {
// conn.Mine()
// },
// }
// var colonizeCommand = &Command{
// name: "colonize",
// help: "establishes a mining colony on the current system",
// handler: func(conn *Connection, arg ...string) {
// system := conn.System()
// if conn.money > 2000 {
// conn.Withdraw(2000)
// if system.colonizedBy != nil {
// system.colonizedBy.Printf("your colony on %s has been stolen by %s\n", system.Label(), conn.Name())
// }
// system.colonizedBy = conn
// conn.Printf("set up a mining colony on %s\n", conn.System().name)
// } else {
// conn.Printf("not enough money! it costs 2000 duckets to start a mining colony\n")
// }
// },
// }
var winCommand = Command{
name: "win",
help: "win the game.",
debug: true,
@ -197,49 +243,49 @@ var winCommand = &Command{
},
}
var bombCommand = &Command{
name: "bomb",
help: "bombs a system, with a big space bomb",
handler: func(conn *Connection, args ...string) {
dest_name := strings.Join(args, " ")
to, ok := nameIndex[dest_name]
if ok {
conn.SendBomb(to)
return
}
id_n, err := strconv.Atoi(dest_name)
if err != nil {
conn.Printf(`hmm, I don't know a system by the name "%s", try something else\n`, dest_name)
return
}
to, ok = index[id_n]
if !ok {
conn.Printf(`oh dear, there doesn't seem to be a system with id %d\n`, id_n)
return
}
conn.SendBomb(to)
},
}
var mkBombCommand = &Command{
name: "mkbomb",
help: "make a bomb. Costs 500 space duckets",
handler: func(conn *Connection, args ...string) {
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)
return
}
conn.Withdraw(500)
conn.bombs += 1
conn.Printf("built a bomb!\n")
conn.Printf("bombs: %d\n", conn.bombs)
conn.Printf("money: %d space duckets\n", conn.money)
},
}
var playersCommand = &Command{
// var bombCommand = &Command{
// name: "bomb",
// help: "bombs a system, with a big space bomb",
// handler: func(conn *Connection, args ...string) {
// dest_name := strings.Join(args, " ")
// to, ok := nameIndex[dest_name]
// if ok {
// conn.SendBomb(to)
// return
// }
//
// id_n, err := strconv.Atoi(dest_name)
// if err != nil {
// conn.Printf(`hmm, I don't know a system by the name "%s", try something else\n`, dest_name)
// return
// }
//
// to, ok = index[id_n]
// if !ok {
// conn.Printf(`oh dear, there doesn't seem to be a system with id %d\n`, id_n)
// return
// }
// conn.SendBomb(to)
// },
// }
// var mkBombCommand = &Command{
// name: "mkbomb",
// help: "make a bomb. Costs 500 space duckets",
// handler: func(conn *Connection, args ...string) {
// 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)
// return
// }
// conn.Withdraw(500)
// conn.bombs += 1
// conn.Printf("built a bomb!\n")
// conn.Printf("bombs: %d\n", conn.bombs)
// conn.Printf("money: %d space duckets\n", conn.money)
// },
// }
var playersCommand = Command{
name: "players",
help: "lists the connected players",
handler: func(conn *Connection, args ...string) {
@ -249,69 +295,10 @@ var playersCommand = &Command{
},
}
var balCommand = &Command{
var balCommand = Command{
name: "bal",
help: "displays your current balance in space duckets",
handler: func(conn *Connection, args ...string) {
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 {
net.Conn
*bufio.Reader
profile *Profile
location *System
dest *System
travelRemaining int64
lastScan time.Time
lastBomb time.Time
kills int
dead bool
money int
colonies []*System
bombs int
state PlayerState // this is wrong...
net.Conn
ConnectionState
bombs int
colonies []*System
kills int
lastBomb time.Time
lastScan time.Time
money int
profile *Profile
}
type PlayerState int
const (
idle PlayerState = iota
dead
inTransit
mining
)
func NewConnection(conn net.Conn) *Connection {
c := &Connection{
Conn: conn,
Reader: bufio.NewReader(conn),
bombs: 1,
}
c.SetState(SpawnRandomly())
currentGame.Join(c)
return c
}
@ -84,59 +72,59 @@ func (c *Connection) Dead() bool {
}
func (c *Connection) Tick(frame int64) {
// fuck
switch c.state {
case idle:
case dead:
case inTransit:
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)
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))
}
func (c *Connection) TravelTo(dest *System) {
dist := c.System().DistanceTo(dest)
c.travelRemaining = int64(dist / (options.lightSpeed * options.playerSpeed))
t := time.Duration(c.travelRemaining) * (time.Second / time.Duration(options.frameRate))
c.Printf("traveling to: %s. ETA: %v\n", dest.Label(), t)
c.location.Leave(c)
c.location = nil
c.dest = dest
c.state = inTransit // fuck everything about this
func (c *Connection) RunCommand(name string, args ...string) {
defer func() {
if r := recover(); r != nil {
c.Printf("shit is *really* fucked up.")
log_error("recovered: %v", r)
}
}()
cmd := c.GetCommand(name)
if cmd == nil {
c.Printf("No such command: %v\n", name)
return
}
cmd.handler(c, args...)
}
func (c *Connection) SendBomb(target *System) {
if c.bombs <= 0 {
fmt.Fprintln(c, "cannot send bomb: no bombs left")
func (c *Connection) SetState(s ConnectionState) {
if c.ConnectionState == s {
return
}
if time.Since(c.lastBomb) < 5*time.Second {
fmt.Fprintln(c, "cannod send bomb: bombs are reloading")
return
log_info("set state: %v", s)
if c.ConnectionState != nil {
log_info("exit state: %v", c.ConnectionState)
c.ConnectionState.Exit(c)
}
c.bombs -= 1
c.lastBomb = time.Now()
bomb := NewBomb(c, target)
currentGame.Register(bomb)
c.Printf("sending bomb to system %v\n", target.Label())
}
log_info("enter state: %v", s)
s.Enter(c)
c.ConnectionState = s
}
// 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) {
defer close(out)
@ -164,22 +152,6 @@ func (c *Connection) Printf(template string, args ...interface{}) (int, error) {
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 {
log_info("player disconnecting: %s", c.Name())
currentGame.Quit(c)
@ -196,10 +168,6 @@ func (c *Connection) Name() string {
return c.profile.name
}
func (c *Connection) InTransit() bool {
return c.location == nil
}
func (c *Connection) RecordScan() {
fmt.Fprintln(c, "scanning known systems for signs of life")
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) {
c.money -= n
}
@ -273,25 +221,30 @@ func (c *Connection) Win(method string) {
currentGame.Win(c, method)
}
func (c *Connection) Die() {
c.Printf("you were bombed. You will respawn in 1 minutes.\n")
c.dead = true
c.System().Leave(c)
time.AfterFunc(30*time.Second, func() {
c.Printf("respawn in 30 seconds.\n")
})
time.AfterFunc(time.Minute, c.Respawn)
type ConnectionState interface {
CommandSuite
String() string
Enter(c *Connection)
Tick(c *Connection, frame int64) ConnectionState
Exit(c *Connection)
}
func (c *Connection) Respawn() {
c.dead = false
// No-op enter struct, for composing connection states that have no interesitng
// Enter mechanic.
type NopEnter struct{}
WUT:
s, err := randomSystem()
func (n NopEnter) Enter(c *Connection) {}
// 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 {
log_error("error in respawn: %v", err)
goto WUT
return NewErrorState(fmt.Errorf("unable to create idle state: %v", err))
}
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
import (
"fmt"
"strings"
)
@ -9,6 +10,7 @@ const (
E_No_Data
E_No_DB
E_No_Port
E_Bad_Duration
)
type errorGroup []error
@ -31,3 +33,32 @@ func (g *errorGroup) AddError(err error) {
}
*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 {
lightSpeed float64
frameRate int
moneySigma float64
moneyMean float64
playerSpeed float64
bombSpeed float64
economic int
debug bool
speckPath string
bombSpeed float64
debug bool
economic int
frameRate int
frameLength time.Duration
lightSpeed float64
moneyMean float64
moneySigma float64
playerSpeed float64
respawnTime time.Duration
respawnFrames int64
speckPath string
}
var (
@ -49,37 +52,30 @@ func handleConnection(conn *Connection) {
defer conn.Close()
conn.Login()
conn.Respawn()
c := make(chan []string)
go conn.ReadLines(c)
for parts := range c {
if isCommand(parts[0]) {
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")
}
conn.RunCommand(parts[0], parts[1:]...)
}
}
// 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() {
flag.Parse()
dbconnect()
options.frameLength = time.Second / time.Duration(options.frameRate)
options.respawnFrames = durToFrames(options.respawnTime)
rand.Seed(time.Now().UnixNano())
info_log = log.New(os.Stdout, "[INFO] ", 0)
error_log = log.New(os.Stderr, "[ERROR] ", 0)
setupDb()
setupCommands()
listener, err := net.Listen("tcp", ":9220")
if err != nil {
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.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.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 {
sys.NotifyInhabitants("scan detected from %s\n", s.origin.Label())
sys.NotifyInhabitants("scan detected from %v\n", s.origin)
r := scanResult{
system: sys,
colonizedBy: sys.colonizedBy,
@ -95,7 +95,7 @@ func (s *scan) echos() {
if res.Empty() {
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))
inhabitants := res.playerNames()
if inhabitants != nil {

@ -5,6 +5,7 @@ import (
"fmt"
"math"
"math/rand"
"strconv"
"time"
)
@ -24,6 +25,22 @@ type System struct {
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) {
if s.colonizedBy != nil {
s.colonizedBy.Deposit(1)
@ -40,22 +57,22 @@ func (s *System) Reset() {
}
func (s *System) Arrive(conn *Connection) {
conn.SetSystem(s)
log_info("player %s has arrived at system %s", conn.Name(), s.Label())
// conn.SetSystem(s)
log_info("player %s has arrived at system %v", conn.Name(), s)
if s.players == nil {
s.players = make(map[*Connection]bool, 8)
}
s.players[conn] = true
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 {
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) {
delete(s.players, p)
p.location = nil
// p.location = nil
}
func (s *System) NotifyInhabitants(template string, args ...interface{}) {
@ -146,7 +163,7 @@ func (s *System) Distances() []Ray {
func (s *System) Bombed(bomber *Connection) {
s.EachConn(func(conn *Connection) {
conn.Die()
// conn.Die()
bomber.MadeKill(conn)
})
if s.colonizedBy != nil {
@ -174,15 +191,10 @@ func bombNotice(to_id, from_id int) {
})
}
// for players to read.
func (s System) Label() string {
func (s System) String() string {
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 {
id int
distance float64
@ -247,7 +259,7 @@ func indexSystems() map[int]*System {
index[p.id] = &p
nameIndex[p.name] = &p
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
}
@ -257,8 +269,7 @@ func randomSystem() (*System, error) {
if n == 0 {
return nil, fmt.Errorf("no planets are known to exist")
}
pick := rand.Intn(n)
planet := index[pick]
return planet, nil
sys := index[pick]
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