! 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;
