forked from tildetown/town
port to sceneManager, IRC feedback
parent
cb83223ab8
commit
86dc9cef2d
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -15,9 +16,6 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
// TODO remove sidebar
|
||||
// TODO add /help
|
||||
|
||||
const (
|
||||
maxInputLength = 10000
|
||||
logDir = "/town/var/signups/log"
|
||||
|
@ -27,7 +25,59 @@ type scene struct {
|
|||
Name string
|
||||
Description string
|
||||
Host *character
|
||||
Write func([]byte)
|
||||
SorryMsg string
|
||||
Input *bytes.Buffer
|
||||
OnAdvance func(*scene)
|
||||
}
|
||||
|
||||
func newScene(name, desc, sorryMsg string, host *character, onAdvance func(*scene)) *scene {
|
||||
return &scene{
|
||||
Name: name,
|
||||
Description: desc,
|
||||
SorryMsg: sorryMsg,
|
||||
Host: host,
|
||||
Input: bytes.NewBuffer([]byte{}),
|
||||
OnAdvance: onAdvance,
|
||||
}
|
||||
}
|
||||
|
||||
type sceneManager struct {
|
||||
scenes []*scene
|
||||
Current *scene
|
||||
index int
|
||||
output io.Writer
|
||||
Save func()
|
||||
}
|
||||
|
||||
func (m *sceneManager) Advance() bool {
|
||||
if m.Current.Name == "done" {
|
||||
return false
|
||||
}
|
||||
if m.Current.Input.Len() == 0 {
|
||||
fmt.Fprintln(m.output, m.Current.Host.Say(m.Current.SorryMsg))
|
||||
return false
|
||||
}
|
||||
m.Current.OnAdvance(m.Current)
|
||||
m.index++
|
||||
m.Current = m.scenes[m.index]
|
||||
if m.Current.Name == "done" {
|
||||
m.Save()
|
||||
}
|
||||
fmt.Fprintln(m.output, heredoc.Doc(`
|
||||
|
||||
[purple]----------[-:-:-]
|
||||
|
||||
`))
|
||||
fmt.Fprintln(m.output, m.Current.Description)
|
||||
return true
|
||||
}
|
||||
|
||||
func newSceneManager(output io.Writer, scenes []*scene) *sceneManager {
|
||||
return &sceneManager{
|
||||
output: output,
|
||||
scenes: scenes,
|
||||
Current: scenes[0],
|
||||
}
|
||||
}
|
||||
|
||||
type character struct {
|
||||
|
@ -47,7 +97,9 @@ func (c *character) Say(msg string) string {
|
|||
if c.Name == "you" {
|
||||
verb = "say"
|
||||
}
|
||||
return fmt.Sprintf("[-:-:b]%s[-:-:-] %s: '%s'",
|
||||
return fmt.Sprintf(`[-:-:b]%s %s:[-:-:-]
|
||||
%s
|
||||
`,
|
||||
c.Name,
|
||||
verb,
|
||||
strings.TrimSpace(msg))
|
||||
|
@ -80,10 +132,9 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
l.Println("starting a session")
|
||||
pages := tview.NewPages()
|
||||
mainFlex := tview.NewFlex()
|
||||
innerFlex := tview.NewFlex()
|
||||
input := tview.NewTextArea()
|
||||
input.SetBorder(true).SetBorderColor(tcell.ColorPaleTurquoise)
|
||||
input.SetTitle("press ctrl+d to send")
|
||||
input.SetTitle("press enter to send")
|
||||
input.SetMaxLength(2000)
|
||||
|
||||
title := tview.NewTextView()
|
||||
|
@ -91,37 +142,19 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
title.SetTextAlign(tview.AlignCenter)
|
||||
title.SetText("[purple]the tilde town sign up portal[-]")
|
||||
|
||||
footer := tview.NewTextView()
|
||||
footer.SetText("type /help and press enter to get help")
|
||||
|
||||
msgScroll := tview.NewTextView()
|
||||
msgScroll.SetDynamicColors(true)
|
||||
msgScroll.SetBackgroundColor(tcell.ColorBlack)
|
||||
msgScroll.SetTextColor(tcell.ColorWhite)
|
||||
|
||||
sidebar := tview.NewTextView()
|
||||
sidebar.SetBorder(true)
|
||||
sidebar.SetDynamicColors(true)
|
||||
sidebar.SetBackgroundColor(tcell.ColorBlack)
|
||||
sidebar.SetTextColor(tcell.ColorGray)
|
||||
sidebar.SetText(heredoc.Doc(`
|
||||
[-:-:b]hey here are some hints[-:-:-]
|
||||
|
||||
quit by pressing [-:-:b]ctrl-c[-:-:-]
|
||||
(your responses won't be saved)
|
||||
|
||||
type stuff. send it with [-:-:b]ctrl+d[-:-:-]
|
||||
|
||||
try a [-:-:b]verb[-:-:-] using [-:-:b]/[-:-:-] like:
|
||||
|
||||
[-:-:b]/nod[-:-:-]
|
||||
`))
|
||||
|
||||
innerFlex.SetDirection(tview.FlexColumn)
|
||||
innerFlex.AddItem(msgScroll, 0, 3, false)
|
||||
innerFlex.AddItem(sidebar, 0, 1, false)
|
||||
|
||||
mainFlex.SetDirection(tview.FlexRow)
|
||||
mainFlex.AddItem(title, 1, -1, false)
|
||||
mainFlex.AddItem(innerFlex, 0, 1, false)
|
||||
mainFlex.AddItem(input, 5, -1, true)
|
||||
mainFlex.AddItem(msgScroll, 0, 1, false)
|
||||
mainFlex.AddItem(input, 4, -1, true)
|
||||
mainFlex.AddItem(footer, 1, -1, false)
|
||||
|
||||
pages.AddPage("main", mainFlex, true, true)
|
||||
|
||||
|
@ -144,9 +177,7 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
}
|
||||
|
||||
scenes := []*scene{
|
||||
{
|
||||
Name: "start",
|
||||
Description: heredoc.Doc(`
|
||||
newScene("start", heredoc.Doc(`
|
||||
You open your eyes.
|
||||
|
||||
You're in some kind of workshop.
|
||||
|
@ -159,18 +190,15 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
[-:-:b]wire guy says:[-:-:-]
|
||||
hello, welcome to the application for membership in tilde town.
|
||||
first, please let me know what a good [-:-:b]email address[-:-:-] is for you?
|
||||
|
||||
just say it out loud. as many times as you need. to get it right.
|
||||
|
||||
when you're ready to move on, [-:-:b]/nod[-:-:-]
|
||||
once you've told me your email you can [-:-:b]/nod[-:-:-] to move on.
|
||||
`),
|
||||
Host: newCharacter("wire guy", "a lil homonculus made of discarded computer cables"),
|
||||
Write: func(b []byte) {
|
||||
su.Email = string(b)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "nodded",
|
||||
Description: heredoc.Doc(`
|
||||
"i'm sorry, before going further could you share an email with me?",
|
||||
newCharacter("wire guy", "a lil homonculus made of discarded computer cables"),
|
||||
func(s *scene) { su.Email = string(s.Input.Bytes()) }),
|
||||
newScene("how", heredoc.Doc(`
|
||||
The workshop fades away. You hear the sound of a dial up modem
|
||||
in the distance.
|
||||
|
||||
|
@ -185,17 +213,13 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
[-:-:b]the shrike says:[-:-:-]
|
||||
phweeturpff. how did you find out about the town? did anyone refer you?
|
||||
|
||||
just say your answer out loud. when you've said what you want, [-:-:b]/lean[-:-:-]
|
||||
against a tree.
|
||||
just say your answer out loud. when you've said what you want, [-:-:b]/nod[-:-:-]
|
||||
to continue.
|
||||
`),
|
||||
Write: func(b []byte) {
|
||||
su.How = string(b)
|
||||
},
|
||||
Host: newCharacter("the shrike", "a little grey bird. it has a pretty song."),
|
||||
},
|
||||
{
|
||||
Name: "leaned",
|
||||
Description: heredoc.Doc(`
|
||||
"phweeturpff",
|
||||
newCharacter("the shrike", "a little grey bird. it has a pretty song."),
|
||||
func(s *scene) { su.How = string(s.Input.Bytes()) }),
|
||||
newScene("what", heredoc.Doc(`
|
||||
You sink backwards into the forest. You find yourself floating in darkness.
|
||||
|
||||
At the far reaches of your vision you can make out a faint neon grid. Around you
|
||||
|
@ -209,14 +233,10 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
as usual, just say your answer. when you're satisfied, please [-:-:b]/spin[-:-:-]
|
||||
around in this void.
|
||||
`),
|
||||
Write: func(b []byte) {
|
||||
su.Why = string(b)
|
||||
},
|
||||
Host: newCharacter("the vcr", "a black and grey VCR from 1991"),
|
||||
},
|
||||
{
|
||||
Name: "spun",
|
||||
Description: heredoc.Doc(`
|
||||
"hmm did you say something?",
|
||||
newCharacter("the vcr", "a black and grey VCR from 1991"),
|
||||
func(s *scene) { su.Why = string(s.Input.Bytes()) }),
|
||||
newScene("link", heredoc.Doc(`
|
||||
You realize your eyes have been shut. You open them and, in an instant,
|
||||
the neon grid and polygons are gone. You're in a convenience store. Outside
|
||||
it's dark besides a single pool of light coming from a street lamp. it's illuminating
|
||||
|
@ -235,14 +255,10 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
when you're happy you can submit this whole experience by leaving the
|
||||
store. just [-:-:b]/open[-:-:-] the door.
|
||||
`),
|
||||
Write: func(b []byte) {
|
||||
su.Links = string(b)
|
||||
},
|
||||
Host: newCharacter("the mop", "a greying mop with a wooden handle."),
|
||||
},
|
||||
{
|
||||
Name: "done",
|
||||
Description: heredoc.Doc(`
|
||||
"just the one last thing please",
|
||||
newCharacter("the mop", "a greying mop with a wooden handle."),
|
||||
func(s *scene) { su.Links = string(s.Input.Bytes()) }),
|
||||
newScene("done", heredoc.Doc(`
|
||||
thank you for applying to tilde.town!
|
||||
|
||||
please be on the look out for an email from [-:-:b]root@tilde.town[-:-:-]
|
||||
|
@ -251,38 +267,13 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
|
||||
ok bye have a good one~
|
||||
`),
|
||||
Write: func(b []byte) {
|
||||
su.Extra = string(b)
|
||||
},
|
||||
},
|
||||
"",
|
||||
nil,
|
||||
func(s *scene) { su.Extra = string(s.Input.Bytes()) }),
|
||||
}
|
||||
|
||||
sceneIx := 0
|
||||
currentScene := scenes[sceneIx]
|
||||
|
||||
inputWriter := bytes.NewBuffer([]byte{})
|
||||
|
||||
advanceScene := func(fromScene, sorryMsg string) {
|
||||
if currentScene.Name != fromScene {
|
||||
return
|
||||
}
|
||||
if inputWriter.Len() == 0 {
|
||||
fmt.Fprintln(msgScroll, currentScene.Host.Say(sorryMsg))
|
||||
return
|
||||
}
|
||||
l.Println("advancing scene")
|
||||
|
||||
currentScene.Write(inputWriter.Bytes())
|
||||
inputWriter = bytes.NewBuffer([]byte{})
|
||||
sceneIx++
|
||||
currentScene = scenes[sceneIx]
|
||||
fmt.Fprintln(msgScroll, heredoc.Doc(`
|
||||
|
||||
[purple]----------[-:-:-]
|
||||
|
||||
`))
|
||||
fmt.Fprintln(msgScroll, currentScene.Description)
|
||||
}
|
||||
sm := newSceneManager(msgScroll, scenes)
|
||||
sm.Save = save
|
||||
|
||||
handleInput := func(msg string) {
|
||||
msg = strings.TrimSpace(msg)
|
||||
|
@ -295,37 +286,42 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
msg = split[0]
|
||||
}
|
||||
switch strings.TrimPrefix(msg, "/") {
|
||||
case "help":
|
||||
fmt.Fprintln(msgScroll, sm.Current.Host.Say(`some artificial beings will guide you through applying to tilde.town.
|
||||
type things, then press enter. to take an action, put a "/" before a word.
|
||||
for example typing:
|
||||
/nod
|
||||
and pressing enter will cause you to nod. some other verbs: /quit /look`))
|
||||
case "quit":
|
||||
l.Println("got /quit")
|
||||
app.Stop()
|
||||
case "look":
|
||||
fmt.Fprintln(msgScroll, "")
|
||||
fmt.Fprintln(msgScroll, currentScene.Description)
|
||||
fmt.Fprintln(msgScroll, sm.Current.Description)
|
||||
case "nod":
|
||||
advanceScene("start",
|
||||
"i'm sorry, before going further could you share an email with me?")
|
||||
case "lean":
|
||||
advanceScene("nodded", "phweeturpff")
|
||||
case "spin":
|
||||
advanceScene("leaned", "hmm did you say something?")
|
||||
case "open":
|
||||
advanceScene("spun", "just the one last thing please")
|
||||
save()
|
||||
if !sm.Advance() {
|
||||
fmt.Fprintln(msgScroll, "you nod, but nothing happens.")
|
||||
fmt.Fprintln(msgScroll)
|
||||
} else {
|
||||
l.Println("advancing scene")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if inputWriter.Len() > maxInputLength {
|
||||
if sm.Current.Input.Len() > maxInputLength {
|
||||
fmt.Fprintln(msgScroll,
|
||||
currentScene.Host.Say("sorry I've heard more than I can remember :( maybe it's time to move on"))
|
||||
sm.Current.Host.Say(
|
||||
"sorry I've heard more than I can remember :( maybe it's time to move on"))
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(msgScroll, player.Say(msg))
|
||||
fmt.Fprintln(inputWriter, msg)
|
||||
fmt.Fprintln(sm.Current.Input, msg)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if currentScene.Name == "done" {
|
||||
currentScene.Write(inputWriter.Bytes())
|
||||
l.Println("exiting")
|
||||
if sm.Current.Name == "done" {
|
||||
sm.Current.OnAdvance(sm.Current)
|
||||
db.UpdateSignup(su)
|
||||
}
|
||||
db.Close()
|
||||
|
@ -333,7 +329,7 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
|
||||
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||
switch event.Key() {
|
||||
case tcell.KeyCtrlD:
|
||||
case tcell.KeyEnter:
|
||||
handleInput(input.GetText())
|
||||
input.SetText("", false)
|
||||
return nil
|
||||
|
@ -343,7 +339,7 @@ func _main(l *log.Logger, db *signup.DB) error {
|
|||
})
|
||||
|
||||
app.SetAfterDrawFunc(func(_ tcell.Screen) {
|
||||
fmt.Fprintln(msgScroll, currentScene.Description)
|
||||
fmt.Fprintln(msgScroll, sm.Current.Description)
|
||||
app.SetAfterDrawFunc(nil)
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue