skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
/**
 * Does all the help stuff you know and love.
 * @author Pinkfish
 * @started Tue Nov  4 14:55:39 EST 1997
 */

#include <nroff.h>

#define SYNONYMS "/doc/SYNONYMS"
#define MATCH_THRESHOLD 55

private nosave mapping help_files_player, help_files_creator, help_files_pt;
private nosave mapping synonyms;
private nosave string *player_dirs, *creator_dirs, *pt_dirs;

/**
 * Reads in the directories and places the results neatly into a mapping.
 * @param directories the directories to recursively read
 * @return a mapping with the locations of the help files
 */
private mapping read_directories( string *directories ) {
    string fname, dir;
    mixed file, files;
    mapping ret;
    int i;

    ret = ([ ]);
    for( i = 0; i < sizeof(directories); i++ ) {
        dir = directories[i];
        files = get_dir( dir+"*", -1 ) - ({"ERROR_REPORTS"});
        foreach( file in files ) {
            fname = file[0];
            if( file[1] == -2 ) {
                if( fname != "." &&
                    fname != ".." &&
                    fname != "old" &&
                    fname != "RCS") {
                    directories += ({ dir + fname + "/" });
                }
            } else if( fname != "." && fname != ".." && fname != "old") {
                if( !ret[fname] )
                    ret[fname] = ({ dir + fname });
                else
                    ret[fname] += ({ dir + fname });

                // Turn '_' into spaces.
                if( strsrch( fname, "_") > 0 ) {
                    fname = replace( fname, "_", " ");
                    if( !ret[fname] )
                        ret[fname] = ({ dir + fname });
                    else
                        ret[fname] += ({ dir + fname });
                }
            }
        }
    }

    return ret;

} /* read_directories() */

private mapping read_synonyms() {
    string *bits, bit;
    mapping tmp;

    tmp = ([ ]);
    bits = explode( read_file(SYNONYMS), "\n");

    foreach( bit in bits ) {
        bits = explode( bit, " ");
        tmp[bits[0]] = bits[1];
    }

    return tmp;

} /* read_synonyms() */

/**
 * This goes through and recreates the hash table for the dirs.
 */
void rehash_dirs() {
    help_files_player = read_directories(player_dirs);
    help_files_creator = read_directories(creator_dirs);
    help_files_pt = read_directories(pt_dirs);
    synonyms = read_synonyms();
} /* rehash_dirs() */

void create() {
    // These dirs will all be depth searched...
    player_dirs = ({ "/doc/helpdir/",
                     "/doc/concepts/",
                     "/doc/known_command/",
                     "/doc/room/",
                     "/doc/object/"
                     });

    creator_dirs = ({ "/doc/creator/",
                      "/doc/driver/",
                      "/doc/policy/",
                      "/doc/new/"
                      });

    pt_dirs = ({"/doc/playtesters/"});

    unguarded( (: rehash_dirs() :) );

} /* create() */

int *find_match_in_array( string entry, string *items )  {
    int i, j, elength, ilength, this_match, best_match, best_try;

    elength = strlen( entry );
    best_match = this_match = -1;

    for( i = sizeof( items ) - 1; i >= 0; i--, this_match = 0 )  {
        ilength = strlen( items[ i ] );
        for( j = 0; j < elength  &&  j < ilength; j++ )
            if( entry[ j ] == items[ i ][ j ] ||
                entry[ j ] == items[ i ][ j - 1 + ( j == 0 ) ]  ||
                entry[ j ] == items[ i ][ j + 1 - ( j + 1 == ilength ) ] )
                ++this_match;

        this_match = 100 * this_match / ( j == elength ? ilength : elength );

        if( this_match > best_match )  {
            best_match = this_match;
            best_try = i;
        }
    }

    return ({ best_try, best_match });

} /* find_match_in_array() */

