From c84a9944356f590d90d819d652bdf1349ebacd40 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Mon, 5 Oct 2026 06:03:49 -0400 Subject: feat: prediction exchange with live polymarket data --- internal/game/prediction_interface.go | 155 ++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 internal/game/prediction_interface.go (limited to 'internal/game/prediction_interface.go') diff --git a/internal/game/prediction_interface.go b/internal/game/prediction_interface.go new file mode 100644 index 0000000..2e37145 --- /dev/null +++ b/internal/game/prediction_interface.go @@ -0,0 +1,155 @@ +package game + +import ( + "strings" + + "thehouseoficarus/internal/net" +) + +func predictionUseTarget(input string) bool { + switch strings.ToLower(strings.TrimSpace(input)) { + case "predictions", "prediction", "market", "counter", "exchange", "prediction market", "prediction counter", "prediction exchange", "prediction market counter": + return true + } + return false +} + +var predictionVerbs = []string{"markets", "view", "find", "next", "prev", "back", "active", "closed", "holding", "buy", "sell", "collect", "refresh", "rules", "stop"} + +func (g *Game) openPredictionCounter(s *net.Session) { + if !g.atPredictionCounter(s.Player) { + s.WriteLine("There is no Prediction Exchange here.") + return + } + if !g.leaveCasinoGames(s.Player) { + s.WriteLine("Finish your current casino round before using the counter.") + return + } + if s.PredictionActive { + g.executePredictions(s, []string{"refresh"}, "") + return + } + s.PredictionActive = true + s.PredictionEpoch++ + s.PredictionBusy = false + s.PredictionSelected = "" + s.PredictionScreen = "list" + s.PredictionPage = 1 + s.PredictionBoardPage = 1 + s.PredictionSearch = "" + s.PredictionUnavailable = false + g.executePredictions(s, nil, "open") +} + +func (g *Game) closePredictionCounter(s *net.Session) { + if s.PredictionCancel != nil { + s.PredictionCancel() + s.PredictionCancel = nil + } + s.PredictionActive = false + s.PredictionEpoch++ // Invalidate any download, including an in-flight trade. + s.PredictionBusy = false + s.PredictionSelected = "" +} + +// Exact world commands keep their meaning unless explicitly part of this UI. +// Abbreviations are scoped to the counter; no new global command is registered. +func predictionVerb(cmd string) (string, bool) { + switch cmd { + case "list": + return "markets", true + case "table", "game": + return "refresh", true + case "status", "portfolio", "board": + return "active", true + case "help": + return "help", true + case "leave", "exit": + return "stop", true + } + for _, v := range predictionVerbs { + if cmd == v { + return v, true + } + } + if _, exists := commandRegistry[cmd]; exists { + return "", false + } + found := "" + for _, v := range predictionVerbs { + if strings.HasPrefix(v, cmd) { + if found != "" { + return "", true + } + found = v + } + } + return found, found != "" +} +func (g *Game) predictionInputOwned(s *net.Session, cmd string) bool { + if !s.PredictionActive || !g.atPredictionCounter(s.Player) { + return false + } + if isAllDigits(cmd) { + return true + } + _, ok := predictionVerb(cmd) + return ok +} +func (g *Game) handlePredictionInput(s *net.Session, cmd string, args []string) bool { + if !s.PredictionActive { + return false + } + if !g.atPredictionCounter(s.Player) { + g.closePredictionCounter(s) + return false + } + if cmd == "help" && len(args) > 0 { + return false + } + if isAllDigits(cmd) { + action := "view" + if s.PredictionScreen == "active" || s.PredictionScreen == "closed" { + action = "holding" + } + g.executePredictions(s, []string{action, cmd}, "") + return true + } + verb, owned := predictionVerb(cmd) + if !owned { + if cmd == "use" && predictionUseTarget(strings.Join(args, " ")) { + return false + } + switch cmd { + case "play", "use", "bank", "quit", "logout": + g.closePredictionCounter(s) + } + return false + } + if verb == "" { + s.WriteLine("That shortcut is ambiguous. Choose a command below.") + g.predictionHints(s) + return true + } + if verb == "stop" { + g.closePredictionCounter(s) + s.WriteLine(g.colorize(s, "casino_action", "You step away from the Prediction Exchange. Your contracts stay with the house.")) + return true + } + switch verb { + case "markets": + verb = "list" + case "back": + args = nil + case "help": + g.predictionHelp(s) + return true + case "rules": + if s.PredictionScreen != "view" || s.PredictionSelected == "" { + g.predictionHelp(s) + return true + } + } + g.executePredictions(s, append([]string{verb}, args...), "") + return true +} -- cgit v1.2.3