diff options
| author | historia <[not public]> | 2026-09-18 15:16:44 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-18 15:16:44 -0400 |
| commit | 7eab582d8a8ee2af1a6baae7baf0696c7005de2e (patch) | |
| tree | 902bbc8c6e39c9f62f779ca23267714ec420b9f5 /internal/game/act_talk.go | |
| parent | 153acb7f644d755c45533b7c5311e3ffa47e8973 (diff) | |
| download | thehouseoficarus-7eab582d8a8ee2af1a6baae7baf0696c7005de2e.tar.gz | |
fix: harden triggers, economy, casino, world data, and admin/net paths
Diffstat (limited to 'internal/game/act_talk.go')
| -rw-r--r-- | internal/game/act_talk.go | 47 |
1 files changed, 31 insertions, 16 deletions
diff --git a/internal/game/act_talk.go b/internal/game/act_talk.go index ef3c6e5..9ae9959 100644 --- a/internal/game/act_talk.go +++ b/internal/game/act_talk.go @@ -55,8 +55,8 @@ func (g *Game) startTalk(sess *net.Session, p *player.Player, obj *object.Object } } -func (g *Game) handleNodeAction(sess *net.Session, na *behavior.Step) (intercepted bool) { - g.applyTalkStep(sess, na) +func (g *Game) handleNodeAction(sess *net.Session, na *behavior.Step) (intercepted bool, applied bool) { + applied = g.applyTalkStep(sess, na) if v, ok := g.GlobalFlags.Get("guard_hostile"); ok && v != nil { g.GlobalFlags.Delete("guard_hostile") @@ -70,11 +70,11 @@ func (g *Game) handleNodeAction(sess *net.Session, na *behavior.Step) (intercept guardMob.Protected = false g.startCombat(sess, p, guardMob) } - return true + return true, applied } } } - return false + return false, applied } func (g *Game) showTalkNode(sess *net.Session, node behavior.TalkNode) { @@ -90,12 +90,19 @@ func (g *Game) showTalkNode(sess *net.Session, node behavior.TalkNode) { for { if node.Condition == nil || g.checkCondition(sess, node.Condition) { - if len(node.Messages) > 0 { - if node.Action != nil { - if g.handleNodeAction(sess, node.Action) { - return - } + // Apply the node's action first. A failed preflight (missing item, + // full inventory, unaffordable cost) applies nothing, so skip the + // node's success messages rather than narrating a trade that did + // not happen; the player still gets the node's options. + actionApplied := true + if node.Action != nil { + intercepted, applied := g.handleNodeAction(sess, node.Action) + if intercepted { + return } + actionApplied = applied + } + if actionApplied && len(node.Messages) > 0 { td.SeqIndex = 0 msg := node.Messages[0] if msg != "" { @@ -107,12 +114,6 @@ func (g *Game) showTalkNode(sess *net.Session, node behavior.TalkNode) { sess.Write(g.colorize(sess, "dialog_options", "[enter to continue]\n")) return } - } else { - if node.Action != nil { - if g.handleNodeAction(sess, node.Action) { - return - } - } } visible := g.visibleOptions(sess, node.Options) if len(visible) > 0 { @@ -313,7 +314,21 @@ func (g *Game) advanceTalk(sess *net.Session, p *player.Player) { td.PendingChoice = "" td.PendingAction = nil if action != nil { - if g.handleNodeAction(sess, action) { + intercepted, applied := g.handleNodeAction(sess, action) + if intercepted { + return + } + if !applied { + // The option's cost could not be met and no effect was applied. + // Re-show the current node's options instead of advancing to the + // success node and its misleading success text. + if node, ok := td.Cfg.Nodes[td.Node]; ok { + g.finishSequence(sess, node) + } else { + g.cancelAction(p) + sess.SetState(net.StateGame) + g.writePrompt(sess) + } return } } |