/** @ignore yes */
private string letter_name( int letter, int size ) {
    string ret;

    if( size > 26 ) {
        ret = "aa";
        ret[0] = 'a' + ( letter / 26 );
        ret[1] = 'a' + ( letter % 26 );
        return ret;
    }

    ret = "a";
    ret[0] = 'a' + letter;
    return ret;

} /* letter_name() */

/** @ignore yes */
private string start_letter( int size ) { return letter_name( 0, size ); }

/** @ignore yes */
private string end_letter( int size ) {
    return letter_name( size - 1, size );
} /* end_letter() */

/** @ignore yes */
private int query_number_from_string( string name, int size ) {
    int pos;

    if( size > 26) {
        if( strlen(name) != 2 )
            return -1;
        name = lower_case(name);
        if( name[0] < 'a' || name[0] > 'z' )
            return -1;
        if( name[1] < 'a' || name[1] > 'z' )
            return -1;
        pos = ( name[0] - 'a' ) * 26 + name[1] - 'a';
        if( pos >= size )
            return -1;
        return pos;
    }

    if( strlen(name) != 1 )
        return -1;
    name = lower_case(name);
    if( name[0] < 'a' || name[0] > 'z' )
        return -1;
    pos = name[0] - 'a';
    if( pos >= size )
        return -1;

    return pos;

} /* query_number_from_string() */

/** @ignore yes */
void do_help( mixed stuff ) {
    string str;

    str = evaluate(stuff[1]);

    if( !str || !strlen(str) ) {
        write("Broken help file!\n");
        return;
    }

    TP->more_string( str, stuff[0] );

} /* do_help() */

/*
 * Make a string from nroff input...
 */
private string nroff_file( string name, string nroff_dir ) {
    string nroff_fn, str;

    nroff_fn = nroff_dir + replace( name, "/", ".");
    str = NROFF_H->cat_file( nroff_fn, 1 );
    if( !str ) {
        NROFF_H->create_nroff( name, nroff_fn );
        str = NROFF_H->cat_file( nroff_fn, 0 );
    }

    return str;

} /* nroff_file() */

/**
 * This method nips through the list of names doing the nroff stuff.
 * The array which is returned is an array of arrays, each internal
 * array consists of a name and help string.
 * @param names the array of names to process
 * @param nroff_dir the nroff directory to use for the output
 * @return an array of arrays
 */
mixed create_help_files( string *names, string nroff_dir ) {
    mixed ret;
    string *bits, name;

    ret = ({ });
    foreach( name in names ) {
        bits = explode( name, "/");
        ret += ({ ({ bits[<1] + " (" + name + ")",
               (: nroff_file( $(name), $(nroff_dir) ) :) }) });
    }

    return ret;

} /* create_help_files() */

/**
 * Searches the lists for things which we might have help on.
 * The array which is returned is an array of arrays, each internal
 * array consists of a name and help string.
 * @param name the help to search for
 * @param creator is this a creator searching
 * @return an array of arrays
 */
mixed query_help_on( string name, int creator, int playtester ) {
    string *files, *tmp;

    files = ({ });
    name = replace_string( name, " ", "_");

    if( help_files_player[name] )
        files += create_help_files( help_files_player[name], NROFF_DIR );

    if( playtester && help_files_pt && help_files_pt[name] )
        files += create_help_files( help_files_pt[name], NROFF_DIR );

    if( creator ) {
        if( help_files_creator && help_files_creator[name] )
            files += create_help_files( help_files_creator[name], NROFF_DIR );
        if( tmp = AUTODOC_H->query_help_on_func(name) )
            files += create_help_files( tmp, NROFF_DIR );
    }

    return files;

} /* query_help_on() */

/*
 * Returns a list of possible help files...
 */
