Concerning the Disambiguator

K.V.
07 May 2021, 00:04

> GET FROB
Which do you mean?

  1. the scenery frob
  2. the red herring frob
  3. the big blue frob

In Inform 7, we could put:

Does the player mean the big blue frob: it is very likely.

What if we used an optional attribute with a specific name which targets an object in Quest?

In ZIL, they used the generic tag.

So, if we put a "generic" attribute on the scenery frob and the red herring frob, each targeting the big blue frob object, the disambiguation script could say, "hey! I have 3 candidates! 2 of them have generic, and both of those target the 3rd candidate. That's it, then. Case closed. Going with with candidate 3!"


Thoughts? Suggestions?


mrangel
07 May 2021, 08:24

I think I can see how that works. But it might be simpler just to put "frob" in the alt attribute for the big blue one. That way it's a complete match and overrides partial ones.


K.V.
28 May 2021, 17:28

it might be simpler just to put "frob" in the alt attribute for the big blue one. That way it's a complete match and overrides partial ones.

That would probably handle things most of the time, but I've got the game I was messing with set up so that the alt attribute is the only thing checked to find the object from the player's input. All the frobs have "frob" in the alt somewhere.


Also, I figured out that I can just set the generic attribute on the target object, with generic set to the object itself.


This is not the game I was messing with. It's just a working example game. This example does not require the alt attributes, although I've added the "alternate" names anyway. (It's a habit.)

<!--Saved by Quest 5.8.7753.35184-->
<asl version="580">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="generic">
    <gameid>fa0a429f-a214-4559-bcbc-b419e81c6c5b</gameid>
    <version>1.0</version>
    <firstpublished>2021</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <isroom />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="old frob">
      <inherit name="editor_object" />
      <take type="boolean">false</take>
      <takemsg>It's too old and fragile to move.</takemsg>
      <alt type="stringlist">
        <value>frob</value>
        <value>old frob</value>
      </alt>
    </object>
    <object name="tiny frob">
      <inherit name="editor_object" />
      <takemsg>It's too small to get hold of.</takemsg>
      <alt type="stringlist">
        <value>frob</value>
        <value>tiny frob</value>
      </alt>
    </object>
    <object name="blue frob">
      <inherit name="editor_object" />
      <take />
      <generic type="object">blue frob</generic>
      <alt type="stringlist">
        <value>frob</value>
        <value>blue frob</value>
      </alt>
    </object>
  </object>
  <function name="ResolveNameFromList" parameters="variable, value, objtype, scope, secondaryscope" type="object"><![CDATA[
    value = Trim(LCase(value))
    fullmatches = NewObjectList()
    partialmatches = NewObjectList()
    foreach (obj, scope) {
      name = LCase(GetDisplayAlias(obj))
      CompareNames (name, value, obj, fullmatches, partialmatches)
      if (obj.alt <> null) {
        foreach (altname, obj.alt) {
          CompareNames (LCase(altname), value, obj, fullmatches, partialmatches)
        }
      }
    }
    // allow referring to objects from the previous command by gender or article
    if (objtype = "object" and game.lastobjects <> null) {
      foreach (obj, game.lastobjects) {
        CompareNames (LCase(obj.article), value, obj, fullmatches, partialmatches)
        CompareNames (LCase(obj.gender), value, obj, fullmatches, partialmatches)
      }
    }
    // Also check the secondary scope, but only if we have not found anything yet
    if (ListCount(fullmatches) = 0 and ListCount(partialmatches) = 0 and not secondaryscope = null) {
      foreach (obj, secondaryscope) {
        name = LCase(GetDisplayAlias(obj))
        CompareNames (name, value, obj, fullmatches, partialmatches)
        if (obj.alt <> null) {
          foreach (altname, obj.alt) {
            CompareNames (LCase(altname), value, obj, fullmatches, partialmatches)
          }
        }
      }
    }
    if (ListCount(fullmatches) = 1) {
      return (ListItem(fullmatches, 0))
    }
    else if (ListCount(fullmatches) = 0 and ListCount(partialmatches) = 1) {
      return (ListItem(partialmatches, 0))
    }
    else if (ListCount(fullmatches) + ListCount(partialmatches) = 0) {
      return (null)
    }
    else {
      game.disambiguating = true
      candidates = ListCompact(ListCombine(fullmatches, partialmatches))
      generic = false
      // msg(candidates)
      foreach (o, candidates) {
        if (HasAttribute(o,"generic")) {
          if (ListContains(ScopeVisible(),o.generic)) {
            generic = true
            generic_object = o.generic
          }
        }
      }
      // Added this line to resolve issue with new FinishTurn setup in 580
      // game.disambiguating = true
      if (LengthOf(variable) > 0) {
        // single object command, so after showing the menu, add the object to game.pov.currentcommandresolvedelements
        if (generic) {
          return (generic_object)
        }
        else {
          game.disambiguating = true
          game.pov.currentcommandpendingvariable = variable
          ShowMenu (DynamicTemplate("DisambiguateMenu", value), candidates, true) {
            varname = game.pov.currentcommandpendingvariable
            game.pov.currentcommandpendingvariable = null
            if (result <> null) {
              AddToResolvedNames (varname, GetObject(result))
            }
          }
        }
      }
      else {
        // multi-object command, so after showing the menu, add the object to the list
        game.pov.currentcommandmultiobjectpending = true
        if (generic) {
          list add (game.pov.currentcommandpendingobjectlist, generic_object)
          ResolveNextNameListItem
        }
        else {
          game.disambiguating = true
          ShowMenu (DynamicTemplate("DisambiguateMenu", value), candidates, true) {
            if (result <> null) {
              list add (game.pov.currentcommandpendingobjectlist, GetObject(result))
              ResolveNextNameListItem
            }
          }
        }
      }
      return (null)
    }
  ]]></function>
</asl>

image