diff options
Diffstat (limited to 'internal/game/act_talk.go')
| -rw-r--r-- | internal/game/act_talk.go | 228 |
1 files changed, 163 insertions, 65 deletions
diff --git a/internal/game/act_talk.go b/internal/game/act_talk.go index 14361f8..c87e3c5 100644 --- a/internal/game/act_talk.go +++ b/internal/game/act_talk.go @@ -87,51 +87,63 @@ func (g *Game) handleNodeAction(sess *net.Session, na *behavior.NodeAction) (int func (g *Game) showTalkNode(sess *net.Session, node behavior.TalkNode) { p := sess.Player td, _ := p.Action.Data.(*behavior.TalkData) - + td.CancelTalk = false + td.PendingSeq = false + td.PendingChoice = "" + td.PendingAction = nil + td.PendingChosen = false dialogSpec := g.resolveColor(sess, "dialog") - msg := node.Message.Pick() - if msg != "" { - sess.WriteLine(color.ExpandTagsDefault(g.colorMode(sess), dialogSpec, msg)) - } - - if node.Action != nil { - if g.handleNodeAction(sess, node.Action) { - return - } - } - cfg := td.Cfg + for { - visible := g.visibleOptions(sess, node.Options) - if len(visible) > 0 { - for i, opt := range visible { - sess.WriteLine(fmt.Sprintf(" %d. %s", i+1, opt.Text)) + if node.Condition == nil || g.checkCondition(sess, node.Condition) { + if len(node.Sequence) > 0 { + if node.Action != nil { + if g.handleNodeAction(sess, node.Action) { + return + } + } + td.SeqIndex = 0 + msg := node.Sequence[0] + if msg != "" { + sess.WriteLine(color.ExpandTagsDefault(g.colorMode(sess), dialogSpec, msg)) + } + td.SeqIndex = 1 + if td.SeqIndex < len(node.Sequence) { + sess.State = net.StateTalkSequence + sess.Write("[enter to continue]\n") + return + } + } else { + msg := node.Message.Pick() + if msg != "" { + sess.WriteLine(color.ExpandTagsDefault(g.colorMode(sess), dialogSpec, msg)) + } + if node.Action != nil { + if g.handleNodeAction(sess, node.Action) { + return + } + } + } + visible := g.visibleOptions(sess, node.Options) + if len(visible) > 0 { + for i, opt := range visible { + sess.WriteLine(fmt.Sprintf(" %d. %s", i+1, opt.Text)) + } + sess.State = net.StateTalk + g.reprompt(sess) + return } - sess.State = net.StateTalk - sess.Write("\nChoice: ") - return } - - if node.Next != "" && cfg != nil { - next, ok := cfg.Nodes[node.Next] + if node.Goto != "" && cfg != nil { + next, ok := cfg.Nodes[node.Goto] if !ok { break } if td != nil { - td.Node = node.Next + td.Node = node.Goto } node = next - - msg := node.Message.Pick() - if msg != "" { - sess.WriteLine(color.ExpandTagsDefault(g.colorMode(sess), dialogSpec, msg)) - } - - if node.Action != nil { - if g.handleNodeAction(sess, node.Action) { - return - } - } } else { break } @@ -152,6 +164,31 @@ func (g *Game) visibleOptions(sess *net.Session, options []behavior.TalkOption) return visible } +func (g *Game) finishSequence(sess *net.Session, node behavior.TalkNode) { + visible := g.visibleOptions(sess, node.Options) + if len(visible) > 0 { + for i, opt := range visible { + sess.WriteLine(fmt.Sprintf(" %d. %s", i+1, opt.Text)) + } + sess.State = net.StateTalk + g.reprompt(sess) + return + } + + td, _ := sess.Player.Action.Data.(*behavior.TalkData) + if node.Goto != "" && td != nil && td.Cfg != nil { + nextNode, ok := td.Cfg.Nodes[node.Goto] + if ok { + td.Node = node.Goto + g.showTalkNode(sess, nextNode) + return + } + } + + g.cancelAction(sess.Player) + sess.State = net.StateGame +} + func (g *Game) handleTalkInput(sess *net.Session, input string) { p := sess.Player if p == nil || p.Action == nil || p.Action.Type != behavior.TypeTalk { @@ -160,46 +197,57 @@ func (g *Game) handleTalkInput(sess *net.Session, input string) { return } - input = strings.TrimSpace(input) - if input == "" { - input = "1" + if p.Action.WaitLeft > 0 { + return } - lower := strings.ToLower(input) - if lower == "bye" || lower == "exit" || lower == "end" || lower == "quit" { + + td, ok := p.Action.Data.(*behavior.TalkData) + if !ok || td.Cfg == nil { g.cancelAction(p) sess.State = net.StateGame g.writePrompt(sess) return } - if td, ok := p.Action.Data.(*behavior.TalkData); ok && td.EstateDirectory { - g.handleEstateDirectoryTalk(sess, input) + input = strings.TrimSpace(input) + if input == "" && sess.State != net.StateTalkSequence { + input = "1" + } + + if sess.State == net.StateTalkSequence { + _, ok := td.Cfg.Nodes[td.Node] + if !ok { + td.CancelTalk = true + p.Action.WaitLeft = 1 + return + } + if input == "" { + td.PendingSeq = true + } else { + td.CancelTalk = true + } + p.Action.WaitLeft = 1 return } - td, ok := p.Action.Data.(*behavior.TalkData) - if !ok || td.Cfg == nil { - g.cancelAction(p) - sess.State = net.StateGame - g.writePrompt(sess) + if td.EstateDirectory { + g.handleEstateDirectoryTalk(sess, input) return } - cfg := td.Cfg + cfg := td.Cfg nodeKey := td.Node node, ok := cfg.Nodes[nodeKey] if !ok { - g.cancelAction(p) - sess.State = net.StateGame - g.writePrompt(sess) + td.CancelTalk = true + p.Action.WaitLeft = 1 return } idx, err := parseChoiceIndex(input) if err != nil || idx <= 0 { - g.cancelAction(p) - sess.State = net.StateGame - g.writePrompt(sess) + td.CancelTalk = true + p.Action.WaitLeft = 1 return } @@ -218,29 +266,79 @@ func (g *Game) handleTalkInput(sess *net.Session, input string) { } if chosen == nil { + td.CancelTalk = true + p.Action.WaitLeft = 1 + return + } + + td.PendingChoice = chosen.Goto + td.PendingAction = chosen.Action + td.PendingChosen = true + p.Action.WaitLeft = 1 +} + +func (g *Game) advanceTalk(sess *net.Session, p *player.Player) { + td, ok := p.Action.Data.(*behavior.TalkData) + if !ok || td.Cfg == nil { g.cancelAction(p) sess.State = net.StateGame - g.writePrompt(sess) return } - if chosen.Action != nil { - if g.handleNodeAction(sess, chosen.Action) { - return - } + if td.CancelTalk { + sess.WriteLine("You leave the conversation.") + g.cancelAction(p) + sess.State = net.StateGame + return } - if chosen.Goto != "" { - if nextNode, ok := cfg.Nodes[chosen.Goto]; ok { - td.Node = chosen.Goto - g.showTalkNode(sess, nextNode) + if td.PendingSeq { + td.PendingSeq = false + node, ok := td.Cfg.Nodes[td.Node] + if !ok { + g.cancelAction(p) + sess.State = net.StateGame + return + } + dialogSpec := g.resolveColor(sess, "dialog") + if td.SeqIndex < len(node.Sequence) { + msg := node.Sequence[td.SeqIndex] + if msg != "" { + sess.WriteLine(color.ExpandTagsDefault(g.colorMode(sess), dialogSpec, msg)) + } + td.SeqIndex++ + } + if td.SeqIndex >= len(node.Sequence) { + g.finishSequence(sess, node) return } + sess.State = net.StateTalkSequence + sess.Write("[enter to continue]\n") + return } - g.cancelAction(p) - sess.State = net.StateGame - g.writePrompt(sess) + if td.PendingChosen { + td.PendingChosen = false + choice := td.PendingChoice + action := td.PendingAction + td.PendingChoice = "" + td.PendingAction = nil + if action != nil { + if g.handleNodeAction(sess, action) { + return + } + } + if choice != "" { + if nextNode, ok := td.Cfg.Nodes[choice]; ok { + td.Node = choice + g.showTalkNode(sess, nextNode) + return + } + } + g.cancelAction(p) + sess.State = net.StateGame + return + } } func (g *Game) enterShop(sess *net.Session, cfg *behavior.ShopConfig) { |
