! sha_hint.h by Ricardo Dague (this file can be used freely)
!
! This is an Inform include file which adds a simple hint system to a game. It adds the
! command "hint" which shows a list of hint topics. Typing "hint <topic>" repeatedly will
! show hints.
!
! Each hint is an object that is a child of hint_list, for example:
!
!     object toaster_hint "toaster"
!     with
!       name 'toaster',
!       description
!         "Edwin might help you if you gave him some toast."
!         "You can use the toaster."
!         "You need some bread."
!         ">PUT BREAD IN TOASTER THEN TURN TOASTER ON.";
!
! Then you add it to the list of topics with "move toaster_hint to hint_list", and the
! game dialog will be:
!
!     >HINT TOASTER
!     (1/4) Edwin might help you if you gave him some toast.
!
!     >HINT TOASTER
!     (2/4) You can use the toaster.
!
! And that command two more times gives the other two hints.
!
! The description property can be a list of strings, as above. Also it can be a routine
! which takes one argument, returning the number of hints if the argument is zero or
! printing them if it's a positive value.
!
! The previous example could have been written like:
!
!     object toaster_hint "toaster"
!     with
!       name 'toaster',
!       description [ code;
!         switch(code) {
!           0: return 4;
!           1: "Edwin might help you if you gave him some toast.";
!           2: "You can use the toaster.";
!           3: "You need some bread.";
!           4: ">PUT BREAD IN TOASTER THEN TURN TOASTER ON.";
!         }
!       ];
!

object hint_list
with
 number 0 0;

[ HintScope x;
 switch(scope_stage) {
   1: rfalse;
   2:
     objectloop(x in hint_list)
       PlaceInScope(x);
     rtrue;
   3: HintSub(true);
 }
];

[ HintSub err ct x;
 if(err || noun == 0) {
   hint_list.&number-->0 = 0;
   ct = children(hint_list);
   if(ct == 0)
     "There aren't any hints available now.";
   if(err)
     print "There are no hints for that topic, but there are for ";
   else
     print "You can get hints for ";
   objectloop(x in hint_list) {
#ifdef TARGET_ZCODE;
     style bold;
#ifnot; ! TARGET_GLULX
     glk($0086, 4); ! set subheader style
#endif; ! TARGET_
     if(~~((x provides short_name) && PrintOrRun(x,short_name,true)))
       print (object)x;
#ifdef TARGET_ZCODE;
     style roman;
#ifnot; ! TARGET_GLULX
     glk($0086, 0); ! set normal style
#endif; ! TARGET_
     ct--;
     if(ct == 1) print " or ";
     else if(ct > 1) print ", ";
   }
   ".";
 }
 if(noun ~= hint_list.&number-->0) {
   hint_list.&number-->0 = noun;
   hint_list.&number-->1 = 0;
 }
 if(metaclass(noun.description) ~= Routine) {
   ct = noun.#description/WORDSIZE;
   if(hint_list.&number-->1 == ct) {
     hint_list.&number-->1 = 0;
     "No more hints for that topic, type ~G~ to go back to the first one.";
   }
   print "(",hint_list.&number-->1+1,"/",ct,") ",
     (string)noun.&description-->(hint_list.&number-->1),"^";
   (hint_list.&number-->1)++;
   return;
 }
 ct = noun.description(0);
 if(hint_list.&number-->1 == ct) {
   hint_list.&number-->1 = 0;
   "No more hints for that topic, type ~G~ to go back to the first one.";
 }
 (hint_list.&number-->1)++;
 print "(",hint_list.&number-->1,"/",ct,") ";
 noun.description(hint_list.&number-->1);
];

verb meta 'hint' 'hints' 'help'
 * ->Hint
 * 'for'/'about'/'with' scope=HintScope ->Hint
 * scope=HintScope ->Hint;