Coffee disambiguation (Inform 6 example)

From IFWiki

The main trick here is liberal use of the parse_name property to force the issue of when an object can or can't be referred to as just "coffee".

Constant Story "Coffee disambiguation example";
Constant Headline "^By David Welbourn for IFWiki^";
Release 1;

Constant MAX_SCORE = 0;
Constant DIALECT_US = 1;
Constant DEATH_MENTION_UNDO;

Include "Parser";

Object LibraryMessages		! see section 21 of the DM4
with
  before [;			! and english.h
    Fill:
      if (lm_o hasnt container) "You can only fill a container.";
      "But there's no coffee here to carry.";
  ];

Include "VerbLib";


Object Kitchen "Test Kitchen"
with
  description "This test kitchen is very clean. It's so clean,
    it hardly has anything in it. The living room is to the south.",
  s_to LivingRoom,
has light;

! The urn's parse_name forces the player to use the word 'urn'.
! 'coffee' is optional, but 'urn' is mandatory.
!
Object urn "coffee urn" Kitchen
with name 'coffee' 'urn',
  capacity 1,    ! Make sure no more than one thing inside the urn.
  description "The urn is large, round, and heavy. It has to be large
    to hold the endless supply of coffee inside it.
    Perhaps you'd like to pour some into a mug?",
  parse_name [ wd num gotit;
    wd = NextWord();
    while (WordInProperty(wd, self, name)) {
      if (wd == 'urn')
        gotit = true;
      num++; wd = NextWord();
    }
    if (~~gotit) return 0; return num;
  ],
  before [;
    Empty: "You can't empty the urn.";
    Fill: "The urn is already filled with an endless supply of coffee.";
    Pour: <<Pour supply second>>;
  ],
has open container static;

! The supply's parse_name might force the player to use the word 'endless' or 'supply'.
! If the cupful is present, 'endless' or 'supply' becomes mandatory.
! This means "verb coffee" won't refer to the supply when the cupful is a better choice.
!
Object supply "endless supply of coffee" urn
with name 'endless' 'supply' 'of' 'coffee',
  article "an",
  description "Hello, tall, dark, and endless.",
  parse_name [ wd num gotit;
    wd = NextWord();
    while (WordInProperty(wd, self, name)) {
      if (wd == 'endless' or 'supply')
        gotit = true;
      num++; wd = NextWord();
    }
    if (~~CommonAncestor(supply,cupful)) gotit = true;
    if (~~gotit) return 0; return num;
  ],
  before [;
    Drink, Taste: "How rude! Use a mug!";
    Smell: "Smells good. Endlessly good.";
    Take: "You can't carry a liquid in your bare hands!";
    Touch: "Hot.";
    Pour:
      if (second == 0) { second = mug; print "(into coffee mug)^"; }
      if (second ~= mug) print_ret "You can't pour coffee into ", (the) second, "!";
      if (mug notin player) "But you don't have a mug!";
      if (cupful in mug) "But the mug is full!";
      move cupful to mug; "Using the urn, you fill the mug with hot coffee.";
  ],
has ;

! The mug's parse_name might force the player to use the word 'mug' or 'cup'.
! If the cupful or supply is present, 'mug' or 'cup' becomes mandatory.
! This means "verb coffee" won't refer to the mug when either liquid is a better choice.
!
Object mug "coffee mug" Kitchen
with name 'coffee' 'mug' 'cup',
  capacity 1,    ! Make sure no more than one thing inside the mug.
  description [;
    print "The mug has the phrase 'WORLD'S BEST EXAMPLE CODER'
      prominently on the outside. The inside of the mug is ";
    if (cupful in mug) "full of coffee."; else "empty.";
  ],
  parse_name [ wd num gotit;
    wd = NextWord();
    while (WordInProperty(wd, self, name)) {
      if (wd == 'mug' or 'cup')
        gotit = true;
      num++; wd = NextWord();
    }
    if (cupful notin mug && location ~= Kitchen) gotit = true;
    if (~~gotit) return 0; return num;
  ],
  before [;
    Drink, Taste: if (cupful in mug) <<Drink cupful>>;
    Pour: if (cupful in mug) <<Pour cupful second>>;
          "The coffee mug is already empty.";
    Empty: if (cupful in mug) <<Pour cupful 0>>;
    Fill: if (urn in location) <<Pour supply mug>>;
          if (cupful in mug) "But the mug is full!";
  ],
has open container;

Object cupful "cupful of coffee"
with name 'cupful' 'of' 'coffee',
  description "The coffee in the mug looks quite drinkable.",
  before [;
    Drink, Taste: remove self; "You drink the mug of coffee. Aaah. The satisfaction.";
    Smell: "Smells good. A cupful of good.";
    Take: "You can't carry a liquid in your bare hands!";
    Pour:
      if (second == 0 && location == Kitchen) second = urn;
      if (second == urn) { remove cupful;
         "You pour the cupful of coffee back into the urn, untasted.";
      }
      if (second == 0) "There's no obvious place to pour the cupful of coffee.";
      "You can't pour coffee into ", (the) second, "!";
  ],
has ;


Object LivingRoom "Living Room"
with
  description "This pleasant living room is ever-so-lightly furnished
    with a coffee table. A kitchen can be found to the north.",
  n_to Kitchen,
has light;

! The table's parse_name might force the player to use the word 'table'.
! If the cupful is present, 'table' becomes mandatory.
! This means "verb coffee" won't refer to the table when the cupful is a better choice.
!
Object coffeetable "coffee table" LivingRoom
with name 'coffee' 'table',
  description "The coffee table is a modern piece of furniture
               with metal legs and a square glass top.",
  parse_name [ wd num gotit;
    wd = NextWord();
    while (WordInProperty(wd, self, name)) {
      if (wd == 'table')
        gotit = true;
      num++; wd = NextWord();
    }
    if (~~CommonAncestor(coffeetable,cupful)) gotit = true;
    if (~~gotit) return 0; return num;
  ],
  before [;
    Enter: "The coffee table doesn't look strong enough to support your weight.";
    Receive: if (noun == supply or cupful) "Don't pour liquids directly on the table.";
  ],
has supporter scenery;


[ Initialise;
  location = LivingRoom;
  score = 0;
];

[ PourSub;
  "You can only pour liquids or containers containing liquids.";
];

Include "Grammar";

Verb 'pour'
 * noun                                -> Pour
 * noun 'in'/'into'/'on'/'onto' noun   -> Pour;