package game import ( "fmt" "os" "path/filepath" "sort" "strings" "thehouseoficarus/internal/behavior" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" "gopkg.in/yaml.v3" ) func (g *Game) startEstateDirectory(sess *net.Session, verb string) { p := sess.Player homeowners := g.scanHomeowners("owns_house_local_neighborhood") ownedByMe := false for _, h := range homeowners { if h == p.Name { ownedByMe = true break } } if verb == "talk" { g.showEstateDirectoryTalk(sess, p, homeowners, ownedByMe) return } if verb == "use" { if ownedByMe { houseRoom := g.getOwnedHouseRoom(p, "owns_house_local_neighborhood") if houseRoom > 0 { g.cancelAction(p) g.teleportPlayer(sess, p, houseRoom) return } } sess.WriteLine("You don't own a house here. Talk to the estate broker to purchase one.") return } } func (g *Game) lookEstateDirectory(sess *net.Session) { homeowners := g.scanHomeowners("owns_house_local_neighborhood") sess.WriteLine("") sess.WriteLine(g.colorize(sess, "dialog", "Estate Directory")) sess.WriteLine(fmt.Sprintf(" A holographic terminal displaying property records for the Local Neighborhood.")) sess.WriteLine("") if len(homeowners) == 0 { sess.WriteLine(" No registered homeowners in this area.") } else { sess.WriteLine(" Registered homeowners:") for i, name := range homeowners { sess.WriteLine(fmt.Sprintf(" %d. %s", i+1, name)) } } sess.WriteLine("") sess.WriteLine(" Use the directory to enter your home, or talk to the estate broker to purchase.") } func (g *Game) showEstateDirectoryTalk(sess *net.Session, p *player.Player, homeowners []string, ownedByMe bool) { sess.WriteLine("") sess.WriteLine(g.colorize(sess, "dialog", "The directory terminal hums quietly, displaying a list of registered homeowners...")) if ownedByMe { sess.WriteLine("") sess.WriteLine(" You are a registered homeowner in this neighborhood.") sess.WriteLine(" Type 'enter' to go to your house, or 'leave' to step away.") sess.State = net.StateTalk p.Action = &behavior.Action{ Type: "talk", TargetID: "estate_directory", TargetName: "Estate Directory", Data: &behavior.TalkData{Node: "start", EstateDirectory: true}, } sess.Write("\nChoice: ") return } sess.WriteLine("") if len(homeowners) > 0 { sess.WriteLine(" Currently owned by: " + strings.Join(homeowners, ", ")) } sess.WriteLine(" You don't own a house here yet.") sess.WriteLine(" Talk to the estate broker to purchase a plot for 10 credits.") } func (g *Game) handleEstateDirectoryTalk(sess *net.Session, input string) { input = strings.TrimSpace(strings.ToLower(input)) switch input { case "enter": p := sess.Player if p == nil { return } houseRoom := g.getOwnedHouseRoom(p, "owns_house_local_neighborhood") if houseRoom > 0 { sess.State = net.StateGame p.Action = nil g.teleportPlayer(sess, p, houseRoom) return } sess.State = net.StateGame p.Action = nil g.writePrompt(sess) case "leave", "bye", "exit", "quit": p := sess.Player if p != nil { p.Action = nil } sess.State = net.StateGame g.writePrompt(sess) default: sess.WriteLine("Type 'enter' to go to your house, or 'leave' to step away.") sess.Write("\nChoice: ") } } func (g *Game) scanHomeowners(flagKey string) []string { var homeowners []string charsDir := filepath.Join(g.DataDir, "players", "characters") entries, err := os.ReadDir(charsDir) if err != nil { return homeowners } for _, entry := range entries { if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".yaml") { continue } name := strings.TrimSuffix(entry.Name(), ".yaml") data, err := os.ReadFile(filepath.Join(charsDir, entry.Name())) if err != nil { continue } var p struct { Flags map[string]any `yaml:"flags"` } if err := yaml.Unmarshal(data, &p); err != nil { continue } if p.Flags != nil { if val, ok := p.Flags[flagKey]; ok && val != nil { owned := false switch v := val.(type) { case bool: owned = v case string: owned = v != "" && v != "false" } if owned { homeowners = append(homeowners, name) } } } } sort.Strings(homeowners) return homeowners } func (g *Game) getOwnedHouseRoom(p *player.Player, flagKey string) int { p.EnsureFlags() val, ok := p.Flags[flagKey] if !ok || val == nil { return 0 } v, ok := val.(string) if !ok || v == "" { return 0 } houseMap := map[string]int{ "local_neighborhood": 300, } return houseMap[v] } func (g *Game) teleportPlayer(sess *net.Session, p *player.Player, roomID int) { if g.Hub != nil { for _, other := range g.Hub.PlayersInRoom(p.RoomID) { if other != sess { other.WriteLine(fmt.Sprintf("%s disappears in a shimmer of light.", p.Name)) } } } p.RoomID = roomID p.Stats.RecordRoomVisit(roomID) if g.Hub != nil { g.Hub.LeaveRoom(sess) g.Hub.EnterRoom(sess, p.RoomID) } g.World.SeedGroundItems(p.RoomID) g.seedRoomMobs(p.RoomID) g.seedRoomObjects(p.RoomID) g.AccountStore.SaveCharacter(p) g.doLook(sess) g.runEnterSteps(sess, p.RoomID) g.writePrompt(sess) }