aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_verbs.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/cmd_verbs.go')
-rw-r--r--internal/game/cmd_verbs.go117
1 files changed, 68 insertions, 49 deletions
diff --git a/internal/game/cmd_verbs.go b/internal/game/cmd_verbs.go
index d13b803..5cbbd5f 100644
--- a/internal/game/cmd_verbs.go
+++ b/internal/game/cmd_verbs.go
@@ -45,28 +45,23 @@ var alwaysAvailable = []string{
"drop",
}
-func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) {
- p := sess.Player
- // A seated casino player has no room verbs: the only valid commands are
- // the game's live hints, so what/verbs shows those instead of exits and
- // objects that cannot be used mid-hand.
- if g.Casino != nil {
- if table, playing := g.Casino.Participation(p.Name); playing {
- if table != nil {
- g.showCasinoHints(sess, table.Hints(p.Name))
- } else if machine, ok := g.Casino.MachineFor(p.Name); ok {
- g.showCasinoHints(sess, machine.Hints())
- }
- return
- }
- }
- showAll := len(args) == 1 && strings.ToLower(args[0]) == "all"
+// roomCommandSections holds the interactable commands advertised for the
+// player's current room, before rendering. It is shared by the verbs display
+// and by prefix resolution, so an abbreviation can only beat a same-prefix
+// rival when the player can actually use it here.
+type roomCommandSections struct {
+ objects []string
+ mobs []string
+ exits []string
+ ground []string
+}
+// collectRoomCommands builds the room's object, mob, exit and ground command
+// listings without writing anything to the session.
+func (g *Game) collectRoomCommands(sess *net.Session) roomCommandSections {
+ p := sess.Player
+ var rc roomCommandSections
seen := make(map[string]bool)
- var sectionObjs []string
- var sectionMobs []string
- var sectionExits []string
- var sectionGround []string
for _, st := range g.World.AllObjInstances(p.RoomID) {
def, _, err := g.resolveObjectDef(p.RoomID, st.DefID)
@@ -80,25 +75,25 @@ func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) {
if bt == "gather" && def.Gather != nil {
for verb, skill := range verbSkill {
if strings.EqualFold(def.Gather.Skill, skill) {
- addUnique(&sectionObjs, &seen, verb+" "+name)
+ addUnique(&rc.objects, &seen, verb+" "+name)
}
}
}
if bt == "talk" {
- addUnique(&sectionObjs, &seen, "talk "+name)
+ addUnique(&rc.objects, &seen, "talk "+name)
}
for _, ui := range def.OnUse {
if ui.ItemID == "" && (ui.Condition == nil || g.checkCondition(sess, ui.Condition)) {
- addUnique(&sectionObjs, &seen, "use "+name)
+ addUnique(&rc.objects, &seen, "use "+name)
break
}
}
recipes := g.stationRecipes(p, def.ID)
if len(recipes) > 0 {
- addUnique(&sectionObjs, &seen, "use "+name)
+ addUnique(&rc.objects, &seen, "use "+name)
for _, r := range recipes {
c := r.FirstCraft()
key := c.Subtype
@@ -107,13 +102,13 @@ func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) {
}
if info, ok := productionTypes[key]; ok {
if info.ActionType != behavior.TypeCombine && info.ActionType != behavior.TypeFletch && info.ActionType != behavior.TypeMix {
- addUnique(&sectionObjs, &seen, string(info.ActionType))
+ addUnique(&rc.objects, &seen, string(info.ActionType))
}
}
for _, c := range r.FirstCraft().Ingredients {
for _, itemID := range c.Items {
if itemDef, err := g.ItemStore.Load(itemID); err == nil {
- addUnique(&sectionObjs, &seen, "use "+itemDef.Name+" on "+name)
+ addUnique(&rc.objects, &seen, "use "+itemDef.Name+" on "+name)
}
}
}
@@ -123,31 +118,31 @@ func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) {
for _, ui := range def.OnUse {
if ui.ItemID != "" && (ui.Condition == nil || g.checkCondition(sess, ui.Condition)) {
if itemDef, err := g.ItemStore.Load(ui.ItemID); err == nil {
- addUnique(&sectionObjs, &seen, "use "+itemDef.Name+" on "+name)
+ addUnique(&rc.objects, &seen, "use "+itemDef.Name+" on "+name)
}
}
}
if def.Steal != nil && len(def.Steal.Drops) > 0 {
- addUnique(&sectionObjs, &seen, "steal "+name)
+ addUnique(&rc.objects, &seen, "steal "+name)
}
- addUnique(&sectionObjs, &seen, "look "+name)
+ addUnique(&rc.objects, &seen, "look "+name)
}
for _, m := range g.MobStore.MobsInRoom(p.RoomID) {
mName := strings.ToLower(m.Name)
if !m.Protected {
- addUnique(&sectionMobs, &seen, "attack "+mName)
+ addUnique(&rc.mobs, &seen, "attack "+mName)
}
if m.IsTalkable() {
- addUnique(&sectionMobs, &seen, "talk "+mName)
+ addUnique(&rc.mobs, &seen, "talk "+mName)
}
if len(m.StealDrops) > 0 {
- addUnique(&sectionMobs, &seen, "steal "+mName)
+ addUnique(&rc.mobs, &seen, "steal "+mName)
}
- addUnique(&sectionMobs, &seen, "look "+mName)
+ addUnique(&rc.mobs, &seen, "look "+mName)
}
if room, err := g.World.LoadRoom(p.RoomID); err == nil {
@@ -163,7 +158,7 @@ func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) {
exitDirs = append(exitDirs, string(dir))
}
if len(exitDirs) > 0 {
- sectionExits = append(sectionExits, strings.Join(exitDirs, ", "))
+ rc.exits = append(rc.exits, strings.Join(exitDirs, ", "))
}
}
@@ -171,42 +166,66 @@ func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) {
if len(ground) > 0 {
for itemID := range ground {
if def, err := g.ItemStore.Load(itemID); err == nil {
- addUnique(&sectionGround, &seen, "get "+def.Name)
+ addUnique(&rc.ground, &seen, "get "+def.Name)
}
}
- addUnique(&sectionGround, &seen, "get all")
+ addUnique(&rc.ground, &seen, "get all")
}
- if info := g.CourseStore.GetObstacle(p.RoomID); info != nil {
- addUnique(&sectionGround, &seen, info.Verb)
+ if g.CourseStore != nil {
+ if info := g.CourseStore.GetObstacle(p.RoomID); info != nil {
+ addUnique(&rc.ground, &seen, info.Verb)
+ }
}
if g.canUseBank(p) {
- addUnique(&sectionObjs, &seen, "bank")
+ addUnique(&rc.objects, &seen, "bank")
}
if g.findTerminalInRoom(p.RoomID) != "" {
- addUnique(&sectionObjs, &seen, "jack")
+ addUnique(&rc.objects, &seen, "jack")
}
- hasRoomCmds := len(sectionObjs) > 0 || len(sectionMobs) > 0 || len(sectionExits) > 0 || len(sectionGround) > 0
+ return rc
+}
+
+func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) {
+ p := sess.Player
+ // A seated casino player has no room verbs: the only valid commands are
+ // the game's live hints, so what/verbs shows those instead of exits and
+ // objects that cannot be used mid-hand.
+ if g.Casino != nil {
+ if table, playing := g.Casino.Participation(p.Name); playing {
+ if table != nil {
+ g.showCasinoHints(sess, table.Hints(p.Name))
+ } else if machine, ok := g.Casino.MachineFor(p.Name); ok {
+ g.showCasinoHints(sess, machine.Hints())
+ }
+ return
+ }
+ }
+ showAll := len(args) == 1 && strings.ToLower(args[0]) == "all"
+
+ rc := g.collectRoomCommands(sess)
+
+ hasRoomCmds := len(rc.objects) > 0 || len(rc.mobs) > 0 || len(rc.exits) > 0 || len(rc.ground) > 0
if hasRoomCmds {
- if len(sectionObjs) > 0 {
+ if len(rc.objects) > 0 {
sess.WriteLine("Objects:")
- writeCmdLines(sess, sectionObjs)
+ writeCmdLines(sess, rc.objects)
}
- if len(sectionMobs) > 0 {
+ if len(rc.mobs) > 0 {
sess.WriteLine("Mobs:")
- writeCmdLines(sess, sectionMobs)
+ writeCmdLines(sess, rc.mobs)
}
- if len(sectionExits) > 0 {
+ if len(rc.exits) > 0 {
sess.WriteLine("Exits:")
- writeCmdLines(sess, sectionExits)
+ writeCmdLines(sess, rc.exits)
}
- if len(sectionGround) > 0 {
+ if len(rc.ground) > 0 {
sess.WriteLine("Ground:")
- writeCmdLines(sess, sectionGround)
+ writeCmdLines(sess, rc.ground)
}
} else {
sess.WriteLine("There is nothing notable to interact with here.")