! ----------------------------------------------------------------------------
! ADNAME - This Inform library provides a system of 'adnames', words which may
!          be used to refer to objects without themselves implicating that the
!          object name has been typed. For example, you'd want "GET TOILET
!          PAPER" to choose the toilet paper, but you wouldn't want "GET
!          TOILET" to, especially if there was also a toilet in scope.
!          Adnames are typically adjectives or other describing words (in the
!          above example, "TOILET" is the adname of the toilet paper). If you
!          want to give an object an adname, make it of class "adnc" and give
!          it the "adname" property. This property, like "name", takes a list
!          of dictionary words. Caution: unlike name, which is a special case,
!          adname names are in single quotes.
!
!          This library provides a solution similar to the answer to example
!          60 in the Inform Designers' Manual, except that groups of identical
!          objects are handled correctly. There is also (for flexibility) no
!          requirement that adnames come before names.
!
! Example  object coffin_stand "coffin stand"
!            class adnc
!            with
!              name "stand",
!              adname 'coffin' 'wooden',
!              description "You can refer to this smart wooden coffin \
!                           stand as 'coffin stand', but 'coffin' on its \
!                           own will mean the coffin itself.",
!            has
!              static;
!
!          Include this library before you define your objects.
!          (c) Andrew Clover, 1995, but freely usable. Release 1.
!          Compatible with Inform 5.5, library 5/12.
! ----------------------------------------------------------------------------

Property adname;
Class adnc
 with
   adname 0,
   parse_name
     [;
     return AdnameParser(self);           ! Calling another routine like
                                          ! this avoids excessive code
                                          ! duplication, and allows you
                                          ! to extend an object's parse_
                                          ! name routine whilst still
                                          ! calling the adname parser.
     ];

[ AdnameParser adobj w n i j a b succ fail;
 if (parser_action==##TheSame)
   {
   w= parser_one.&adname;
   n= (parser_one.#adname)/2;
   i= parser_two.&adname;
   j= (parser_two.#adname)/2;
   for (a= 0: a<n: a++)
     {
     fail= 1;
     for (b= 0: b<j: b++)
       if ((w-->a)==(i-->b))
         fail= 0;
     if (fail==1)
       return -2;
     }
   for (a= 0: a<j: a++)
     {
     fail= 1;
       for (b= 0: b<n: b++)
         if ((w-->b)==(i-->a))
           fail= 0;
     if (fail==1)
       return -2;
     }
   return 0;                              ! This bit adapted from the parser
                                          ! - check all words in adname of
                                          ! parser_one to see if they occur
                                          ! in adname of parser_two, then
                                          ! vice-versa. If either case is
                                          ! false, we say the objects are not
                                          ! the same (the player may type a
                                          ! word that distiguishes then); if
                                          ! both are true, we give the parser
                                          ! a crack at seeing if they're
                                          ! different (by looking at the name
                                          ! property).
   }
 else
   {
   n= 0;
   succ= 0;
   fail= 0;
   while (fail==0)
     {
     fail= 1;
     w= NextWord();
     for (i= 0: i<(adobj.#adname)/2: i++)
       {
       if (w==adobj.&adname-->i)
         fail= 0;
       }
     for (i= 0: i<(adobj.#name)/2: i++)
       {
       if (w==adobj.&name-->i)
         {
         fail= 0;
         succ= 1;
         }
       }
     n++;
     }
   if (succ==1)
     return n-1;
   else
     return 0;                            ! This is the bit of code executed
                                          ! normally (when the parser isn't
                                          ! trying to resolve identical
                                          ! objects). We just check that
                                          ! every word typed is in the adname
                                          ! or name property, and say that
                                          ! the phrase matches the object if
                                          ! any words are in the name.
   }
 ];