diff options
| author | historia <[not public]> | 2026-10-03 17:36:06 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-10-03 17:36:06 -0400 |
| commit | c6d4702c0be4d2b37e1d82ff96265c52847c3f9a (patch) | |
| tree | c0a3d0638b961a9ba06e6fdb30ee5f1cd2061f2e /internal/game/cmd_prefix.go | |
| parent | 0fb83bdf433b9b48240f4ac7a5d4c912f6b808cc (diff) | |
| download | thehouseoficarus-c6d4702c0be4d2b37e1d82ff96265c52847c3f9a.tar.gz | |
feat: partial commands now always work
Diffstat (limited to 'internal/game/cmd_prefix.go')
| -rw-r--r-- | internal/game/cmd_prefix.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/internal/game/cmd_prefix.go b/internal/game/cmd_prefix.go new file mode 100644 index 0000000..da3e646 --- /dev/null +++ b/internal/game/cmd_prefix.go @@ -0,0 +1,114 @@ +package game + +import ( + "strings" + + "thehouseoficarus/internal/net" +) + +// resolveCommandPrefix expands an unambiguous, currently usable command prefix +// to its full command name. It is the general (non-casino) counterpart to +// casinoAbbreviation: a prefix such as "inven" runs inventory, while an +// ambiguous prefix such as "in" is left alone. +// +// Exact commands are never rewritten — the registry dispatch already handles +// them, and rewriting would make the result indistinguishable from a real +// command. When several commands share a prefix, the player's own room breaks +// the tie: if exactly one of the candidates is advertised where they are +// standing (an object verb, a mob action, an exit, an obstacle, a fixture, or +// the always-runnable play gateway), that one wins. This is what lets "pl" +// mean play even though "plant" also starts with "pl". +func (g *Game) resolveCommandPrefix(sess *net.Session, cmd string) (string, bool) { + if sess == nil || sess.Player == nil || cmd == "" { + return "", false + } + // Exact commands and action aliases dispatch as typed. + if _, ok := commandRegistry[cmd]; ok { + return "", false + } + if _, ok := verbAliases[cmd]; ok { + return "", false + } + obstacleVerbsMu.RLock() + exactObstacle := obstacleVerbs[cmd] + obstacleVerbsMu.RUnlock() + if exactObstacle { + return "", false + } + + var matches []string + add := func(name string) { + if strings.HasPrefix(name, cmd) { + matches = append(matches, name) + } + } + for name := range commandRegistry { + add(name) + } + for name := range verbAliases { + add(name) + } + obstacleVerbsMu.RLock() + for name := range obstacleVerbs { + add(name) + } + obstacleVerbsMu.RUnlock() + + switch len(matches) { + case 0: + return "", false + case 1: + return matches[0], true + } + + // Ambiguous on the whole command table: prefer a single candidate the + // player can actually use here. + usable := g.roomVerbSet(sess) + only := "" + for _, name := range matches { + if !usable[name] { + continue + } + if only != "" { + return "", false + } + only = name + } + if only != "" { + return only, true + } + return "", false +} + +// roomVerbSet returns the verbs the player can use where they are: the verbs +// advertised by the current room's objects, mobs, ground and exits, plus the +// always-runnable play gateway. It deliberately excludes the global +// always-available list so a context-free command cannot shadow a same-prefix +// command that is actually offered here. +func (g *Game) roomVerbSet(sess *net.Session) map[string]bool { + set := map[string]bool{ + // play responds anywhere: at a table it opens the game, and away from + // one it reports that there is nothing to play. Making it usable + // everywhere lets "pl" name play instead of tying with plant. + "play": true, + } + if sess == nil || sess.Player == nil { + return set + } + rc := g.collectRoomCommands(sess) + for _, group := range [][]string{rc.objects, rc.mobs, rc.ground} { + for _, entry := range group { + if fields := strings.Fields(entry); len(fields) > 0 { + set[fields[0]] = true + } + } + } + for _, exit := range rc.exits { + for _, dir := range strings.Split(exit, ",") { + if dir = strings.TrimSpace(dir); dir != "" { + set[dir] = true + } + } + } + return set +} |