private mixed help_list( string name ) {
    string *stuff;
    mixed str;
    object *fluff, blue;

    stuff = query_help_on( name, creatorp(TP), playtesterp(TP) );

    if( name == "room" || name == "here") {
        str = ENV(TP)->help_function();
        if( pointerp(str) )
            stuff += str;
        else if( str )
            stuff += ({ ({ ENV(TP)->short(), str }) });
    }

    if( stringp( str = TP->help_spell(name) ) )
        stuff += ({ ({ name + " (Spell)", (: $(str) :) }) });

    if( functionp(str) )
        stuff += ({ ({ name + " (Spell)", str }) });

    if( member_array( name, TP->query_channels() ) != -1 &&
        stringp( str = CHANNEL_H->channel_syntax( name, 1 ) ) )
        stuff += ({ ({ name + " (Channel)", (: $(str) :) }) });

    if( str = SOUL_H->help_string(name) )
        stuff += ({ ({ name + " (Soul)",
            (: $(SOUL_H)->help_string($(name)) :) }) });

    fluff = filter( match_objects_for_existence( name, ({ TP, ENV(TP) }) ),
        (: $1 && $1->help_function() :) );

    if( sizeof(fluff) )
        foreach( blue in fluff )
            stuff += blue->help_function();

    return stuff;

} /* help_list() */

/**
 * This method deals with the case where an entire string matches.
 * @param name the name to look for help on
 * @return 1 if the help was found, 0 if not
 */
int cmd( string name ) {
    mixed list;
    string suggestion, str;
    int *matches, i;

    list = help_list(name);

    // find out if they're looking for a synonym
    // eg. colour == colour or plan == finger.
    if( !sizeof(list) && mapp(synonyms) && synonyms[name] )
        list = help_list(synonyms[name]);

    if( !sizeof(list) ) {
        if( PLAYER_H->test_user(name) ) {
            add_failed_mess("That is a player, silly.\n");
            return 0;
        }

        // try a match for similarity.
        list = keys(help_files_player) + ({"command_list", "concepts"});
        matches = find_match_in_array( name, list );
        if( matches[1] > MATCH_THRESHOLD ) {
            suggestion = list[matches[0]];
        } else {
            // try a match for similarity among the synonyms
            list = keys(synonyms);
            matches = find_match_in_array( name, list );
            if( matches[1] > MATCH_THRESHOLD )
                suggestion = synonyms[list[matches[0]]];
        }

        if( !creatorp(TP) ) {
            log_file("MISSING_HELP", "%s %s looked for help on %s, "
                "recommended %s\n", ctime(time()), TP->query_name(),
                name, suggestion );
        }

        if( !suggestion )
            return notify_fail("Could not find any help on '"+name+"'.  You "
                "might find what you're looking for in 'help essentials'.\n");

        return notify_fail("Could not find any help on '"+name+"'.  Perhaps "
            "you are looking for "+suggestion+".\n");
    }

    if( sizeof(list) == 1 ) {
        if( creatorp(TP) )
            tell_object( TP, "Reading - "+list[0][0]+":\n");
        do_help(list[0]);
        return 1;
    }

    str = "";
    for( i = 0; i < sizeof(list); i++ )
        str += sprintf("%s) %s\n", letter_name( i, sizeof(list) ), list[i][0] );

    printf("%s help found multiple matches, please choose one of:\n"
      "%-*#s\nChoice: ", mud_name(), TP->query_cols(), str );

    input_to("help_input", 0, list );
    return 1;

} /* cmd() */

/**
 * The input loop for the help routines.
 * @param str the just inputed string
 * @param list the set of helps to choose from
 */
void help_input( string str, mixed list ) {
    int num;

    str = lower_case(str);

    if( str == "quit" || str == "**" || str == "." || str == "" ) {
        write("Ok, exiting help.\n");
        return ;
    }

    if( ( num = query_number_from_string( str, sizeof(list) ) ) == -1 ) {
        printf("Incorrect choice, must be between %s and %s.\nChoice: ",
            start_letter( sizeof(list) ), end_letter( sizeof(list) ) );
        input_to("help_input", 0, list );
        return;
    }

    if( creatorp(TP) )
        tell_object( TP, "Reading - "+list[num][0]+":\n");

    do_help(list[num]);

} /* help_input() */

