diff options
| author | historia <[not public]> | 2026-06-11 04:46:27 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-11 08:58:37 +0000 |
| commit | 1b9e2da3b3c438d8dc53d3489725dd5ba0022777 (patch) | |
| tree | 62264f24420bf4cfaa734942c65cc8dd45ba3d3b /internal/game/action_talk.go | |
| parent | 06c02a697e5daf8832a462de5970dd4c0e13a02c (diff) | |
| download | thehouseoficarus-1b9e2da3b3c438d8dc53d3489725dd5ba0022777.tar.gz | |
feat: web client, get/drop updates and fixes
Diffstat (limited to 'internal/game/action_talk.go')
| -rw-r--r-- | internal/game/action_talk.go | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/internal/game/action_talk.go b/internal/game/action_talk.go new file mode 100644 index 0000000..f4929e9 --- /dev/null +++ b/internal/game/action_talk.go @@ -0,0 +1,211 @@ +package game + +import ( + "fmt" + "strings" + + "thirdcollapse/internal/action" + "thirdcollapse/internal/net" + "thirdcollapse/internal/object" + "thirdcollapse/internal/player" + "thirdcollapse/internal/world" +) + +func (g *Game) startMobTalk(sess *net.Session, p *player.Player, mob *world.MobInstance) { + cfg, err := g.BehaviorStore.LoadTalk(mob.BehaviorID) + if err != nil { + sess.WriteLine("This person has nothing to say.") + return + } + + if node, ok := cfg.Nodes["start"]; ok { + p.Action = &action.Action{ + Type: "talk", + TargetID: mob.DefID, + TargetName: mob.Name, + Data: map[string]any{"node": "start", "behavior_id": mob.BehaviorID}, + } + g.showTalkNode(sess, node) + } else { + sess.WriteLine("This person has nothing to say.") + } +} + +func (g *Game) startTalk(sess *net.Session, p *player.Player, obj *object.ObjectDef) { + cfg, err := g.BehaviorStore.LoadTalk(obj.BehaviorID) + if err != nil { + sess.WriteLine("This person has nothing to say.") + return + } + + if node, ok := cfg.Nodes["start"]; ok { + p.Action = &action.Action{ + Type: "talk", + TargetID: obj.ID, + TargetName: obj.Name, + Data: map[string]any{"node": "start", "behavior_id": obj.BehaviorID}, + } + g.showTalkNode(sess, node) + } else { + sess.WriteLine("This person has nothing to say.") + } +} + +func (g *Game) showTalkNode(sess *net.Session, node action.TalkNode) { + sess.WriteLine(fmt.Sprintf("\n%s", node.Message)) + + if node.Action != nil { + g.applyNodeAction(sess, node.Action) + } + + if len(node.Options) == 0 { + sess.State = net.StateGame + sess.Write("\r\n> ") + return + } + + visible := 0 + for _, opt := range node.Options { + if opt.Condition != nil && !g.checkCondition(sess, opt.Condition) { + continue + } + visible++ + sess.WriteLine(fmt.Sprintf(" %d. %s", visible, opt.Text)) + } + sess.State = net.StateTalk + sess.Write("\nChoice: ") +} + +func (g *Game) handleTalkInput(sess *net.Session, input string) { + p, ok := sess.Player.(*player.Player) + if !ok || p.Action == nil || p.Action.Type != "talk" { + sess.State = net.StateGame + sess.Write("\r\n> ") + return + } + + input = strings.TrimSpace(input) + lower := strings.ToLower(input) + if lower == "bye" || lower == "exit" || lower == "end" || lower == "quit" { + g.CancelAction(p) + sess.State = net.StateGame + sess.Write("\r\n> ") + return + } + + behaviorID := p.Action.Data["behavior_id"].(string) + cfg, err := g.BehaviorStore.LoadTalk(behaviorID) + if err != nil { + g.CancelAction(p) + sess.State = net.StateGame + sess.Write("\r\n> ") + return + } + + nodeKey := p.Action.Data["node"].(string) + node, ok := cfg.Nodes[nodeKey] + if !ok { + g.CancelAction(p) + sess.State = net.StateGame + sess.Write("\r\n> ") + return + } + + idx, err := parseIndex(input) + if err != nil || idx <= 0 { + g.CancelAction(p) + sess.State = net.StateGame + sess.Write("\r\n> ") + return + } + + validIdx := 0 + var chosen *action.TalkOption + for i := range node.Options { + opt := &node.Options[i] + if opt.Condition != nil && !g.checkCondition(sess, opt.Condition) { + continue + } + validIdx++ + if validIdx == idx { + chosen = opt + break + } + } + + if chosen == nil { + g.CancelAction(p) + sess.State = net.StateGame + sess.Write("\r\n> ") + return + } + + if chosen.End { + g.CancelAction(p) + sess.State = net.StateGame + sess.Write("\r\n> ") + return + } + + if chosen.Goto != "" { + if nextNode, ok := cfg.Nodes[chosen.Goto]; ok { + p.Action.Data["node"] = chosen.Goto + g.showTalkNode(sess, nextNode) + return + } + } + + g.CancelAction(p) + sess.State = net.StateGame + sess.Write("\r\n> ") +} + +func (g *Game) applyNodeAction(sess *net.Session, na *action.NodeAction) { + p, ok := sess.Player.(*player.Player) + if !ok { + return + } + for k, v := range na.SetFlags { + g.WorldFlags[k] = v + } + for k, v := range na.SetPlayerFlags { + if p.Flags == nil { + p.Flags = make(map[string]any) + } + p.Flags[k] = v + } + if na.TakeItem != "" { + if p.HasItem(na.TakeItem) { + p.RemoveItem(na.TakeItem, 1) + } + } + if na.GiveItem != "" { + slot := p.FirstFreeSlot() + if slot == -1 { + sess.WriteLine("Your inventory is too full to receive that.") + } else { + p.SetInvSlot(slot, &player.InventorySlot{ItemID: na.GiveItem, Quantity: 1}) + g.AccountStore.SaveCharacter(p) + } + } + if na.Teleport > 0 { + p.RoomID = na.Teleport + g.AccountStore.SaveCharacter(p) + g.World.SeedGroundItems(p.RoomID) + g.seedRoomMobs(p.RoomID) + g.ensureRoomObjects(p.RoomID) + if g.Hub != nil { + g.Hub.EnterRoom(sess, p.RoomID) + } + g.doLook(sess) + g.RunEnterSteps(sess, p.RoomID) + } + if na.Heal > 0 { + p.HP += na.Heal + if maxHP := p.MaxHP(); p.HP > maxHP { + p.HP = maxHP + } + g.AccountStore.SaveCharacter(p) + sess.WriteLine(fmt.Sprintf("You regain %d hitpoints.", na.Heal)) + } +} |
