lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* Do not remove the headers from this file! see /USAGE for more info. */

/*
** helpsys.c
**
** Standard help system object.  Interfaces with the Help Daemon to
** provide a complete help system to the user.  This object also acts
** as a modal input object via the standard input system functions.
**
** 26-OCT-94.  Created.  Deathblade.
** 14-APR-95   Wirehead added memory for old topcs vs. new ones.
*/

#include <mudlib.h>
#include <daemons.h>
#include <log.h>

inherit M_ACCESS;
inherit M_INPUT;
inherit M_ANSI;

private nosave string * topic_files;
private nosave string *	lines;
private nosave int	cur_line;
private nosave mapping	directives;

/* hack. */
private nosave int	i;

nomask void display_topics(mixed);
private nomask void receive_choice(string arg);
private nomask void receive_more(string arg);
private nomask void receive_topic(string arg);
private nomask void display_choice(string topic);

string array shorten(string array names)
{
  string array short = ({});
  mixed temp;
  string array dup = ({});
  string array ret = ({});
  string last;

  if(!sizeof(names))
    return ({});
  foreach(string name in names)
    short += ({explode(name, "/")[<1]});

  temp = unique_array(short, (:$1:));

  foreach(string array t in temp)
    if(sizeof(t)>1)
      dup += ({t[0]});

// dup is now an array of duplicate names

  for(int j=0;j<sizeof(names);j++)
  {
    if(member_array(short[j], dup)>-1)
      ret += ({names[j]});
    else
      ret += ({short[j]});
  }
  return ret;
}

private nomask string query_prompt()
{
  if ( topic_files )
    return sprintf("\nWhich topic to display? [1-%d,?]: ",
        sizeof(topic_files));

  if ( cur_line )
    return sprintf("--More--(%d%%) [?]: ", 100 * cur_line / sizeof(lines));

  return "\nHelp topic? [?]: ";
}

private nomask void quit_help()
{
  modal_pop();
  destruct(this_object());
}

private nomask int f_parse(string s)
{
  string * x;

  if ( s[0..1] != "$$" )
    return 1;

  if ( s[2] == '#' )
    return 0;

  if ( member_array(':', s) == -1 )
    directives[trim_spaces(s[2..])] = 1;
  else
  {
    x = explode(s[2..], ":");
    directives[trim_spaces(x[0])] = trim_spaces(x[1]);
  }

  return 0;
}

private nomask string last_component(string fname)
{
  return (explode(fname, "/") - ({ "" }))[<1];
}

private nomask void parse_directory(string fname) 
{
  string array files = get_dir(fname + "*") - ({ ".", ".." });
  string topic = last_component(fname);

  cur_line = 0;
  directives = ([]);

//  lines = ({"Help topics available under the general topic '" + topic + "':"}) +
//  map_array(files, (: "\t" + last_component($1) :));
  topic_files = map(files, (: $(fname) + ($1) :));
  display_choice(topic);
}

private nomask void parse_file(string fname)
{
  cur_line = 0;
  directives = ([ ]);

  if( file_size(fname) < 1)
  {
    lines = ({ "This file has no text.\n" });
    return;
  }
  if(wizardp(this_user()))
    write( sprintf("\n%*|s\n",this_user()->query_screen_width(),"["+fname+"]" ));
  lines = explode(read_file(fname), "\n");
  lines = filter_array(lines, (: f_parse :));

  if ( directives["see"] )
//### make this a bit more "in-your-face" ??
    lines += ({ "", "See also: " + directives["see"] });
}

/*
** present_topic()
**
** Present a topic to the user
*/
private nomask void present_topic(string fname)
{
  switch (file_size(fname))
  {
    case -1:
      lines = ({ "This helpfile no longer exists.", "Its reference will vanish next time help_d is updated" });
      topic_files = 0;
      break;
    case -2:
      parse_directory(fname);
//      write("\n");
//      more(lines);
      break;
    default:
      parse_file(fname);
      write("\n");
      more(lines);
      topic_files = 0;
  }

/*
 ** The current receive function is unknown on entry to this function.
 ** Make sure it is set correctly.  cur_line will be zero if print_lines()
 ** ends up printing everything.
 */
//    modal_push(cur_line ? (: receive_more :) : (: receive_topic :), (: query_prompt()  :));
}

private nomask string format_choice(string choice)
{
  return sprintf("%2d. %s", ++i, choice);
}