/**
 * This method deals with the case where a command pattern was matched.
 * @param name the command to get help on
 * @return 0 if the command does not exist, 1 if it does exist
 */
int command_cmd( string name ) {
    mixed help;

    if( !help = TP->help_command(name) )
        return notify_fail("No such command as '"+name+"'.\n");

    if( functionp(help) )
        help = evaluate(help);

    TP->more_string( help, name );
    return 1;

} /* command_cmd() */

/**
 * This method deals with the case where a soul pattern was matched.
 * @param name the soul to get help on
 * @return 0 if the soul does not exist, 1 if it does exist
 */
int soul_cmd(string name) {
    string help;

    if( !help = SOUL_H->help_string(name) )
        return notify_fail("No such soul as '"+name+"'.\n");

    TP->more_string( help, name );
    return 1;

} /* soul_cmd() */

/**
 * This method deals with the case where a ritual or spell pattern was matched.
 * @param name the ritual or spell to get help on
 * @param spell 0 if it is a spell, 1 if it is a ritual
 * @return 0 if the ritual or spell does not exist, 1 if it does exist
 */
int spell_cmd(string name, int spell) {
    mixed help;

    if( !help = TP->help_spell(name) )
        return notify_fail("No such spell as '" + name + "'.\n");

    TP->more_string( ( functionp(help) ? evaluate(help) : help ), name );
    return 1;

} /* spell_cmd() */

/*
 * Print all the names of all the files in a dir...
 */
private void list_help( string title, string dir ) {
    string *files;

    files = get_dir( dir+"*") - ({".", "..", "ERROR_REPORTS", "RCS", "old"});
    printf("%s\n%-#*s\n", title, (int)TP->query_cols(),
        implode( files, "\n") );

} /* list_help() */

/**
 * This method gives the list of commands currently available.
 * @return always returns 1
 */
int command_list_cmd() {
    list_help("Command list, try 'help concepts' for a list of concepts.",
        "/doc/helpdir/");
    return 1;
} /* command_list_cmd() */

/**
 * This method gives the list of concepts currently available.
 * @return always returns 1
 */
int concepts_list_cmd() {
    list_help("Concepts list, try 'help command_list' for a list of commands.",
        "/doc/concepts/");
    return 1;
} /* concepts_list_cmd() */

string query_synonym( string name ) {
    if( mapp(synonyms) && synonyms[name] )
        return synonyms[name];
    return "";
} /* query_synonym() */

/**
 * This method returns the mapping of all the player help files.
 * @return the mapping of player help files
 */
mapping query_help_files_player() { return help_files_player; }

/**
 * This method returns the mapping of all the creator help files.
 * @return the mapping of creator help files
 */
mapping query_help_files_creator() { return help_files_creator; }

/**
 * This method returns the mapping of all the creator help files.
 * @return the mapping of creator help files
 */
mapping query_help_files_pt() { return help_files_pt; }

/** @ignore yes */
mixed query_patterns() {
    return ({ "<string>", (: cmd($4[0]) :),
      "command <string>", (: command_cmd($4[0]) :),
      "spell <string>", (: spell_cmd($4[0], 0 ) :),
      "ritual <string>", (: spell_cmd($4[0], 1 ) :),
      "soul <string>", (: soul_cmd($4[0]) :),
      "command_list", (: command_list_cmd() :),
      "concepts", (: concepts_list_cmd() :),
      "", (: concepts_list_cmd() :) });
} /* query_patterns() */

/** @ignore yes */
mixed stats() {
    return ({
        ({"player help files", sizeof( keys(help_files_player) ) }),
        ({"creator help files", sizeof( keys(help_files_creator) ) }),
        ({"playtester help files", sizeof( keys(help_files_pt) ) }),
        ({"autodoc help map", AUTODOC_H->query_help_map_size() }) ,
    });
} /* stats() */