diff options
| author | historia <[not public]> | 2026-06-25 19:37:20 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-25 19:37:20 -0400 |
| commit | c55d0e4150b23f2c5c9f96bbc3d4dc2fc6dbaa36 (patch) | |
| tree | d1c02acea2b4c8d0f672c1539cfdb373b6272ed0 /internal/game/act_talk.go | |
| parent | 068ce514ea3eebdc42b595c631b4b00ce4594577 (diff) | |
| download | thehouseoficarus-c55d0e4150b23f2c5c9f96bbc3d4dc2fc6dbaa36.tar.gz | |
feat: yaml conversation trees more robust
Diffstat (limited to 'internal/game/act_talk.go')
| -rw-r--r-- | internal/game/act_talk.go | 119 |
1 files changed, 85 insertions, 34 deletions
diff --git a/internal/game/act_talk.go b/internal/game/act_talk.go index e9047b2..f54290a 100644 --- a/internal/game/act_talk.go +++ b/internal/game/act_talk.go @@ -6,6 +6,7 @@ import ( "strings" "thehouseoficarus/internal/behavior" + "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" @@ -52,51 +53,99 @@ func (g *Game) startTalk(sess *net.Session, p *player.Player, obj *object.Object } } +func (g *Game) handleNodeAction(sess *net.Session, na *behavior.NodeAction) (intercepted bool) { + if na.Shop != nil { + g.applyNodeAction(sess, na) + g.enterShop(sess, na.Shop) + return true + } + g.applyNodeAction(sess, na) + + if v, ok := g.Flags.Get("guard_hostile"); ok && v != nil { + g.Flags.Delete("guard_hostile") + p := sess.Player + if p != nil && p.Action != nil { + if td, ok := p.Action.Data.(*behavior.TalkData); ok && td.StealGuard { + guardMob := g.findGuardInRoom(p.RoomID, "guard") + if guardMob != nil { + sess.State = net.StateGame + g.cancelAction(p) + guardMob.Protected = false + g.startCombat(sess, p, guardMob) + } + return true + } + } + } + return false +} + func (g *Game) showTalkNode(sess *net.Session, node behavior.TalkNode) { - sess.WriteLine(fmt.Sprintf("%s", g.colorize(sess, "dialog", node.Message))) + p := sess.Player + td, _ := p.Action.Data.(*behavior.TalkData) + + 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 node.Action.Shop != nil { - g.applyNodeAction(sess, node.Action) - g.enterShop(sess, node.Action.Shop) + 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)) + } + sess.State = net.StateTalk + sess.Write("\nChoice: ") return } - g.applyNodeAction(sess, node.Action) - - if v, ok := g.Flags.Get("guard_hostile"); ok && v != nil { - g.Flags.Delete("guard_hostile") - p := sess.Player - if p != nil && p.Action != nil { - if td, ok := p.Action.Data.(*behavior.TalkData); ok && td.StealGuard { - guardMob := g.findGuardInRoom(p.RoomID, "guard") - if guardMob != nil { - sess.State = net.StateGame - g.cancelAction(p) - guardMob.Protected = false - g.startCombat(sess, p, guardMob) - } + + if node.Next != "" && cfg != nil { + next, ok := cfg.Nodes[node.Next] + if !ok { + break + } + if td != nil { + td.Node = node.Next + } + 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 } } - if len(node.Options) == 0 { - sess.State = net.StateGame - g.writePrompt(sess) - return - } + sess.State = net.StateGame + g.writePrompt(sess) +} - visible := 0 - for _, opt := range node.Options { +func (g *Game) visibleOptions(sess *net.Session, options []behavior.TalkOption) []behavior.TalkOption { + var visible []behavior.TalkOption + for _, opt := range options { if opt.Condition != nil && !g.checkCondition(sess, opt.Condition) { continue } - visible++ - sess.WriteLine(fmt.Sprintf(" %d. %s", visible, opt.Text)) + visible = append(visible, opt) } - sess.State = net.StateTalk - sess.Write("\nChoice: ") + return visible } func (g *Game) handleTalkInput(sess *net.Session, input string) { @@ -108,6 +157,9 @@ func (g *Game) handleTalkInput(sess *net.Session, input string) { } input = strings.TrimSpace(input) + if input == "" { + input = "1" + } lower := strings.ToLower(input) if lower == "bye" || lower == "exit" || lower == "end" || lower == "quit" { g.cancelAction(p) @@ -168,11 +220,10 @@ func (g *Game) handleTalkInput(sess *net.Session, input string) { return } - if chosen.End { - g.cancelAction(p) - sess.State = net.StateGame - g.writePrompt(sess) - return + if chosen.Action != nil { + if g.handleNodeAction(sess, chosen.Action) { + return + } } if chosen.Goto != "" { |