private nomask void display_choice(string topic)
{
//### need to devise a better scheme for presenting these.
//### preferably, we can use the topic's "parent".  if one
//### or more topics don't have parents, though... ??
//### not to mention that we don't have their parents until
//### we read the files.

  string array files = shorten(topic_files);
/* ack. must use a global to get the index to work */
  i = 0;

  write("There are multiple help files for \"" + topic + "\"\n" +
      "Please choose one:\n\n" +
//       implode(map_array(files, (: format_choice :)), "\n")
      colour_table(
          map_array(files, (: format_choice :)),
          this_user()->query_screen_width())
      + "\n");

   modal_func((: receive_choice :));
}

private nomask void lookup_topic(string topic)
{
  string * files;

  topic=replace_string(topic," ","_");

  files = HELP_D->find_topic(topic);
  if ( sizeof(files) == 0 )
  {
    write("\nSorry, there is no help on that topic (try: topics)\n\n");
    LOG_D->log(LOG_HELP_MISS,
        sprintf("%s: %s\n", this_user()->query_userid(), topic));
  }
  else if ( sizeof(files) == 1 )
  {
    present_topic(files[0]);
  } else {
    topic_files = files;
    display_choice(topic);
  }
}

private nomask void receive_choice(mixed arg)
{
  if(arg == -1)
    destruct(this_object());

  if ( arg )
    arg = trim_spaces(arg);

  if ( !arg || arg == "" || arg == "q" )
    quit_help();
  else if ( arg == "?" )
    write("\nThe following commands are available:\n\n" +
        "             q : quit using the help system.\n" +
        "             ? : this help.\n\n" +
	      "  <topic name> : will display help for the new topic.\n\n"
        );
  else if ( to_int(arg) > 0 )
  {
    int which;

    which = to_int(arg) - 1;
    if ( which >= sizeof(topic_files) )
	    printf("\nPlease type a number between 1 and %d.\n",
	      sizeof(topic_files));
    else
    {
	    present_topic(topic_files[which]);
	  }
  } else {
    topic_files = 0;
    lookup_topic(arg);
  }
}

private nomask void receive_more(mixed arg)
{
  if (arg == -1)
    destruct(this_object());
  if ( arg )
    arg = trim_spaces(arg);

  if ( arg == "q" )
    quit_help();
  else if ( arg == "?" )
  {
    write("\nThe following commands are available:\n\n" +
        "             q : quit using the help system.\n" +
        "             ? : this help.\n\n" +
        "      <return> : will display more of this help topic.\n" +
        "  <topic name> : will display help for the new topic.\n\n"
        );
//  }
//    else if ( arg == "topics" )
//    {
//	display_topics();
  } else if ( !arg || arg == "" ) {
    more(lines);
    if ( cur_line == 0 )
      modal_func((: receive_topic :));
  } else {
/*
 ** We will ignore the lookup and continue the "more" process or
 ** a topic will be found and we'll switch to that one.
 */
    lookup_topic(arg);
  }
}

private nomask void receive_topic(mixed arg)
{
  if (arg == -1)
    destruct(this_object());

  if ( arg )
    arg = trim_spaces(arg);

  if ( !arg || arg == "" || arg == "q" )
  {
    quit_help();
    return;
  }
  if ( arg == "?" )
    arg = "help";

  lookup_topic(arg);
}

nomask void begin_help(string topic)
{
  if( !topic || topic == "")
    topic = "topics";
  modal_push((: receive_topic :), (: query_prompt :));
  lookup_topic(topic);
}


//=====================================================
// NON-FUNCTIONAL ??
//=====================================================
// display_topic_columns and display_topics by Wirehead

private nomask void display_topic_columns(string *files, string header)
{
  int i;
  int n = sizeof(files);

  files = map_array(files, (: explode($1, "/")[<1] :) );
  write(header + "\n\n");
  for (i = 0; i < (n/2) + 1; i++)
  {
    if ((i == n/2) && (n % 2))
    {
      printf("\t%-20s\n", files[i]);
      break;
    }
    printf("\t%-20s%-20s\n", files[i], files[i + n/2]);
  }
}

// uses this_body()->query_help_topic() to determine what has been
// read recently.
nomask void display_topics(string *arr)
{
  string *new_stuff, *old_stuff;

  old_stuff = filter_array(arr,
      (: stat($1)[1] <= $(this_body())->query_help_topic($1) :));

  new_stuff = arr - old_stuff;
  if (sizeof(new_stuff))
    display_topic_columns(new_stuff, "Unread topics:");
  if (sizeof(old_stuff))
    display_topic_columns(old_stuff, "Topics already read:");
}

private void create(){ set_privilege(1); }