diff --git a/bomb.go b/bomb.go index 26a4ba6..90d2819 100644 --- a/bomb.go +++ b/bomb.go @@ -78,21 +78,23 @@ func (m *MakeBombState) Tick(c *Connection, frame int64) ConnectionState { return m } +func (MakeBombState) String() string { return "Making a Bomb" } + func (m *MakeBombState) Exit(c *Connection) { c.bombs += 1 c.Printf("Done! You now have %v bombs.\n", c.bombs) } -func (m *MakeBombState) PrintStatus(c *Connection) { +func (m *MakeBombState) FillStatus(c *Connection, s *status) { elapsedFrames := c.game.frame - m.start elapsedDur := framesToDur(elapsedFrames) - msg := fmt.Sprintf(` + desc := fmt.Sprintf(` Currently making a bomb! -Current System: %s Build time elapsed: %v Build time remaining: %v -`, m.System, elapsedDur, options.makeBombTime-elapsedDur) - c.Printf(strings.TrimSpace(msg)) +`, elapsedDur, options.makeBombTime-elapsedDur) + s.Description = strings.TrimSpace(desc) + s.Location = m.System.String() } diff --git a/colony.go b/colony.go index 104b09b..bcdfcb0 100644 --- a/colony.go +++ b/colony.go @@ -49,6 +49,6 @@ func (m *MakeColonyState) Exit(c *Connection) { c.Printf("Established colony on %v.\n", m.System) } -func (m *MakeColonyState) PrintStatus(c *Connection) { - panic("not done") +func (m *MakeColonyState) FillStatus(c *Connection, s *status) { + s.Location = m.System.String() } diff --git a/commands.go b/commands.go index 6039470..9fa5e69 100644 --- a/commands.go +++ b/commands.go @@ -6,11 +6,42 @@ import ( "text/template" ) +var helpTemplate = template.Must(template.New("help").Parse(` +{{.Name}} Command Reference + + Summary: {{.Summary}} +{{- if .Usage}} + Usage: {{.Usage}} +{{end}} +{{- if .Description}} +Details: + + {{.Description}} +{{end}} +`)) + +func printHelp(conn *Connection, cmd *Command) { + desc := strings.ReplaceAll(strings.TrimSpace(cmd.help), "\n", "\n ") + helpTemplate.Execute(conn, struct { + Name string + Summary string + Usage string + Description string + }{ + Name: cmd.name, + Summary: cmd.summary, + Usage: cmd.usage, + Description: desc, + }) +} + var commandRegistry map[string]*Command type Command struct { name string summary string + usage string + help string arity int variadic bool handler func(*Connection, ...string) @@ -58,7 +89,14 @@ func (c CommandSet) Commands() []Command { var helpCommand = Command{ name: "help", - summary: "helpful things to help you", + summary: "explains how to play the game", + usage: "help [command-name]", + help: ` +help explains the usage of various commands in Exocolonus. On its own, the help +command displays some basic info about how the game is played. If given an +argument of a command name, the help command displays the detailed usage of the +specified command. +`, handler: func(conn *Connection, args ...string) { msg := ` Exocolonus is a game of cunning text-based, real-time strategy. You play as @@ -98,14 +136,14 @@ are farther away take longer to communicate with. conn.Printf("no such command: %v\n", cmdName) continue } - conn.Printf("%v: %v\n", cmdName, cmd.summary) + printHelp(conn, cmd) } }, } type status struct { - GameCode string State string + GameCode string Balance int Bombs int Kills int @@ -114,13 +152,15 @@ type status struct { } var statusTemplate = template.Must(template.New("status").Parse(` +Current State: {{.State}} -------------------------------------------------------------------------------- +{{- if .GameCode}} Current Game: {{.GameCode}} -Current State: {{.State}} Balance: {{.Balance}} Bombs: {{.Bombs}} Kills: {{.Kills}} Location: {{.Location}} +{{end}} {{.Description}} @@ -130,7 +170,17 @@ var statusCommand = Command{ name: "status", summary: "display your current status", handler: func(conn *Connection, args ...string) { - conn.ConnectionState.PrintStatus(conn) + s := status{ + State: conn.ConnectionState.String(), + } + conn.ConnectionState.FillStatus(conn, &s) + if conn.game != nil { + s.GameCode = conn.game.id + s.Balance = conn.money + s.Bombs = conn.bombs + s.Kills = conn.kills + } + statusTemplate.Execute(conn, s) }, } @@ -138,7 +188,7 @@ var statusCommand = Command{ // is weird and circular, this is a special case. var commandsCommand = Command{ name: "commands", - summary: "gives you a handy list of commands", + summary: "lists currently available commands", } func BroadcastCommand(sys *System) Command { diff --git a/connection.go b/connection.go index 987c74e..8f894d8 100644 --- a/connection.go +++ b/connection.go @@ -209,7 +209,7 @@ func (c *Connection) Die(frame int64) { type ConnectionState interface { CommandSuite String() string - PrintStatus(c *Connection) + FillStatus(*Connection, *status) Enter(c *Connection) Tick(c *Connection, frame int64) ConnectionState Exit(c *Connection) diff --git a/dead.go b/dead.go index 6c241c1..df92d75 100644 --- a/dead.go +++ b/dead.go @@ -26,10 +26,6 @@ func (d *DeadState) Exit(c *Connection) { c.Printf("You're alive again.\n") } -func (d *DeadState) String() string { - return "dead" -} +func (d *DeadState) String() string { return "dead" } -func (d *DeadState) PrintStatus(c *Connection) { - panic("not done") -} +func (d *DeadState) FillStatus(c *Connection, s *status) {} diff --git a/errors.go b/errors.go index 2cdecba..7b1c8fb 100644 --- a/errors.go +++ b/errors.go @@ -63,6 +63,4 @@ func (e *ErrorState) RunCommand(c *Connection, name string, args ...string) Conn return e } -func (e *ErrorState) PrintStatus(c *Connection) { - panic("not done") -} +func (e *ErrorState) FillStatus(c *Connection, s *status) {} diff --git a/idle.go b/idle.go index c871419..76f9fcd 100644 --- a/idle.go +++ b/idle.go @@ -28,6 +28,7 @@ func Idle(sys *System) ConnectionState { name: "bomb", summary: "bomb another star system", arity: 1, + usage: "bomb [system-name or system-id]", handler: i.bomb, }, Command{ @@ -36,12 +37,6 @@ func Idle(sys *System) ConnectionState { arity: 0, handler: i.mine, }, - Command{ - name: "info", - summary: "gives you information about the current star system", - arity: 0, - handler: i.info, - }, Command{ name: "scan", summary: "scans the galaxy for signs of life", @@ -104,11 +99,6 @@ func (i *IdleState) mine(c *Connection, args ...string) { c.SetState(Mine(i.System)) } -func (i *IdleState) info(c *Connection, args ...string) { - c.Printf("Currently idle on system %v\n", i.System) - c.Printf("Space duckets available: %v\n", i.money) -} - func (i *IdleState) scan(c *Connection, args ...string) { if time.Since(c.lastScan) < 1*time.Minute { return @@ -119,6 +109,10 @@ func (i *IdleState) scan(c *Connection, args ...string) { // "make" is already a keyword func (i *IdleState) maek(c *Connection, args ...string) { + if len(args) != 1 { + c.Printf("not sure what to do! Expecting a command like this: make [thing]\ne.g.:\nmake bomb\nmake colony") + return + } switch args[0] { case "bomb": if c.money < options.bombCost { @@ -136,6 +130,7 @@ func (i *IdleState) maek(c *Connection, args ...string) { } } -func (i *IdleState) PrintStatus(c *Connection) { - panic("not done") +func (i *IdleState) FillStatus(c *Connection, s *status) { + s.Location = i.System.String() + s.Description = "Just hanging out, enjoying outer space." } diff --git a/lobby.go b/lobby.go index 6fff04f..6781890 100644 --- a/lobby.go +++ b/lobby.go @@ -84,7 +84,7 @@ func (st *LobbyState) Enter(c *Connection) { c.profile = profile } else { c.profile = profile - c.Printf("welcome back, %s.\n", profile.name) + c.Printf("Welcome back, %s.\n", profile.name) } break } @@ -93,8 +93,11 @@ func (st *LobbyState) Enter(c *Connection) { func (st *LobbyState) Tick(c *Connection, frame int64) ConnectionState { return st } -func (st *LobbyState) PrintStatus(c *Connection) { - panic("not done") +func (st *LobbyState) FillStatus(c *Connection, s *status) { + s.Description = strings.TrimSpace(` +Currently in the Lobby, waiting for you to issue a "new" command to start a new +game, or a "join" command to join an existing game. +`) } var newGameCommand = Command{ @@ -119,9 +122,18 @@ var newGameCommand = Command{ var joinGameCommand = Command{ name: "join", summary: "joins an existing game", + usage: "join [game-code]", arity: 1, variadic: false, handler: func(c *Connection, args ...string) { + if len(args) == 0 { + c.Printf(strings.TrimLeft(` +Missing game code! When a player starts a game, they will be given a code to +identify their game. Use this game to join the other player's game. + +Usage: join [game-code]`, " \n\t")) + return + } id := args[0] c.game = gm.Get(id) c.SetState(SpawnRandomly()) diff --git a/mining.go b/mining.go index 1ce0dcc..953e4d3 100644 --- a/mining.go +++ b/mining.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "strings" ) type MiningState struct { @@ -23,12 +24,6 @@ func Mine(sys *System) ConnectionState { arity: 0, handler: m.stop, }, - Command{ - name: "info", - summary: "gives you information about the current mining operation", - arity: 0, - handler: m.info, - }, } return m } @@ -65,12 +60,11 @@ func (m *MiningState) stop(c *Connection, args ...string) { c.SetState(Idle(m.System)) } -func (m *MiningState) info(c *Connection, args ...string) { - c.Printf("Currently mining system %v\n", m.System) - c.Printf("Mined so far: %v\n", m.mined) - c.Printf("Remaining space duckets on %v: %v\n", m.System, m.money) -} - -func (m *MiningState) PrintStatus(c *Connection) { - panic("not done") +func (m *MiningState) FillStatus(c *Connection, s *status) { + s.Location = m.System.String() + s.Description = strings.TrimSpace(fmt.Sprintf(` +Currently mining on system: %s +Mined so far: %d +Available space duckets: %d +`, m.System.String(), m.mined, m.money)) } diff --git a/shield.go b/shield.go index e564d91..5e483ca 100644 --- a/shield.go +++ b/shield.go @@ -46,8 +46,8 @@ func (m *MakeShieldState) String() string { return fmt.Sprintf("Making shield on %v", m.System) } -func (m *MakeShieldState) PrintStatus(c *Connection) { - panic("not done") +func (m *MakeShieldState) FillStatus(c *Connection, s *status) { + s.Location = m.System.String() } type Shield struct { diff --git a/travel.go b/travel.go index 67110ed..0828ed3 100644 --- a/travel.go +++ b/travel.go @@ -107,17 +107,8 @@ func (t *TravelState) String() string { return fmt.Sprintf("Traveling from %v to %v", t.start, t.dest) } -func (t *TravelState) PrintStatus(c *Connection) { - desc := fmt.Sprintf("Traveling from %v to %v", t.start, t.dest) - statusTemplate.Execute(c, status{ - GameCode: c.game.id, - State: "In Transit", - Balance: c.money, - Bombs: c.bombs, - Kills: c.kills, - Location: fmt.Sprintf("%s -> %s", t.start, t.dest), - Description: desc, - }) +func (t *TravelState) FillStatus(c *Connection, s *status) { + s.Location = fmt.Sprintf("between %s and %s", t.start, t.dest) } func (t *TravelState) progress(c *Connection, args ...string) {